summaryrefslogtreecommitdiffstats
path: root/source4/torture
diff options
context:
space:
mode:
Diffstat (limited to 'source4/torture')
-rw-r--r--source4/torture/auth/ntlmssp.c163
-rw-r--r--source4/torture/auth/pac.c741
-rw-r--r--source4/torture/auth/smbencrypt.c70
-rw-r--r--source4/torture/basic/aliases.c397
-rw-r--r--source4/torture/basic/attr.c437
-rw-r--r--source4/torture/basic/base.c2090
-rw-r--r--source4/torture/basic/charset.c209
-rw-r--r--source4/torture/basic/cxd_known.h8670
-rw-r--r--source4/torture/basic/delaywrite.c3095
-rw-r--r--source4/torture/basic/delete.c2624
-rw-r--r--source4/torture/basic/denytest.c2819
-rw-r--r--source4/torture/basic/dir.c171
-rw-r--r--source4/torture/basic/disconnect.c182
-rw-r--r--source4/torture/basic/locking.c811
-rw-r--r--source4/torture/basic/mangle_test.c208
-rw-r--r--source4/torture/basic/misc.c1003
-rw-r--r--source4/torture/basic/properties.c118
-rw-r--r--source4/torture/basic/rename.c98
-rw-r--r--source4/torture/basic/scanner.c623
-rw-r--r--source4/torture/basic/secleak.c77
-rw-r--r--source4/torture/basic/unlink.c91
-rw-r--r--source4/torture/basic/utable.c202
-rw-r--r--source4/torture/dfs/common.c71
-rw-r--r--source4/torture/dfs/domaindfs.c540
-rw-r--r--source4/torture/dns/dlz_bind9.c2514
-rw-r--r--source4/torture/dns/internal_dns.c189
-rw-r--r--source4/torture/dns/wscript_build19
-rw-r--r--source4/torture/drs/drs_init.c80
-rw-r--r--source4/torture/drs/drs_util.c167
-rw-r--r--source4/torture/drs/python/cracknames.py204
-rw-r--r--source4/torture/drs/python/delete_object.py376
-rw-r--r--source4/torture/drs/python/drs_base.py632
-rw-r--r--source4/torture/drs/python/fsmo.py152
-rw-r--r--source4/torture/drs/python/getnc_exop.py1304
-rw-r--r--source4/torture/drs/python/getnc_schema.py304
-rw-r--r--source4/torture/drs/python/getnc_unpriv.py306
-rw-r--r--source4/torture/drs/python/getncchanges.py1427
-rw-r--r--source4/torture/drs/python/link_conflicts.py763
-rw-r--r--source4/torture/drs/python/linked_attributes_drs.py162
-rw-r--r--source4/torture/drs/python/repl_move.py2608
-rw-r--r--source4/torture/drs/python/repl_rodc.py735
-rw-r--r--source4/torture/drs/python/repl_schema.py444
-rw-r--r--source4/torture/drs/python/repl_secdesc.py400
-rw-r--r--source4/torture/drs/python/replica_sync.py747
-rw-r--r--source4/torture/drs/python/replica_sync_rodc.py155
-rw-r--r--source4/torture/drs/python/ridalloc_exop.py802
-rw-r--r--source4/torture/drs/python/samba_tool_drs.py410
-rw-r--r--source4/torture/drs/python/samba_tool_drs_critical.py98
-rw-r--r--source4/torture/drs/python/samba_tool_drs_no_dns.py174
-rw-r--r--source4/torture/drs/python/samba_tool_drs_showrepl.py377
-rw-r--r--source4/torture/drs/rpc/dssync.c1072
-rw-r--r--source4/torture/drs/rpc/msds_intid.c792
-rw-r--r--source4/torture/drs/unit/prefixmap_tests.c900
-rw-r--r--source4/torture/drs/unit/schemainfo_tests.c740
-rw-r--r--source4/torture/drs/wscript_build12
-rw-r--r--source4/torture/gentest.c3463
-rw-r--r--source4/torture/gpo/apply.c390
-rw-r--r--source4/torture/gpo/gpo.c35
-rw-r--r--source4/torture/gpo/wscript_build13
-rw-r--r--source4/torture/krb5/kdc-canon-heimdal.c1091
-rw-r--r--source4/torture/krb5/kdc-heimdal.c1065
-rw-r--r--source4/torture/krb5/kdc-mit.c795
-rw-r--r--source4/torture/krb5/wscript_build19
-rw-r--r--source4/torture/ldap/basic.c1004
-rw-r--r--source4/torture/ldap/cldap.c179
-rw-r--r--source4/torture/ldap/cldapbench.c233
-rw-r--r--source4/torture/ldap/common.c135
-rw-r--r--source4/torture/ldap/ldap_sort.c158
-rw-r--r--source4/torture/ldap/nested_search.c206
-rw-r--r--source4/torture/ldap/netlogon.c668
-rw-r--r--source4/torture/ldap/schema.c408
-rw-r--r--source4/torture/ldap/session_expiry.c122
-rw-r--r--source4/torture/ldap/uptodatevector.c173
-rw-r--r--source4/torture/ldb/ldb.c1794
-rw-r--r--source4/torture/libnet/domain.c117
-rw-r--r--source4/torture/libnet/groupinfo.c128
-rw-r--r--source4/torture/libnet/groupman.c97
-rw-r--r--source4/torture/libnet/grouptest.h20
-rw-r--r--source4/torture/libnet/libnet.c70
-rw-r--r--source4/torture/libnet/libnet_BecomeDC.c191
-rw-r--r--source4/torture/libnet/libnet_domain.c440
-rw-r--r--source4/torture/libnet/libnet_group.c210
-rw-r--r--source4/torture/libnet/libnet_lookup.c191
-rw-r--r--source4/torture/libnet/libnet_rpc.c230
-rw-r--r--source4/torture/libnet/libnet_share.c285
-rw-r--r--source4/torture/libnet/libnet_user.c520
-rw-r--r--source4/torture/libnet/python/samr-test.py59
-rw-r--r--source4/torture/libnet/userinfo.c192
-rw-r--r--source4/torture/libnet/userman.c473
-rw-r--r--source4/torture/libnet/usertest.h42
-rw-r--r--source4/torture/libnet/utils.c556
-rw-r--r--source4/torture/libnetapi/libnetapi.c94
-rw-r--r--source4/torture/libnetapi/libnetapi_group.c522
-rw-r--r--source4/torture/libnetapi/libnetapi_server.c76
-rw-r--r--source4/torture/libnetapi/libnetapi_user.c487
-rw-r--r--source4/torture/libnetapi/wscript_build11
-rw-r--r--source4/torture/libsmbclient/libsmbclient.c1617
-rw-r--r--source4/torture/libsmbclient/wscript_build14
-rw-r--r--source4/torture/local/dbspeed.c268
-rw-r--r--source4/torture/local/fsrvp_state.c492
-rw-r--r--source4/torture/local/local.c105
-rw-r--r--source4/torture/local/mdspkt.c104
-rw-r--r--source4/torture/local/nss_tests.c1061
-rw-r--r--source4/torture/local/smbtorture_fullname.c31
-rw-r--r--source4/torture/local/torture.c85
-rw-r--r--source4/torture/local/verif_trailer.c99
-rw-r--r--source4/torture/local/wscript_build45
-rw-r--r--source4/torture/locktest.c700
-rw-r--r--source4/torture/man/gentest.1.xml162
-rw-r--r--source4/torture/man/locktest.1.xml160
-rw-r--r--source4/torture/man/masktest.1.xml142
-rw-r--r--source4/torture/man/smbtorture.1.xml253
-rw-r--r--source4/torture/masktest.c418
-rw-r--r--source4/torture/nbench/nbench.c309
-rw-r--r--source4/torture/nbench/nbio.c994
-rw-r--r--source4/torture/nbt/dgram.c699
-rw-r--r--source4/torture/nbt/nbt.c69
-rw-r--r--source4/torture/nbt/query.c115
-rw-r--r--source4/torture/nbt/register.c176
-rw-r--r--source4/torture/nbt/wins.c545
-rw-r--r--source4/torture/nbt/winsbench.c300
-rw-r--r--source4/torture/nbt/winsreplication.c9884
-rw-r--r--source4/torture/ndr/README21
-rw-r--r--source4/torture/ndr/atsvc.c215
-rw-r--r--source4/torture/ndr/backupkey.c163
-rw-r--r--source4/torture/ndr/cabinet.c4335
-rw-r--r--source4/torture/ndr/charset.c91
-rw-r--r--source4/torture/ndr/clusapi.c390
-rw-r--r--source4/torture/ndr/dcerpc.c148
-rw-r--r--source4/torture/ndr/dfs.c115
-rw-r--r--source4/torture/ndr/dfsblob.c85
-rw-r--r--source4/torture/ndr/dnsp.c389
-rw-r--r--source4/torture/ndr/drsblobs.c558
-rw-r--r--source4/torture/ndr/drsuapi.c309
-rw-r--r--source4/torture/ndr/epmap.c80
-rw-r--r--source4/torture/ndr/krb5pac.c705
-rw-r--r--source4/torture/ndr/lsa.c2229
-rw-r--r--source4/torture/ndr/nbt.c253
-rw-r--r--source4/torture/ndr/ndr.c831
-rw-r--r--source4/torture/ndr/ndr.h249
-rw-r--r--source4/torture/ndr/negoex.c100
-rw-r--r--source4/torture/ndr/netlogon.c825
-rw-r--r--source4/torture/ndr/ntlmssp.c296
-rw-r--r--source4/torture/ndr/ntprinting.c655
-rw-r--r--source4/torture/ndr/odj.c210
-rw-r--r--source4/torture/ndr/samr.c355
-rw-r--r--source4/torture/ndr/spoolss.c2064
-rw-r--r--source4/torture/ndr/string.c223
-rw-r--r--source4/torture/ndr/svcctl.c88
-rw-r--r--source4/torture/ndr/winreg.c620
-rw-r--r--source4/torture/ndr/winspool.c173
-rw-r--r--source4/torture/ndr/witness.c411
-rw-r--r--source4/torture/ntp/ntp_signd.c306
-rw-r--r--source4/torture/rap/printing.c711
-rw-r--r--source4/torture/rap/rap.c275
-rw-r--r--source4/torture/rap/rpc.c100
-rw-r--r--source4/torture/rap/sam.c376
-rw-r--r--source4/torture/raw/acls.c2556
-rw-r--r--source4/torture/raw/chkpath.c390
-rw-r--r--source4/torture/raw/close.c178
-rw-r--r--source4/torture/raw/composite.c417
-rw-r--r--source4/torture/raw/context.c893
-rw-r--r--source4/torture/raw/eas.c594
-rw-r--r--source4/torture/raw/ioctl.c191
-rw-r--r--source4/torture/raw/lock.c3586
-rw-r--r--source4/torture/raw/lockbench.c447
-rw-r--r--source4/torture/raw/lookuprate.c318
-rw-r--r--source4/torture/raw/missing.txt160
-rw-r--r--source4/torture/raw/mkdir.c171
-rw-r--r--source4/torture/raw/mux.c342
-rw-r--r--source4/torture/raw/notify.c2297
-rw-r--r--source4/torture/raw/offline.c514
-rw-r--r--source4/torture/raw/open.c2253
-rw-r--r--source4/torture/raw/openbench.c502
-rw-r--r--source4/torture/raw/oplock.c4672
-rw-r--r--source4/torture/raw/pingpong.c248
-rw-r--r--source4/torture/raw/qfileinfo.c1084
-rw-r--r--source4/torture/raw/qfsinfo.c340
-rw-r--r--source4/torture/raw/raw.c87
-rw-r--r--source4/torture/raw/read.c1039
-rw-r--r--source4/torture/raw/rename.c692
-rw-r--r--source4/torture/raw/samba3hide.c326
-rw-r--r--source4/torture/raw/samba3misc.c1137
-rw-r--r--source4/torture/raw/search.c1653
-rw-r--r--source4/torture/raw/seek.c242
-rw-r--r--source4/torture/raw/session.c446
-rw-r--r--source4/torture/raw/setfileinfo.c1152
-rw-r--r--source4/torture/raw/streams.c2091
-rw-r--r--source4/torture/raw/tconrate.c208
-rw-r--r--source4/torture/raw/unlink.c470
-rw-r--r--source4/torture/raw/write.c799
-rw-r--r--source4/torture/rpc/alter_context.c112
-rw-r--r--source4/torture/rpc/async_bind.c86
-rw-r--r--source4/torture/rpc/atsvc.c138
-rw-r--r--source4/torture/rpc/backupkey.c2431
-rw-r--r--source4/torture/rpc/bench.c152
-rw-r--r--source4/torture/rpc/bind.c245
-rw-r--r--source4/torture/rpc/browser.c124
-rw-r--r--source4/torture/rpc/clusapi.c4185
-rw-r--r--source4/torture/rpc/countcalls.c131
-rw-r--r--source4/torture/rpc/dfs.c651
-rw-r--r--source4/torture/rpc/drsuapi.c1049
-rw-r--r--source4/torture/rpc/drsuapi.h94
-rw-r--r--source4/torture/rpc/drsuapi_cracknames.c1087
-rw-r--r--source4/torture/rpc/drsuapi_w2k8.c334
-rw-r--r--source4/torture/rpc/dsgetinfo.c452
-rw-r--r--source4/torture/rpc/dssetup.c64
-rw-r--r--source4/torture/rpc/echo.c474
-rw-r--r--source4/torture/rpc/epmapper.c679
-rw-r--r--source4/torture/rpc/eventlog.c501
-rw-r--r--source4/torture/rpc/forest_trust.c914
-rw-r--r--source4/torture/rpc/frsapi.c276
-rw-r--r--source4/torture/rpc/fsrvp.c973
-rw-r--r--source4/torture/rpc/handles.c622
-rw-r--r--source4/torture/rpc/initshutdown.c116
-rw-r--r--source4/torture/rpc/iremotewinspool.c1090
-rw-r--r--source4/torture/rpc/iremotewinspool_common.c269
-rw-r--r--source4/torture/rpc/iremotewinspool_common.h110
-rw-r--r--source4/torture/rpc/iremotewinspool_driver.c840
-rw-r--r--source4/torture/rpc/join.c86
-rw-r--r--source4/torture/rpc/lsa.c5645
-rw-r--r--source4/torture/rpc/lsa_lookup.c428
-rw-r--r--source4/torture/rpc/mdssvc.c1056
-rw-r--r--source4/torture/rpc/mgmt.c328
-rw-r--r--source4/torture/rpc/netlogon.c6038
-rw-r--r--source4/torture/rpc/netlogon.h37
-rw-r--r--source4/torture/rpc/netlogon_crypto.c274
-rw-r--r--source4/torture/rpc/ntsvcs.c189
-rw-r--r--source4/torture/rpc/object_uuid.c85
-rw-r--r--source4/torture/rpc/remote_pac.c1425
-rw-r--r--source4/torture/rpc/rpc.c661
-rw-r--r--source4/torture/rpc/samba3rpc.c4729
-rw-r--r--source4/torture/rpc/samlogon.c2121
-rw-r--r--source4/torture/rpc/samr.c9466
-rw-r--r--source4/torture/rpc/samr_accessmask.c1197
-rw-r--r--source4/torture/rpc/samr_handletype.c217
-rw-r--r--source4/torture/rpc/samr_priv.c580
-rw-r--r--source4/torture/rpc/samsync.c1798
-rw-r--r--source4/torture/rpc/scanner.c187
-rw-r--r--source4/torture/rpc/schannel.c1338
-rw-r--r--source4/torture/rpc/session_key.c250
-rw-r--r--source4/torture/rpc/spoolss.c11705
-rw-r--r--source4/torture/rpc/spoolss_access.c905
-rw-r--r--source4/torture/rpc/spoolss_notify.c636
-rw-r--r--source4/torture/rpc/spoolss_win.c612
-rw-r--r--source4/torture/rpc/srvsvc.c1206
-rw-r--r--source4/torture/rpc/svcctl.c828
-rw-r--r--source4/torture/rpc/testjoin.c915
-rw-r--r--source4/torture/rpc/torture_rpc.h126
-rw-r--r--source4/torture/rpc/unixinfo.c149
-rw-r--r--source4/torture/rpc/winreg.c3335
-rw-r--r--source4/torture/rpc/witness.c911
-rw-r--r--source4/torture/rpc/wkssvc.c1458
-rw-r--r--source4/torture/shell.c326
-rw-r--r--source4/torture/smb2/acls.c3340
-rw-r--r--source4/torture/smb2/attr.c710
-rw-r--r--source4/torture/smb2/bench.c1376
-rw-r--r--source4/torture/smb2/block.c446
-rw-r--r--source4/torture/smb2/block.h43
-rw-r--r--source4/torture/smb2/charset.c235
-rw-r--r--source4/torture/smb2/compound.c2595
-rw-r--r--source4/torture/smb2/connect.c257
-rw-r--r--source4/torture/smb2/create.c3629
-rw-r--r--source4/torture/smb2/credits.c268
-rw-r--r--source4/torture/smb2/delete-on-close.c762
-rw-r--r--source4/torture/smb2/deny.c526
-rw-r--r--source4/torture/smb2/dir.c1606
-rw-r--r--source4/torture/smb2/dosmode.c254
-rw-r--r--source4/torture/smb2/durable_open.c2872
-rw-r--r--source4/torture/smb2/durable_v2_open.c2371
-rw-r--r--source4/torture/smb2/ea.c152
-rw-r--r--source4/torture/smb2/getinfo.c951
-rw-r--r--source4/torture/smb2/ioctl.c7552
-rw-r--r--source4/torture/smb2/lease.c4819
-rw-r--r--source4/torture/smb2/lease_break_handler.c161
-rw-r--r--source4/torture/smb2/lease_break_handler.h134
-rw-r--r--source4/torture/smb2/lock.c3513
-rw-r--r--source4/torture/smb2/mangle.c341
-rw-r--r--source4/torture/smb2/max_allowed.c248
-rw-r--r--source4/torture/smb2/maxfid.c149
-rw-r--r--source4/torture/smb2/maxwrite.c137
-rw-r--r--source4/torture/smb2/mkdir.c105
-rw-r--r--source4/torture/smb2/multichannel.c2743
-rw-r--r--source4/torture/smb2/notify.c2786
-rw-r--r--source4/torture/smb2/notify_disabled.c120
-rw-r--r--source4/torture/smb2/oplock.c5405
-rw-r--r--source4/torture/smb2/oplock_break_handler.c169
-rw-r--r--source4/torture/smb2/oplock_break_handler.h57
-rw-r--r--source4/torture/smb2/read.c573
-rw-r--r--source4/torture/smb2/read_write.c361
-rw-r--r--source4/torture/smb2/rename.c1751
-rw-r--r--source4/torture/smb2/replay.c5515
-rw-r--r--source4/torture/smb2/samba3misc.c189
-rw-r--r--source4/torture/smb2/scan.c265
-rw-r--r--source4/torture/smb2/secleak.c91
-rw-r--r--source4/torture/smb2/sessid.c100
-rw-r--r--source4/torture/smb2/session.c5670
-rw-r--r--source4/torture/smb2/setinfo.c410
-rw-r--r--source4/torture/smb2/sharemode.c755
-rw-r--r--source4/torture/smb2/smb2.c230
-rw-r--r--source4/torture/smb2/streams.c2424
-rw-r--r--source4/torture/smb2/tcon.c146
-rw-r--r--source4/torture/smb2/timestamps.c1344
-rw-r--r--source4/torture/smb2/util.c1045
-rw-r--r--source4/torture/smb2/wscript_build59
-rw-r--r--source4/torture/smbtorture.c770
-rw-r--r--source4/torture/smbtorture.h146
-rwxr-xr-xsource4/torture/tests/test_gentest.sh35
-rwxr-xr-xsource4/torture/tests/test_locktest.sh28
-rwxr-xr-xsource4/torture/tests/test_masktest.sh28
-rw-r--r--source4/torture/torture.c59
-rw-r--r--source4/torture/unix/unix.c40
-rw-r--r--source4/torture/unix/unix_info2.c503
-rw-r--r--source4/torture/unix/whoami.c433
-rw-r--r--source4/torture/util.h121
-rw-r--r--source4/torture/util_smb.c1020
-rw-r--r--source4/torture/vfs/acl_xattr.c281
-rw-r--r--source4/torture/vfs/fruit.c8839
-rw-r--r--source4/torture/vfs/vfs.c123
-rw-r--r--source4/torture/winbind/struct_based.c1190
-rw-r--r--source4/torture/winbind/winbind.c335
-rw-r--r--source4/torture/winbind/wscript_build10
-rw-r--r--source4/torture/wscript_build361
323 files changed, 297361 insertions, 0 deletions
diff --git a/source4/torture/auth/ntlmssp.c b/source4/torture/auth/ntlmssp.c
new file mode 100644
index 0000000..e549671
--- /dev/null
+++ b/source4/torture/auth/ntlmssp.c
@@ -0,0 +1,163 @@
+/*
+ Unix SMB/CIFS implementation.
+ Small self-tests for the NTLMSSP code
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
+#include "auth/ntlmssp/ntlmssp.h"
+#include "auth/ntlmssp/ntlmssp_private.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/torture.h"
+#include "param/param.h"
+#include "torture/auth/proto.h"
+
+static bool torture_ntlmssp_self_check(struct torture_context *tctx)
+{
+ struct gensec_security *gensec_security;
+ struct gensec_ntlmssp_context *gensec_ntlmssp;
+ struct ntlmssp_state *ntlmssp_state;
+ DATA_BLOB data;
+ DATA_BLOB sig, expected_sig;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ torture_assert_ntstatus_ok(tctx,
+ gensec_client_start(mem_ctx, &gensec_security,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)),
+ "gensec client start");
+
+ gensec_set_credentials(gensec_security, samba_cmdline_get_creds());
+
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
+
+ torture_assert_ntstatus_ok(tctx,
+ gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP),
+ "Failed to start GENSEC for NTLMSSP");
+
+ gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
+ struct gensec_ntlmssp_context);
+ ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+
+ ntlmssp_state->session_key = strhex_to_data_blob(tctx, "0102030405060708090a0b0c0d0e0f00");
+ dump_data_pw("NTLMSSP session key: \n",
+ ntlmssp_state->session_key.data,
+ ntlmssp_state->session_key.length);
+
+ ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_NTLM2;
+
+ torture_assert_ntstatus_ok(tctx,
+ ntlmssp_sign_init(ntlmssp_state),
+ "Failed to sign_init");
+
+ data = strhex_to_data_blob(tctx, "6a43494653");
+ gensec_ntlmssp_sign_packet(gensec_security, gensec_security,
+ data.data, data.length, data.data, data.length, &sig);
+
+ expected_sig = strhex_to_data_blob(tctx, "01000000e37f97f2544f4d7e00000000");
+
+ dump_data_pw("NTLMSSP calc sig: ", sig.data, sig.length);
+ dump_data_pw("NTLMSSP expected sig: ", expected_sig.data, expected_sig.length);
+
+ torture_assert_int_equal(tctx, sig.length, expected_sig.length, "Wrong sig length");
+
+ torture_assert_mem_equal(tctx, sig.data, expected_sig.data, sig.length,
+ "data mismatch");
+
+ torture_assert_ntstatus_equal(tctx,
+ gensec_ntlmssp_check_packet(gensec_security,
+ data.data, data.length, data.data, data.length, &sig),
+ NT_STATUS_ACCESS_DENIED, "Check of just signed packet (should fail, wrong end)");
+
+ ntlmssp_state->session_key = data_blob(NULL, 0);
+
+ torture_assert_ntstatus_equal(tctx,
+ gensec_ntlmssp_check_packet(gensec_security,
+ data.data, data.length, data.data, data.length, &sig),
+ NT_STATUS_NO_USER_SESSION_KEY, "Check of just signed packet without a session key should fail");
+
+ talloc_free(gensec_security);
+
+ torture_assert_ntstatus_ok(tctx,
+ gensec_client_start(mem_ctx, &gensec_security,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)),
+ "Failed to start GENSEC for NTLMSSP");
+
+ gensec_set_credentials(gensec_security, samba_cmdline_get_creds());
+
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
+
+ torture_assert_ntstatus_ok(tctx,
+ gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP),
+ "GENSEC start mech by oid");
+
+ gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data,
+ struct gensec_ntlmssp_context);
+ ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
+
+ ntlmssp_state->session_key = strhex_to_data_blob(tctx, "0102030405e538b0");
+ dump_data_pw("NTLMSSP session key: \n",
+ ntlmssp_state->session_key.data,
+ ntlmssp_state->session_key.length);
+
+ ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_KEY_EXCH;
+
+ torture_assert_ntstatus_ok(tctx,
+ ntlmssp_sign_init(ntlmssp_state),
+ "Failed to sign_init");
+
+ data = strhex_to_data_blob(tctx, "6a43494653");
+ gensec_ntlmssp_sign_packet(gensec_security, gensec_security,
+ data.data, data.length, data.data, data.length, &sig);
+
+ expected_sig = strhex_to_data_blob(tctx, "0100000078010900397420fe0e5a0f89");
+
+ dump_data_pw("NTLMSSP calc sig: ", sig.data, sig.length);
+ dump_data_pw("NTLMSSP expected sig: ", expected_sig.data, expected_sig.length);
+
+ torture_assert_int_equal(tctx, sig.length, expected_sig.length, "Wrong sig length");
+
+ torture_assert_mem_equal(tctx, sig.data+8, expected_sig.data+8, sig.length-8,
+ "data mismatch");
+
+ torture_assert_ntstatus_equal(tctx,
+ gensec_ntlmssp_check_packet(gensec_security,
+ data.data, data.length, data.data, data.length, &sig),
+ NT_STATUS_ACCESS_DENIED, "Check of just signed packet (should fail, wrong end)");
+
+ sig.length /= 2;
+
+ torture_assert_ntstatus_equal(tctx,
+ gensec_ntlmssp_check_packet(gensec_security,
+ data.data, data.length, data.data, data.length, &sig),
+ NT_STATUS_ACCESS_DENIED, "Check of just signed packet with short sig");
+
+ talloc_free(gensec_security);
+ return true;
+}
+
+struct torture_suite *torture_ntlmssp(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "ntlmssp");
+
+ torture_suite_add_simple_test(suite, "NTLMSSP self check",
+ torture_ntlmssp_self_check);
+
+ return suite;
+}
diff --git a/source4/torture/auth/pac.c b/source4/torture/auth/pac.c
new file mode 100644
index 0000000..8ba8ed4
--- /dev/null
+++ b/source4/torture/auth/pac.c
@@ -0,0 +1,741 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Validate the krb5 pac generation routines
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "auth/auth.h"
+#include "auth/kerberos/kerberos.h"
+#include "samba3/samba3.h"
+#include "libcli/security/security.h"
+#include "torture/torture.h"
+#include "auth/auth_sam_reply.h"
+#include "param/param.h"
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+#include "torture/auth/proto.h"
+#include "auth/kerberos/pac_utils.h"
+
+static bool torture_pac_self_check(struct torture_context *tctx)
+{
+ NTSTATUS nt_status;
+ DATA_BLOB tmp_blob;
+ struct PAC_DATA *pac_data;
+ struct PAC_LOGON_INFO *logon_info;
+ union netr_Validation validation;
+
+ /* Generate a nice, arbitrary keyblock */
+ uint8_t server_bytes[16];
+ uint8_t krbtgt_bytes[16];
+ krb5_keyblock server_keyblock;
+ krb5_keyblock krbtgt_keyblock;
+
+ krb5_error_code ret;
+
+ struct smb_krb5_context *smb_krb5_context;
+
+ struct auth_user_info_dc *user_info_dc;
+ struct auth_user_info_dc *user_info_dc_out;
+
+ krb5_principal client_principal;
+ time_t logon_time = time(NULL);
+
+ TALLOC_CTX *mem_ctx = tctx;
+
+ torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx,
+ tctx->lp_ctx,
+ &smb_krb5_context),
+ "smb_krb5_init_context");
+
+ generate_random_buffer(server_bytes, 16);
+ generate_random_buffer(krbtgt_bytes, 16);
+
+ ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
+ ENCTYPE_ARCFOUR_HMAC,
+ server_bytes, sizeof(server_bytes),
+ &server_keyblock);
+ torture_assert(tctx, !ret, talloc_asprintf(tctx,
+ "(self test) Server Keyblock encoding failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+
+ ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
+ ENCTYPE_ARCFOUR_HMAC,
+ krbtgt_bytes, sizeof(krbtgt_bytes),
+ &krbtgt_keyblock);
+ if (ret) {
+ char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx);
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(self test) KRBTGT Keyblock encoding failed: %s", err));
+ }
+
+ /* We need an input, and this one requires no underlying database */
+ nt_status = auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(tctx->lp_ctx), &user_info_dc);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ torture_fail(tctx, "auth_anonymous_user_info_dc");
+ }
+
+ ret = krb5_parse_name_flags(smb_krb5_context->krb5_context,
+ user_info_dc->info->account_name,
+ KRB5_PRINCIPAL_PARSE_NO_REALM,
+ &client_principal);
+ if (ret) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ torture_fail(tctx, "krb5_parse_name_flags(norealm)");
+ }
+
+ /* OK, go ahead and make a PAC */
+ ret = kerberos_create_pac(mem_ctx,
+ user_info_dc,
+ smb_krb5_context->krb5_context,
+ &krbtgt_keyblock,
+ &server_keyblock,
+ client_principal,
+ logon_time,
+ &tmp_blob);
+
+ if (ret) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(self test) PAC encoding failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+ }
+
+ dump_data(10,tmp_blob.data,tmp_blob.length);
+
+ /* Now check that we can read it back (using full decode and validate) */
+ nt_status = kerberos_decode_pac(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ &krbtgt_keyblock,
+ &server_keyblock,
+ client_principal,
+ logon_time,
+ &pac_data);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(self test) PAC decoding failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ /* Now check we can read it back (using Heimdal's pac parsing) */
+ nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ &user_info_dc_out, NULL, NULL);
+
+ /* The user's SID is the first element in the list */
+ if (!dom_sid_equal(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
+ &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
+ dom_sid_string(mem_ctx, &user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid),
+ dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
+ }
+ talloc_free(user_info_dc_out);
+
+ /* Now check that we can read it back (yet again) */
+ nt_status = kerberos_pac_logon_info(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ &krbtgt_keyblock,
+ &server_keyblock,
+ client_principal,
+ logon_time,
+ &logon_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(self test) PAC decoding (for logon info) failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
+
+ /* And make a server info from the samba-parsed PAC */
+ validation.sam3 = &logon_info->info3;
+ nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
+ "",
+ 3, &validation,
+ true, /* This user was authenticated */
+ &user_info_dc_out);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(self test) PAC decoding (make server info) failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ if (!dom_sid_equal(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
+ &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
+ dom_sid_string(mem_ctx, &user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid),
+ dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
+ }
+ return true;
+}
+
+
+/* This is the PAC generated on my test network, by my test Win2k3 server.
+ -- abartlet 2005-07-04
+*/
+
+static const uint8_t saved_pac[] = {
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x30, 0xdf, 0xa6, 0xcb,
+ 0x4f, 0x7d, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x7f, 0xc0, 0x3c, 0x4e, 0x59, 0x62, 0x73, 0xc5, 0x01, 0xc0, 0x3c, 0x4e, 0x59,
+ 0x62, 0x73, 0xc5, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x16, 0x00, 0x16, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0xed, 0x03, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x16, 0x00, 0x20, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00,
+ 0x41, 0x00, 0x4c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00,
+ 0x4e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x54, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4e, 0x00,
+ 0x4b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x11, 0x2f, 0xaf, 0xb5, 0x90, 0x04, 0x1b, 0xec, 0x50, 0x3b, 0xec, 0xdc,
+ 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x66, 0x28, 0xea, 0x37, 0x80, 0xc5, 0x01, 0x16, 0x00, 0x77, 0x00, 0x32, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x33, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x24, 0x00,
+ 0x76, 0xff, 0xff, 0xff, 0x37, 0xd5, 0xb0, 0xf7, 0x24, 0xf0, 0xd6, 0xd4, 0xec, 0x09, 0x86, 0x5a,
+ 0xa0, 0xe8, 0xc3, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xb4, 0xd8, 0xb8, 0xfe,
+ 0x83, 0xb3, 0x13, 0x3f, 0xfc, 0x5c, 0x41, 0xad, 0xe2, 0x64, 0x83, 0xe0, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Check with a known 'well formed' PAC, from my test server */
+static bool torture_pac_saved_check(struct torture_context *tctx)
+{
+ NTSTATUS nt_status;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB tmp_blob, validate_blob;
+ struct PAC_DATA *pac_data, pac_data2;
+ struct PAC_LOGON_INFO *logon_info;
+ union netr_Validation validation;
+ const char *pac_file, *pac_kdc_key, *pac_member_key;
+ struct auth_user_info_dc *user_info_dc_out;
+
+ krb5_keyblock server_keyblock;
+ krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p;
+ struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
+
+ krb5_error_code ret;
+ struct smb_krb5_context *smb_krb5_context;
+
+ const char *principal_string;
+ char *broken_principal_string;
+ krb5_principal client_principal;
+ const char *authtime_string;
+ time_t authtime;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx,
+ tctx->lp_ctx,
+ &smb_krb5_context),
+ "smb_krb5_init_context");
+
+ pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key",
+ "B286757148AF7FD252C53603A150B7E7");
+
+ pac_member_key = torture_setting_string(tctx, "pac_member_key",
+ "D217FAEAE5E6B5F95CCC94077AB8A5FC");
+
+ torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key);
+ torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key);
+
+ /* The krbtgt key in use when the above PAC was generated.
+ * This is an arcfour-hmac-md5 key, extracted with our 'net
+ * samdump' tool. */
+ if (*pac_kdc_key == 0) {
+ krbtgt_bytes = NULL;
+ } else {
+ krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
+ if (!krbtgt_bytes) {
+ torture_fail(tctx, "(saved test) Could not interpret krbtgt key");
+ }
+ }
+
+ krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
+ if (!krbsrv_bytes) {
+ torture_fail(tctx, "(saved test) Could not interpret krbsrv key");
+ }
+
+ ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
+ ENCTYPE_ARCFOUR_HMAC,
+ krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
+ &server_keyblock);
+ torture_assert(tctx, !ret,
+ talloc_asprintf(tctx,
+ "(saved test) Server Keyblock encoding failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+
+ if (krbtgt_bytes) {
+ ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
+ ENCTYPE_ARCFOUR_HMAC,
+ krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
+ &krbtgt_keyblock);
+ if (ret) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) Server Keyblock encoding failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+ }
+ krbtgt_keyblock_p = &krbtgt_keyblock;
+ } else {
+ krbtgt_keyblock_p = NULL;
+ }
+
+ pac_file = torture_setting_string(tctx, "pac_file", NULL);
+ if (pac_file) {
+ tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx);
+ torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file);
+ } else {
+ tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac));
+ }
+
+ dump_data(10,tmp_blob.data,tmp_blob.length);
+
+ principal_string = torture_setting_string(tctx, "pac_client_principal",
+ "w2003final$@WIN2K3.THINKER.LOCAL");
+
+ authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609");
+ authtime = strtoull(authtime_string, NULL, 0);
+
+ ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string,
+ &client_principal);
+ if (ret) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) parsing of client principal [%s] failed: %s",
+ principal_string,
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
+ }
+
+ /* Decode and verify the signaure on the PAC */
+ nt_status = kerberos_decode_pac(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ client_principal, authtime, &pac_data);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(saved test) PAC decoding failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ /* Now check we can read it back (using Heimdal's pac parsing) */
+ nt_status = kerberos_pac_blob_to_user_info_dc(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ &user_info_dc_out,
+ NULL, NULL);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(saved test) Heimdal PAC decoding failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ if (!pac_file &&
+ !dom_sid_equal(dom_sid_parse_talloc(mem_ctx,
+ "S-1-5-21-3048156945-3961193616-3706469200-1005"),
+ &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s",
+ "S-1-5-21-3048156945-3961193616-3706469200-1005",
+ dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
+ }
+
+ talloc_free(user_info_dc_out);
+
+ /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
+ nt_status = kerberos_pac_logon_info(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ client_principal, authtime, &logon_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) PAC decoding (for logon info) failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ validation.sam3 = &logon_info->info3;
+ nt_status = make_user_info_dc_netlogon_validation(mem_ctx,
+ "",
+ 3, &validation,
+ true, /* This user was authenticated */
+ &user_info_dc_out);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) PAC decoding (make server info) failed: %s",
+ nt_errstr(nt_status)));
+ }
+
+ if (!pac_file &&
+ !dom_sid_equal(dom_sid_parse_talloc(mem_ctx,
+ "S-1-5-21-3048156945-3961193616-3706469200-1005"),
+ &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) PAC Decode resulted in *different* domain SID: %s != %s",
+ "S-1-5-21-3048156945-3961193616-3706469200-1005",
+ dom_sid_string(mem_ctx, &user_info_dc_out->sids[PRIMARY_USER_SID_INDEX].sid)));
+ }
+
+ if (krbtgt_bytes == NULL) {
+ torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+ return true;
+ }
+
+ ret = kerberos_encode_pac(mem_ctx,
+ pac_data,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ &validate_blob);
+
+ if (ret != 0) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx, "(saved test) PAC push failed");
+ }
+
+ dump_data(10, validate_blob.data, validate_blob.length);
+
+ /* compare both the length and the data bytes after a
+ * pull/push cycle. This ensures we use the exact same
+ * pointer, padding etc algorithms as win2k3.
+ */
+ if (tmp_blob.length != validate_blob.length) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]",
+ (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
+ }
+
+ if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ DEBUG(0, ("tmp_data:\n"));
+ dump_data(0, tmp_blob.data, tmp_blob.length);
+ DEBUG(0, ("validate_blob:\n"));
+ dump_data(0, validate_blob.data, validate_blob.length);
+
+ torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
+ }
+
+ ret = kerberos_create_pac(mem_ctx,
+ user_info_dc_out,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ client_principal, authtime,
+ &validate_blob);
+
+ if (ret != 0) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx, "(saved test) regnerated PAC create failed");
+ }
+
+ dump_data(10,validate_blob.data,validate_blob.length);
+
+ /* compare both the length and the data bytes after a
+ * pull/push cycle. This ensures we use the exact same
+ * pointer, padding etc algorithms as win2k3.
+ */
+ if (tmp_blob.length != validate_blob.length) {
+ ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx,
+ &pac_data2,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
+ nt_status = ndr_map_error2ntstatus(ndr_err);
+ torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
+
+ NDR_PRINT_DEBUG(PAC_DATA, pac_data);
+
+ NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]",
+ (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
+ }
+
+ if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
+ ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx,
+ &pac_data2,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
+ nt_status = ndr_map_error2ntstatus(ndr_err);
+ torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
+
+ NDR_PRINT_DEBUG(PAC_DATA, pac_data);
+
+ NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ DEBUG(0, ("tmp_data:\n"));
+ dump_data(0, tmp_blob.data, tmp_blob.length);
+ DEBUG(0, ("validate_blob:\n"));
+ dump_data(0, validate_blob.data, validate_blob.length);
+
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
+ }
+
+ /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
+ nt_status = kerberos_decode_pac(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ client_principal,
+ authtime + 1, &pac_data);
+ if (NT_STATUS_IS_OK(nt_status)) {
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+ torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
+ }
+
+ /* Break the client principal */
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ broken_principal_string = talloc_strdup(mem_ctx, principal_string);
+ broken_principal_string[0]++;
+
+ ret = krb5_parse_name(smb_krb5_context->krb5_context,
+ broken_principal_string, &client_principal);
+ if (ret) {
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(saved test) parsing of broken client principal failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
+ }
+
+ nt_status = kerberos_decode_pac(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ client_principal,
+ authtime, &pac_data);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
+ }
+
+ /* Finally... Bugger up the signature, and check we fail the checksum */
+ tmp_blob.data[tmp_blob.length - 2]++;
+
+ nt_status = kerberos_decode_pac(mem_ctx,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p,
+ &server_keyblock,
+ client_principal,
+ authtime,
+ &pac_data);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
+ }
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ krbtgt_keyblock_p);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ return true;
+}
+
+struct torture_suite *torture_pac(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
+
+ torture_suite_add_simple_test(suite, "self check",
+ torture_pac_self_check);
+ torture_suite_add_simple_test(suite, "saved check",
+ torture_pac_saved_check);
+ return suite;
+}
diff --git a/source4/torture/auth/smbencrypt.c b/source4/torture/auth/smbencrypt.c
new file mode 100644
index 0000000..79c90eb
--- /dev/null
+++ b/source4/torture/auth/smbencrypt.c
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ tests for smbencrypt code
+
+ Copyright (C) Andrew Tridgell 2011
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/auth/libcli_auth.h"
+#include "torture/torture.h"
+#include "torture/auth/proto.h"
+
+static bool torture_deshash(struct torture_context *tctx)
+{
+ struct {
+ const char *input;
+ uint8_t output[16];
+ bool should_pass;
+ } testcases[] = {
+ { "",
+ { 0xAA, 0xD3, 0xB4, 0x35, 0xB5, 0x14, 0x04, 0xEE,
+ 0xAA, 0xD3, 0xB4, 0x35, 0xB5, 0x14, 0x04, 0xEE }, true},
+ { "abcdefgh",
+ { 0xE0, 0xC5, 0x10, 0x19, 0x9C, 0xC6, 0x6A, 0xBD,
+ 0x5A, 0xCD, 0xCD, 0x7C, 0x24, 0x7F, 0xA8, 0x3A }, true},
+ { "0123456789abc",
+ { 0x56, 0x45, 0xF1, 0x3F, 0x50, 0x08, 0x82, 0xB2,
+ 0x50, 0x79, 0x8A, 0xE6, 0x33, 0x38, 0xAF, 0xE9 }, true},
+ { "0123456789abcd",
+ { 0x56, 0x45, 0xF1, 0x3F, 0x50, 0x08, 0x82, 0xB2,
+ 0x1A, 0xC3, 0x88, 0x4B, 0x83, 0x32, 0x45, 0x40 }, true},
+ { "0123456789abcde",
+ { 0x56, 0x45, 0xF1, 0x3F, 0x50, 0x08, 0x82, 0xB2,
+ 0x1A, 0xC3, 0x88, 0x4B, 0x83, 0x32, 0x45, 0x40 }, false},
+ };
+ int i;
+ for (i=0; i<ARRAY_SIZE(testcases); i++) {
+ uint8_t res[16];
+ bool ret;
+ ret = E_deshash(testcases[i].input, res);
+ torture_assert(tctx, ret == testcases[i].should_pass,
+ "E_deshash bad result");
+ torture_assert_mem_equal(tctx, res, testcases[i].output, 16, "E_deshash bad return data");
+ }
+ return true;
+}
+
+struct torture_suite *torture_smbencrypt(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "smbencrypt");
+
+ torture_suite_add_simple_test(suite, "deshash check", torture_deshash);
+
+ return suite;
+}
diff --git a/source4/torture/basic/aliases.c b/source4/torture/basic/aliases.c
new file mode 100644
index 0000000..ee3ea50
--- /dev/null
+++ b/source4/torture/basic/aliases.c
@@ -0,0 +1,397 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB trans2 alias scanner
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../lib/util/dlinklist.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname);
+
+struct trans2_blobs {
+ struct trans2_blobs *next, *prev;
+ uint16_t level;
+ DATA_BLOB params, data;
+};
+
+/* look for aliases for a query */
+static bool gen_aliases(struct torture_context *tctx,
+ struct smbcli_state *cli, struct smb_trans2 *t2,
+ int level_offset)
+{
+ uint16_t level;
+ struct trans2_blobs *alias_blobs = NULL;
+ struct trans2_blobs *t2b, *t2b2;
+ int count=0, alias_count=0;
+
+ for (level=0;level<2000;level++) {
+ NTSTATUS status;
+
+ SSVAL(t2->in.params.data, level_offset, level);
+
+ status = smb_raw_trans2(cli->tree, tctx, t2);
+ if (!NT_STATUS_IS_OK(status)) continue;
+
+ t2b = talloc(tctx, struct trans2_blobs);
+ t2b->level = level;
+ t2b->params = t2->out.params;
+ t2b->data = t2->out.data;
+ DLIST_ADD(alias_blobs, t2b);
+ torture_comment(tctx,
+ "\tFound level %4u (0x%03x) of size %3d (0x%02x)\n",
+ level, level,
+ (int)t2b->data.length, (int)t2b->data.length);
+ count++;
+ }
+
+ torture_comment(tctx, "Found %d levels with success status\n", count);
+
+ for (t2b=alias_blobs; t2b; t2b=t2b->next) {
+ for (t2b2=alias_blobs; t2b2; t2b2=t2b2->next) {
+ if (t2b->level >= t2b2->level) continue;
+ if (data_blob_cmp(&t2b->params, &t2b2->params) == 0 &&
+ data_blob_cmp(&t2b->data, &t2b2->data) == 0) {
+ torture_comment(tctx,
+ "\tLevel %u (0x%x) and level %u (0x%x) are possible aliases\n",
+ t2b->level, t2b->level, t2b2->level, t2b2->level);
+ alias_count++;
+ }
+ }
+ }
+
+ torture_comment(tctx, "Found %d aliased levels\n", alias_count);
+
+ return true;
+}
+
+/* look for qfsinfo aliases */
+static bool qfsinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ struct smb_trans2 t2;
+ uint16_t setup = TRANSACT2_QFSINFO;
+
+ t2.in.max_param = 0;
+ t2.in.max_data = UINT16_MAX;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc_zero(tctx, 2);
+ t2.in.data = data_blob(NULL, 0);
+ ZERO_STRUCT(t2.out);
+
+ return gen_aliases(tctx, cli, &t2, 0);
+}
+
+/* look for qfileinfo aliases */
+static bool qfileinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ struct smb_trans2 t2;
+ uint16_t setup = TRANSACT2_QFILEINFO;
+ const char *fname = "\\qfileinfo_aliases.txt";
+ int fnum;
+
+ t2.in.max_param = 2;
+ t2.in.max_data = UINT16_MAX;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc_zero(tctx, 4);
+ t2.in.data = data_blob(NULL, 0);
+ ZERO_STRUCT(t2.out);
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = create_complex_file(cli, cli, fname);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
+ "open of %s failed (%s)", fname,
+ smbcli_errstr(cli->tree)));
+
+ smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
+
+ SSVAL(t2.in.params.data, 0, fnum);
+
+ if (!gen_aliases(tctx, cli, &t2, 2))
+ return false;
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ return true;
+}
+
+
+/* look for qpathinfo aliases */
+static bool qpathinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ struct smb_trans2 t2;
+ uint16_t setup = TRANSACT2_QPATHINFO;
+ const char *fname = "\\qpathinfo_aliases.txt";
+ int fnum;
+
+ ZERO_STRUCT(t2);
+ t2.in.max_param = 2;
+ t2.in.max_data = UINT16_MAX;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc_zero(tctx, 6);
+ t2.in.data = data_blob(NULL, 0);
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = create_complex_file(cli, cli, fname);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
+ "open of %s failed (%s)", fname,
+ smbcli_errstr(cli->tree)));
+
+ smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
+ smbcli_close(cli->tree, fnum);
+
+ SIVAL(t2.in.params.data, 2, 0);
+
+ smbcli_blob_append_string(cli->session, tctx, &t2.in.params,
+ fname, STR_TERMINATE);
+
+ if (!gen_aliases(tctx, cli, &t2, 0))
+ return false;
+
+ smbcli_unlink(cli->tree, fname);
+
+ return true;
+}
+
+
+/* look for trans2 findfirst aliases */
+static bool findfirst_aliases(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ struct smb_trans2 t2;
+ uint16_t setup = TRANSACT2_FINDFIRST;
+ const char *fname = "\\findfirst_aliases.txt";
+ int fnum;
+
+ ZERO_STRUCT(t2);
+ t2.in.max_param = 16;
+ t2.in.max_data = UINT16_MAX;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc_zero(tctx, 12);
+ t2.in.data = data_blob(NULL, 0);
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = create_complex_file(cli, cli, fname);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
+ "open of %s failed (%s)", fname,
+ smbcli_errstr(cli->tree)));
+
+ smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
+ smbcli_close(cli->tree, fnum);
+
+ SSVAL(t2.in.params.data, 0, 0);
+ SSVAL(t2.in.params.data, 2, 1);
+ SSVAL(t2.in.params.data, 4, FLAG_TRANS2_FIND_CLOSE);
+ SSVAL(t2.in.params.data, 6, 0);
+ SIVAL(t2.in.params.data, 8, 0);
+
+ smbcli_blob_append_string(cli->session, tctx, &t2.in.params,
+ fname, STR_TERMINATE);
+
+ if (!gen_aliases(tctx, cli, &t2, 6))
+ return false;
+
+ smbcli_unlink(cli->tree, fname);
+
+ return true;
+}
+
+
+
+/* look for aliases for a set function */
+static bool gen_set_aliases(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smb_trans2 *t2, int level_offset)
+{
+ uint16_t level;
+ struct trans2_blobs *alias_blobs = NULL;
+ struct trans2_blobs *t2b;
+ int count=0, dsize;
+
+ for (level=1;level<1100;level++) {
+ NTSTATUS status, status1;
+ SSVAL(t2->in.params.data, level_offset, level);
+
+ status1 = NT_STATUS_OK;
+
+ for (dsize=2; dsize<1024; dsize += 2) {
+ data_blob_free(&t2->in.data);
+ t2->in.data = data_blob(NULL, dsize);
+ data_blob_clear(&t2->in.data);
+ status = smb_raw_trans2(cli->tree, tctx, t2);
+ /* some error codes mean that this whole level doesn't exist */
+ if (NT_STATUS_EQUAL(NT_STATUS_INVALID_LEVEL, status) ||
+ NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, status) ||
+ NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) {
+ break;
+ }
+ if (NT_STATUS_IS_OK(status)) break;
+
+ /* invalid parameter means that the level exists at this
+ size, but the contents are wrong (not surprising with
+ all zeros!) */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) break;
+
+ /* this is the usual code for 'wrong size' */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INFO_LENGTH_MISMATCH)) {
+ continue;
+ }
+
+ if (!NT_STATUS_EQUAL(status, status1)) {
+ torture_comment(tctx, "level=%d size=%d %s\n", level, dsize, nt_errstr(status));
+ }
+ status1 = status;
+ }
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) continue;
+
+ t2b = talloc(tctx, struct trans2_blobs);
+ t2b->level = level;
+ t2b->params = t2->out.params;
+ t2b->data = t2->out.data;
+ DLIST_ADD(alias_blobs, t2b);
+ torture_comment(tctx,
+ "\tFound level %4u (0x%03x) of size %3d (0x%02x)\n",
+ level, level,
+ (int)t2->in.data.length, (int)t2->in.data.length);
+ count++;
+ }
+
+ torture_comment(tctx, "Found %d valid levels\n", count);
+
+ return true;
+}
+
+
+
+/* look for setfileinfo aliases */
+static bool setfileinfo_aliases(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ struct smb_trans2 t2;
+ uint16_t setup = TRANSACT2_SETFILEINFO;
+ const char *fname = "\\setfileinfo_aliases.txt";
+ int fnum;
+
+ ZERO_STRUCT(t2);
+ t2.in.max_param = 2;
+ t2.in.max_data = 0;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc_zero(tctx, 6);
+ t2.in.data = data_blob(NULL, 0);
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = create_complex_file(cli, cli, fname);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
+ "open of %s failed (%s)", fname,
+ smbcli_errstr(cli->tree)));
+
+ smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
+
+ SSVAL(t2.in.params.data, 0, fnum);
+ SSVAL(t2.in.params.data, 4, 0);
+
+ gen_set_aliases(tctx, cli, &t2, 2);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ return true;
+}
+
+/* look for setpathinfo aliases */
+static bool setpathinfo_aliases(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct smb_trans2 t2;
+ uint16_t setup = TRANSACT2_SETPATHINFO;
+ const char *fname = "\\setpathinfo_aliases.txt";
+ int fnum;
+
+ ZERO_STRUCT(t2);
+ t2.in.max_param = 32;
+ t2.in.max_data = UINT16_MAX;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc_zero(tctx, 4);
+ t2.in.data = data_blob(NULL, 0);
+
+ smbcli_unlink(cli->tree, fname);
+
+ fnum = create_complex_file(cli, cli, fname);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx,
+ "open of %s failed (%s)", fname,
+ smbcli_errstr(cli->tree)));
+
+ smbcli_write(cli->tree, fnum, 0, &t2, 0, sizeof(t2));
+ smbcli_close(cli->tree, fnum);
+
+ SSVAL(t2.in.params.data, 2, 0);
+
+ smbcli_blob_append_string(cli->session, tctx, &t2.in.params,
+ fname, STR_TERMINATE);
+
+ if (!gen_set_aliases(tctx, cli, &t2, 0))
+ return false;
+
+ torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli->tree, fname),
+ talloc_asprintf(tctx, "unlink: %s", smbcli_errstr(cli->tree)));
+
+ return true;
+}
+
+
+/* look for aliased info levels in trans2 calls */
+struct torture_suite *torture_trans2_aliases(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "aliases");
+
+ torture_suite_add_1smb_test(suite, "QFSINFO aliases", qfsinfo_aliases);
+ torture_suite_add_1smb_test(suite, "QFILEINFO aliases", qfileinfo_aliases);
+ torture_suite_add_1smb_test(suite, "QPATHINFO aliases", qpathinfo_aliases);
+ torture_suite_add_1smb_test(suite, "FINDFIRST aliases", findfirst_aliases);
+ torture_suite_add_1smb_test(suite, "setfileinfo_aliases", setfileinfo_aliases);
+ torture_suite_add_1smb_test(suite, "setpathinfo_aliases", setpathinfo_aliases);
+
+ return suite;
+}
diff --git a/source4/torture/basic/attr.c b/source4/torture/basic/attr.c
new file mode 100644
index 0000000..f2a554d
--- /dev/null
+++ b/source4/torture/basic/attr.c
@@ -0,0 +1,437 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ openattr tester
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "system/filesys.h"
+#include "libcli/security/security_descriptor.h"
+#include "torture/basic/proto.h"
+
+extern int torture_failures;
+
+#define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0)
+
+
+static const uint32_t open_attrs_table[] = {
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_ATTRIBUTE_ARCHIVE,
+ FILE_ATTRIBUTE_READONLY,
+ FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_SYSTEM,
+
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_SYSTEM,
+};
+
+struct trunc_open_results {
+ unsigned int num;
+ uint32_t init_attr;
+ uint32_t trunc_attr;
+ uint32_t result_attr;
+};
+
+static const struct trunc_open_results attr_results[] = {
+ { 0, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
+ { 1, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
+ { 2, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
+ { 16, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
+ { 17, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
+ { 18, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
+ { 51, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 54, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 56, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 68, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 71, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 73, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
+ { 99, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 102, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 104, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 116, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 119, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 121, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
+ { 170, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN },
+ { 173, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM },
+ { 227, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 230, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 232, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 244, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 247, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 249, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM }
+};
+
+
+bool torture_openattrtest(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *fname = "\\openattr.file";
+ int fnum1;
+ uint16_t attr;
+ unsigned int i, j, k, l;
+ int failures = 0;
+
+ for (k = 0, i = 0; i < sizeof(open_attrs_table)/sizeof(uint32_t); i++) {
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_WRITE_DATA,
+ open_attrs_table[i],
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open %d (1) of %s failed (%s)", i,
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close %d (1) of %s failed (%s)", i, fname,
+ smbcli_errstr(cli1->tree)));
+
+ for (j = 0; j < ARRAY_SIZE(open_attrs_table); j++) {
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA,
+ open_attrs_table[j],
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE, 0, 0);
+
+ if (fnum1 == -1) {
+ for (l = 0; l < ARRAY_SIZE(attr_results); l++) {
+ if (attr_results[l].num == k) {
+ torture_result(tctx, TORTURE_FAIL,
+ "[%d] trunc open 0x%x -> 0x%x of %s failed - should have succeeded !(%s)",
+ k, open_attrs_table[i],
+ open_attrs_table[j],
+ fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_exit);
+ }
+ }
+ if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_ACCESS_DENIED)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "[%d] trunc open 0x%x -> 0x%x failed with wrong error code %s",
+ k, open_attrs_table[i], open_attrs_table[j],
+ smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_exit);
+ }
+#if 0
+ torture_comment(tctx, "[%d] trunc open 0x%x -> 0x%x failed\n", k, open_attrs_table[i], open_attrs_table[j]);
+#endif
+ k++;
+ continue;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close %d (2) of %s failed (%s)", j,
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_getatr(cli1->tree, fname, &attr, NULL, NULL),
+ talloc_asprintf(tctx, "getatr(2) failed (%s)", smbcli_errstr(cli1->tree)));
+
+#if 0
+ torture_comment(tctx, "[%d] getatr check [0x%x] trunc [0x%x] got attr 0x%x\n",
+ k, open_attrs_table[i], open_attrs_table[j], attr );
+#endif
+
+ for (l = 0; l < ARRAY_SIZE(attr_results); l++) {
+ if (attr_results[l].num == k) {
+ if (attr != attr_results[l].result_attr ||
+ open_attrs_table[i] != attr_results[l].init_attr ||
+ open_attrs_table[j] != attr_results[l].trunc_attr) {
+ torture_result(tctx, TORTURE_FAIL,
+ "[%d] getatr check failed. [0x%x] trunc [0x%x] got attr 0x%x, should be 0x%x",
+ k, open_attrs_table[i],
+ open_attrs_table[j],
+ (unsigned int)attr,
+ attr_results[l].result_attr);
+ CHECK_MAX_FAILURES(error_exit);
+ }
+ break;
+ }
+ }
+ k++;
+ }
+ }
+error_exit:
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ if (failures) {
+ return false;
+ }
+ return true;
+}
+
+bool torture_winattrtest(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *fname = "\\winattr1.file";
+ const char *dname = "\\winattr1.dir";
+ int fnum1;
+ uint16_t attr;
+ uint16_t j;
+ uint32_t aceno;
+ int failures = 0;
+ union smb_fileinfo query, query_org;
+ NTSTATUS status;
+ struct security_descriptor *sd1, *sd2;
+ ZERO_STRUCT(query);
+ ZERO_STRUCT(query_org);
+
+ /* Test winattrs for file */
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Open a file*/
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open(1) of %s failed (%s)\n",
+ fname, smbcli_errstr(cli1->tree)));
+
+
+ /* Get security descriptor and store it*/
+ query_org.generic.level = RAW_FILEINFO_SEC_DESC;
+ query_org.generic.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli1->tree, tctx, &query_org);
+ if(!NT_STATUS_IS_OK(status)){
+ torture_comment(tctx, "smb_raw_fileinfo(1) of %s failed (%s)\n",
+ fname, nt_errstr(status));
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close(1) of %s failed (%s)\n",
+ fname, smbcli_errstr(cli1->tree)));
+ CHECK_MAX_FAILURES(error_exit_file);
+ }
+ sd1 = query_org.query_secdesc.out.sd;
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close(1) of %s failed (%s)\n",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /*Set and get attributes*/
+ for (j = 0; j < ARRAY_SIZE(open_attrs_table); j++) {
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_setatr(cli1->tree, fname, open_attrs_table[j],0),
+ talloc_asprintf(tctx, "setatr(2) failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_getatr(cli1->tree, fname, &attr, NULL, NULL),
+ talloc_asprintf(tctx, "getatr(2) failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ /* Check the result */
+ if((j == 0)&&(attr != FILE_ATTRIBUTE_ARCHIVE)){
+ torture_comment(tctx, "getatr check failed. \
+ Attr applied [0x%x], got attr [0x%x], \
+ should be [0x%x]",
+ open_attrs_table[j],
+ (uint16_t)attr,open_attrs_table[j +1]);
+ CHECK_MAX_FAILURES(error_exit_file);
+ }else{
+
+ if((j != 0) &&(attr != open_attrs_table[j])){
+ torture_comment(tctx, "getatr check failed. \
+ Attr applied [0x%x],got attr 0x%x, \
+ should be 0x%x ",
+ open_attrs_table[j], (uint16_t)attr,
+ open_attrs_table[j]);
+ CHECK_MAX_FAILURES(error_exit_file);
+ }
+
+ }
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY | O_CREAT,
+ DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open(2) of %s failed (%s)\n",
+ fname, smbcli_errstr(cli1->tree)));
+ /*Get security descriptor */
+ query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ query.query_secdesc.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli1->tree, tctx, &query);
+ if(!NT_STATUS_IS_OK(status)){
+ torture_comment(tctx,
+ "smb_raw_fileinfo(2) of %s failed (%s)\n",
+ fname, nt_errstr(status));
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close(2) of %s failed (%s)\n",
+ fname, smbcli_errstr(cli1->tree)));
+ CHECK_MAX_FAILURES(error_exit_file);
+ }
+ sd2 = query.query_secdesc.out.sd;
+
+ torture_assert_ntstatus_ok(tctx,smbcli_close(cli1->tree,fnum1),
+ talloc_asprintf(tctx, "close(2) of %s failed (%s)\n",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /*Compare security descriptors -- Must be same*/
+ for (aceno=0;(sd1->dacl&&aceno < sd1->dacl->num_aces);aceno++){
+ struct security_ace *ace1 = &sd1->dacl->aces[aceno];
+ struct security_ace *ace2 = &sd2->dacl->aces[aceno];
+
+ if (!security_ace_equal(ace1, ace2)) {
+ torture_comment(tctx,
+ "ACLs changed! Not expected!\n");
+ CHECK_MAX_FAILURES(error_exit_file);
+ }
+ }
+
+ torture_comment(tctx, "[%d] setattr = [0x%x] got attr 0x%x\n",
+ j, open_attrs_table[j], attr );
+
+ }
+
+error_exit_file:
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+/* Check for Directory. */
+
+ smbcli_deltree(cli1->tree, dname);
+ smbcli_rmdir(cli1->tree,dname);
+
+ /* Open a directory */
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_RIGHTS_DIR_ALL,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OPEN_IF,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ /*smbcli_mkdir(cli1->tree,dname);*/
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx,
+ "open (1) of %s failed (%s)",
+ dname, smbcli_errstr(cli1->tree)));
+
+
+ /* Get Security Descriptor */
+ query_org.generic.level = RAW_FILEINFO_SEC_DESC;
+ query_org.generic.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli1->tree, tctx, &query_org);
+ if(!NT_STATUS_IS_OK(status)){
+ torture_comment(tctx, "smb_raw_fileinfo(1) of %s failed (%s)\n",
+ dname, nt_errstr(status));
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close(1) of %s failed (%s)\n",
+ dname, smbcli_errstr(cli1->tree)));
+ CHECK_MAX_FAILURES(error_exit_dir);
+ }
+ sd1 = query_org.query_secdesc.out.sd;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close (1) of %s failed (%s)", dname,
+ smbcli_errstr(cli1->tree)));
+
+ /* Set and get win attributes*/
+ for (j = 1; j < ARRAY_SIZE(open_attrs_table); j++) {
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_setatr(cli1->tree, dname, open_attrs_table[j], 0),
+ talloc_asprintf(tctx, "setatr(2) failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_getatr(cli1->tree, dname, &attr, NULL, NULL),
+ talloc_asprintf(tctx, "getatr(2) failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_comment(tctx, "[%d] setatt = [0x%x] got attr 0x%x\n",
+ j, open_attrs_table[j], attr );
+
+ /* Check the result */
+ if(attr != (open_attrs_table[j]|FILE_ATTRIBUTE_DIRECTORY)){
+ torture_comment(tctx, "getatr check failed. set attr \
+ [0x%x], got attr 0x%x, should be 0x%x\n",
+ open_attrs_table[j],
+ (uint16_t)attr,
+ (unsigned int)(open_attrs_table[j]|FILE_ATTRIBUTE_DIRECTORY));
+ CHECK_MAX_FAILURES(error_exit_dir);
+ }
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_RIGHTS_DIR_READ,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OPEN,
+ 0,0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx,
+ "open (2) of %s failed (%s)",
+ dname, smbcli_errstr(cli1->tree)));
+ /* Get security descriptor */
+ query.generic.level = RAW_FILEINFO_SEC_DESC;
+ query.generic.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli1->tree, tctx, &query);
+ if(!NT_STATUS_IS_OK(status)){
+ torture_comment(tctx, "smb_raw_fileinfo(2) of %s failed\
+ (%s)\n", dname, nt_errstr(status));
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close (2) of %s failed (%s)", dname,
+ smbcli_errstr(cli1->tree)));
+ CHECK_MAX_FAILURES(error_exit_dir);
+ }
+ sd2 = query.query_secdesc.out.sd;
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close (2) of %s failed (%s)", dname,
+ smbcli_errstr(cli1->tree)));
+
+ /* Security descriptor must be same*/
+ for (aceno=0;(sd1->dacl&&aceno < sd1->dacl->num_aces);aceno++){
+ struct security_ace *ace1 = &sd1->dacl->aces[aceno];
+ struct security_ace *ace2 = &sd2->dacl->aces[aceno];
+
+ if (!security_ace_equal(ace1, ace2)) {
+ torture_comment(tctx,
+ "ACLs changed! Not expected!\n");
+ CHECK_MAX_FAILURES(error_exit_dir);
+ }
+ }
+
+ }
+error_exit_dir:
+ smbcli_deltree(cli1->tree, dname);
+ smbcli_rmdir(cli1->tree,dname);
+
+ if(failures)
+ return false;
+ return true;
+}
diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c
new file mode 100644
index 0000000..fc36e6b
--- /dev/null
+++ b/source4/torture/basic/base.c
@@ -0,0 +1,2090 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/basic/proto.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "torture/util.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/events/events.h"
+#include "param/param.h"
+
+
+#define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0)
+
+
+static struct smbcli_state *open_nbt_connection(struct torture_context *tctx)
+{
+ struct nbt_name called, calling;
+ struct smbcli_state *cli;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ struct smbcli_options options;
+ bool ok;
+
+ make_nbt_name_client(&calling, lpcfg_netbios_name(tctx->lp_ctx));
+
+ nbt_choose_called_name(NULL, &called, host, NBT_NAME_SERVER);
+
+ cli = smbcli_state_init(NULL);
+ if (!cli) {
+ torture_result(tctx, TORTURE_FAIL, "Failed initialize smbcli_struct to connect with %s\n", host);
+ goto failed;
+ }
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ ok = smbcli_socket_connect(cli, host, lpcfg_smb_ports(tctx->lp_ctx),
+ tctx->ev,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ &calling, &called);
+ if (!ok) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to connect with %s\n", host);
+ goto failed;
+ }
+
+ cli->transport = smbcli_transport_init(cli->sock, cli,
+ true, &cli->options);
+ cli->sock = NULL;
+ if (!cli->transport) {
+ torture_result(tctx, TORTURE_FAIL, "smbcli_transport_init failed\n");
+ goto failed;
+ }
+
+ return cli;
+
+failed:
+ talloc_free(cli);
+ return NULL;
+}
+
+static bool tcon_devtest(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *myshare, const char *devtype,
+ NTSTATUS expected_error)
+{
+ bool status;
+ const char *password = torture_setting_string(tctx, "password", NULL);
+
+ status = NT_STATUS_IS_OK(smbcli_tconX(cli, myshare, devtype,
+ password));
+
+ torture_comment(tctx, "Trying share %s with devtype %s\n", myshare, devtype);
+
+ if (NT_STATUS_IS_OK(expected_error)) {
+ if (!status) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "tconX to share %s with type %s "
+ "should have succeeded but failed",
+ myshare, devtype));
+ }
+ smbcli_tdis(cli);
+ } else {
+ if (status) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "tconx to share %s with type %s "
+ "should have failed but succeeded",
+ myshare, devtype));
+ } else {
+ if (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),
+ expected_error)) {
+ } else {
+ torture_fail(tctx, "Returned unexpected error");
+ }
+ }
+ }
+ return true;
+}
+
+
+
+/**
+test whether fnums and tids open on one VC are available on another (a major
+security hole)
+*/
+static bool run_fdpasstest(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = "\\fdpass.tst";
+ int fnum1, oldtid;
+ uint8_t buf[1024];
+
+ smbcli_unlink(cli1->tree, fname);
+
+ torture_comment(tctx, "Opening a file on connection 1\n");
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx,
+ "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
+
+ torture_comment(tctx, "writing to file on connection 1\n");
+
+ torture_assert(tctx,
+ smbcli_write(cli1->tree, fnum1, 0, "hello world\n", 0, 13) == 13,
+ talloc_asprintf(tctx,
+ "write failed (%s)\n", smbcli_errstr(cli1->tree)));
+
+ oldtid = cli2->tree->tid;
+ cli2->session->vuid = cli1->session->vuid;
+ cli2->tree->tid = cli1->tree->tid;
+ cli2->session->pid = cli1->session->pid;
+
+ torture_comment(tctx, "reading from file on connection 2\n");
+
+ torture_assert(tctx, smbcli_read(cli2->tree, fnum1, buf, 0, 13) != 13,
+ talloc_asprintf(tctx,
+ "read succeeded! nasty security hole [%s]\n", buf));
+
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_unlink(cli1->tree, fname);
+
+ cli2->tree->tid = oldtid;
+
+ return true;
+}
+
+/**
+ This checks how the getatr calls works
+*/
+static bool run_attrtest(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int fnum;
+ time_t t, t2;
+ const char *fname = "\\attrib123456789.tst";
+ bool correct = true;
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = smbcli_open(cli->tree, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ smbcli_close(cli->tree, fnum);
+
+ if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, fname, NULL, NULL, &t))) {
+ torture_result(tctx, TORTURE_FAIL, "getatr failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ }
+
+ torture_comment(tctx, "New file time is %s", ctime(&t));
+
+ if (labs(t - time(NULL)) > 60*60*24*10) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: SMBgetatr bug. time is %s",
+ ctime(&t));
+ t = time(NULL);
+ correct = false;
+ }
+
+ t2 = t-60*60*24; /* 1 day ago */
+
+ torture_comment(tctx, "Setting file time to %s", ctime(&t2));
+
+ if (NT_STATUS_IS_ERR(smbcli_setatr(cli->tree, fname, 0, t2))) {
+ torture_comment(tctx, "setatr failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = true;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_getatr(cli->tree, fname, NULL, NULL, &t))) {
+ torture_comment(tctx, "getatr failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = true;
+ }
+
+ torture_comment(tctx, "Retrieved file time as %s", ctime(&t));
+
+ if (t != t2) {
+ torture_comment(tctx, "ERROR: getatr/setatr bug. times are\n%s",
+ ctime(&t));
+ torture_comment(tctx, "%s", ctime(&t2));
+ correct = true;
+ }
+
+ smbcli_unlink(cli->tree, fname);
+
+ return correct;
+}
+
+/**
+ This checks a couple of trans2 calls
+*/
+static bool run_trans2test(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int fnum;
+ size_t size;
+ time_t c_time, a_time, m_time, w_time, m_time2;
+ const char *fname = "\\trans2.tst";
+ const char *dname = "\\trans2";
+ const char *fname2 = "\\trans2\\trans2.tst";
+ const char *pname;
+ bool correct = true;
+
+ smbcli_unlink(cli->tree, fname);
+
+ torture_comment(tctx, "Testing qfileinfo\n");
+
+ fnum = smbcli_open(cli->tree, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, NULL, &size, &c_time, &a_time, &m_time,
+ NULL, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qfileinfo failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ }
+
+ torture_comment(tctx, "Testing NAME_INFO\n");
+
+ if (NT_STATUS_IS_ERR(smbcli_qfilename(cli->tree, fnum, &pname))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qfilename failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ }
+
+ if (!pname || strcmp(pname, fname)) {
+ torture_result(tctx, TORTURE_FAIL, "qfilename gave different name? [%s] [%s]\n",
+ fname, pname);
+ correct = false;
+ }
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ fnum = smbcli_open(cli->tree, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ torture_comment(tctx, "Checking for sticky create times\n");
+
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo(cli->tree, fname, &c_time, &a_time, &m_time, &size, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ } else {
+ time_t t = time(NULL);
+
+ if (c_time != m_time) {
+ torture_comment(tctx, "create time=%s", ctime(&c_time));
+ torture_comment(tctx, "modify time=%s", ctime(&m_time));
+ torture_comment(tctx, "This system appears to have sticky create times\n");
+ }
+ if ((labs(a_time - t) > 60) && (a_time % (60*60) == 0)) {
+ torture_comment(tctx, "access time=%s", ctime(&a_time));
+ torture_result(tctx, TORTURE_FAIL, "This system appears to set a midnight access time\n");
+ correct = false;
+ }
+
+ if (labs(m_time - t) > 60*60*24*7) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: totally incorrect times - maybe word reversed? mtime=%s", ctime(&m_time));
+ correct = false;
+ }
+ }
+
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = smbcli_open(cli->tree, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ smbcli_close(cli->tree, fnum);
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, fname, &c_time, &a_time, &m_time, &w_time, &size, NULL, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo2 failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ } else {
+ if (w_time < 60*60*24*2) {
+ torture_comment(tctx, "write time=%s", ctime(&w_time));
+ torture_result(tctx, TORTURE_FAIL, "This system appears to set a initial 0 write time\n");
+ correct = false;
+ }
+ }
+
+ smbcli_unlink(cli->tree, fname);
+
+
+ /* check if the server updates the directory modification time
+ when creating a new file */
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: mkdir failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ }
+ sleep(3);
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, "\\trans2\\", &c_time, &a_time, &m_time, &w_time, &size, NULL, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo2 failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ }
+
+ fnum = smbcli_open(cli->tree, fname2,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ smbcli_write(cli->tree, fnum, 0, &fnum, 0, sizeof(fnum));
+ smbcli_close(cli->tree, fnum);
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, "\\trans2\\", &c_time, &a_time, &m_time2, &w_time, &size, NULL, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo2 failed (%s)\n", smbcli_errstr(cli->tree));
+ correct = false;
+ } else {
+ if (m_time2 == m_time) {
+ torture_result(tctx, TORTURE_FAIL, "This system does not update directory modification times\n");
+ correct = false;
+ }
+ }
+ smbcli_unlink(cli->tree, fname2);
+ smbcli_rmdir(cli->tree, dname);
+
+ return correct;
+}
+
+/* send smb negprot commands, not reading the response */
+static bool run_negprot_nowait(struct torture_context *tctx)
+{
+ int i;
+ struct smbcli_state *cli, *cli2;
+ bool correct = true;
+
+ torture_comment(tctx, "starting negprot nowait test\n");
+
+ cli = open_nbt_connection(tctx);
+ if (!cli) {
+ return false;
+ }
+
+ torture_comment(tctx, "Filling send buffer\n");
+
+ for (i=0;i<100;i++) {
+ struct tevent_req *req;
+ req = smb_raw_negotiate_send(cli, tctx->ev,
+ cli->transport,
+ PROTOCOL_CORE,
+ PROTOCOL_NT1);
+ tevent_loop_once(tctx->ev);
+ if (!tevent_req_is_in_progress(req)) {
+ NTSTATUS status;
+
+ status = smb_raw_negotiate_recv(req);
+ TALLOC_FREE(req);
+ if (i > 0) {
+ torture_comment(tctx, "Failed to fill pipe packet[%d] - %s (ignored)\n",
+ i+1, nt_errstr(status));
+ break;
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "Failed to fill pipe - %s \n",
+ nt_errstr(status));
+ torture_close_connection(cli);
+ return false;
+ }
+ }
+ }
+
+ torture_comment(tctx, "Opening secondary connection\n");
+ if (!torture_open_connection(&cli2, tctx, 1)) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to open secondary connection\n");
+ correct = false;
+ }
+
+ if (!torture_close_connection(cli2)) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to close secondary connection\n");
+ correct = false;
+ }
+
+ torture_close_connection(cli);
+
+ return correct;
+}
+
+/**
+ this checks to see if a secondary tconx can use open files from an
+ earlier tconx
+ */
+static bool run_tcon_test(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ const char *fname = "\\tcontest.tmp";
+ int fnum1;
+ uint16_t cnum1, cnum2, cnum3;
+ uint16_t vuid1, vuid2;
+ uint8_t buf[4];
+ bool ret = true;
+ struct smbcli_tree *tree1;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ const char *password = torture_setting_string(tctx, "password", NULL);
+
+ if (smbcli_deltree(cli->tree, fname) == -1) {
+ torture_comment(tctx, "unlink of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ }
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ cnum1 = cli->tree->tid;
+ vuid1 = cli->session->vuid;
+
+ memset(buf, 0, 4); /* init buf so valgrind won't complain */
+ if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) != 4) {
+ torture_result(tctx, TORTURE_FAIL, "initial write failed (%s)\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ tree1 = cli->tree; /* save old tree connection */
+ if (NT_STATUS_IS_ERR(smbcli_tconX(cli, share, "?????", password))) {
+ torture_result(tctx, TORTURE_FAIL, "%s refused 2nd tree connect (%s)\n", host,
+ smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ cnum2 = cli->tree->tid;
+ cnum3 = MAX(cnum1, cnum2) + 1; /* any invalid number */
+ vuid2 = cli->session->vuid + 1;
+
+ /* try a write with the wrong tid */
+ cli->tree->tid = cnum2;
+
+ if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) == 4) {
+ torture_result(tctx, TORTURE_FAIL, "* server allows write with wrong TID\n");
+ ret = false;
+ } else {
+ torture_comment(tctx, "server fails write with wrong TID : %s\n", smbcli_errstr(cli->tree));
+ }
+
+
+ /* try a write with an invalid tid */
+ cli->tree->tid = cnum3;
+
+ if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) == 4) {
+ torture_result(tctx, TORTURE_FAIL, "* server allows write with invalid TID\n");
+ ret = false;
+ } else {
+ torture_comment(tctx, "server fails write with invalid TID : %s\n", smbcli_errstr(cli->tree));
+ }
+
+ /* try a write with an invalid vuid */
+ cli->session->vuid = vuid2;
+ cli->tree->tid = cnum1;
+
+ if (smbcli_write(cli->tree, fnum1, 0, buf, 130, 4) == 4) {
+ torture_result(tctx, TORTURE_FAIL, "* server allows write with invalid VUID\n");
+ ret = false;
+ } else {
+ torture_comment(tctx, "server fails write with invalid VUID : %s\n", smbcli_errstr(cli->tree));
+ }
+
+ cli->session->vuid = vuid1;
+ cli->tree->tid = cnum1;
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum1))) {
+ torture_result(tctx, TORTURE_FAIL, "close failed (%s)\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ cli->tree->tid = cnum2;
+
+ if (NT_STATUS_IS_ERR(smbcli_tdis(cli))) {
+ torture_result(tctx, TORTURE_FAIL, "secondary tdis failed (%s)\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ cli->tree = tree1; /* restore initial tree */
+ cli->tree->tid = cnum1;
+
+ smbcli_unlink(tree1, fname);
+
+ return ret;
+}
+
+/**
+ checks for correct tconX support
+ */
+static bool run_tcon_devtype_test(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *share = torture_setting_string(tctx, "share", NULL);
+
+ if (!tcon_devtest(tctx, cli1, "IPC$", "A:", NT_STATUS_BAD_DEVICE_TYPE))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, "IPC$", "?????", NT_STATUS_OK))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, "IPC$", "LPT:", NT_STATUS_BAD_DEVICE_TYPE))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, "IPC$", "IPC", NT_STATUS_OK))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, "IPC$", "FOOBA", NT_STATUS_BAD_DEVICE_TYPE))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, share, "A:", NT_STATUS_OK))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, share, "?????", NT_STATUS_OK))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, share, "LPT:", NT_STATUS_BAD_DEVICE_TYPE))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, share, "IPC", NT_STATUS_BAD_DEVICE_TYPE))
+ return false;
+
+ if (!tcon_devtest(tctx, cli1, share, "FOOBA", NT_STATUS_BAD_DEVICE_TYPE))
+ return false;
+
+ return true;
+}
+
+static bool rw_torture2(struct torture_context *tctx,
+ struct smbcli_state *c1, struct smbcli_state *c2)
+{
+ const char *lockfname = "\\torture2.lck";
+ int fnum1;
+ int fnum2;
+ int i;
+ uint8_t buf[131072];
+ uint8_t buf_rd[131072];
+ bool correct = true;
+ ssize_t bytes_read, bytes_written;
+
+ torture_assert(tctx, smbcli_deltree(c1->tree, lockfname) != -1,
+ talloc_asprintf(tctx,
+ "unlink failed (%s)", smbcli_errstr(c1->tree)));
+
+ fnum1 = smbcli_open(c1->tree, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx,
+ "first open read/write of %s failed (%s)",
+ lockfname, smbcli_errstr(c1->tree)));
+ fnum2 = smbcli_open(c2->tree, lockfname, O_RDONLY,
+ DENY_NONE);
+ torture_assert(tctx, fnum2 != -1,
+ talloc_asprintf(tctx,
+ "second open read-only of %s failed (%s)",
+ lockfname, smbcli_errstr(c2->tree)));
+
+ torture_comment(tctx, "Checking data integrity over %d ops\n",
+ torture_numops);
+
+ for (i=0;i<torture_numops;i++)
+ {
+ size_t buf_size = ((unsigned int)random()%(sizeof(buf)-1))+ 1;
+ if (i % 10 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%d\r", i); fflush(stdout);
+ }
+ }
+
+ generate_random_buffer(buf, buf_size);
+
+ if ((bytes_written = smbcli_write(c1->tree, fnum1, 0, buf, 0, buf_size)) != buf_size) {
+ torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c1->tree));
+ torture_result(tctx, TORTURE_FAIL, "wrote %d, expected %d\n", (int)bytes_written, (int)buf_size);
+ correct = false;
+ break;
+ }
+
+ if ((bytes_read = smbcli_read(c2->tree, fnum2, buf_rd, 0, buf_size)) != buf_size) {
+ torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c2->tree));
+ torture_result(tctx, TORTURE_FAIL, "read %d, expected %d\n", (int)bytes_read, (int)buf_size);
+ correct = false;
+ break;
+ }
+
+ torture_assert_mem_equal(tctx, buf_rd, buf, buf_size,
+ "read/write compare failed\n");
+ }
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(c2->tree, fnum2),
+ talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(c2->tree)));
+ torture_assert_ntstatus_ok(tctx, smbcli_close(c1->tree, fnum1),
+ talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(c1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_unlink(c1->tree, lockfname),
+ talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(c1->tree)));
+
+ torture_comment(tctx, "\n");
+
+ return correct;
+}
+
+
+
+static bool run_readwritetest(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ torture_comment(tctx, "Running readwritetest v1\n");
+ if (!rw_torture2(tctx, cli1, cli2))
+ return false;
+
+ torture_comment(tctx, "Running readwritetest v2\n");
+
+ if (!rw_torture2(tctx, cli1, cli1))
+ return false;
+
+ return true;
+}
+
+/*
+test the timing of deferred open requests
+*/
+static bool run_deferopen(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
+{
+ const char *fname = "\\defer_open_test.dat";
+ int i = 0;
+ bool correct = true;
+ int nsec;
+ int msec;
+ double sec;
+ NTSTATUS status;
+
+ nsec = torture_setting_int(tctx, "sharedelay", 1000000);
+ msec = nsec / 1000;
+ sec = ((double)nsec) / ((double) 1000000);
+
+ torture_comment(tctx, "pid %u: Testing deferred open requests.\n",
+ (unsigned)getpid());
+
+ while (i < 4) {
+ int fnum = -1;
+ int j = 1;
+
+ do {
+ struct timeval tv;
+ tv = timeval_current();
+
+ torture_comment(tctx,
+ "pid %u: create[%d,%d]...\n",
+ (unsigned)getpid(), i, j);
+
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OPEN_IF, 0, 0);
+ status = smbcli_nt_error(cli->tree);
+
+ torture_comment(tctx,
+ "pid %u: create[%d,%d] gave fnum %d, status %s\n",
+ (unsigned)getpid(), i, j, fnum,
+ nt_errstr(status));
+
+ if (fnum != -1) {
+ break;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ double e = timeval_elapsed(&tv);
+
+ torture_comment(tctx, "pid %u: create[%d,%d] "
+ "time elapsed: %.2f (1 sec = %.2f)\n",
+ (unsigned)getpid(), i, j, e, sec);
+ if (e < (0.5 * sec) || e > ((1.5 * sec) + 1.5)) {
+ torture_comment(tctx, "pid %u: create[%d,%d] "
+ "timing incorrect\n",
+ (unsigned)getpid(), i, j);
+ torture_result(tctx, TORTURE_FAIL, "Timing incorrect %.2f violation 1 sec == %.2f\n",
+ e, sec);
+ return false;
+ }
+ }
+
+ j++;
+
+ } while (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
+
+ torture_comment(tctx,
+ "pid %u: create loop %d done: fnum %d, status %s\n",
+ (unsigned)getpid(), i, fnum, nt_errstr(status));
+
+ torture_assert(tctx, fnum != -1,
+ talloc_asprintf(tctx,
+ "pid %u: Failed to open %s, error=%s\n",
+ (unsigned)getpid(), fname,
+ smbcli_errstr(cli->tree)));
+
+ torture_comment(tctx, "pid %u: open %d\n", (unsigned)getpid(), i);
+
+ smb_msleep(10 * msec);
+
+ status = smbcli_close(cli->tree, fnum);
+
+ torture_comment(tctx, "pid %u: open %d closed, status %s\n",
+ (unsigned)getpid(), i, nt_errstr(status));
+
+ torture_assert(tctx, !NT_STATUS_IS_ERR(status),
+ talloc_asprintf(tctx,
+ "pid %u: Failed to close %s, "
+ "error=%s\n",
+ (unsigned)getpid(), fname,
+ smbcli_errstr(cli->tree)));
+
+ smb_msleep(2 * msec);
+
+ i++;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
+ /* All until the last unlink will fail with sharing violation
+ but also the last request can fail since the file could have
+ been successfully deleted by another (test) process */
+ status = smbcli_nt_error(cli->tree);
+ if ((!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION))
+ && (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))) {
+ torture_result(tctx, TORTURE_FAIL, "unlink of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ correct = false;
+ }
+ }
+
+ torture_comment(tctx, "pid %u: deferred test finished\n",
+ (unsigned)getpid());
+ return correct;
+}
+
+/**
+ Try with a wrong vuid and check error message.
+ */
+
+static bool run_vuidtest(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *fname = "\\vuid.tst";
+ int fnum;
+ size_t size;
+ time_t c_time, a_time, m_time;
+
+ NTSTATUS result;
+
+ smbcli_unlink(cli->tree, fname);
+
+ fnum = smbcli_open(cli->tree, fname,
+ O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+
+ cli->session->vuid += 1234;
+
+ torture_comment(tctx, "Testing qfileinfo with wrong vuid\n");
+
+ if (NT_STATUS_IS_OK(result = smbcli_qfileinfo(cli->tree, fnum, NULL,
+ &size, &c_time, &a_time,
+ &m_time, NULL, NULL))) {
+ torture_fail(tctx, "qfileinfo passed with wrong vuid");
+ }
+
+ if (!NT_STATUS_EQUAL(cli->transport->error.e.nt_status,
+ NT_STATUS_DOS(ERRSRV, ERRbaduid)) &&
+ !NT_STATUS_EQUAL(cli->transport->error.e.nt_status,
+ NT_STATUS_INVALID_HANDLE)) {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "qfileinfo should have returned DOS error "
+ "ERRSRV:ERRbaduid\n but returned %s",
+ smbcli_errstr(cli->tree)));
+ }
+
+ cli->session->vuid -= 1234;
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum),
+ talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(cli->tree)));
+
+ smbcli_unlink(cli->tree, fname);
+
+ return true;
+}
+
+/*
+ Test open mode returns on read-only files.
+ */
+ static bool run_opentest(struct torture_context *tctx, struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = "\\readonly.file";
+ char *control_char_fname;
+ int fnum1, fnum2;
+ uint8_t buf[20];
+ size_t fsize;
+ bool correct = true;
+ char *tmp_path;
+ int failures = 0;
+ int i;
+
+ control_char_fname = talloc_strdup(tctx, "\\readonly.afile");
+ torture_assert_not_null(tctx, control_char_fname, "asprintf failed\n");
+
+ for (i = 1; i <= 0x1f; i++) {
+ control_char_fname[10] = i;
+ fnum1 = smbcli_nt_create_full(cli1->tree, control_char_fname, 0, SEC_FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (!check_error(__location__, cli1, ERRDOS, ERRinvalidname,
+ NT_STATUS_OBJECT_NAME_INVALID)) {
+ torture_result(tctx, TORTURE_FAIL, "Error code should be NT_STATUS_OBJECT_NAME_INVALID, was %s for file with %d char\n",
+ smbcli_errstr(cli1->tree), i);
+ failures++;
+ }
+
+ if (fnum1 != -1) {
+ smbcli_close(cli1->tree, fnum1);
+ }
+ smbcli_setatr(cli1->tree, control_char_fname, 0, 0);
+ smbcli_unlink(cli1->tree, control_char_fname);
+ }
+ TALLOC_FREE(control_char_fname);
+
+ if (!failures)
+ torture_comment(tctx, "Create file with control char names passed.\n");
+
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_result(tctx, TORTURE_FAIL, "close2 failed (%s)\n", smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_setatr(cli1->tree, fname, FILE_ATTRIBUTE_READONLY, 0))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": smbcli_setatr failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test1);
+ return false;
+ }
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test1);
+ return false;
+ }
+
+ /* This will fail - but the error should be ERRnoaccess, not ERRbadshare. */
+ fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_ALL);
+
+ if (check_error(__location__, cli1, ERRDOS, ERRnoaccess,
+ NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "correct error code ERRDOS/ERRnoaccess returned\n");
+ }
+
+ torture_comment(tctx, "finished open test 1\n");
+
+error_test1:
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Now try not readonly and ensure ERRbadshare is returned. */
+
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ /* This will fail - but the error should be ERRshare. */
+ fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_ALL);
+
+ if (check_error(__location__, cli1, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION)) {
+ torture_comment(tctx, "correct error code ERRDOS/ERRbadshare returned\n");
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_result(tctx, TORTURE_FAIL, "close2 failed (%s)\n", smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ smbcli_unlink(cli1->tree, fname);
+
+ torture_comment(tctx, "finished open test 2\n");
+
+ /* Test truncate open disposition on file opened for read. */
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "(3) open (1) of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ /* write 20 bytes. */
+
+ memset(buf, '\0', 20);
+
+ if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, 20) != 20) {
+ torture_result(tctx, TORTURE_FAIL, "write failed (%s)\n", smbcli_errstr(cli1->tree));
+ correct = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_result(tctx, TORTURE_FAIL, "(3) close1 failed (%s)\n", smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ /* Ensure size == 20. */
+ if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (3) getatr failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test3);
+ return false;
+ }
+
+ if (fsize != 20) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (3) file size != 20\n");
+ CHECK_MAX_FAILURES(error_test3);
+ return false;
+ }
+
+ /* Now test if we can truncate a file opened for readonly. */
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY|O_TRUNC, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (3) open (2) of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test3);
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": close2 failed (%s)\n", smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ /* Ensure size == 0. */
+ if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (3) getatr failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test3);
+ return false;
+ }
+
+ if (fsize != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (3) file size != 0\n");
+ CHECK_MAX_FAILURES(error_test3);
+ return false;
+ }
+ torture_comment(tctx, "finished open test 3\n");
+error_test3:
+
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+
+ torture_comment(tctx, "Testing ctemp\n");
+ fnum1 = smbcli_ctemp(cli1->tree, "\\", &tmp_path);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": ctemp failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test4);
+ return false;
+ }
+ torture_comment(tctx, "ctemp gave path %s\n", tmp_path);
+
+error_test4:
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "close of temp failed (%s)\n", smbcli_errstr(cli1->tree));
+ }
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli1->tree, tmp_path))) {
+ torture_comment(tctx, "unlink of temp failed (%s)\n", smbcli_errstr(cli1->tree));
+ }
+
+ /* Test the non-io opens... */
+
+ torture_comment(tctx, "Test #1 testing 2 non-io opens (no delete)\n");
+ fnum1 = fnum2 = -1;
+ smbcli_setatr(cli2->tree, fname, 0, 0);
+ smbcli_unlink(cli2->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 1 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test10);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 1 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test10);
+ return false;
+ }
+
+ torture_comment(tctx, "non-io open test #1 passed.\n");
+error_test10:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 1 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+ if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 1 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ }
+
+ torture_comment(tctx, "Test #2 testing 2 non-io opens (first with delete)\n");
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 2 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test20);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 2 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test20);
+ return false;
+ }
+
+ torture_comment(tctx, "non-io open test #2 passed.\n");
+error_test20:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 1 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+ if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 1 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ torture_comment(tctx, "Test #3 testing 2 non-io opens (second with delete)\n");
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 3 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test30);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 3 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test30);
+ return false;
+ }
+
+ torture_comment(tctx, "non-io open test #3 passed.\n");
+error_test30:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 3 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+ if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 3 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ }
+
+ torture_comment(tctx, "Test #4 testing 2 non-io opens (both with delete)\n");
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 4 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test40);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum2 != -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 4 open 2 of %s SUCCEEDED - should have failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test40);
+ return false;
+ }
+
+ torture_comment(tctx, "Test 4 open 2 of %s gave %s (correct error should be %s)\n", fname, smbcli_errstr(cli2->tree), "sharing violation");
+
+ torture_comment(tctx, "non-io open test #4 passed.\n");
+error_test40:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 4 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+ if (fnum2 != -1 && NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 4 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ }
+
+ torture_comment(tctx, "Test #5 testing 2 non-io opens (both with delete - both with file share delete)\n");
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 5 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test50);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 5 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test50);
+ return false;
+ }
+
+ torture_comment(tctx, "non-io open test #5 passed.\n");
+error_test50:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 5 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 5 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ }
+
+ torture_comment(tctx, "Test #6 testing 1 non-io open, one io open\n");
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 6 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test60);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 6 open 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test60);
+ return false;
+ }
+
+ torture_comment(tctx, "non-io open test #6 passed.\n");
+error_test60:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 6 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 6 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ }
+
+ torture_comment(tctx, "Test #7 testing 1 non-io open, one io open with delete\n");
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 7 open 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test70);
+ return false;
+ }
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0, SEC_STD_DELETE|SEC_FILE_READ_ATTRIBUTE, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum2 != -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Test 7 open 2 of %s SUCCEEDED - should have failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ CHECK_MAX_FAILURES(error_test70);
+ return false;
+ }
+
+ torture_comment(tctx, "Test 7 open 2 of %s gave %s (correct error should be %s)\n", fname, smbcli_errstr(cli2->tree), "sharing violation");
+
+ torture_comment(tctx, "non-io open test #7 passed.\n");
+error_test70:
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_comment(tctx, "Test 7 close 1 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ }
+ if (fnum2 != -1 && NT_STATUS_IS_ERR(smbcli_close(cli2->tree, fnum2))) {
+ torture_comment(tctx, "Test 7 close 2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree));
+ }
+
+ torture_comment(tctx, "Test #8 testing one normal open, followed by lock, followed by open with truncate\n");
+ fnum1 = fnum2 = -1;
+ smbcli_unlink(cli1->tree, fname);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "(8) open (1) of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ /* write 20 bytes. */
+
+ memset(buf, '\0', 20);
+
+ if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, 20) != 20) {
+ torture_result(tctx, TORTURE_FAIL, "(8) write failed (%s)\n", smbcli_errstr(cli1->tree));
+ correct = false;
+ }
+
+ /* Ensure size == 20. */
+ if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (8) getatr (1) failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test80);
+ return false;
+ }
+
+ if (fsize != 20) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (8) file size %lu != 20\n", (unsigned long)fsize);
+ CHECK_MAX_FAILURES(error_test80);
+ return false;
+ }
+
+ /* Get an exclusive lock on the open file. */
+ if (NT_STATUS_IS_ERR(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (8) lock1 failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test80);
+ return false;
+ }
+
+ fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "(8) open (2) of %s with truncate failed (%s)\n", fname, smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ /* Ensure size == 0. */
+ if (NT_STATUS_IS_ERR(smbcli_getatr(cli1->tree, fname, NULL, &fsize, NULL))) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (8) getatr (2) failed (%s)\n", smbcli_errstr(cli1->tree));
+ CHECK_MAX_FAILURES(error_test80);
+ return false;
+ }
+
+ if (fsize != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": (8) file size %lu != 0\n", (unsigned long)fsize);
+ CHECK_MAX_FAILURES(error_test80);
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ torture_result(tctx, TORTURE_FAIL, "(8) close1 failed (%s)\n", smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum2))) {
+ torture_result(tctx, TORTURE_FAIL, "(8) close1 failed (%s)\n", smbcli_errstr(cli1->tree));
+ return false;
+ }
+
+error_test80:
+
+ torture_comment(tctx, "open test #8 passed.\n");
+
+ smbcli_unlink(cli1->tree, fname);
+
+ return failures > 0 ? false : correct;
+}
+
+/* FIRST_DESIRED_ACCESS 0xf019f */
+#define FIRST_DESIRED_ACCESS SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA|\
+ SEC_FILE_READ_EA| /* 0xf */ \
+ SEC_FILE_WRITE_EA|SEC_FILE_READ_ATTRIBUTE| /* 0x90 */ \
+ SEC_FILE_WRITE_ATTRIBUTE| /* 0x100 */ \
+ SEC_STD_DELETE|SEC_STD_READ_CONTROL|\
+ SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER /* 0xf0000 */
+/* SECOND_DESIRED_ACCESS 0xe0080 */
+#define SECOND_DESIRED_ACCESS SEC_FILE_READ_ATTRIBUTE| /* 0x80 */ \
+ SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC|\
+ SEC_STD_WRITE_OWNER /* 0xe0000 */
+
+#if 0
+#define THIRD_DESIRED_ACCESS FILE_READ_ATTRIBUTE| /* 0x80 */ \
+ READ_CONTROL|WRITE_DAC|\
+ SEC_FILE_READ_DATA|\
+ WRITE_OWNER /* */
+#endif
+
+
+
+/**
+ Test ntcreate calls made by xcopy
+ */
+static bool run_xcopy(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *fname = "\\test.txt";
+ int fnum1, fnum2;
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ FIRST_DESIRED_ACCESS,
+ FILE_ATTRIBUTE_ARCHIVE,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0x4044, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx,
+ "First open failed - %s", smbcli_errstr(cli1->tree)));
+
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SECOND_DESIRED_ACCESS, 0,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OPEN,
+ 0x200000, 0);
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
+ "second open failed - %s", smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+static bool run_iometer(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *fname = "\\iobw.tst";
+ int fnum;
+ size_t filesize;
+ NTSTATUS status;
+ char buf[2048];
+ int ops;
+
+ memset(buf, 0, sizeof(buf));
+
+ status = smbcli_getatr(cli->tree, fname, NULL, &filesize, NULL);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "smbcli_getatr failed: %s", nt_errstr(status)));
+
+ torture_comment(tctx, "size: %d\n", (int)filesize);
+
+ filesize -= (sizeof(buf) - 1);
+
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0x16,
+ 0x2019f, 0, 0x3, 3, 0x42, 0x3);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, "open failed: %s",
+ smbcli_errstr(cli->tree)));
+
+ ops = 0;
+
+ while (true) {
+ int i, num_reads, num_writes;
+
+ num_reads = random() % 10;
+ num_writes = random() % 3;
+
+ for (i=0; i<num_reads; i++) {
+ ssize_t res;
+ if (ops++ > torture_numops) {
+ return true;
+ }
+ res = smbcli_read(cli->tree, fnum, buf,
+ random() % filesize, sizeof(buf));
+ torture_assert(tctx, res == sizeof(buf),
+ talloc_asprintf(tctx, "read failed: %s",
+ smbcli_errstr(cli->tree)));
+ }
+ for (i=0; i<num_writes; i++) {
+ ssize_t res;
+ if (ops++ > torture_numops) {
+ return true;
+ }
+ res = smbcli_write(cli->tree, fnum, 0, buf,
+ random() % filesize, sizeof(buf));
+ torture_assert(tctx, res == sizeof(buf),
+ talloc_asprintf(tctx, "read failed: %s",
+ smbcli_errstr(cli->tree)));
+ }
+ }
+}
+
+/**
+ tries variants of chkpath
+ */
+static bool torture_chkpath_test(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int fnum;
+ bool ret;
+
+ torture_comment(tctx, "Testing valid and invalid paths\n");
+
+ /* cleanup from an old run */
+ smbcli_rmdir(cli->tree, "\\chkpath.dir\\dir2");
+ smbcli_unlink_wcard(cli->tree, "\\chkpath.dir\\*");
+ smbcli_rmdir(cli->tree, "\\chkpath.dir");
+
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\chkpath.dir"))) {
+ torture_result(tctx, TORTURE_FAIL, "mkdir1 failed : %s\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\chkpath.dir\\dir2"))) {
+ torture_result(tctx, TORTURE_FAIL, "mkdir2 failed : %s\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ fnum = smbcli_open(cli->tree, "\\chkpath.dir\\foo.txt", O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL, "open1 failed (%s)\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir"))) {
+ torture_result(tctx, TORTURE_FAIL, "chkpath1 failed: %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\dir2"))) {
+ torture_result(tctx, TORTURE_FAIL, "chkpath2 failed: %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\foo.txt"))) {
+ ret = check_error(__location__, cli, ERRDOS, ERRbadpath,
+ NT_STATUS_NOT_A_DIRECTORY);
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "* chkpath on a file should fail\n");
+ ret = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\bar.txt"))) {
+ ret = check_error(__location__, cli, ERRDOS, ERRbadpath,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "* chkpath on a non existent file should fail\n");
+ ret = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_chkpath(cli->tree, "\\chkpath.dir\\dirxx\\bar.txt"))) {
+ ret = check_error(__location__, cli, ERRDOS, ERRbadpath,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "* chkpath on a non existent component should fail\n");
+ ret = false;
+ }
+
+ smbcli_rmdir(cli->tree, "\\chkpath.dir\\dir2");
+ smbcli_unlink_wcard(cli->tree, "\\chkpath.dir\\*");
+ smbcli_rmdir(cli->tree, "\\chkpath.dir");
+
+ return ret;
+}
+
+/*
+ * This is a test to exercise some weird Samba3 error paths.
+ */
+
+static bool torture_samba3_errorpaths(struct torture_context *tctx)
+{
+ bool nt_status_support;
+ bool client_ntlmv2_auth;
+ struct smbcli_state *cli_nt = NULL, *cli_dos = NULL;
+ bool result = false;
+ int fnum;
+ const char *os2_fname = ".+,;=[].";
+ const char *dname = "samba3_errordir";
+ union smb_open io;
+ NTSTATUS status;
+
+ nt_status_support = lpcfg_nt_status_support(tctx->lp_ctx);
+ client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(tctx->lp_ctx);
+
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "yes")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = yes'\n");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "yes")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = yes'\n");
+ goto fail;
+ }
+
+ if (!torture_open_connection(&cli_nt, tctx, 0)) {
+ goto fail;
+ }
+
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = no'\n");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = no'\n");
+ goto fail;
+ }
+
+ if (!torture_open_connection(&cli_dos, tctx, 1)) {
+ goto fail;
+ }
+
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support",
+ nt_status_support ? "yes":"no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support'");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth",
+ client_ntlmv2_auth ? "yes":"no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not reset 'client ntlmv2 auth'");
+ goto fail;
+ }
+
+ smbcli_unlink(cli_nt->tree, os2_fname);
+ smbcli_rmdir(cli_nt->tree, dname);
+
+ if (!NT_STATUS_IS_OK(smbcli_mkdir(cli_nt->tree, dname))) {
+ torture_result(tctx, TORTURE_FAIL, "smbcli_mkdir(%s) failed: %s\n", dname,
+ smbcli_errstr(cli_nt->tree));
+ goto fail;
+ }
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 1024*1024;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli_nt->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s should be %s\n",
+ __location__, nt_errstr(status),
+ nt_errstr(NT_STATUS_OBJECT_NAME_COLLISION));
+ goto fail;
+ }
+ status = smb_raw_open(cli_dos->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRfilexists))) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s should be %s\n",
+ __location__, nt_errstr(status),
+ nt_errstr(NT_STATUS_DOS(ERRDOS, ERRfilexists)));
+ goto fail;
+ }
+
+ status = smbcli_mkdir(cli_nt->tree, dname);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s should be %s\n",
+ __location__, nt_errstr(status),
+ nt_errstr(NT_STATUS_OBJECT_NAME_COLLISION));
+ goto fail;
+ }
+ status = smbcli_mkdir(cli_dos->tree, dname);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnoaccess))) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s should be %s\n",
+ __location__, nt_errstr(status),
+ nt_errstr(NT_STATUS_DOS(ERRDOS, ERRnoaccess)));
+ goto fail;
+ }
+
+ {
+ union smb_mkdir md;
+ md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
+ md.t2mkdir.in.path = dname;
+ md.t2mkdir.in.num_eas = 0;
+ md.t2mkdir.in.eas = NULL;
+
+ status = smb_raw_mkdir(cli_nt->tree, &md);
+ if (!NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_COLLISION)) {
+ torture_comment(
+ tctx, "(%s) incorrect status %s should be "
+ "NT_STATUS_OBJECT_NAME_COLLISION\n",
+ __location__, nt_errstr(status));
+ goto fail;
+ }
+ status = smb_raw_mkdir(cli_dos->tree, &md);
+ if (!NT_STATUS_EQUAL(status,
+ NT_STATUS_DOS(ERRDOS, ERRrename))) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s "
+ "should be ERRDOS:ERRrename\n",
+ __location__, nt_errstr(status));
+ goto fail;
+ }
+ }
+
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ status = smb_raw_open(cli_nt->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s should be %s\n",
+ __location__, nt_errstr(status),
+ nt_errstr(NT_STATUS_OBJECT_NAME_COLLISION));
+ goto fail;
+ }
+
+ status = smb_raw_open(cli_dos->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRfilexists))) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) incorrect status %s should be %s\n",
+ __location__, nt_errstr(status),
+ nt_errstr(NT_STATUS_DOS(ERRDOS, ERRfilexists)));
+ goto fail;
+ }
+
+ {
+ /* Test an invalid DOS deny mode */
+ const char *fname = "test.txt";
+
+ fnum = smbcli_open(cli_nt->tree, fname, O_RDWR | O_CREAT, 5);
+ if (fnum != -1) {
+ torture_result(tctx, TORTURE_FAIL, "Open(%s) with invalid deny mode succeeded -- "
+ "expected failure\n", fname);
+ smbcli_close(cli_nt->tree, fnum);
+ goto fail;
+ }
+ if (!NT_STATUS_EQUAL(smbcli_nt_error(cli_nt->tree),
+ NT_STATUS_DOS(ERRDOS,ERRbadaccess))) {
+ torture_result(tctx, TORTURE_FAIL, "Expected DOS error ERRDOS/ERRbadaccess, "
+ "got %s\n", smbcli_errstr(cli_nt->tree));
+ goto fail;
+ }
+
+ fnum = smbcli_open(cli_dos->tree, fname, O_RDWR | O_CREAT, 5);
+ if (fnum != -1) {
+ torture_result(tctx, TORTURE_FAIL, "Open(%s) with invalid deny mode succeeded -- "
+ "expected failure\n", fname);
+ smbcli_close(cli_nt->tree, fnum);
+ goto fail;
+ }
+ if (!NT_STATUS_EQUAL(smbcli_nt_error(cli_nt->tree),
+ NT_STATUS_DOS(ERRDOS,ERRbadaccess))) {
+ torture_result(tctx, TORTURE_FAIL, "Expected DOS error ERRDOS:ERRbadaccess, "
+ "got %s\n", smbcli_errstr(cli_nt->tree));
+ goto fail;
+ }
+ }
+
+ {
+ /*
+ * Samba 3.0.23 has a bug that an existing file can be opened
+ * as a directory using ntcreate&x. Test this.
+ */
+
+ const char *fname = "\\test_dir.txt";
+
+ fnum = smbcli_open(cli_nt->tree, fname, O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum == -1) {
+ d_printf("(%s) smbcli_open failed: %s\n", __location__,
+ smbcli_errstr(cli_nt->tree));
+ }
+ smbcli_close(cli_nt->tree, fnum);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.impersonation =
+ NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+
+ status = smb_raw_open(cli_nt->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
+ torture_result(tctx, TORTURE_FAIL, "ntcreate as dir gave %s, "
+ "expected NT_STATUS_NOT_A_DIRECTORY\n",
+ nt_errstr(status));
+ result = false;
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ smbcli_close(cli_nt->tree, io.ntcreatex.out.file.fnum);
+ }
+
+ status = smb_raw_open(cli_dos->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS,
+ ERRbaddirectory))) {
+ torture_result(tctx, TORTURE_FAIL, "ntcreate as dir gave %s, "
+ "expected NT_STATUS_NOT_A_DIRECTORY\n",
+ nt_errstr(status));
+ result = false;
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ smbcli_close(cli_dos->tree,
+ io.ntcreatex.out.file.fnum);
+ }
+
+ smbcli_unlink(cli_nt->tree, fname);
+ }
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ goto done;
+ }
+
+ fnum = smbcli_open(cli_dos->tree, os2_fname,
+ O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ if (fnum != -1) {
+ torture_result(tctx, TORTURE_FAIL, "Open(%s) succeeded -- expected failure\n",
+ os2_fname);
+ smbcli_close(cli_dos->tree, fnum);
+ goto fail;
+ }
+
+ if (!NT_STATUS_EQUAL(smbcli_nt_error(cli_dos->tree),
+ NT_STATUS_DOS(ERRDOS, ERRcannotopen))) {
+ torture_result(tctx, TORTURE_FAIL, "Expected DOS error ERRDOS/ERRcannotopen, got %s\n",
+ smbcli_errstr(cli_dos->tree));
+ goto fail;
+ }
+
+ fnum = smbcli_open(cli_nt->tree, os2_fname,
+ O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ if (fnum != -1) {
+ torture_result(tctx, TORTURE_FAIL, "Open(%s) succeeded -- expected failure\n",
+ os2_fname);
+ smbcli_close(cli_nt->tree, fnum);
+ goto fail;
+ }
+
+ if (!NT_STATUS_EQUAL(smbcli_nt_error(cli_nt->tree),
+ NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ torture_result(tctx, TORTURE_FAIL, "Expected error NT_STATUS_OBJECT_NAME_NOT_FOUND, "
+ "got %s\n", smbcli_errstr(cli_nt->tree));
+ goto fail;
+ }
+
+ done:
+ result = true;
+
+ fail:
+ if (cli_dos != NULL) {
+ torture_close_connection(cli_dos);
+ }
+ if (cli_nt != NULL) {
+ torture_close_connection(cli_nt);
+ }
+
+ return result;
+}
+
+/**
+ This checks file/dir birthtime
+*/
+static void list_fn(struct clilist_file_info *finfo, const char *name,
+ void *state){
+
+ /* Just to change dir access time*/
+ sleep(5);
+
+}
+
+static bool run_birthtimetest(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int fnum;
+ size_t size;
+ time_t c_time, a_time, m_time, w_time, c_time1;
+ const char *fname = "\\birthtime.tst";
+ const char *dname = "\\birthtime";
+ const char *fname2 = "\\birthtime\\birthtime.tst";
+ bool correct = true;
+ uint8_t buf[16];
+
+
+ smbcli_unlink(cli->tree, fname);
+
+ torture_comment(tctx, "Testing Birthtime for File\n");
+
+ /* Save File birthtime/creationtime */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, NULL, &size,
+ &c_time, &a_time, &m_time, NULL, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qfileinfo failed (%s)\n",
+ smbcli_errstr(cli->tree));
+ correct = false;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ sleep(10);
+
+ /* Change in File attribute changes file change time*/
+ smbcli_setatr(cli->tree, fname, FILE_ATTRIBUTE_SYSTEM, 0);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT , DENY_NONE);
+ /* Writing updates modification time*/
+ smbcli_smbwrite(cli->tree, fnum, &fname, 0, sizeof(fname));
+ /*Reading updates access time */
+ smbcli_read(cli->tree, fnum, buf, 0, 13);
+ smbcli_close(cli->tree, fnum);
+
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, fname, &c_time1,
+ &a_time, &m_time, &w_time, &size, NULL, NULL))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo2 failed (%s)\n",
+ smbcli_errstr(cli->tree));
+ correct = false;
+ } else {
+ fprintf(stdout, "c_time = %li, c_time1 = %li\n",
+ (long) c_time, (long) c_time1);
+ if (c_time1 != c_time) {
+ torture_result(tctx, TORTURE_FAIL, "This system updated file \
+ birth times! Not expected!\n");
+ correct = false;
+ }
+ }
+ smbcli_unlink(cli->tree, fname);
+
+ torture_comment(tctx, "Testing Birthtime for Directory\n");
+
+ /* check if the server does not update the directory birth time
+ when creating a new file */
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
+ torture_result(tctx, TORTURE_FAIL, "ERROR: mkdir failed (%s)\n",
+ smbcli_errstr(cli->tree));
+ correct = false;
+ }
+ sleep(3);
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, "\\birthtime\\",
+ &c_time,&a_time,&m_time,&w_time, &size, NULL, NULL))){
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo2 failed (%s)\n",
+ smbcli_errstr(cli->tree));
+ correct = false;
+ }
+
+ /* Creating a new file changes dir modification time and change time*/
+ smbcli_unlink(cli->tree, fname2);
+ fnum = smbcli_open(cli->tree, fname2, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ smbcli_smbwrite(cli->tree, fnum, &fnum, 0, sizeof(fnum));
+ smbcli_read(cli->tree, fnum, buf, 0, 13);
+ smbcli_close(cli->tree, fnum);
+
+ /* dir listing changes dir access time*/
+ smbcli_list(cli->tree, "\\birthtime\\*", 0, list_fn, cli );
+
+ if (NT_STATUS_IS_ERR(smbcli_qpathinfo2(cli->tree, "\\birthtime\\",
+ &c_time1, &a_time, &m_time,&w_time,&size,NULL,NULL))){
+ torture_result(tctx, TORTURE_FAIL, "ERROR: qpathinfo2 failed (%s)\n",
+ smbcli_errstr(cli->tree));
+ correct = false;
+ } else {
+ fprintf(stdout, "c_time = %li, c_time1 = %li\n",
+ (long) c_time, (long) c_time1);
+ if (c_time1 != c_time) {
+ torture_result(tctx, TORTURE_FAIL, "This system updated directory \
+ birth times! Not Expected!\n");
+ correct = false;
+ }
+ }
+ smbcli_unlink(cli->tree, fname2);
+ smbcli_rmdir(cli->tree, dname);
+
+ return correct;
+}
+
+/**
+ SMB1 TWRP open on root of share.
+ */
+static bool torture_smb1_twrp_openroot(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *snapshot = NULL;
+ const char *p = NULL;
+ NTSTATUS status;
+ struct tm tm = {};
+ bool ret = true;
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_skip(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ torture_comment(tctx, "Testing open of root of "
+ "share with timewarp (%s)\n",
+ snapshot);
+
+ setenv("TZ", "GMT", 1);
+
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ cli->session->flags2 |= FLAGS2_REPARSE_PATH;
+ status = smbcli_chkpath(cli->tree, snapshot);
+ cli->session->flags2 &= ~FLAGS2_REPARSE_PATH;
+
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ "smbcli_chkpath on %s : %s\n",
+ snapshot,
+ smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ done:
+
+ return ret;
+}
+
+static void torture_smb1_find_gmt_mask_list_fn(struct clilist_file_info *finfo,
+ const char *name,
+ void *state)
+{
+}
+
+/**
+ * SMB1 @GMT token as search mask is valid
+ */
+static bool torture_smb1_find_gmt_mask(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *dname = "\\torture_smb1_find_gmt_mask";
+ const char *path = "\\torture_smb1_find_gmt_mask\\@GMT-2022.11.24-16.24.00";
+ int fnum;
+ int n;
+ NTSTATUS status;
+ bool ret = true;
+
+ smbcli_unlink(cli->tree, path);
+ smbcli_rmdir(cli->tree, dname);
+
+ status = smbcli_mkdir(cli->tree, dname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smbcli_mkdir() failed\n");
+ fnum = smbcli_open(cli->tree, path, O_RDWR | O_CREAT, DENY_NONE);
+ smbcli_close(cli->tree, fnum);
+
+ /* Note: we don't set FLAGS2_REPARSE_PATH, so this is just a path */
+ n = smbcli_list(cli->tree, path, 0, torture_smb1_find_gmt_mask_list_fn, cli);
+ torture_assert_int_equal_goto(tctx, n, 1, ret, done, "Wrong count\n");
+
+done:
+ smbcli_unlink(cli->tree, path);
+ smbcli_rmdir(cli->tree, dname);
+ return ret;
+}
+
+NTSTATUS torture_base_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "base");
+
+ torture_suite_add_2smb_test(suite, "fdpass", run_fdpasstest);
+ torture_suite_add_suite(suite, torture_base_locktest(suite));
+ torture_suite_add_1smb_test(suite, "unlink", torture_unlinktest);
+ torture_suite_add_1smb_test(suite, "attr", run_attrtest);
+ torture_suite_add_1smb_test(suite, "trans2", run_trans2test);
+ torture_suite_add_1smb_test(suite, "birthtime", run_birthtimetest);
+ torture_suite_add_simple_test(suite, "negnowait", run_negprot_nowait);
+ torture_suite_add_1smb_test(suite, "dir1", torture_dirtest1);
+ torture_suite_add_1smb_test(suite, "dir2", torture_dirtest2);
+ torture_suite_add_1smb_test(suite, "deny1", torture_denytest1);
+ torture_suite_add_2smb_test(suite, "deny2", torture_denytest2);
+ torture_suite_add_2smb_test(suite, "deny3", torture_denytest3);
+ torture_suite_add_1smb_test(suite, "denydos", torture_denydos_sharing);
+ torture_suite_add_smb_multi_test(suite, "ntdeny1", torture_ntdenytest1);
+ torture_suite_add_2smb_test(suite, "ntdeny2", torture_ntdenytest2);
+ torture_suite_add_1smb_test(suite, "tcon", run_tcon_test);
+ torture_suite_add_1smb_test(suite, "tcondev", run_tcon_devtype_test);
+ torture_suite_add_1smb_test(suite, "vuid", run_vuidtest);
+ torture_suite_add_2smb_test(suite, "rw1", run_readwritetest);
+ torture_suite_add_2smb_test(suite, "open", run_opentest);
+ torture_suite_add_smb_multi_test(suite, "defer_open", run_deferopen);
+ torture_suite_add_1smb_test(suite, "xcopy", run_xcopy);
+ torture_suite_add_1smb_test(suite, "iometer", run_iometer);
+ torture_suite_add_1smb_test(suite, "rename", torture_test_rename);
+ torture_suite_add_suite(suite, torture_test_delete(suite));
+ torture_suite_add_1smb_test(suite, "properties", torture_test_properties);
+ torture_suite_add_1smb_test(suite, "mangle", torture_mangle);
+ torture_suite_add_1smb_test(suite, "openattr", torture_openattrtest);
+ torture_suite_add_1smb_test(suite, "winattr", torture_winattrtest);
+ torture_suite_add_suite(suite, torture_charset(suite));
+ torture_suite_add_1smb_test(suite, "chkpath", torture_chkpath_test);
+ torture_suite_add_1smb_test(suite, "secleak", torture_sec_leak);
+ torture_suite_add_simple_test(suite, "disconnect", torture_disconnect);
+ torture_suite_add_suite(suite, torture_delay_write(suite));
+ torture_suite_add_simple_test(suite, "samba3error", torture_samba3_errorpaths);
+ torture_suite_add_1smb_test(suite, "casetable", torture_casetable);
+ torture_suite_add_1smb_test(suite, "utable", torture_utable);
+ torture_suite_add_simple_test(suite, "smb", torture_smb_scan);
+ torture_suite_add_suite(suite, torture_trans2_aliases(suite));
+ torture_suite_add_1smb_test(suite, "trans2-scan", torture_trans2_scan);
+ torture_suite_add_1smb_test(suite, "nttrans", torture_nttrans_scan);
+ torture_suite_add_1smb_test(suite, "createx_access", torture_createx_access);
+ torture_suite_add_2smb_test(suite, "createx_sharemodes_file", torture_createx_sharemodes_file);
+ torture_suite_add_2smb_test(suite, "createx_sharemodes_dir", torture_createx_sharemodes_dir);
+ torture_suite_add_1smb_test(suite, "maximum_allowed", torture_maximum_allowed);
+
+ torture_suite_add_simple_test(suite, "bench-holdcon", torture_holdcon);
+ torture_suite_add_1smb_test(suite, "bench-holdopen", torture_holdopen);
+ torture_suite_add_simple_test(suite, "bench-readwrite", run_benchrw);
+ torture_suite_add_smb_multi_test(suite, "bench-torture", run_torture);
+ torture_suite_add_1smb_test(suite, "scan-pipe_number", run_pipe_number);
+ torture_suite_add_1smb_test(suite, "scan-ioctl", torture_ioctl_test);
+ torture_suite_add_1smb_test(suite, "scan-maxfid", torture_maxfid_test);
+ torture_suite_add_1smb_test(suite,
+ "smb1-twrp-openroot",
+ torture_smb1_twrp_openroot);
+ torture_suite_add_1smb_test(suite,
+ "smb1-find-gmt-mask",
+ torture_smb1_find_gmt_mask);
+
+ suite->description = talloc_strdup(suite,
+ "Basic SMB tests (imported from the original smbtorture)");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/basic/charset.c b/source4/torture/basic/charset.c
new file mode 100644
index 0000000..e497489
--- /dev/null
+++ b/source4/torture/basic/charset.c
@@ -0,0 +1,209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB torture tester - charset test routines
+
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "param/param.h"
+#include "torture/basic/proto.h"
+
+#define BASEDIR "\\chartest\\"
+
+/*
+ open a file using a set of unicode code points for the name
+
+ the prefix BASEDIR is added before the name
+*/
+static NTSTATUS unicode_open(struct torture_context *tctx,
+ struct smbcli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ uint32_t open_disposition,
+ const uint32_t *u_name,
+ size_t u_name_len)
+{
+ union smb_open io;
+ char *fname, *fname2=NULL, *ucs_name;
+ size_t i;
+ NTSTATUS status;
+
+ ucs_name = talloc_size(mem_ctx, (1+u_name_len)*2);
+ if (!ucs_name) {
+ printf("Failed to create UCS2 Name - talloc() failure\n");
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<u_name_len;i++) {
+ SSVAL(ucs_name, i*2, u_name[i]);
+ }
+ SSVAL(ucs_name, i*2, 0);
+
+ if (!convert_string_talloc_handle(ucs_name, lpcfg_iconv_handle(tctx->lp_ctx), CH_UTF16, CH_UNIX, ucs_name, (1+u_name_len)*2, (void **)&fname, &i)) {
+ torture_comment(tctx, "Failed to convert UCS2 Name into unix - convert_string_talloc() failure\n");
+ talloc_free(ucs_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fname2 = talloc_asprintf(ucs_name, "%s%s", BASEDIR, fname);
+ if (!fname2) {
+ talloc_free(ucs_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname2;
+ io.ntcreatex.in.open_disposition = open_disposition;
+
+ status = smb_raw_open(tree, tctx, &io);
+
+ talloc_free(ucs_name);
+
+ return status;
+}
+
+
+/*
+ see if the server recognises composed characters
+*/
+static bool test_composed(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const uint32_t name1[] = {0x61, 0x308};
+ const uint32_t name2[] = {0xe4};
+ NTSTATUS status1, status2;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "setting up basedir");
+
+ status1 = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name1, 2);
+ torture_assert_ntstatus_ok(tctx, status1, "Failed to create composed name");
+
+ status2 = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name2, 1);
+
+ torture_assert_ntstatus_ok(tctx, status2, "Failed to create accented character");
+
+ return true;
+}
+
+/*
+ see if the server recognises a naked diacritical
+*/
+static bool test_diacritical(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const uint32_t name1[] = {0x308};
+ const uint32_t name2[] = {0x308, 0x308};
+ NTSTATUS status1, status2;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "setting up basedir");
+
+ status1 = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name1, 1);
+
+ torture_assert_ntstatus_ok(tctx, status1, "Failed to create naked diacritical");
+
+ /* try a double diacritical */
+ status2 = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name2, 2);
+
+ torture_assert_ntstatus_ok(tctx, status2, "Failed to create double naked diacritical");
+
+ return true;
+}
+
+/*
+ see if the server recognises a partial surrogate pair
+*/
+static bool test_surrogate(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const uint32_t name1[] = {0xd800};
+ const uint32_t name2[] = {0xdc00};
+ const uint32_t name3[] = {0xd800, 0xdc00};
+ NTSTATUS status;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "setting up basedir");
+
+ status = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name1, 1);
+
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create partial surrogate 1");
+
+ status = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name2, 1);
+
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create partial surrogate 2");
+
+ status = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name3, 2);
+
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create full surrogate");
+
+ return true;
+}
+
+/*
+ see if the server recognises wide-a characters
+*/
+static bool test_widea(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const uint32_t name1[] = {'a'};
+ const uint32_t name2[] = {0xff41};
+ const uint32_t name3[] = {0xff21};
+ NTSTATUS status;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "setting up basedir");
+
+ status = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name1, 1);
+
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create 'a'");
+
+ status = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name2, 1);
+
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create wide-a");
+
+ status = unicode_open(tctx, cli->tree, tctx, NTCREATEX_DISP_CREATE, name3, 1);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_COLLISION,
+ "Failed to create wide-A");
+
+ return true;
+}
+
+struct torture_suite *torture_charset(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "charset");
+
+ torture_suite_add_1smb_test(suite, "Testing composite character (a umlaut)", test_composed);
+ torture_suite_add_1smb_test(suite, "Testing naked diacritical (umlaut)", test_diacritical);
+ torture_suite_add_1smb_test(suite, "Testing partial surrogate", test_surrogate);
+ torture_suite_add_1smb_test(suite, "Testing wide-a", test_widea);
+
+ return suite;
+}
diff --git a/source4/torture/basic/cxd_known.h b/source4/torture/basic/cxd_known.h
new file mode 100644
index 0000000..2fc0928
--- /dev/null
+++ b/source4/torture/basic/cxd_known.h
@@ -0,0 +1,8670 @@
+/**
+ * Results file used for BASE-CREATEX_* TESTS.
+ */
+
+enum {
+ CXD_CREATEX = 0,
+ CXD_FILE_READ = 1,
+ CXD_DIR_ENUMERATE = 1,
+ CXD_FILE_WRITE = 2,
+ CXD_DIR_CREATE_CHILD = 2,
+ CXD_FILE_EXECUTE = 3,
+ CXD_DIR_TRAVERSE = 3,
+ CXD_MAX,
+} cxd_results;
+
+enum cxd_test {
+ CXD_TEST_CREATEX_ACCESS = 0,
+ CXD_TEST_CREATEX_ACCESS_EXHAUSTIVE = 1,
+ CXD_TEST_CREATEX_SHAREMODE = 2,
+ CXD_TEST_CREATEX_SHAREMODE_EXTENDED = 3,
+};
+
+enum cxd_flags {
+ CXD_FLAGS_DIRECTORY = 0x1,
+ CXD_FLAGS_MAKE_BEFORE_CREATEX = 0x2,
+
+ CXD_FLAGS_MASK = 0x3,
+ CXD_FLAGS_COUNT = CXD_FLAGS_MASK + 1,
+};
+
+/**
+ * CXD.
+ */
+struct createx_data {
+ /* In. */
+ enum cxd_test cxd_test;
+ enum cxd_flags cxd_flags;
+ uint32_t cxd_access1;
+ uint32_t cxd_sharemode1;
+ uint32_t cxd_access2;
+ uint32_t cxd_sharemode2;
+
+ /* Out. */
+ NTSTATUS cxd_result[CXD_MAX];
+ NTSTATUS cxd_result2[CXD_MAX];
+};
+
+/**
+ * Known CXD results, for CREATEX_ACCESS and CREATEX_SHAREMODE.
+ * Taken by running against a Windows XP Pro 2002 Edition, Service Pack 2.
+ */
+static const struct createx_data cxd_known[] = {
+/**
+ * CXD_TEST_CREATEX_ACCESS data.
+ */
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x4, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x8, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x10, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x20, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x40, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x80, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x4000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x8000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x10000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x20000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x40000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x80000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x1000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x4000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x6000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x7000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x8000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0xa000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0xb000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x10000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x12000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x13000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x20000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x22000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x23000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x40000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x42000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x43000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x80000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x82000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0, .cxd_access1 = 0x83000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x4, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x8, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x10, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x20, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x40, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x80, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x4000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x8000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x10000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x20000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x40000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x80000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x1000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x4000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x6000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x7000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x8000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0xa000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0xb000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x10000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x12000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x13000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x20000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x22000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x23000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x40000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x42000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x43000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x80000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x82000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x1, .cxd_access1 = 0x83000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x4, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x8, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x10, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x20, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x40, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x80, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x4000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x8000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x10000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x20000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x40000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x80000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x1000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x4000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x6000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x7000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x8000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0xa000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0xb000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x10000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x12000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x13000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x20000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x22000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x23000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x40000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x42000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x43000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x80000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x82000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x2, .cxd_access1 = 0x83000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000001, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000002, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x4, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000004, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x8, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000008, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x10, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000010, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x20, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000020, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x40, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000040, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x80, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000080, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000100, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000200, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000400, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000800, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3001000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3002000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x4000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3004000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x8000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3008000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x10000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3010000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x20000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3020000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x40000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3040000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x80000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3080000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3100000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3200000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3400000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3800000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x1000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x2000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x3000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x4000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x6000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x7000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x8000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0xa000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0xb000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x10000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x12000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x13000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x20000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x22000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x23000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x40000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x42000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x43000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x80000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x82000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 0, .cxd_flags = 0x3, .cxd_access1 = 0x83000000, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+/**
+ * CXD_TEST_CREATEX_SHAREMODE (file, non extended)
+ */
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+/**
+ * CXD_TEST_CREATEX_SHAREMODE (dir, non extended)
+ */
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=0, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=1, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=2, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=3, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=4, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=5, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=6, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=0, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=1, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=2, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=3, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=4, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=5, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=6, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120089, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x120116, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x12019f, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a0, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1200a9, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201b6, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120089, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x120116, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x12019f, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a0, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1200a9, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201b6, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+ { .cxd_test = 2, .cxd_flags = 0x1, .cxd_access1 = 0x1201bf, .cxd_sharemode1=7, .cxd_access2= 0x1201bf, .cxd_sharemode2=7, .cxd_result = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }, .cxd_result2 = { NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, NT_STATUS_OK, }},
+};
diff --git a/source4/torture/basic/delaywrite.c b/source4/torture/basic/delaywrite.c
new file mode 100644
index 0000000..b9d4a06
--- /dev/null
+++ b/source4/torture/basic/delaywrite.c
@@ -0,0 +1,3095 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for delayed write update
+
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Jeremy Allison 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+#define BASEDIR "\\delaywrite"
+
+static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_fileinfo finfo1, finfo2;
+ const char *fname = BASEDIR "\\torture_file.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
+ "Failed to open %s", fname));
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ torture_assert_int_equal(tctx, written, 1,
+ "unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (120 * sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+
+ if (finfo1.basic_info.out.write_time !=
+ finfo2.basic_info.out.write_time)
+ {
+ double diff = timeval_elapsed(&start);
+
+ torture_assert(tctx,
+ diff >= (used_delay / (double)1000000),
+ talloc_asprintf(tctx,
+ "Server updated write_time after %.2f "
+ "seconds (expected >= %.2f)\n",
+ diff, used_delay/(double)1000000));
+
+ torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
+ diff);
+ break;
+ }
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ torture_assert_u64_not_equal(tctx,
+ finfo2.basic_info.out.write_time,
+ finfo1.basic_info.out.write_time,
+ "Server did not update write time within "
+ "120 seconds");
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file1.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ char buf[2048];
+ bool first;
+ bool updated;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
+ "Failed to open %s", fname));
+
+ memset(buf, 'x', 2048);
+ written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+ /* 3 second delay to ensure we get past any 2 second time
+ granularity (older systems may have that) */
+ smb_msleep(3 * msec);
+
+ finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+ finfo1.all_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+ finfo3 = finfo1;
+ pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+ pinfo4.all_info.in.file.path = fname;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
+ "file size not as expected after write(2048)");
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, finfo1.all_info.out.write_time));
+
+ /* 3 second delay to ensure we get past any 2 second time
+ granularity (older systems may have that) */
+ smb_msleep(3 * msec);
+
+ /* Do a zero length SMBwrite call to truncate. */
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
+ torture_assert_int_equal(tctx, written, 0,
+ "unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (120 * sec), 0);
+ first = true;
+ updated = false;
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
+ "file not truncated to expected size "
+ "(1024)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.all_info.out.write_time));
+
+ if (finfo1.all_info.out.write_time !=
+ finfo2.all_info.out.write_time)
+ {
+ updated = true;
+ break;
+ }
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ first = false;
+ }
+
+ torture_assert(tctx, updated,
+ "Server did not update write time within 120 seconds");
+
+ torture_assert(tctx, first, talloc_asprintf(tctx,
+ "Server did not update write time immediately but only "
+ "after %.2f seconds!", timeval_elapsed(&start)));
+
+ torture_comment(tctx, "Server updated write time immediately. Good!\n");
+
+ fflush(stdout);
+ smb_msleep(2 * msec);
+
+ /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
+ torture_assert_int_equal(tctx, written, 1,
+ "unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (10*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
+ "file not truncated to expected size "
+ "(1024)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo3.all_info.out.write_time));
+
+ torture_assert_u64_equal(tctx,
+ finfo3.all_info.out.write_time,
+ finfo2.all_info.out.write_time,
+ talloc_asprintf(tctx,
+ "Server updated write time "
+ "after %.2f seconds (wrong!)",
+ timeval_elapsed(&start)));
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ torture_comment(tctx, "Server did not update write time within 10 "
+ "seconds. Good!\n");
+
+ fflush(stdout);
+ smb_msleep(2 * msec);
+
+ /* the close should trigger an write time update */
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
+ torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
+
+ torture_assert_u64_not_equal(tctx,
+ pinfo4.all_info.out.write_time,
+ finfo3.all_info.out.write_time,
+ "Server did not update write time on "
+ "close (wrong!)");
+ torture_assert(tctx,
+ pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
+ "Server updated write time on close, but to an earlier point "
+ "in time");
+
+ torture_comment(tctx, "Server updated write time on close (correct)\n");
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/* Updating with a SMBwrite of zero length
+ * changes the write time immediately - even on expand. */
+
+static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file1a.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ char buf[2048];
+ bool first;
+ bool updated;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
+ "Failed to open %s", fname));
+
+ memset(buf, 'x', 2048);
+ written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+ /* 3 second delay to ensure we get past any 2 second time
+ granularity (older systems may have that) */
+ smb_msleep(3 * msec);
+
+ finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+ finfo1.all_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+ finfo3 = finfo1;
+ pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+ pinfo4.all_info.in.file.path = fname;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
+ "file size not as expected after write(2048)");
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, finfo1.all_info.out.write_time));
+
+ /* Do a zero length SMBwrite call to truncate. */
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
+
+ torture_assert_int_equal(tctx, written, 0,
+ "unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (120*sec), 0);
+ first = true;
+ updated = false;
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
+ "file not truncated to expected size "
+ "(10240)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.all_info.out.write_time));
+
+ if (finfo1.all_info.out.write_time !=
+ finfo2.all_info.out.write_time)
+ {
+ updated = true;
+ break;
+ }
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ first = false;
+ }
+
+ torture_assert(tctx, updated,
+ "Server did not update write time within 120 seconds");
+
+ torture_assert(tctx, first, talloc_asprintf(tctx,
+ "Server did not update write time immediately but only "
+ "after %.2f seconds!", timeval_elapsed(&start)));
+
+ torture_comment(tctx, "Server updated write time immediately. Good!\n");
+
+ fflush(stdout);
+ smb_msleep(2 * msec);
+
+ /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
+
+ torture_assert_int_equal(tctx, written, 1,
+ "unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (10*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
+ "file not truncated to expected size "
+ "(10240)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo3.all_info.out.write_time));
+
+ torture_assert_u64_equal(tctx,
+ finfo3.all_info.out.write_time,
+ finfo2.all_info.out.write_time,
+ talloc_asprintf(tctx,
+ "Server updated write time "
+ "after %.2f seconds (wrong!)",
+ timeval_elapsed(&start)));
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ torture_comment(tctx, "Server did not update write time within 10 "
+ "seconds. Good!\n");
+
+ /* the close should trigger an write time update */
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
+ torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
+
+ torture_assert_u64_not_equal(tctx,
+ pinfo4.all_info.out.write_time,
+ finfo3.all_info.out.write_time,
+ "Server did not update write time on "
+ "close (wrong!)");
+ torture_assert(tctx,
+ pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
+ "Server updated write time on close, but to an earlier point "
+ "in time");
+
+ torture_comment(tctx, "Server updated write time on close (correct)\n");
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/* Updating with a SET_FILE_END_OF_FILE_INFO
+ * changes the write time immediately - even on expand. */
+
+static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file1b.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ char buf[2048];
+ bool first;
+ bool updated;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
+ "Failed to open %s", fname));
+
+ memset(buf, 'x', 2048);
+ written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+ /* 3 second delay to ensure we get past any 2 second time
+ granularity (older systems may have that) */
+ smb_msleep(3 * msec);
+
+ finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+ finfo1.all_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+ finfo3 = finfo1;
+ pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+ pinfo4.all_info.in.file.path = fname;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
+ "file size not as expected after write(2048)");
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, finfo1.all_info.out.write_time));
+
+ /* Do a SET_END_OF_FILE_INFO call to truncate. */
+ status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
+
+ torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
+
+ start = timeval_current();
+ end = timeval_add(&start, (120*sec), 0);
+ first = true;
+ updated = false;
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
+ "file not truncated to expected size "
+ "(10240)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.all_info.out.write_time));
+
+ if (finfo1.all_info.out.write_time !=
+ finfo2.all_info.out.write_time)
+ {
+ updated = true;
+ break;
+ }
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ first = false;
+ }
+
+ torture_assert(tctx, updated,
+ "Server did not update write time within 120 seconds");
+
+ torture_assert(tctx, first, talloc_asprintf(tctx,
+ "Server did not update write time immediately but only "
+ "after %.2f seconds!", timeval_elapsed(&start)));
+
+ torture_comment(tctx, "Server updated write time immediately. Good!\n");
+
+ fflush(stdout);
+ smb_msleep(2 * msec);
+
+ /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
+
+ torture_assert_int_equal(tctx, written, 1,
+ "unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (10*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
+ "file not truncated to expected size "
+ "(10240)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo3.all_info.out.write_time));
+
+ torture_assert_u64_equal(tctx,
+ finfo3.all_info.out.write_time,
+ finfo2.all_info.out.write_time,
+ talloc_asprintf(tctx,
+ "Server updated write time "
+ "after %.2f seconds (wrong!)",
+ timeval_elapsed(&start)));
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ torture_comment(tctx, "Server did not update write time within 10 "
+ "seconds. Good!\n");
+
+ /* the close should trigger an write time update */
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
+ torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
+
+ torture_assert_u64_not_equal(tctx,
+ pinfo4.all_info.out.write_time,
+ finfo3.all_info.out.write_time,
+ "Server did not update write time on "
+ "close (wrong!)");
+ torture_assert(tctx,
+ pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
+ "Server updated write time on close, but to an earlier point "
+ "in time");
+
+ torture_comment(tctx, "Server updated write time on close (correct)\n");
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
+
+static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_setfileinfo parms;
+ union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file1c.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ char buf[2048];
+ bool first;
+ bool updated;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
+ "Failed to open %s", fname));
+
+ memset(buf, 'x', 2048);
+ written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+ /* 3 second delay to ensure we get past any 2 second time
+ granularity (older systems may have that) */
+ smb_msleep(3 * msec);
+
+ finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+ finfo1.all_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+ finfo3 = finfo1;
+ pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+ pinfo4.all_info.in.file.path = fname;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
+ "file size not as expected after write(2048)");
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, finfo1.all_info.out.write_time));
+
+ /* Do a SET_ALLOCATION_SIZE call to truncate. */
+ parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
+ parms.allocation_info.in.file.fnum = fnum1;
+ parms.allocation_info.in.alloc_size = 0;
+
+ status = smb_raw_setfileinfo(cli->tree, &parms);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "RAW_SFILEINFO_ALLOCATION_INFO failed");
+
+ start = timeval_current();
+ end = timeval_add(&start, (120*sec), 0);
+ first = true;
+ updated = false;
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 0,
+ "file not truncated to expected size "
+ "(0)");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.all_info.out.write_time));
+
+ if (finfo1.all_info.out.write_time !=
+ finfo2.all_info.out.write_time)
+ {
+ updated = true;
+ break;
+ }
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ first = false;
+ }
+
+ torture_assert(tctx, updated,
+ "Server did not update write time within 120 seconds");
+
+ torture_assert(tctx, first, talloc_asprintf(tctx,
+ "Server did not update write time immediately but only "
+ "after %.2f seconds!", timeval_elapsed(&start)));
+
+ torture_comment(tctx, "Server updated write time immediately. Good!\n");
+
+ fflush(stdout);
+ smb_msleep(2 * msec);
+
+ /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
+ torture_assert_int_equal(tctx, written, 1,
+ "Unexpected number of bytes written");
+
+ start = timeval_current();
+ end = timeval_add(&start, (10*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1,
+ "file not expaneded");
+
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo3.all_info.out.write_time));
+
+ torture_assert_u64_equal(tctx,
+ finfo3.all_info.out.write_time,
+ finfo2.all_info.out.write_time,
+ talloc_asprintf(tctx,
+ "Server updated write time "
+ "after %.2f seconds (wrong!)",
+ timeval_elapsed(&start)));
+
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ torture_comment(tctx, "Server did not update write time within 10 "
+ "seconds. Good!\n");
+
+ /* the close should trigger an write time update */
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
+ torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
+
+ torture_assert_u64_not_equal(tctx,
+ pinfo4.all_info.out.write_time,
+ finfo3.all_info.out.write_time,
+ "Server did not update write time on "
+ "close (wrong!)");
+ torture_assert(tctx,
+ pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
+ "Server updated write time on close, but to an earlier point "
+ "in time");
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Do as above, but using 2 connections.
+ */
+
+static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo1, finfo2;
+ const char *fname = BASEDIR "\\torture_file.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ union smb_flush flsh;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_comment(tctx, "Failed to open %s\n", fname);
+ return false;
+ }
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+ /* 3 second delay to ensure we get past any 2 second time
+ granularity (older systems may have that) */
+ smb_msleep(3 * msec);
+
+ {
+ /* Try using setfileinfo instead of write to update write time. */
+ union smb_setfileinfo sfinfo;
+ time_t t_set = time(NULL);
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.basic_info.in.file.fnum = fnum1;
+ sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
+ sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
+
+ /* I tried this with both + and - ve to see if it makes a different.
+ It doesn't - once the filetime is set via setfileinfo it stays that way. */
+#if 1
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
+#else
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
+#endif
+ sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
+ sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
+
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+
+ torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
+ }
+
+ finfo2.basic_info.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ torture_comment(tctx, "Server updated write_time (correct)\n");
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
+ ret = false;
+ }
+
+ /* Now try a write to see if the write time gets reset. */
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+
+ torture_comment(tctx, "Modified write time %s\n",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+
+ torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
+
+ written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
+
+ if (written != 10) {
+ torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
+ (int)written, __location__);
+ return false;
+ }
+
+ /* Just to prove to tridge that the an smbflush has no effect on
+ the write time :-). The setfileinfo IS STICKY. JRA. */
+
+ torture_comment(tctx, "Doing flush after write\n");
+
+ flsh.flush.level = RAW_FLUSH_FLUSH;
+ flsh.flush.in.file.fnum = fnum1;
+ status = smb_raw_flush(cli->tree, &flsh);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+
+ /* Once the time was set using setfileinfo then it stays set - writes
+ don't have any effect. But make sure. */
+ start = timeval_current();
+ end = timeval_add(&start, (15*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ ret = false;
+ break;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write time (correct)\n");
+ }
+
+ fflush(stdout);
+ smb_msleep(2 * msec);
+
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
+ return false;
+ }
+
+ torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
+
+ written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
+
+ if (written != 10) {
+ torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
+ (int)written, __location__);
+ return false;
+ }
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
+ ret = false;
+ }
+
+ torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
+
+ written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
+
+ if (written != 10) {
+ torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
+ (int)written, __location__);
+ return false;
+ }
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum2;
+ finfo2 = finfo1;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
+ ret = false;
+ }
+
+ /* Once the time was set using setfileinfo then it stays set - writes
+ don't have any effect. But make sure. */
+ start = timeval_current();
+ end = timeval_add(&start, (15*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ ret = false;
+ break;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ fflush(stdout);
+ smb_msleep(1 * msec);
+ }
+
+ if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write time (correct)\n");
+ }
+
+ torture_comment(tctx, "Closing second fd to see if write time updated.\n");
+
+ smbcli_close(cli->tree, fnum2);
+ fnum2 = -1;
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_comment(tctx, "Failed to open %s\n", fname);
+ return false;
+ }
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+
+ torture_comment(tctx, "Second open initial write time %s\n",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+ smb_msleep(10 * msec);
+ torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
+
+ written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
+
+ if (written != 10) {
+ torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
+ (int)written, __location__);
+ return false;
+ }
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ return false;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
+ ret = false;
+ }
+
+ /* Now the write time should be updated again */
+ start = timeval_current();
+ end = timeval_add(&start, (15*sec), 0);
+ while (!timeval_expired(&end)) {
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+ ret = false;
+ break;
+ }
+ torture_comment(tctx, "write time %s\n",
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ if (diff < (used_delay / (double)1000000)) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
+ "(expected > %.2f) (wrong!)\n",
+ diff, used_delay / (double)1000000);
+ ret = false;
+ break;
+ }
+
+ torture_comment(tctx, "Server updated write_time after %.2f seconds"
+ "(correct)\n",
+ diff);
+ break;
+ }
+ fflush(stdout);
+ smb_msleep(1*msec);
+ }
+
+ if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
+ ret = false;
+ }
+
+
+ /* One more test to do. We should read the filetime via findfirst on the
+ second connection to ensure it's the same. This is very easy for a Windows
+ server but a bastard to get right on a POSIX server. JRA. */
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/* Windows does obviously not update the stat info during a write call. I
+ * *think* this is the problem causing a spurious Excel 2003 on XP error
+ * message when saving a file. Excel does a setfileinfo, writes, and then does
+ * a getpath(!)info. Or so... For Samba sometimes it displays an error message
+ * that the file might have been changed in between. What i've been able to
+ * trace down is that this happens if the getpathinfo after the write shows a
+ * different last write time than the setfileinfo showed. This is really
+ * nasty....
+ */
+
+static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo1, finfo2;
+ const char *fname = BASEDIR "\\torture_file.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ int fnum2;
+ bool ret = true;
+ ssize_t written;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_finfo_after_write\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
+ goto done;
+ }
+
+ smb_msleep(1 * msec);
+
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+
+ fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
+ smbcli_errstr(cli2->tree));
+ ret = false;
+ goto done;
+ }
+
+ written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
+
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
+ (int)written);
+ ret = false;
+ goto done;
+ }
+
+ finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo2.basic_info.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (finfo1.basic_info.out.create_time !=
+ finfo2.basic_info.out.create_time) {
+ torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
+ ret = false;
+ goto done;
+ }
+
+ if (finfo1.basic_info.out.access_time !=
+ finfo2.basic_info.out.access_time) {
+ torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
+ ret = false;
+ goto done;
+ }
+
+ if (finfo1.basic_info.out.write_time !=
+ finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
+ "write time conn 1 = %s, conn 2 = %s",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time),
+ nt_time_string(tctx, finfo2.basic_info.out.write_time));
+ ret = false;
+ goto done;
+ }
+
+ if (finfo1.basic_info.out.change_time !=
+ finfo2.basic_info.out.change_time) {
+ torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
+ ret = false;
+ goto done;
+ }
+
+ /* One of the two following calls updates the qpathinfo. */
+
+ /* If you had skipped the smbcli_write on fnum2, it would
+ * *not* have updated the stat on disk */
+
+ smbcli_close(cli2->tree, fnum2);
+ cli2 = NULL;
+
+ /* This call is only for the people looking at ethereal :-) */
+ finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo2.basic_info.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+#define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
+ uint64_t r = 10*1000*1000; \
+ NTTIME g = (given).basic_info.out.write_time; \
+ NTTIME gr = (g / r) * r; \
+ NTTIME c = (correct).basic_info.out.write_time; \
+ NTTIME cr = (c / r) * r; \
+ bool strict = torture_setting_bool(tctx, "strict mode", false); \
+ bool err = false; \
+ if (strict && (g cmp c)) { \
+ err = true; \
+ } else if ((g cmp c) && (gr cmp cr)) { \
+ /* handle filesystem without high resolution timestamps */ \
+ err = true; \
+ } \
+ if (err) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
+ #given, nt_time_string(tctx, g), (unsigned long long)g, \
+ #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
+ ret = false; \
+ goto done; \
+ } \
+} while (0)
+#define COMPARE_WRITE_TIME_EQUAL(given,correct) \
+ COMPARE_WRITE_TIME_CMP(given,correct,!=)
+#define COMPARE_WRITE_TIME_GREATER(given,correct) \
+ COMPARE_WRITE_TIME_CMP(given,correct,<=)
+#define COMPARE_WRITE_TIME_LESS(given,correct) \
+ COMPARE_WRITE_TIME_CMP(given,correct,>=)
+
+#define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
+ NTTIME g = (given).basic_info.out.access_time; \
+ NTTIME c = (correct).basic_info.out.access_time; \
+ if (g cmp c) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
+ #given, nt_time_string(tctx, g), \
+ #cmp, #correct, nt_time_string(tctx, c)); \
+ ret = false; \
+ goto done; \
+ } \
+} while (0)
+#define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
+ COMPARE_ACCESS_TIME_CMP(given,correct,!=)
+
+#define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
+ COMPARE_ACCESS_TIME_EQUAL(given,correct); \
+ COMPARE_WRITE_TIME_EQUAL(given,correct); \
+} while (0)
+
+#define GET_INFO_FILE(finfo) do { \
+ NTSTATUS _status; \
+ _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
+ if (!NT_STATUS_IS_OK(_status)) { \
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
+ nt_errstr(_status)); \
+ goto done; \
+ } \
+ torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
+ nt_time_string(tctx, finfo.basic_info.out.access_time), \
+ nt_time_string(tctx, finfo.basic_info.out.write_time)); \
+} while (0)
+#define GET_INFO_FILE2(finfo) do { \
+ NTSTATUS _status; \
+ _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
+ if (!NT_STATUS_IS_OK(_status)) { \
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
+ nt_errstr(_status)); \
+ goto done; \
+ } \
+ torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
+ nt_time_string(tctx, finfo.basic_info.out.access_time), \
+ nt_time_string(tctx, finfo.basic_info.out.write_time)); \
+} while (0)
+#define GET_INFO_PATH(pinfo) do { \
+ NTSTATUS _status; \
+ _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
+ if (!NT_STATUS_IS_OK(_status)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
+ nt_errstr(_status)); \
+ ret = false; \
+ goto done; \
+ } \
+ torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
+ nt_time_string(tctx, pinfo.basic_info.out.access_time), \
+ nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
+} while (0)
+#define GET_INFO_BOTH(finfo,pinfo) do { \
+ GET_INFO_FILE(finfo); \
+ GET_INFO_PATH(pinfo); \
+ COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
+} while (0)
+
+#define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
+ NTSTATUS _status; \
+ union smb_setfileinfo sfinfo; \
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
+ sfinfo.basic_info.in.file.fnum = tfnum; \
+ sfinfo.basic_info.in.create_time = 0; \
+ sfinfo.basic_info.in.access_time = 0; \
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
+ sfinfo.basic_info.in.change_time = 0; \
+ sfinfo.basic_info.in.attrib = finfo.basic_info.out.attrib; \
+ _status = smb_raw_setfileinfo(tree, &sfinfo); \
+ if (!NT_STATUS_IS_OK(_status)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
+ nt_errstr(_status)); \
+ ret = false; \
+ goto done; \
+ } \
+} while (0)
+#define SET_INFO_FILE(finfo, wrtime) \
+ SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
+
+#define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
+ NTSTATUS _status; \
+ union smb_setfileinfo sfinfo; \
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
+ sfinfo.basic_info.in.file.fnum = tfnum; \
+ sfinfo.basic_info.in.create_time = 0; \
+ sfinfo.basic_info.in.access_time = 0; \
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
+ sfinfo.basic_info.in.write_time += (ns); \
+ sfinfo.basic_info.in.change_time = 0; \
+ sfinfo.basic_info.in.attrib = finfo.basic_info.out.attrib; \
+ _status = smb_raw_setfileinfo(tree, &sfinfo); \
+ if (!NT_STATUS_IS_OK(_status)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
+ nt_errstr(_status)); \
+ ret = false; \
+ goto done; \
+ } \
+} while (0)
+
+static bool test_delayed_write_update3(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file3.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /*
+ * make sure the write time is updated 2 seconds later
+ * calculated from the first write
+ * (but expect up to 5 seconds extra time for a busy server)
+ */
+ start = timeval_current();
+ end = timeval_add(&start, 7 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_FILE(finfo1);
+
+ if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ if (diff < (used_delay / (double)1000000)) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(write time update delay == %.2f) (wrong!)\n",
+ diff, used_delay / (double)1000000);
+ ret = false;
+ break;
+ }
+
+ torture_comment(tctx, "Server updated write_time after %.2f seconds "
+ "(correct)\n",
+ diff);
+ break;
+ }
+ smb_msleep(0.5 * msec);
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+
+ if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+ if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+ /*
+ * the close updates the write time to the time of the close
+ * and not to the time of the last write!
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo4);
+ COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
+
+ if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Show that a truncate write always updates the write time even
+ * if an initial write has already updated the write time.
+ */
+
+static bool test_delayed_write_update3a(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file3a.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ int i;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /*
+ * sleep some time, to demonstrate the handling of write times
+ * doesn't depend on the time since the open
+ */
+ smb_msleep(5 * msec);
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+ /*
+ * make sure the write time is updated 2 seconds later
+ * calculated from the first write
+ * (but expect up to 5 seconds extra time for a busy server)
+ */
+ start = timeval_current();
+ end = timeval_add(&start, 7 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_FILE(finfo1);
+
+ if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ if (diff < (used_delay / (double)1000000)) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(1sec == %.2f) (wrong!)\n",
+ diff, sec);
+ ret = false;
+ break;
+ }
+
+ torture_comment(tctx, "Server updated write_time after %.2f seconds "
+ "(correct)\n",
+ diff);
+ break;
+ }
+ smb_msleep(0.5 * msec);
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+ smb_msleep(3 * msec);
+
+ /*
+ * demonstrate that a truncate write always
+ * updates the write time immediately
+ */
+ for (i=0; i < 3; i++) {
+ smb_msleep(2 * msec);
+ /* do a write */
+ torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
+ if (written != 0) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+ finfo1 = finfo2;
+ }
+
+ smb_msleep(3 * msec);
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+
+ if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+ if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(3 * msec);
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
+
+ /*
+ * demonstrate that a truncate write always
+ * updates the write time immediately
+ */
+ for (i=0; i < 3; i++) {
+ smb_msleep(2 * msec);
+ /* do a write */
+ torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
+ if (written != 0) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+ finfo1 = finfo2;
+ }
+
+ /* sleep */
+ smb_msleep(3 * msec);
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+ /*
+ * the close doesn't update the write time
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo4);
+ COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
+
+ if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Show a close after write updates the write timestamp to
+ * the close time, not the last write time.
+ */
+
+static bool test_delayed_write_update3b(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file3b.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /*
+ * sleep some time, to demonstrate the handling of write times
+ * doesn't depend on the time since the open
+ */
+ smb_msleep(5 * msec);
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+ /*
+ * make sure the write time is updated 2 seconds later
+ * calculated from the first write
+ * (but expect up to 5 seconds extra time for a busy server)
+ */
+ start = timeval_current();
+ end = timeval_add(&start, 7 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_FILE(finfo1);
+
+ if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ if (diff < (used_delay / (double)1000000)) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
+ "(expected > %.2f) (wrong!)\n",
+ diff, used_delay / (double)1000000);
+ ret = false;
+ break;
+ }
+
+ torture_comment(tctx, "Server updated write_time after %.2f seconds "
+ "(write time update delay == %.2f) (correct)\n",
+ diff, used_delay / (double)1000000);
+ break;
+ }
+ smb_msleep(0.5 * msec);
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+
+ if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+ if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+ /*
+ * the close updates the write time to the time of the close
+ * and not to the time of the last write!
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo4);
+ COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
+
+ if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Check that a write after a truncate write doesn't update
+ * the timestamp, but a truncate write after a write does.
+ * Also prove that a close after a truncate write updates the
+ * timestamp to current, not the time of last write.
+ */
+
+static bool test_delayed_write_update3c(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file3c.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ int i;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /*
+ * sleep some time, to demonstrate the handling of write times
+ * doesn't depend on the time since the open
+ */
+ smb_msleep(5 * msec);
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+ /*
+ * demonstrate that a truncate write always
+ * updates the write time immediately
+ */
+ for (i=0; i < 3; i++) {
+ smb_msleep(2 * msec);
+ /* do a write */
+ torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
+ if (written != 0) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+ finfo1 = finfo2;
+ }
+
+ start = timeval_current();
+ end = timeval_add(&start, 7 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_FILE(finfo2);
+
+ if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+ if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
+
+ /*
+ * demonstrate that a truncate write always
+ * updates the write time immediately
+ */
+ for (i=0; i < 3; i++) {
+ smb_msleep(2 * msec);
+ /* do a write */
+ torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
+ if (written != 0) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+ finfo1 = finfo2;
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+
+ if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+ if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+ /*
+ * the close updates the write time to the time of the close
+ * and not to the time of the last write!
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo4);
+ COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
+
+ if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Show only the first write updates the timestamp, and a close
+ * after writes updates to current (I think this is the same
+ * as test 3b. JRA).
+ */
+
+static bool test_delayed_write_update4(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
+ const char *fname = BASEDIR "\\torture_file4.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /* sleep a bit */
+ smb_msleep(5 * msec);
+
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
+
+ /*
+ * make sure the write time is updated 2 seconds later
+ * calculated from the first write
+ * (but expect up to 3 seconds extra time for a busy server)
+ */
+ start = timeval_current();
+ end = timeval_add(&start, 5 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* get the times after the first write */
+ GET_INFO_FILE(finfo1);
+
+ if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ if (diff < (used_delay / (double)1000000)) {
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
+ "(expected > %.2f) (wrong!)\n",
+ diff, used_delay / (double)1000000);
+ ret = false;
+ break;
+ }
+
+ torture_comment(tctx, "Server updated write_time after %.2f seconds "
+ "(write time update delay == %.2f) (correct)\n",
+ diff, used_delay / (double)1000000);
+ break;
+ }
+ smb_msleep(0.5 * msec);
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo2,pinfo2);
+
+ if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+ if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+ /*
+ * the close updates the write time to the time of the close
+ * and not to the time of the last write!
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo4);
+ COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
+
+ if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
+ */
+
+static bool test_delayed_write_update5(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
+ const char *fname = BASEDIR "\\torture_file5.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ finfo4 = finfo0;
+ finfo5 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+ pinfo5 = pinfo0;
+ pinfo6 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+ torture_comment(tctx, "Set write time in the future on the file handle\n");
+ SET_INFO_FILE(finfo0, time(NULL) + 86400);
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+
+ torture_comment(tctx, "Set write time in the past on the file handle\n");
+ SET_INFO_FILE(finfo0, time(NULL) - 86400);
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
+
+ /* make sure the 2 second delay from the first write are canceled */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+
+ /* get the times after the first write */
+ GET_INFO_BOTH(finfo3,pinfo3);
+
+ if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+ if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo4,pinfo4);
+
+ if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo4,pinfo4);
+ COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
+ if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo5,pinfo5);
+ COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
+
+ /*
+ * the close doesn't update the write time
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo6);
+ COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
+
+ if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
+ */
+
+static bool test_delayed_write_update5b(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
+ const char *fname = BASEDIR "\\torture_fileb.txt";
+ int fnum1 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ finfo4 = finfo0;
+ finfo5 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+ pinfo5 = pinfo0;
+ pinfo6 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+ torture_comment(tctx, "Set write time in the future on the file handle\n");
+ SET_INFO_FILE(finfo0, time(NULL) + 86400);
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+
+ torture_comment(tctx, "Set write time in the past on the file handle\n");
+ SET_INFO_FILE(finfo0, time(NULL) - 86400);
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
+
+ /* make sure the 2 second delay from the first write are canceled */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+
+ /* get the times after the first write */
+ GET_INFO_BOTH(finfo3,pinfo3);
+
+ if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+ if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* Do any further write (truncates) update the write time ? */
+ start = timeval_current();
+ end = timeval_add(&start, 15 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a truncate write on the file handle\n");
+ written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
+ if (written != 0) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo4,pinfo4);
+
+ if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo4,pinfo4);
+ COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
+ if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo5,pinfo5);
+ COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
+
+ /*
+ * the close doesn't update the write time
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo6);
+ COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
+
+ if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ * Open 2 handles on a file. Write one one and then set the
+ * WRITE TIME explicitly on the other. Ensure the write time
+ * update is cancelled. Ensure the write time is updated to
+ * the close time when the non-explicit set handle is closed.
+ *
+ */
+
+static bool test_delayed_write_update6(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
+ union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
+ const char *fname = BASEDIR "\\torture_file6.txt";
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool ret = true;
+ ssize_t written;
+ struct timeval start;
+ struct timeval end;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ bool first = true;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+again:
+ torture_comment(tctx, "Open the file handle\n");
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+
+ if (fnum2 == -1) {
+ torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
+ fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum2 == -1) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+ goto done;
+ }
+ }
+
+ finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo0.basic_info.in.file.fnum = fnum1;
+ finfo1 = finfo0;
+ finfo2 = finfo0;
+ finfo3 = finfo0;
+ finfo4 = finfo0;
+ finfo5 = finfo0;
+ pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ pinfo0.basic_info.in.file.path = fname;
+ pinfo1 = pinfo0;
+ pinfo2 = pinfo0;
+ pinfo3 = pinfo0;
+ pinfo4 = pinfo0;
+ pinfo5 = pinfo0;
+ pinfo6 = pinfo0;
+ pinfo7 = pinfo0;
+
+ /* get the initial times */
+ GET_INFO_BOTH(finfo0,pinfo0);
+
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+
+ GET_INFO_BOTH(finfo1,pinfo1);
+ COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+ torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
+ SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+
+ torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
+ SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
+ GET_INFO_BOTH(finfo2,pinfo2);
+ COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
+
+ /* make sure the 2 second delay from the first write are canceled */
+ start = timeval_current();
+ end = timeval_add(&start, 10 * sec, 0);
+ while (!timeval_expired(&end)) {
+
+ /* get the times after the first write */
+ GET_INFO_BOTH(finfo3,pinfo3);
+
+ if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo3,pinfo3);
+ COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+ if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sure any further write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 10 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the file handle\n");
+ written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_BOTH(finfo4,pinfo4);
+
+ if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ GET_INFO_BOTH(finfo4,pinfo4);
+ COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
+ if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update write_time (correct)\n");
+ }
+
+ /* sleep */
+ smb_msleep(5 * msec);
+
+ GET_INFO_BOTH(finfo5,pinfo5);
+ COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
+
+ /*
+ * the close updates the write time to the time of the close
+ * as the write time was set on the 2nd handle
+ */
+ torture_comment(tctx, "Close the file handle\n");
+ smbcli_close(cli->tree, fnum1);
+ fnum1 = -1;
+
+ GET_INFO_PATH(pinfo6);
+ COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
+
+ if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
+ torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+ }
+
+ /* See what the second write handle thinks the time is ? */
+ finfo5.basic_info.in.file.fnum = fnum2;
+ GET_INFO_FILE2(finfo5);
+ COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
+
+ /* See if we have lost the sticky write time on handle2 */
+ smb_msleep(3 * msec);
+ torture_comment(tctx, "Have we lost the sticky write time ?\n");
+
+ /* Make sure any further normal write doesn't update the write time */
+ start = timeval_current();
+ end = timeval_add(&start, 10 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a write on the second file handle\n");
+ written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
+ if (written != 1) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_FILE2(finfo5);
+ GET_INFO_PATH(pinfo6);
+
+ if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+ /* What about a truncate write ? */
+ start = timeval_current();
+ end = timeval_add(&start, 10 * sec, 0);
+ while (!timeval_expired(&end)) {
+ /* do a write */
+ torture_comment(tctx, "Do a truncate write on the second file handle\n");
+ written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
+ if (written != 0) {
+ torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+ ret = false;
+ goto done;
+ }
+ /* get the times after the write */
+ GET_INFO_FILE2(finfo5);
+ GET_INFO_PATH(pinfo6);
+
+ if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
+ double diff = timeval_elapsed(&start);
+ torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
+ "(wrong!)\n",
+ diff);
+ ret = false;
+ break;
+ }
+ smb_msleep(1 * msec);
+ }
+
+
+ /* keep the 2nd handle open and rerun tests */
+ if (first) {
+ first = false;
+ goto again;
+ }
+
+ /*
+ * closing the 2nd handle will cause no write time update
+ * as the write time was explicit set on this handle
+ */
+ torture_comment(tctx, "Close the 2nd file handle\n");
+ smbcli_close(cli2->tree, fnum2);
+ fnum2 = -1;
+
+ GET_INFO_PATH(pinfo7);
+ COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
+
+ if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
+ torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
+ }
+
+ done:
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ if (fnum2 != -1)
+ smbcli_close(cli2->tree, fnum2);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open open_parms;
+ union smb_fileinfo finfo1, finfo2, finfo3;
+ const char *fname = BASEDIR "\\torture_file7.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ bool ret = true;
+ TALLOC_CTX *mem_ctx;
+
+ torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
+
+ mem_ctx = talloc_init("test_delayed_write_update7");
+ if (!mem_ctx) return false;
+
+ ZERO_STRUCT(finfo1);
+ ZERO_STRUCT(finfo2);
+ ZERO_STRUCT(finfo3);
+ ZERO_STRUCT(open_parms);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* Create the file. */
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum1 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
+ return false;
+ }
+
+ finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ finfo1.basic_info.in.file.fnum = fnum1;
+ finfo2 = finfo1;
+ finfo3 = finfo1;
+
+ /* Get the initial timestamps. */
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ /* Set the pending write time to a value with non zero msec. */
+ SET_INFO_FILE_NS(finfo1, time(NULL) + 86400, 103 * NTTIME_MSEC,
+ cli->tree, fnum1);
+
+ /* Get the current pending write time by fnum. */
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ /* Ensure the time is actually different. */
+ if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL,
+ "setfileinfo time matches original fileinfo time");
+ ret = false;
+ }
+
+ /* Get the current pending write time by path. */
+ finfo3.basic_info.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
+
+ if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL,
+ "qpathinfo time doesn't match fileinfo time");
+ ret = false;
+ }
+
+ /* Now close the file. Re-open and check that the write
+ time is identical to the one we wrote. */
+
+ smbcli_close(cli->tree, fnum1);
+
+ open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = 0;
+ open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
+ open_parms.ntcreatex.in.file_attr = 0;
+ open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ open_parms.ntcreatex.in.create_options = 0;
+ open_parms.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
+ talloc_free(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "setfileinfo time matches original fileinfo time");
+ ret = false;
+ }
+
+ fnum1 = open_parms.ntcreatex.out.file.fnum;
+
+ /* Check the returned time matches. */
+ if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
+ torture_result(tctx, TORTURE_FAIL,
+ "final open time does not match set time");
+ ret = false;
+ }
+
+ done:
+
+ smbcli_close(cli->tree, fnum1);
+
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ Test if creating a file in a directory with an open handle updates the
+ write timestamp (it should).
+*/
+static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_fileinfo dir_info1, dir_info2;
+ union smb_open open_parms;
+ const char *fname = BASEDIR "\\torture_file.txt";
+ NTSTATUS status;
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool ret = true;
+ double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+ int normal_delay = 2000000;
+ double sec = ((double)used_delay) / ((double)normal_delay);
+ int msec = 1000 * sec;
+ TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
+
+ if (!mem_ctx) return false;
+
+ torture_comment(tctx, "\nRunning test directory write update\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* Open a handle on the directory - and leave it open. */
+ ZERO_STRUCT(open_parms);
+ open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = 0;
+ open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
+ open_parms.ntcreatex.in.file_attr = 0;
+ open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ open_parms.ntcreatex.in.fname = BASEDIR;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
+ talloc_free(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "failed to open directory handle");
+ ret = false;
+ goto done;
+ }
+
+ fnum1 = open_parms.ntcreatex.out.file.fnum;
+
+ /* Store the returned write time. */
+ ZERO_STRUCT(dir_info1);
+ dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
+
+ torture_comment(tctx, "Initial write time %s\n",
+ nt_time_string(tctx, dir_info1.basic_info.out.write_time));
+
+ /* sleep */
+ smb_msleep(3 * msec);
+
+ /* Now create a file within the directory. */
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum2 == -1) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum2);
+
+ /* Read the directory write time again. */
+ ZERO_STRUCT(dir_info2);
+ dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+ dir_info2.basic_info.in.file.fnum = fnum1;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
+
+ torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
+
+ /* Ensure it's been incremented. */
+ COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
+
+ torture_comment(tctx, "Updated write time %s\n",
+ nt_time_string(tctx, dir_info2.basic_info.out.write_time));
+
+ done:
+
+ if (fnum1 != -1)
+ smbcli_close(cli->tree, fnum1);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ testing of delayed update of write_time
+*/
+struct torture_suite *torture_delay_write(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "delaywrite");
+
+ torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
+ torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
+ torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
+ torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
+ torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
+ torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
+ torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
+ torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
+ torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
+ torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
+
+ return suite;
+}
diff --git a/source4/torture/basic/delete.c b/source4/torture/basic/delete.c
new file mode 100644
index 0000000..647f5e0
--- /dev/null
+++ b/source4/torture/basic/delete.c
@@ -0,0 +1,2624 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ delete on close testing
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "system/filesys.h"
+#include "libcli/raw/raw_proto.h"
+
+#include "torture/raw/proto.h"
+#include "torture/basic/proto.h"
+
+static bool check_delete_on_close(struct torture_context *tctx,
+ struct smbcli_state *cli, int fnum,
+ const char *fname, bool expect_it,
+ const char *where)
+{
+ union smb_search_data data;
+ NTSTATUS status;
+
+ time_t c_time, a_time, m_time;
+ size_t size;
+ uint16_t mode;
+
+ status = torture_single_search(cli, tctx,
+ fname,
+ RAW_SEARCH_TRANS2,
+ RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
+ FILE_ATTRIBUTE_DIRECTORY,
+ &data);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "single_search failed (%s)", where));
+
+ if (fnum != -1) {
+ union smb_fileinfo io;
+ int nlink = expect_it ? 0 : 1;
+
+ io.all_info.level = RAW_FILEINFO_ALL_INFO;
+ io.all_info.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx,
+ "qfileinfo failed (%s)", where));
+
+ torture_assert(tctx, expect_it == io.all_info.out.delete_pending,
+ talloc_asprintf(tctx,
+ "%s - Expected del_on_close flag %d, qfileinfo/all_info gave %d",
+ where, expect_it, io.all_info.out.delete_pending));
+
+ torture_assert(tctx, nlink == io.all_info.out.nlink,
+ talloc_asprintf(tctx,
+ "%s - Expected nlink %d, qfileinfo/all_info gave %d",
+ where, nlink, io.all_info.out.nlink));
+
+ io.standard_info.level = RAW_FILEINFO_STANDARD_INFO;
+ io.standard_info.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
+
+ torture_assert(tctx, expect_it == io.standard_info.out.delete_pending,
+ talloc_asprintf(tctx, "%s - Expected del_on_close flag %d, qfileinfo/standard_info gave %d\n",
+ where, expect_it, io.standard_info.out.delete_pending));
+
+ torture_assert(tctx, nlink == io.standard_info.out.nlink,
+ talloc_asprintf(tctx, "%s - Expected nlink %d, qfileinfo/standard_info gave %d",
+ where, nlink, io.all_info.out.nlink));
+ }
+
+ status = smbcli_qpathinfo(cli->tree, fname,
+ &c_time, &a_time, &m_time,
+ &size, &mode);
+
+ if (expect_it) {
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
+ "qpathinfo did not give correct error code");
+ } else {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "qpathinfo failed (%s)", where));
+ }
+
+ return true;
+}
+
+#define CHECK_STATUS(_cli, _expected) \
+ torture_assert_ntstatus_equal(tctx, _cli->tree->session->transport->error.e.nt_status, _expected, \
+ "Incorrect status")
+
+static const char *fname = "\\delete.file";
+static const char *fname_new = "\\delete.new";
+static const char *dname = "\\delete.dir";
+
+static void del_clean_area(struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+
+ smbcli_deltree(cli1->tree, dname);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_setatr(cli1->tree, fname_new, 0, 0);
+ smbcli_unlink(cli1->tree, fname_new);
+}
+
+/* Test 1 - this should delete the file on close. */
+
+static bool deltest1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE, NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close failed (%s)", smbcli_errstr(cli1->tree)));
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
+ fname));
+
+ return true;
+}
+
+/* Test 2 - this should delete the file on close. */
+static bool deltest2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
+ talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("(%s) open of %s succeeded should have been deleted on close !\n",
+ __location__, fname);
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ printf("(%s) close failed (%s)\n",
+ __location__, smbcli_errstr(cli1->tree));
+ return false;
+ }
+ smbcli_unlink(cli1->tree, fname);
+ }
+ return true;
+}
+
+/* Test 3 - ... */
+static bool deltest3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* This should fail with a sharing violation - open for delete is only compatible
+ with SHARE_DELETE. */
+
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+
+ torture_assert(tctx, fnum2 == -1,
+ talloc_asprintf(tctx, "open - 2 of %s succeeded - should have failed.",
+ fname));
+
+ /* This should succeed. */
+
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
+ talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close 1 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
+ talloc_asprintf(tctx, "close 2 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ /* This should fail - file should no longer be there. */
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
+ if (fnum1 != -1) {
+ printf("(%s) open of %s succeeded should have been deleted on close !\n",
+ __location__, fname);
+ if (NT_STATUS_IS_ERR(smbcli_close(cli1->tree, fnum1))) {
+ printf("(%s) close failed (%s)\n",
+ __location__, smbcli_errstr(cli1->tree));
+ }
+ smbcli_unlink(cli1->tree, fname);
+ return false;
+ }
+ return true;
+}
+
+/* Test 4 ... */
+static bool deltest4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* This should succeed. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum2),
+ talloc_asprintf(tctx, "close - 1 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
+ talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ /* This should fail - no more opens once delete on close set. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+ torture_assert(tctx, fnum2 == -1,
+ talloc_asprintf(tctx, "open - 3 of %s succeeded ! Should have failed.",
+ fname ));
+
+ CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 2 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ return correct;
+}
+
+/* Test 5 ... */
+static bool deltest5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* This should fail - only allowed on NT opens with DELETE access. */
+
+ torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
+ "setting delete_on_close on OpenX file succeeded - should fail !");
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+/* Test 6 ... */
+static bool deltest6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* This should fail - only allowed on NT opens with DELETE access. */
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_nt_delete_on_close(cli1->tree, fnum1, true)),
+ "setting delete_on_close on file with no delete access succeeded - should fail !");
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close - 2 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+/* Test 7 ... */
+static bool deltest7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL, 0,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
+ "setting delete_on_close on file failed !");
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_nt_delete_on_close(cli1->tree, fnum1, false),
+ "unsetting delete_on_close on file failed !");
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ /* This next open should succeed - we reset the flag. */
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 2 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ return correct;
+}
+
+/* Test 8 ... */
+static bool deltest8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
+ "setting delete_on_close on file failed !");
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 1 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, -1, fname, true, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
+ talloc_asprintf(tctx, "close - 2 failed (%s)", smbcli_errstr(cli2->tree)));
+
+ /* This should fail.. */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !\n", fname));
+
+ return correct;
+}
+
+/* Test 9 ... */
+static bool deltest9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ NTSTATUS status;
+ uint32_t disps[4] = {
+ NTCREATEX_DISP_SUPERSEDE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_DISP_OPEN_IF};
+ unsigned int i;
+
+ del_clean_area(cli1, cli2);
+
+ for (i = 0; i < sizeof(disps)/sizeof(disps[0]); i++) {
+ /* This should fail - we need to set DELETE_ACCESS. */
+
+ /*
+ * A file or directory create with DELETE_ON_CLOSE but
+ * without DELETE_ACCESS should fail with
+ * NT_STATUS_INVALID_PARAMETER.
+ */
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ disps[i],
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded "
+ "should have failed!",
+ fname));
+
+ /* Must fail with NT_STATUS_INVALID_PARAMETER. */
+ status = smbcli_nt_error(cli1->tree);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_INVALID_PARAMETER,
+ talloc_asprintf(tctx, "create of %s should return "
+ "NT_STATUS_INVALID_PARAMETER, got %s",
+ fname,
+ smbcli_errstr(cli1->tree)));
+
+ /* This should fail - the file should not have been created. */
+ status = smbcli_getatr(cli1->tree, fname, NULL, NULL, NULL);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ talloc_asprintf(tctx, "getattr of %s succeeded should "
+ "not have been created !",
+ fname));
+ }
+
+ return true;
+}
+
+/* Test 9a ... */
+static bool deltest9a(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ NTSTATUS status;
+ uint32_t disps[4] = {
+ NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_DISP_OVERWRITE,
+ NTCREATEX_DISP_OPEN_IF};
+
+ unsigned int i;
+
+ del_clean_area(cli1, cli2);
+
+ /* Create the file, and try with open calls. */
+ fnum1 = smbcli_open(cli1->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert(tctx,
+ fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname,
+ smbcli_errstr(cli1->tree)));
+ status = smbcli_close(cli1->tree, fnum1);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ talloc_asprintf(tctx, "close failed"));
+
+ for (i = 0; i < sizeof(disps)/sizeof(disps[0]); i++) {
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ disps[i],
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded "
+ "should have failed!",
+ fname));
+
+ /* Must fail with NT_STATUS_INVALID_PARAMETER. */
+ status = smbcli_nt_error(cli1->tree);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_INVALID_PARAMETER,
+ talloc_asprintf(tctx, "create of %s should return "
+ "NT_STATUS_INVALID_PARAMETER, got %s",
+ fname,
+ smbcli_errstr(cli1->tree)));
+
+ /*
+ * This should succeed - the file should not have been deleted.
+ */
+ status = smbcli_getatr(cli1->tree, fname, NULL, NULL, NULL);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ talloc_asprintf(tctx, "getattr of %s failed %s",
+ fname,
+ smbcli_errstr(cli1->tree)));
+ }
+
+ del_clean_area(cli1, cli2);
+ return true;
+}
+
+/* Test 10 ... */
+static bool deltest10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+
+ del_clean_area(cli1, cli2);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* This should delete the file. */
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ /* This should fail.. */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded should have been deleted on close !",
+ fname));
+ return true;
+}
+
+/* Test 11 ... */
+static bool deltest11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ NTSTATUS status;
+
+ del_clean_area(cli1, cli2);
+
+ /* test 11 - does having read only attribute still allow delete on close. */
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_READONLY,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ status = smbcli_nt_delete_on_close(cli1->tree, fnum1, true);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
+ talloc_asprintf(tctx, "setting delete_on_close should fail with NT_STATUS_CANNOT_DELETE. Got %s instead)", smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+/* Test 12 ... */
+static bool deltest12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ NTSTATUS status;
+
+ del_clean_area(cli1, cli2);
+
+ /* test 12 - does having read only attribute still allow delete on
+ * close at time of open. */
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_READONLY,
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded. Should fail with "
+ "NT_STATUS_CANNOT_DELETE.\n", fname));
+
+ status = smbcli_nt_error(cli1->tree);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_CANNOT_DELETE,
+ talloc_asprintf(tctx, "setting delete_on_close on open should "
+ "fail with NT_STATUS_CANNOT_DELETE. Got %s "
+ "instead)",
+ smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+/* Test 13 ... */
+static bool deltest13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 13: Does resetting the delete on close flag affect a second
+ * fd? */
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
+ "open of %s failed (%s)",
+ fname, smbcli_errstr(cli2->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_nt_delete_on_close(cli1->tree, fnum1,
+ true),
+ "setting delete_on_close on file failed !");
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli2->tree, fnum2,
+ false),
+ "unsetting delete_on_close on file failed !");
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 1 failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
+ talloc_asprintf(tctx, "close - 2 failed (%s)",
+ smbcli_errstr(cli2->tree)));
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDONLY, DENY_NONE);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed!",
+ fname));
+
+ smbcli_close(cli1->tree, fnum1);
+
+ return correct;
+}
+
+/* Test 14 ... */
+static bool deltest14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int dnum1 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 14 -- directory */
+
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE, 0, 0);
+ torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
+ dname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
+ torture_assert_ntstatus_ok(tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
+ "setting delete_on_close on file failed !");
+ correct &= check_delete_on_close(tctx, cli1, dnum1, dname, true, __location__);
+ smbcli_close(cli1->tree, dnum1);
+
+ /* Now it should be gone... */
+
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+ torture_assert(tctx, dnum1 == -1, "setting delete_on_close on file succeeded !");
+
+ return correct;
+}
+
+/* Test 15 ... */
+static bool deltest15(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ bool correct = true;
+ int fnum2 = -1;
+ NTSTATUS status;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 15: delete on close under rename */
+
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_unlink(cli1->tree, fname_new);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
+
+ status = smbcli_rename(cli2->tree, fname, fname_new);
+
+ torture_assert_ntstatus_ok(tctx, status, "renaming failed!");
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname_new, 0,
+ SEC_GENERIC_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+
+ torture_assert(tctx, fnum2 != -1,
+ talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname_new, smbcli_errstr(cli1->tree)));
+
+ status = smbcli_nt_delete_on_close(cli2->tree, fnum2, true);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "setting delete_on_close on file failed !");
+
+ smbcli_close(cli2->tree, fnum2);
+
+ /* The file should be around under the new name, there's a second
+ * handle open */
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname_new, true, __location__);
+
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_GENERIC_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+
+ smbcli_close(cli2->tree, fnum2);
+ smbcli_close(cli1->tree, fnum1);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_EA,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, fnum1);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname_new, 0,
+ SEC_FILE_READ_EA,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ torture_assert(tctx, fnum1 == -1,
+ "smbcli_open succeeded, should have "
+ "failed");
+
+ return correct;
+}
+
+/* Test 16 ... */
+static bool deltest16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 16. */
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly create with all access, but delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert (tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, true, __location__);
+ correct &= check_delete_on_close(tctx, cli2, -1, fname, true, __location__);
+
+ smbcli_close(cli2->tree, fnum2);
+
+ /* And the file should be deleted ! */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 16 ... */
+static bool deltest16a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 16. */
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Firstly create with all access, but delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert (tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, -1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, -1, fname, false, __location__);
+
+ smbcli_close(cli2->tree, fnum2);
+
+ /* And the file should be deleted ! */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ return correct;
+}
+
+/* Test 17 ... */
+static bool deltest17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 17. */
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Next open with all access, but add delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /* After the first close, the files has the delete on close bit set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, true, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ /* Make sure the file has been deleted */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s failed (should succeed) - %s",
+ fname, smbcli_errstr(cli1->tree)));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 17a - like 17, but the delete on close handle is closed last */
+static bool deltest17a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Next open with all access, but add delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /*
+ * The file is still there:
+ * The second open seems to have removed the initial
+ * delete on close flag from the first handle
+ */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 3 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ return correct;
+}
+
+/* Test 17b - like 17a, but the initial delete on close is set on the second handle */
+static bool deltest17b(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Next open with all access, but add delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ /* Make sure the file has been deleted */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 3 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 17c - like 17, but the initial delete on close is set on the second handle */
+static bool deltest17c(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Next open with all access, but add delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
+
+ fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 == -1, talloc_asprintf(tctx, "open - 3 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Make sure the file has been deleted */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 4 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 17d - like 17a, but the first delete-on-close opener creates the file */
+static bool deltest17d(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+
+ /* Create the file with delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /*
+ * The file is still there:
+ * The second open seems to have removed the initial
+ * delete on close flag from the first handle
+ */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 3 of %s succeed (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+static bool deltest17e(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ int fnum3 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum3 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* Next open with all access, but add delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 3 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /*
+ * closing the handle that has delete_on_close set
+ * inherits the flag to the global context
+ */
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, true, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, true, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, true, __location__);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 4 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
+
+ smbcli_close(cli1->tree, fnum3);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 5 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+static bool deltest17f(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ int fnum3 = -1;
+ bool correct = true;
+ NTSTATUS status;
+
+ del_clean_area(cli1, cli2);
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+
+ /* Next open with all access, but add delete on close. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum3 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx, "open - 3 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* still not reported as being set on either */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /*
+ * closing the handle that has delete_on_close set
+ * inherits the flag to the global context
+ */
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, true, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, true, __location__);
+
+
+ status = smbcli_nt_delete_on_close(cli1->tree, fnum2, false);
+ torture_assert_ntstatus_ok(tctx, status,
+ "clearing delete_on_close on file failed !");
+
+ correct &= check_delete_on_close(tctx, cli1, fnum2, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum3, fname, true, __location__);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 4 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
+
+ smbcli_close(cli1->tree, fnum3);
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open - 5 of %s succeeded (should fail)",
+ fname));
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 18 ... */
+static bool deltest18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 18. With directories. */
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+
+ smbcli_deltree(cli1->tree, dname);
+
+ /* Firstly create with all access, but delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ dname, smbcli_errstr(cli1->tree)));
+
+ /*
+ * The delete on close bit is *not* reported as being set.
+ * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
+ * close as being set. This causes the subsequent create to fail with
+ * NT_STATUS_DELETE_PENDING.
+ */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ dname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli1, fnum2, dname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ /* And the directory should be deleted ! */
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail)",
+ dname));
+
+ return correct;
+}
+
+/* Test 19 ... */
+static bool deltest19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 19. */
+
+ smbcli_deltree(cli1->tree, dname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ dname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the directory. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Next open with all access, but add delete on close. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open - 1 of %s failed (%s)", fname, smbcli_errstr(cli1->tree)));
+
+ /*
+ * The delete on close bit is *not* reported as being set.
+ * Win2k3/win2k8 should pass this check, but WinXPsp2 reports delete on
+ * close as being set. This causes the subsequent create to fail with
+ * NT_STATUS_DELETE_PENDING.
+ */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, dname, false, __location__);
+
+ /* Now try opening again for read-only. */
+ fnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ /* Should work. */
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ dname, smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli1, fnum2, dname, true, __location__);
+
+ smbcli_close(cli1->tree, fnum2);
+
+ /* See if the file is deleted - for a directory this seems to be true ! */
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded (should fail)", dname));
+
+ return correct;
+}
+
+/* Test 20 ... */
+static bool deltest20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int dnum1 = -1;
+ bool correct = true;
+ NTSTATUS status;
+ int ret;
+
+ if (geteuid() == 0) {
+ torture_skip(tctx, "This test doesn't work as user root.");
+ }
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 20 -- non-empty directory hardest to get right... */
+
+ smbcli_deltree(cli1->tree, dname);
+
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s!",
+ dname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, __location__);
+ status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
+
+ {
+ char *fullname;
+ ret = asprintf(&fullname, "\\%s%s", dname, fname);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
+ DENY_NONE);
+ torture_assert(tctx, fnum1 == -1,
+ "smbcli_open succeeded, should have "
+ "failed with NT_STATUS_DELETE_PENDING"
+ );
+
+ torture_assert_ntstatus_equal(tctx,
+ smbcli_nt_error(cli1->tree),
+ NT_STATUS_DELETE_PENDING,
+ "smbcli_open failed");
+ }
+
+ status = smbcli_nt_delete_on_close(cli1->tree, dnum1, false);
+ torture_assert_ntstatus_ok(tctx, status,
+ "unsetting delete_on_close on file failed !");
+
+ {
+ char *fullname;
+ ret = asprintf(&fullname, "\\%s%s", dname, fname);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ fnum1 = smbcli_open(cli1->tree, fullname, O_CREAT|O_RDWR,
+ DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "smbcli_open failed: %s\n",
+ smbcli_errstr(cli1->tree)));
+ smbcli_close(cli1->tree, fnum1);
+ }
+
+ status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DIRECTORY_NOT_EMPTY,
+ "setting delete_on_close failed");
+ smbcli_close(cli1->tree, dnum1);
+
+ return correct;
+}
+
+/* Test 20a ... */
+static bool deltest20a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 20a. */
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* Next open with all access, but add delete on close. */
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli2->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+
+ smbcli_close(cli2->tree, fnum2);
+
+ /* See if the file is deleted - should be.... */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
+ fname, smbcli_errstr(cli1->tree)));
+
+ return correct;
+}
+
+/* Test 20b ... */
+/* This is the delete semantics that the cifsfs client depends on when
+ * trying to delete an open file on a Windows server. It
+ * opens a file with initial delete on close set, renames it then closes
+ * all open handles. The file goes away on Windows.
+ */
+
+static bool deltest20b(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int fnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 20b. */
+
+ /* Ensure the file doesn't already exist. */
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_setatr(cli1->tree, fname, 0, 0);
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_setatr(cli1->tree, fname_new, 0, 0);
+ smbcli_unlink(cli1->tree, fname_new);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Firstly open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open - 1 of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* Next open with all access, but add delete on close. */
+ fnum2 = smbcli_nt_create_full(cli2->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx, "open - 2 of %s failed (%s)",
+ fname, smbcli_errstr(cli2->tree)));
+
+ /* The delete on close bit is *not* reported as being set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, false, __location__);
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+
+ smbcli_close(cli1->tree, fnum1);
+
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname, false, __location__);
+
+ /* Rename the file by handle. */
+
+ {
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status;
+
+ memset(&sfinfo, '\0', sizeof(sfinfo));
+ sfinfo.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfinfo.generic.in.file.fnum = fnum2;
+ sfinfo.rename_information.in.root_fid = 0;
+ /* Don't start the filename with '\\', we get NT_STATUS_NOT_SUPPORTED if so. */
+ sfinfo.rename_information.in.new_name = fname_new + 1;
+ sfinfo.rename_information.in.overwrite = 1;
+
+ status = smb_raw_setfileinfo(cli2->tree, &sfinfo);
+
+ torture_assert_ntstatus_equal(tctx,status,NT_STATUS_OK,talloc_asprintf(tctx, "rename of %s to %s failed (%s)",
+ fname, fname_new, smbcli_errstr(cli2->tree)));
+ }
+
+ correct &= check_delete_on_close(tctx, cli2, fnum2, fname_new, false, __location__);
+
+ smbcli_close(cli2->tree, fnum2);
+
+ /* See if the file is deleted - should be.... */
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
+ fname, smbcli_errstr(cli1->tree)));
+ fnum1 = smbcli_open(cli1->tree, fname_new, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum1 == -1, talloc_asprintf(tctx, "open of %s succeeded (should fail) - %s",
+ fname_new, smbcli_errstr(cli1->tree)));
+
+ return correct;
+}
+
+/* Test 20c */
+/* Along the lines of deltest20 we try to open a non-empty directory with delete
+ * on close set and subsequent close to verify its presence in the tree.
+ */
+static bool deltest20c(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ int dnum1 = -1;
+ int ret;
+ char *fullname;
+
+ del_clean_area(cli1, cli2);
+
+ smbcli_deltree(cli1->tree, dname);
+
+ /* Firstly open and create with all access */
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s",
+ dname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the directory */
+ smbcli_close(cli1->tree, dnum1);
+
+ ret = asprintf(&fullname, "\\%s%s", dname, fname);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+
+ /* Open and create with all access */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fullname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ 0, 0);
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* And close - just to create the file. */
+ smbcli_close(cli1->tree, fnum1);
+
+ /* Open with all access, but add delete on close */
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY|NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+ /* Should work */
+ torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s",
+ dname, smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, dnum1);
+
+ /* Try to open again */
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ /* Directory should be still present*/
+ torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, "open of %s failed: %s",
+ dname, smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, dnum1);
+
+ return true;
+}
+
+/* Test 21 ... */
+static bool deltest21(struct torture_context *tctx)
+{
+ int fnum1 = -1;
+ struct smbcli_state *cli1;
+ struct smbcli_state *cli2;
+ bool correct = true;
+
+ if (!torture_open_connection(&cli1, tctx, 0))
+ return false;
+
+ if (!torture_open_connection(&cli2, tctx, 1))
+ return false;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 21 -- Test removal of file after socket close. */
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "open of %s failed (%s)",
+ fname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_nt_delete_on_close(cli1->tree, fnum1, true),
+ talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ /* Ensure delete on close is set. */
+ correct &= check_delete_on_close(tctx, cli1, fnum1, fname, true, __location__);
+
+ /* Now yank the rug from under cli1. */
+ smbcli_transport_dead(cli1->transport, NT_STATUS_LOCAL_DISCONNECT);
+
+ fnum1 = -1;
+
+ if (!torture_open_connection(&cli1, tctx, 0)) {
+ return false;
+ }
+
+ /* On slow build farm machines it might happen that they are not fast
+ * enough to delete the file for this test */
+ smb_msleep(200);
+
+ /* File should not be there. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 22 ... */
+
+/*
+ * Test whether a second *directory* handle inhibits delete if the first has
+ * del-on-close set and is closed
+ */
+static bool deltest22(struct torture_context *tctx)
+{
+ int dnum1 = -1;
+ int dnum2 = -1;
+ struct smbcli_state *cli1;
+ bool correct = true;
+
+ if (!torture_open_connection(&cli1, tctx, 0))
+ return false;
+
+ smbcli_deltree(cli1->tree, dname);
+
+ torture_assert_ntstatus_ok(
+ tctx, smbcli_mkdir(cli1->tree, dname),
+ talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
+ smbcli_errstr(cli1->tree)));
+
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ torture_assert(tctx, dnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed: %s!",
+ dname, smbcli_errstr(cli1->tree)));
+
+ dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ torture_assert(tctx, dnum2 != -1,
+ talloc_asprintf(tctx, "open of %s failed: %s!",
+ dname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(
+ tctx, smbcli_nt_delete_on_close(cli1->tree, dnum1, true),
+ talloc_asprintf(tctx, "setting delete_on_close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, dnum1);
+
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ torture_assert(tctx, dnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded!\n",
+ dname));
+
+ CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING);
+
+ smbcli_close(cli1->tree, dnum2);
+ CHECK_STATUS(cli1, NT_STATUS_OK);
+
+ return correct;
+}
+
+/* Test 23 - Second directory open fails when delete is pending. */
+static bool deltest23(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ int dnum1 = -1;
+ int dnum2 = -1;
+ bool correct = true;
+
+ del_clean_area(cli1, cli2);
+
+ /* Test 23 -- Basic delete on close for directories. */
+
+ /* Open a directory */
+ dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx,
+ "open of %s failed: %s!",
+ dname, smbcli_errstr(cli1->tree)));
+
+ correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false,
+ __location__);
+
+ /* Set delete on close */
+ (void)smbcli_nt_delete_on_close(cli1->tree, dnum1, true);
+
+ /* Attempt opening the directory again. It should fail. */
+ dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+
+ torture_assert(tctx, dnum2 == -1, talloc_asprintf(tctx,
+ "open of %s succeeded: %s. It should have failed "
+ "with NT_STATUS_DELETE_PENDING",
+ dname, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree),
+ NT_STATUS_DELETE_PENDING, "smbcli_open failed");
+
+ return correct;
+}
+
+/* Test 24 ... */
+
+/*
+ * Test whether unsetting delete-on-close before the close has any effect.
+ * It should be ignored.
+ */
+static bool deltest24(struct torture_context *tctx)
+{
+ int fnum1 = -1;
+ struct smbcli_state *cli1;
+ bool correct = true;
+
+ if (!torture_open_connection(&cli1, tctx, 0))
+ return false;
+
+ smbcli_deltree(cli1->tree, fname);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed: %s!",
+ fname, smbcli_errstr(cli1->tree)));
+
+ /* Now, unset Delete-On-Close, but it should have no effect */
+ torture_assert_ntstatus_ok(
+ tctx, smbcli_nt_delete_on_close(cli1->tree, fnum1, false),
+ talloc_asprintf(tctx, "unsetting delete_on_close failed (%s)",
+ smbcli_errstr(cli1->tree)));
+
+ smbcli_close(cli1->tree, fnum1);
+
+ /* File should not be there. */
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+
+ CHECK_STATUS(cli1, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return correct;
+}
+
+/* Test 25 ... */
+static bool deltest25(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ NTSTATUS status;
+ uint32_t disps[4] = {
+ NTCREATEX_DISP_SUPERSEDE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_DISP_CREATE,
+ NTCREATEX_DISP_OPEN_IF};
+ unsigned int i;
+
+ del_clean_area(cli1, cli2);
+
+ for (i = 0; i < sizeof(disps)/sizeof(disps[0]); i++) {
+ /* This should fail - we need to set DELETE_ACCESS. */
+
+ /*
+ * A file or directory create with DELETE_ON_CLOSE but
+ * without DELETE_ACCESS should fail with
+ * NT_STATUS_INVALID_PARAMETER.
+ */
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ disps[i],
+ NTCREATEX_OPTIONS_DIRECTORY|
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded "
+ "should have failed!",
+ dname));
+
+ /* Must fail with NT_STATUS_INVALID_PARAMETER. */
+ status = smbcli_nt_error(cli1->tree);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_INVALID_PARAMETER,
+ talloc_asprintf(tctx, "create of %s should return "
+ "NT_STATUS_INVALID_PARAMETER, got %s",
+ dname,
+ smbcli_errstr(cli1->tree)));
+
+ /*
+ * This should fail - the directory
+ * should not have been created.
+ */
+ status = smbcli_getatr(cli1->tree, dname, NULL, NULL, NULL);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ talloc_asprintf(tctx, "getattr of %s succeeded should "
+ "not have been created !",
+ dname));
+ }
+
+ return true;
+}
+
+/* Test 25a... */
+static bool deltest25a(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ int fnum1 = -1;
+ NTSTATUS status;
+ uint32_t disps[4] = {
+ NTCREATEX_DISP_OVERWRITE_IF,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_DISP_OVERWRITE,
+ NTCREATEX_DISP_OPEN_IF};
+
+ unsigned int i;
+
+ del_clean_area(cli1, cli2);
+
+ /* Create the directory, and try with open calls. */
+ status = smbcli_mkdir(cli1->tree, dname);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ talloc_asprintf(tctx, "mkdir of %s failed %s",
+ dname,
+ smbcli_errstr(cli1->tree)));
+
+ for (i = 0; i < sizeof(disps)/sizeof(disps[0]); i++) {
+ fnum1 = smbcli_nt_create_full(cli1->tree, dname, 0,
+ SEC_FILE_READ_DATA,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ disps[i],
+ NTCREATEX_OPTIONS_DIRECTORY|
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0);
+
+ torture_assert(tctx, fnum1 == -1,
+ talloc_asprintf(tctx, "open of %s succeeded "
+ "should have failed!",
+ dname));
+
+ /* Must fail with NT_STATUS_INVALID_PARAMETER. */
+ status = smbcli_nt_error(cli1->tree);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_INVALID_PARAMETER,
+ talloc_asprintf(tctx, "create of %s should return "
+ "NT_STATUS_INVALID_PARAMETER, got %s",
+ dname,
+ smbcli_errstr(cli1->tree)));
+
+ /*
+ * This should succeed - the directory
+ * should not have been deleted.
+ */
+ status = smbcli_getatr(cli1->tree, dname, NULL, NULL, NULL);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ talloc_asprintf(tctx, "getattr of %s failed %s",
+ fname,
+ smbcli_errstr(cli1->tree)));
+ }
+
+ del_clean_area(cli1, cli2);
+ return true;
+}
+
+/*
+ Test delete on close semantics.
+ */
+struct torture_suite *torture_test_delete(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "delete");
+
+ torture_suite_add_2smb_test(suite, "deltest1", deltest1);
+ torture_suite_add_2smb_test(suite, "deltest2", deltest2);
+ torture_suite_add_2smb_test(suite, "deltest3", deltest3);
+ torture_suite_add_2smb_test(suite, "deltest4", deltest4);
+ torture_suite_add_2smb_test(suite, "deltest5", deltest5);
+ torture_suite_add_2smb_test(suite, "deltest6", deltest6);
+ torture_suite_add_2smb_test(suite, "deltest7", deltest7);
+ torture_suite_add_2smb_test(suite, "deltest8", deltest8);
+ torture_suite_add_2smb_test(suite, "deltest9", deltest9);
+ torture_suite_add_2smb_test(suite, "deltest9a", deltest9a);
+ torture_suite_add_2smb_test(suite, "deltest10", deltest10);
+ torture_suite_add_2smb_test(suite, "deltest11", deltest11);
+ torture_suite_add_2smb_test(suite, "deltest12", deltest12);
+ torture_suite_add_2smb_test(suite, "deltest13", deltest13);
+ torture_suite_add_2smb_test(suite, "deltest14", deltest14);
+ torture_suite_add_2smb_test(suite, "deltest15", deltest15);
+ torture_suite_add_2smb_test(suite, "deltest16", deltest16);
+ torture_suite_add_2smb_test(suite, "deltest16a", deltest16a);
+ torture_suite_add_2smb_test(suite, "deltest17", deltest17);
+ torture_suite_add_2smb_test(suite, "deltest17a", deltest17a);
+ torture_suite_add_2smb_test(suite, "deltest17b", deltest17b);
+ torture_suite_add_2smb_test(suite, "deltest17c", deltest17c);
+ torture_suite_add_2smb_test(suite, "deltest17d", deltest17d);
+ torture_suite_add_2smb_test(suite, "deltest17e", deltest17e);
+ torture_suite_add_2smb_test(suite, "deltest17f", deltest17f);
+ torture_suite_add_2smb_test(suite, "deltest18", deltest18);
+ torture_suite_add_2smb_test(suite, "deltest19", deltest19);
+ torture_suite_add_2smb_test(suite, "deltest20", deltest20);
+ torture_suite_add_2smb_test(suite, "deltest20a", deltest20a);
+ torture_suite_add_2smb_test(suite, "deltest20b", deltest20b);
+ torture_suite_add_2smb_test(suite, "deltest20c", deltest20c);
+ torture_suite_add_simple_test(suite, "deltest21", deltest21);
+ torture_suite_add_simple_test(suite, "deltest22", deltest22);
+ torture_suite_add_2smb_test(suite, "deltest23", deltest23);
+ torture_suite_add_simple_test(suite, "deltest24", deltest24);
+ torture_suite_add_2smb_test(suite, "deltest25", deltest25);
+ torture_suite_add_2smb_test(suite, "deltest25a", deltest25a);
+
+ return suite;
+}
diff --git a/source4/torture/basic/denytest.c b/source4/torture/basic/denytest.c
new file mode 100644
index 0000000..c9f4a97
--- /dev/null
+++ b/source4/torture/basic/denytest.c
@@ -0,0 +1,2819 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - deny mode scanning functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "libcli/security/security.h"
+#include "torture/util.h"
+#include "cxd_known.h"
+#include "torture/basic/proto.h"
+
+extern int torture_failures;
+
+#define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0)
+
+enum deny_result {A_0=0, A_X=1, A_R=2, A_W=3, A_RW=5};
+
+static const char *denystr(int denymode)
+{
+ const struct {
+ int v;
+ const char *name;
+ } deny_modes[] = {
+ {DENY_DOS, "DENY_DOS"},
+ {DENY_ALL, "DENY_ALL"},
+ {DENY_WRITE, "DENY_WRITE"},
+ {DENY_READ, "DENY_READ"},
+ {DENY_NONE, "DENY_NONE"},
+ {DENY_FCB, "DENY_FCB"},
+ {-1, NULL}};
+ int i;
+ for (i=0;deny_modes[i].name;i++) {
+ if (deny_modes[i].v == denymode) return deny_modes[i].name;
+ }
+ return "DENY_XXX";
+}
+
+static const char *openstr(int mode)
+{
+ const struct {
+ int v;
+ const char *name;
+ } open_modes[] = {
+ {O_RDWR, "O_RDWR"},
+ {O_RDONLY, "O_RDONLY"},
+ {O_WRONLY, "O_WRONLY"},
+ {-1, NULL}};
+ int i;
+ for (i=0;open_modes[i].name;i++) {
+ if (open_modes[i].v == mode) return open_modes[i].name;
+ }
+ return "O_XXX";
+}
+
+static const char *resultstr(enum deny_result res)
+{
+ const struct {
+ enum deny_result res;
+ const char *name;
+ } results[] = {
+ {A_X, "X"},
+ {A_0, "-"},
+ {A_R, "R"},
+ {A_W, "W"},
+ {A_RW,"RW"}};
+ int i;
+ for (i=0;i<ARRAY_SIZE(results);i++) {
+ if (results[i].res == res) return results[i].name;
+ }
+ return "*";
+}
+
+static const struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable2[] = {
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_0}
+};
+
+
+static const struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable1[] = {
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{1, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{1, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{1, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{1, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_DOS, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_DOS, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_DOS, A_RW},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_DOS, A_R},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_DOS, A_W},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_DOS, O_RDWR, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_DOS, O_RDONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_DOS, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_ALL, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_WRITE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_READ, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_READ, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDWR, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_RDONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_RDONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_DOS, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_READ, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_READ, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_READ, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_NONE, A_RW},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_NONE, A_R},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_NONE, A_W},
+{0, O_WRONLY, DENY_NONE, O_RDWR, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_RDONLY, DENY_FCB, A_0},
+{0, O_WRONLY, DENY_NONE, O_WRONLY, DENY_FCB, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDWR, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDWR, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_RDONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_RDONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_DOS, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_DOS, A_R},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_DOS, A_W},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_ALL, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_WRITE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_READ, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_NONE, A_0},
+{0, O_WRONLY, DENY_FCB, O_RDWR, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_RDONLY, DENY_FCB, A_RW},
+{0, O_WRONLY, DENY_FCB, O_WRONLY, DENY_FCB, A_RW}
+};
+
+
+static void progress_bar(struct torture_context *tctx, unsigned int i, unsigned int total)
+{
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%5d/%5d\r", i, total);
+ fflush(stdout);
+ }
+}
+
+/*
+ this produces a matrix of deny mode behaviour for 1 connection
+ */
+bool torture_denytest1(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ int fnum1, fnum2;
+ int i;
+ bool correct = true;
+ struct timespec tv, tv_start;
+ const char *fnames[2] = {"\\denytest1.dat", "\\denytest1.exe"};
+ int failures=0;
+
+ torture_comment(tctx, "Testing deny modes with 1 connection\n");
+
+ for (i=0;i<2;i++) {
+ smbcli_unlink(cli1->tree, fnames[i]);
+ fnum1 = smbcli_open(cli1->tree, fnames[i], O_RDWR|O_CREAT, DENY_NONE);
+ smbcli_write(cli1->tree, fnum1, 0, fnames[i], 0, strlen(fnames[i]));
+ smbcli_close(cli1->tree, fnum1);
+ }
+
+ torture_comment(tctx, "Testing %d entries\n", (int)ARRAY_SIZE(denytable1));
+
+ clock_gettime_mono(&tv_start);
+
+ for (i=0; i<ARRAY_SIZE(denytable1); i++) {
+ enum deny_result res;
+ const char *fname = fnames[denytable1[i].isexe];
+
+ progress_bar(tctx, i, ARRAY_SIZE(denytable1));
+
+ if (!torture_setting_bool(tctx, "deny_fcb_support", true) &&
+ (denytable1[i].deny1 == DENY_FCB ||
+ denytable1[i].deny2 == DENY_FCB))
+ continue;
+
+ if (!torture_setting_bool(tctx, "deny_dos_support", true) &&
+ (denytable1[i].deny1 == DENY_DOS ||
+ denytable1[i].deny2 == DENY_DOS))
+ continue;
+
+ fnum1 = smbcli_open(cli1->tree, fname,
+ denytable1[i].mode1,
+ denytable1[i].deny1);
+ fnum2 = smbcli_open(cli1->tree, fname,
+ denytable1[i].mode2,
+ denytable1[i].deny2);
+
+ if (fnum1 == -1) {
+ res = A_X;
+ } else if (fnum2 == -1) {
+ res = A_0;
+ } else {
+ uint8_t x = 1;
+ res = A_0;
+ if (smbcli_read(cli1->tree, fnum2, &x, 0, 1) == 1) {
+ res += A_R;
+ }
+ if (smbcli_write(cli1->tree, fnum2, 0, &x, 0, 1) == 1) {
+ res += A_W;
+ }
+ }
+
+ if (torture_setting_bool(tctx, "showall", false) ||
+ res != denytable1[i].result) {
+ int64_t tdif;
+ clock_gettime_mono(&tv);
+ tdif = nsec_time_diff(&tv, &tv_start);
+ tdif /= 1000000;
+ torture_comment(tctx, "%lld: %s %8s %10s %8s %10s %s (correct=%s)\n",
+ (long long)tdif,
+ fname,
+ denystr(denytable1[i].deny1),
+ openstr(denytable1[i].mode1),
+ denystr(denytable1[i].deny2),
+ openstr(denytable1[i].mode2),
+ resultstr(res),
+ resultstr(denytable1[i].result));
+ }
+
+ if (res != denytable1[i].result) {
+ correct = false;
+ CHECK_MAX_FAILURES(failed);
+ }
+
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ }
+
+failed:
+ for (i=0;i<2;i++) {
+ smbcli_unlink(cli1->tree, fnames[i]);
+ }
+
+ torture_comment(tctx, "finished denytest1 (%d failures)\n", failures);
+ return correct;
+}
+
+
+/*
+ this produces a matrix of deny mode behaviour with 2 connections
+ */
+bool torture_denytest2(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ int fnum1, fnum2;
+ int i;
+ bool correct = true;
+ const char *fnames[2] = {"\\denytest2.dat", "\\denytest2.exe"};
+ struct timespec tv, tv_start;
+ int failures=0;
+
+ for (i=0;i<2;i++) {
+ smbcli_unlink(cli1->tree, fnames[i]);
+ fnum1 = smbcli_open(cli1->tree, fnames[i], O_RDWR|O_CREAT, DENY_NONE);
+ smbcli_write(cli1->tree, fnum1, 0, fnames[i], 0, strlen(fnames[i]));
+ smbcli_close(cli1->tree, fnum1);
+ }
+
+ clock_gettime_mono(&tv_start);
+
+ for (i=0; i<ARRAY_SIZE(denytable2); i++) {
+ enum deny_result res;
+ const char *fname = fnames[denytable2[i].isexe];
+
+ progress_bar(tctx, i, ARRAY_SIZE(denytable1));
+
+ if (!torture_setting_bool(tctx, "deny_fcb_support", true) &&
+ (denytable1[i].deny1 == DENY_FCB ||
+ denytable1[i].deny2 == DENY_FCB))
+ continue;
+
+ if (!torture_setting_bool(tctx, "deny_dos_support", true) &&
+ (denytable1[i].deny1 == DENY_DOS ||
+ denytable1[i].deny2 == DENY_DOS))
+ continue;
+
+ fnum1 = smbcli_open(cli1->tree, fname,
+ denytable2[i].mode1,
+ denytable2[i].deny1);
+ fnum2 = smbcli_open(cli2->tree, fname,
+ denytable2[i].mode2,
+ denytable2[i].deny2);
+
+ if (fnum1 == -1) {
+ res = A_X;
+ } else if (fnum2 == -1) {
+ res = A_0;
+ } else {
+ uint8_t x = 1;
+ res = A_0;
+ if (smbcli_read(cli2->tree, fnum2, &x, 0, 1) == 1) {
+ res += A_R;
+ }
+ if (smbcli_write(cli2->tree, fnum2, 0, &x, 0, 1) == 1) {
+ res += A_W;
+ }
+ }
+
+ if (torture_setting_bool(tctx, "showall", false) ||
+ res != denytable2[i].result) {
+ int64_t tdif;
+ clock_gettime_mono(&tv);
+ tdif = nsec_time_diff(&tv, &tv_start);
+ tdif /= 1000000;
+ torture_comment(tctx, "%lld: %s %8s %10s %8s %10s %s (correct=%s)\n",
+ (long long)tdif,
+ fname,
+ denystr(denytable2[i].deny1),
+ openstr(denytable2[i].mode1),
+ denystr(denytable2[i].deny2),
+ openstr(denytable2[i].mode2),
+ resultstr(res),
+ resultstr(denytable2[i].result));
+ }
+
+ if (res != denytable2[i].result) {
+ correct = false;
+ CHECK_MAX_FAILURES(failed);
+ }
+
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli2->tree, fnum2);
+ }
+
+failed:
+ for (i=0;i<2;i++) {
+ smbcli_unlink(cli1->tree, fnames[i]);
+ }
+
+ torture_comment(tctx, "finished denytest2 (%d failures)\n", failures);
+ return correct;
+}
+
+
+
+/*
+ simple test harness for playing with deny modes
+ */
+bool torture_denytest3(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ int fnum1, fnum2;
+ const char *fname;
+
+ fname = "\\deny_dos1.dat";
+
+ smbcli_unlink(cli1->tree, fname);
+ fnum1 = smbcli_open(cli1->tree, fname, O_CREAT|O_TRUNC|O_WRONLY, DENY_DOS);
+ fnum2 = smbcli_open(cli1->tree, fname, O_CREAT|O_TRUNC|O_WRONLY, DENY_DOS);
+ if (fnum1 != -1) smbcli_close(cli1->tree, fnum1);
+ if (fnum2 != -1) smbcli_close(cli1->tree, fnum2);
+ smbcli_unlink(cli1->tree, fname);
+ torture_comment(tctx, "fnum1=%d fnum2=%d\n", fnum1, fnum2);
+
+
+ fname = "\\deny_dos2.dat";
+
+ smbcli_unlink(cli1->tree, fname);
+ fnum1 = smbcli_open(cli1->tree, fname, O_CREAT|O_TRUNC|O_WRONLY, DENY_DOS);
+ fnum2 = smbcli_open(cli2->tree, fname, O_CREAT|O_TRUNC|O_WRONLY, DENY_DOS);
+ if (fnum1 != -1) smbcli_close(cli1->tree, fnum1);
+ if (fnum2 != -1) smbcli_close(cli2->tree, fnum2);
+ smbcli_unlink(cli1->tree, fname);
+ torture_comment(tctx, "fnum1=%d fnum2=%d\n", fnum1, fnum2);
+
+ return true;
+}
+
+struct bit_value {
+ uint32_t value;
+ const char *name;
+};
+
+static uint32_t map_bits(const struct bit_value *bv, int b, int nbits)
+{
+ int i;
+ uint32_t ret = 0;
+ for (i=0;i<nbits;i++) {
+ if (b & (1<<i)) {
+ ret |= bv[i].value;
+ }
+ }
+ return ret;
+}
+
+static const char *bit_string(TALLOC_CTX *mem_ctx, const struct bit_value *bv, int b, int nbits)
+{
+ char *ret = NULL;
+ int i;
+ for (i=0;i<nbits;i++) {
+ if (b & (1<<i)) {
+ if (ret == NULL) {
+ ret = talloc_asprintf(mem_ctx, "%s", bv[i].name);
+ } else {
+ ret = talloc_asprintf_append_buffer(ret, " | %s", bv[i].name);
+ }
+ }
+ }
+ if (ret == NULL) ret = talloc_strdup(mem_ctx, "(NONE)");
+ return ret;
+}
+
+
+/*
+ determine if two opens conflict
+*/
+static NTSTATUS predict_share_conflict(uint32_t sa1, uint32_t am1, uint32_t sa2, uint32_t am2,
+ bool read_for_execute, enum deny_result *res)
+{
+#define CHECK_MASK(am, sa, right, share) do { \
+ if (((am) & (right)) && !((sa) & (share))) { \
+ *res = A_0; \
+ return NT_STATUS_SHARING_VIOLATION; \
+ }} while (0)
+
+ *res = A_0;
+ if (am2 & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
+ *res += A_W;
+ }
+ if (am2 & SEC_FILE_READ_DATA) {
+ *res += A_R;
+ } else if ((am2 & SEC_FILE_EXECUTE) && read_for_execute) {
+ *res += A_R;
+ }
+
+ /* if either open involves no read.write or delete access then
+ it can't conflict */
+ if (!(am1 & (SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_EXECUTE |
+ SEC_STD_DELETE))) {
+ return NT_STATUS_OK;
+ }
+ if (!(am2 & (SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_EXECUTE |
+ SEC_STD_DELETE))) {
+ return NT_STATUS_OK;
+ }
+
+ /* check the basic share access */
+ CHECK_MASK(am1, sa2,
+ SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
+ NTCREATEX_SHARE_ACCESS_WRITE);
+ CHECK_MASK(am2, sa1,
+ SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
+ NTCREATEX_SHARE_ACCESS_WRITE);
+
+ CHECK_MASK(am1, sa2,
+ SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
+ NTCREATEX_SHARE_ACCESS_READ);
+ CHECK_MASK(am2, sa1,
+ SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
+ NTCREATEX_SHARE_ACCESS_READ);
+
+ CHECK_MASK(am1, sa2,
+ SEC_STD_DELETE,
+ NTCREATEX_SHARE_ACCESS_DELETE);
+ CHECK_MASK(am2, sa1,
+ SEC_STD_DELETE,
+ NTCREATEX_SHARE_ACCESS_DELETE);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ a denytest for ntcreatex
+ */
+static bool torture_ntdenytest(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2, int client)
+{
+ const struct bit_value share_access_bits[] = {
+ { NTCREATEX_SHARE_ACCESS_READ, "S_R" },
+ { NTCREATEX_SHARE_ACCESS_WRITE, "S_W" },
+ { NTCREATEX_SHARE_ACCESS_DELETE, "S_D" }
+ };
+ const struct bit_value access_mask_bits[] = {
+ { SEC_FILE_READ_DATA, "R_DATA" },
+ { SEC_FILE_WRITE_DATA, "W_DATA" },
+ { SEC_FILE_READ_ATTRIBUTE, "R_ATTR" },
+ { SEC_FILE_WRITE_ATTRIBUTE, "W_ATTR" },
+ { SEC_FILE_READ_EA, "R_EAS " },
+ { SEC_FILE_WRITE_EA, "W_EAS " },
+ { SEC_FILE_APPEND_DATA, "A_DATA" },
+ { SEC_FILE_EXECUTE, "EXEC " }
+ };
+ int fnum1;
+ int i;
+ bool correct = true;
+ struct timespec tv, tv_start;
+ const char *fname;
+ int nbits1 = ARRAY_SIZE(share_access_bits);
+ int nbits2 = ARRAY_SIZE(access_mask_bits);
+ union smb_open io1, io2;
+ extern int torture_numops;
+ int failures = 0;
+ uint8_t buf[1];
+
+ torture_comment(tctx, "format: server correct\n");
+
+ ZERO_STRUCT(buf);
+
+ fname = talloc_asprintf(cli1, "\\ntdeny_%d.dll", client);
+
+ smbcli_unlink(cli1->tree, fname);
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf));
+ smbcli_close(cli1->tree, fnum1);
+
+ clock_gettime_mono(&tv_start);
+
+ io1.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io1.ntcreatex.in.root_fid.fnum = 0;
+ io1.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io1.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io1.ntcreatex.in.file_attr = 0;
+ io1.ntcreatex.in.alloc_size = 0;
+ io1.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io1.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io1.ntcreatex.in.security_flags = 0;
+ io1.ntcreatex.in.fname = fname;
+ io2 = io1;
+
+ torture_comment(tctx, "Testing %d entries on %s\n", torture_numops, fname);
+
+ for (i=0;i<torture_numops;i++) {
+ NTSTATUS status1, status2, status2_p;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ enum deny_result res, res2;
+ int b_sa1 = random() & ((1<<nbits1)-1);
+ int b_am1 = random() & ((1<<nbits2)-1);
+ int b_sa2 = random() & ((1<<nbits1)-1);
+ int b_am2 = random() & ((1<<nbits2)-1);
+ bool read_for_execute;
+
+ progress_bar(tctx, i, torture_numops);
+
+ io1.ntcreatex.in.share_access = map_bits(share_access_bits, b_sa1, nbits1);
+ io1.ntcreatex.in.access_mask = map_bits(access_mask_bits, b_am1, nbits2);
+
+ io2.ntcreatex.in.share_access = map_bits(share_access_bits, b_sa2, nbits1);
+ io2.ntcreatex.in.access_mask = map_bits(access_mask_bits, b_am2, nbits2);
+
+ status1 = smb_raw_open(cli1->tree, mem_ctx, &io1);
+ status2 = smb_raw_open(cli2->tree, mem_ctx, &io2);
+
+ if (random() % 2 == 0) {
+ read_for_execute = true;
+ } else {
+ read_for_execute = false;
+ }
+
+ if (!NT_STATUS_IS_OK(status1)) {
+ res = A_X;
+ } else if (!NT_STATUS_IS_OK(status2)) {
+ res = A_0;
+ } else {
+ union smb_read r;
+ NTSTATUS status;
+
+ /* we can't use smbcli_read() as we need to
+ set read_for_execute */
+ r.readx.level = RAW_READ_READX;
+ r.readx.in.file.fnum = io2.ntcreatex.out.file.fnum;
+ r.readx.in.offset = 0;
+ r.readx.in.mincnt = sizeof(buf);
+ r.readx.in.maxcnt = sizeof(buf);
+ r.readx.in.remaining = 0;
+ r.readx.in.read_for_execute = read_for_execute;
+ r.readx.out.data = buf;
+
+ res = A_0;
+ status = smb_raw_read(cli2->tree, &r);
+ if (NT_STATUS_IS_OK(status)) {
+ res += A_R;
+ }
+ if (smbcli_write(cli2->tree, io2.ntcreatex.out.file.fnum,
+ 0, buf, 0, sizeof(buf)) >= 1) {
+ res += A_W;
+ }
+ }
+
+ if (NT_STATUS_IS_OK(status1)) {
+ smbcli_close(cli1->tree, io1.ntcreatex.out.file.fnum);
+ }
+ if (NT_STATUS_IS_OK(status2)) {
+ smbcli_close(cli2->tree, io2.ntcreatex.out.file.fnum);
+ }
+
+ status2_p = predict_share_conflict(io1.ntcreatex.in.share_access,
+ io1.ntcreatex.in.access_mask,
+ io2.ntcreatex.in.share_access,
+ io2.ntcreatex.in.access_mask,
+ read_for_execute,
+ &res2);
+
+ clock_gettime_mono(&tv);
+ if (torture_setting_bool(tctx, "showall", false) ||
+ !NT_STATUS_EQUAL(status2, status2_p) ||
+ res != res2) {
+ torture_comment(tctx, "\n%-20s %-70s\n%-20s %-70s %4s %4s %s/%s\n",
+ bit_string(mem_ctx, share_access_bits, b_sa1, nbits1),
+ bit_string(mem_ctx, access_mask_bits, b_am1, nbits2),
+ bit_string(mem_ctx, share_access_bits, b_sa2, nbits1),
+ bit_string(mem_ctx, access_mask_bits, b_am2, nbits2),
+ resultstr(res),
+ resultstr(res2),
+ nt_errstr(status2),
+ nt_errstr(status2_p));
+ fflush(stdout);
+ }
+
+ if (res != res2 ||
+ !NT_STATUS_EQUAL(status2, status2_p)) {
+ CHECK_MAX_FAILURES(failed);
+ correct = false;
+ }
+
+ talloc_free(mem_ctx);
+ }
+
+failed:
+ smbcli_unlink(cli1->tree, fname);
+
+ torture_comment(tctx, "finished ntdenytest (%d failures)\n", failures);
+ return correct;
+}
+
+
+
+/*
+ a denytest for ntcreatex
+ */
+bool torture_ntdenytest1(struct torture_context *tctx,
+ struct smbcli_state *cli, int client)
+{
+ extern int torture_seed;
+
+ srandom(torture_seed + client);
+
+ torture_comment(tctx, "starting ntdenytest1 client %d\n", client);
+
+ return torture_ntdenytest(tctx, cli, cli, client);
+}
+
+/*
+ a denytest for ntcreatex
+ */
+bool torture_ntdenytest2(struct torture_context *torture,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ return torture_ntdenytest(torture, cli1, cli2, 0);
+}
+
+#define COMPARE_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ failed = true; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)(v), (int)correct); \
+ ret = false; \
+ }} while (0)
+
+/*
+ test sharing of handles with DENY_DOS on a single connection
+*/
+bool torture_denydos_sharing(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = "\\torture_denydos.txt";
+ NTSTATUS status;
+ int fnum1 = -1, fnum2 = -1;
+ bool ret = true;
+ union smb_setfileinfo sfinfo;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(cli);
+
+ torture_comment(tctx, "Checking DENY_DOS shared handle semantics\n");
+ smbcli_unlink(cli->tree, fname);
+
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.fname = fname;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 0;
+ io.openx.in.timeout = 0;
+
+ torture_comment(tctx, "openx twice with RDWR/DENY_DOS\n");
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.openx.out.file.fnum;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.openx.out.file.fnum;
+
+ torture_comment(tctx, "fnum1=%d fnum2=%d\n", fnum1, fnum2);
+
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.position_information.in.file.fnum = fnum1;
+ sfinfo.position_information.in.position = 1000;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "two handles should be same file handle\n");
+ finfo.position_information.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(finfo.position_information.out.position, 1000);
+
+ finfo.position_information.in.file.fnum = fnum2;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(finfo.position_information.out.position, 1000);
+
+
+ smbcli_close(cli->tree, fnum1);
+ smbcli_close(cli->tree, fnum2);
+
+ torture_comment(tctx, "openx twice with RDWR/DENY_NONE\n");
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_NONE;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.openx.out.file.fnum;
+
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.openx.out.file.fnum;
+
+ torture_comment(tctx, "fnum1=%d fnum2=%d\n", fnum1, fnum2);
+
+ torture_comment(tctx, "two handles should be separate\n");
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.position_information.in.file.fnum = fnum1;
+ sfinfo.position_information.in.position = 1000;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ finfo.position_information.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(finfo.position_information.out.position, 1000);
+
+ finfo.position_information.in.file.fnum = fnum2;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(finfo.position_information.out.position, 0);
+
+done:
+ smbcli_close(cli->tree, fnum1);
+ smbcli_close(cli->tree, fnum2);
+ smbcli_unlink(cli->tree, fname);
+
+ return ret;
+}
+
+#define CXD_MATCHES(_cxd, i) \
+ ((cxd_known[i].cxd_test == (_cxd)->cxd_test) && \
+ (cxd_known[i].cxd_flags == (_cxd)->cxd_flags) && \
+ (cxd_known[i].cxd_access1 == (_cxd)->cxd_access1) && \
+ (cxd_known[i].cxd_sharemode1 == (_cxd)->cxd_sharemode1) && \
+ (cxd_known[i].cxd_access2 == (_cxd)->cxd_access2) && \
+ (cxd_known[i].cxd_sharemode2 == (_cxd)->cxd_sharemode2))
+
+static int cxd_find_known(struct createx_data *cxd)
+{
+ static int i = -1;
+
+ /* Optimization for tests which we don't have results saved for. */
+ if ((cxd->cxd_test == CXD_TEST_CREATEX_ACCESS_EXHAUSTIVE) ||
+ (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE_EXTENDED))
+ return -1;
+
+ /* Optimization: If our cxd_known table is too large, it hurts test
+ * performance to search through the entire table each time. If the
+ * caller can pass in the previous result, we can try the next entry.
+ * This works if results are taken directly from the same code. */
+ i++;
+ if ((i >= 0) && (i < sizeof(cxd_known) / sizeof(cxd_known[0])) &&
+ CXD_MATCHES(cxd, i))
+ return i;
+
+ for (i = 0; i < (sizeof(cxd_known) / sizeof(cxd_known[0])); i++) {
+ if (CXD_MATCHES(cxd, i))
+ return i;
+ }
+
+ return -1;
+}
+
+#define CREATEX_NAME "\\createx_dir"
+
+static bool createx_make_dir(struct torture_context *tctx,
+ struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, const char *fname)
+{
+ bool ret = true;
+ NTSTATUS status;
+
+ status = smbcli_mkdir(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ return ret;
+}
+
+static bool createx_make_file(struct torture_context *tctx,
+ struct smbcli_tree *tree, TALLOC_CTX *mem_ctx, const char *fname)
+{
+ union smb_open open_parms;
+ bool ret = true;
+ NTSTATUS status;
+
+ ZERO_STRUCT(open_parms);
+ open_parms.generic.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = 0;
+ open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ open_parms.ntcreatex.in.share_access = 0;
+ open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ open_parms.ntcreatex.in.create_options = 0;
+ open_parms.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(tree, mem_ctx, &open_parms);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ return ret;
+}
+
+static void createx_fill_dir(union smb_open *open_parms, int accessmode,
+ int sharemode, const char *fname)
+{
+ ZERO_STRUCTP(open_parms);
+ open_parms->generic.level = RAW_OPEN_NTCREATEX;
+ open_parms->ntcreatex.in.flags = 0;
+ open_parms->ntcreatex.in.access_mask = accessmode;
+ open_parms->ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ open_parms->ntcreatex.in.share_access = sharemode;
+ open_parms->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ open_parms->ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ open_parms->ntcreatex.in.fname = fname;
+}
+
+static void createx_fill_file(union smb_open *open_parms, int accessmode,
+ int sharemode, const char *fname)
+{
+ ZERO_STRUCTP(open_parms);
+ open_parms->generic.level = RAW_OPEN_NTCREATEX;
+ open_parms->ntcreatex.in.flags = 0;
+ open_parms->ntcreatex.in.access_mask = accessmode;
+ open_parms->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ open_parms->ntcreatex.in.share_access = sharemode;
+ open_parms->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ open_parms->ntcreatex.in.create_options = 0;
+ open_parms->ntcreatex.in.fname = fname;
+ open_parms->ntcreatex.in.root_fid.fnum = 0;
+}
+
+static int data_file_fd = -1;
+
+#define KNOWN "known"
+#define CHILD "child"
+static bool createx_test_dir(struct torture_context *tctx,
+ struct smbcli_tree *tree, int fnum, TALLOC_CTX *mem_ctx, NTSTATUS *result)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open open_parms;
+
+ /* bypass original handle to guarantee creation */
+ ZERO_STRUCT(open_parms);
+ open_parms.generic.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = 0;
+ open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ open_parms.ntcreatex.in.share_access = 0;
+ open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ open_parms.ntcreatex.in.create_options = 0;
+ open_parms.ntcreatex.in.fname = CREATEX_NAME "\\" KNOWN;
+
+ status = smb_raw_open(tree, mem_ctx, &open_parms);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+
+ result[CXD_DIR_ENUMERATE] = NT_STATUS_OK;
+
+ /* try to create a child */
+ ZERO_STRUCT(open_parms);
+ open_parms.generic.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = 0;
+ open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ open_parms.ntcreatex.in.share_access = 0;
+ open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ open_parms.ntcreatex.in.create_options = 0;
+ open_parms.ntcreatex.in.fname = CHILD;
+ open_parms.ntcreatex.in.root_fid.fnum = fnum;
+
+ result[CXD_DIR_CREATE_CHILD] =
+ smb_raw_open(tree, mem_ctx, &open_parms);
+ smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+
+ /* try to traverse dir to known good file */
+ ZERO_STRUCT(open_parms);
+ open_parms.generic.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = 0;
+ open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ open_parms.ntcreatex.in.share_access = 0;
+ open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ open_parms.ntcreatex.in.create_options = 0;
+ open_parms.ntcreatex.in.fname = KNOWN;
+ open_parms.ntcreatex.in.root_fid.fnum = fnum;
+
+ result[CXD_DIR_TRAVERSE] =
+ smb_raw_open(tree, mem_ctx, &open_parms);
+
+
+ smbcli_close(tree, open_parms.ntcreatex.out.file.fnum);
+ smbcli_unlink(tree, CREATEX_NAME "\\" KNOWN);
+ smbcli_unlink(tree, CREATEX_NAME "\\" CHILD);
+
+ done:
+ return ret;
+}
+
+static bool createx_test_file(struct torture_context *tctx,
+ struct smbcli_tree *tree, int fnum, TALLOC_CTX *mem_ctx, NTSTATUS *result)
+{
+ union smb_read rd;
+ union smb_write wr;
+ char buf[256] = "";
+
+ memset(&rd, 0, sizeof(rd));
+ rd.readx.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = sizeof(buf);
+ rd.readx.in.maxcnt = sizeof(buf);
+ rd.readx.out.data = (uint8_t *)buf;
+
+ result[CXD_FILE_READ] = smb_raw_read(tree, &rd);
+
+ memset(&wr, 0, sizeof(wr));
+ wr.writex.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum;
+ wr.writex.in.count = sizeof(buf);
+ wr.writex.in.data = (uint8_t *)buf;
+
+ result[CXD_FILE_WRITE] = smb_raw_write(tree, &wr);
+
+ memset(&rd, 0, sizeof(rd));
+ rd.readx.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = sizeof(buf);
+ rd.readx.in.maxcnt = sizeof(buf);
+ rd.readx.in.read_for_execute = 1;
+ rd.readx.out.data = (uint8_t *)buf;
+
+ result[CXD_FILE_EXECUTE] = smb_raw_read(tree, &rd);
+
+ return true;
+}
+
+/* TODO When redirecting stdout to a file, the progress bar really screws up
+ * the output. Could use a switch "--noprogress", or direct the progress bar to
+ * stderr? No other solution? */
+static void createx_progress_bar(struct torture_context *tctx, unsigned int i,
+ unsigned int total, unsigned int skipped)
+{
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%5d/%5d (%d skipped)\r", i, total,
+ skipped);
+ fflush(stdout);
+ }
+}
+
+static bool torture_createx_specific(struct torture_context *tctx, struct
+ smbcli_state *cli, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx, struct
+ createx_data *cxd, int estimated_count)
+{
+ static int call_count = 1;
+ static int unskipped_call_count = 1;
+ const char *fname = CREATEX_NAME;
+ int fnum = -1, fnum2 = -1, res, i;
+ union smb_open open_parms1, open_parms2;
+ bool ret = true;
+ bool is_dir = cxd->cxd_flags & CXD_FLAGS_DIRECTORY;
+ NTSTATUS *result = &cxd->cxd_result[0];
+ NTSTATUS *result2 = &cxd->cxd_result2[0];
+ bool found = false, failed = false;
+
+ bool (*make_func)(struct torture_context *,
+ struct smbcli_tree *, TALLOC_CTX *, const char *);
+ void (*fill_func)(union smb_open *, int, int, const char *);
+ bool (*test_func)(struct torture_context *,
+ struct smbcli_tree *, int, TALLOC_CTX *, NTSTATUS *);
+ NTSTATUS (*destroy_func)(struct smbcli_tree *, const char *);
+
+ if (is_dir) {
+ make_func = createx_make_dir;
+ fill_func = createx_fill_dir;
+ test_func = createx_test_dir;
+ destroy_func = smbcli_rmdir;
+ } else {
+ make_func = createx_make_file;
+ fill_func = createx_fill_file;
+ test_func = createx_test_file;
+ destroy_func = smbcli_unlink;
+ }
+
+ /* Skip all SACL related tests. */
+ if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
+ ((cxd->cxd_access1 & SEC_FLAG_SYSTEM_SECURITY) ||
+ (cxd->cxd_access2 & SEC_FLAG_SYSTEM_SECURITY)))
+ goto done;
+
+ if (cxd->cxd_flags & CXD_FLAGS_MAKE_BEFORE_CREATEX) {
+ ret = make_func(tctx, cli->tree, mem_ctx, fname);
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Initial creation failed\n");
+ goto done;
+ }
+ }
+
+ /* Initialize. */
+ fill_func(&open_parms1, cxd->cxd_access1, cxd->cxd_sharemode1, fname);
+
+ if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+ fill_func(&open_parms2, cxd->cxd_access2, cxd->cxd_sharemode2,
+ fname);
+ }
+
+ for (i = CXD_CREATEX + 1; i < CXD_MAX; i++) {
+ result[i] = NT_STATUS_UNSUCCESSFUL;
+ result2[i] = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* Perform open(s). */
+ result[CXD_CREATEX] = smb_raw_open(cli->tree, mem_ctx, &open_parms1);
+ if (NT_STATUS_IS_OK(result[CXD_CREATEX])) {
+ fnum = open_parms1.ntcreatex.out.file.fnum;
+ ret = test_func(tctx, cli->tree, fnum, mem_ctx, result);
+ smbcli_close(cli->tree, fnum);
+ }
+
+ if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+ result2[CXD_CREATEX] = smb_raw_open(cli2->tree, mem_ctx,
+ &open_parms2);
+ if (NT_STATUS_IS_OK(result2[CXD_CREATEX])) {
+ fnum2 = open_parms2.ntcreatex.out.file.fnum;
+ ret = test_func(tctx, cli2->tree, fnum2, mem_ctx,
+ result2);
+ smbcli_close(cli2->tree, fnum2);
+ }
+ }
+
+ if (data_file_fd >= 0) {
+ size_t cxd_len = sizeof(struct createx_data);
+ found = true;
+ res = write(data_file_fd, cxd, cxd_len);
+ if (res != cxd_len) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): write failed: %s!",
+ __location__, strerror(errno));
+ ret = false;
+ }
+ } else if ((res = cxd_find_known(cxd)) >= 0) {
+ found = true;
+ for (i = 0; i < CXD_MAX; i++) {
+ /* Note: COMPARE_STATUS will set the "failed" bool. */
+ COMPARE_STATUS(result[i], cxd_known[res].cxd_result[i]);
+ if (i == 0 && !NT_STATUS_IS_OK(result[i]))
+ break;
+
+ if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+ COMPARE_STATUS(result2[i],
+ cxd_known[res].cxd_result2[i]);
+ if (i == 0 && !NT_STATUS_IS_OK(result2[i]))
+ break;
+ }
+ }
+ }
+
+ /* We print if its not in the "cxd_known" list or if we fail. */
+ if (!found || failed) {
+ torture_comment(tctx,
+ " { .cxd_test = %d, .cxd_flags = %#3x, "
+ ".cxd_access1 = %#10x, .cxd_sharemode1=%1x, "
+ ".cxd_access2=%#10x, .cxd_sharemode2=%1x, "
+ ".cxd_result = { ", cxd->cxd_test, cxd->cxd_flags,
+ cxd->cxd_access1, cxd->cxd_sharemode1, cxd->cxd_access2,
+ cxd->cxd_sharemode2);
+ for (i = 0; i < CXD_MAX; i++) {
+ torture_comment(tctx, "%s, ", nt_errstr(result[i]));
+ if (i == 0 && !NT_STATUS_IS_OK(result[i]))
+ break;
+ }
+ torture_comment(tctx, "}");
+ if (cxd->cxd_test == CXD_TEST_CREATEX_SHAREMODE) {
+ torture_comment(tctx, ", .cxd_result2 = { ");
+ for (i = 0; i < CXD_MAX; i++) {
+ torture_comment(tctx, "%s, ",
+ nt_errstr(result2[i]));
+ if (i == 0 && !NT_STATUS_IS_OK(result2[i]))
+ break;
+ }
+ torture_comment(tctx, "}");
+ }
+ torture_comment(tctx, "}, \n");
+ } else {
+ createx_progress_bar(tctx, call_count, estimated_count,
+ call_count - unskipped_call_count);
+ }
+ /* Count tests that we didn't skip. */
+ unskipped_call_count++;
+ done:
+ call_count++;
+
+ destroy_func(cli->tree, fname);
+ return ret;
+}
+
+uint32_t sec_access_bit_groups[] = {
+ SEC_RIGHTS_FILE_READ,
+ SEC_RIGHTS_FILE_WRITE,
+ SEC_RIGHTS_FILE_EXECUTE
+};
+#define NUM_ACCESS_GROUPS (sizeof(sec_access_bit_groups) / sizeof(uint32_t))
+#define ACCESS_GROUPS_COUNT ((1 << NUM_ACCESS_GROUPS))
+#define BITSINBYTE 8
+
+/* Note: See NTCREATEX_SHARE_ACCESS_{NONE,READ,WRITE,DELETE} for share mode
+ * declarations. */
+#define NUM_SHAREMODE_PERMUTATIONS 8
+
+/**
+ * NTCREATEX and SHARE MODE test.
+ *
+ * Open with combinations of (access_mode, share_mode).
+ * - Check status
+ * Open 2nd time with combination of (access_mode2, share_mode2).
+ * - Check status
+ * Perform operations to verify?
+ * - Read
+ * - Write
+ * - Delete
+ */
+bool torture_createx_sharemodes(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2,
+ bool dir,
+ bool extended)
+{
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ int i, j, est;
+ int gp1, gp2; /* group permuters */
+ struct createx_data cxd = {0};
+ int num_access_bits1 = sizeof(cxd.cxd_access1) * BITSINBYTE;
+ int num_access_bits2 = sizeof(cxd.cxd_access2) * BITSINBYTE;
+
+ mem_ctx = talloc_init("createx_sharemodes");
+ if (!mem_ctx)
+ return false;
+
+ if (!torture_setting_bool(tctx, "sacl_support", true))
+ torture_warning(tctx, "Skipping SACL related tests!\n");
+
+ cxd.cxd_test = extended ? CXD_TEST_CREATEX_SHAREMODE_EXTENDED :
+ CXD_TEST_CREATEX_SHAREMODE;
+ cxd.cxd_flags = dir ? CXD_FLAGS_DIRECTORY: 0;
+
+ /* HACK for progress bar: figure out estimated count. */
+ est = (NUM_SHAREMODE_PERMUTATIONS * NUM_SHAREMODE_PERMUTATIONS) *
+ ((ACCESS_GROUPS_COUNT * ACCESS_GROUPS_COUNT) +
+ (extended ? num_access_bits1 * num_access_bits2 : 0));
+
+ /* Blank slate. */
+ smbcli_deltree(cli->tree, CREATEX_NAME);
+ smbcli_unlink(cli->tree, CREATEX_NAME);
+
+ /* Choose 2 random share modes. */
+ for (cxd.cxd_sharemode1 = 0;
+ cxd.cxd_sharemode1 < NUM_SHAREMODE_PERMUTATIONS;
+ cxd.cxd_sharemode1++) {
+ for (cxd.cxd_sharemode2 = 0;
+ cxd.cxd_sharemode2 < NUM_SHAREMODE_PERMUTATIONS;
+ cxd.cxd_sharemode2++) {
+
+ /* Permutate through our access_bit_groups. */
+ for (gp1 = 0; gp1 < ACCESS_GROUPS_COUNT; gp1++) {
+ for (gp2 = 0; gp2 < ACCESS_GROUPS_COUNT; gp2++)
+ {
+ cxd.cxd_access1 = cxd.cxd_access2 = 0;
+
+ for (i = 0; i < NUM_ACCESS_GROUPS; i++)
+ {
+ cxd.cxd_access1 |=
+ (gp1 & (1 << i)) ?
+ sec_access_bit_groups[i]:0;
+ cxd.cxd_access2 |=
+ (gp2 & (1 << i)) ?
+ sec_access_bit_groups[i]:0;
+ }
+
+ torture_createx_specific(tctx, cli,
+ cli2, mem_ctx, &cxd, est);
+ }
+ }
+
+ /* Only do the single access bits on an extended run. */
+ if (!extended)
+ continue;
+
+ for (i = 0; i < num_access_bits1; i++) {
+ for (j = 0; j < num_access_bits2; j++) {
+ cxd.cxd_access1 = 1ull << i;
+ cxd.cxd_access2 = 1ull << j;
+
+ torture_createx_specific(tctx, cli,
+ cli2, mem_ctx, &cxd, est);
+ }
+ }
+ }
+ }
+ torture_comment(tctx, "\n");
+
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+bool torture_createx_sharemodes_file(struct torture_context *tctx,
+ struct smbcli_state *cli, struct smbcli_state *cli2)
+{
+ return torture_createx_sharemodes(tctx, cli, cli2, false, false);
+}
+
+bool torture_createx_sharemodes_dir(struct torture_context *tctx,
+ struct smbcli_state *cli, struct smbcli_state *cli2)
+{
+ return torture_createx_sharemodes(tctx, cli, cli2, true, false);
+}
+
+bool torture_createx_access(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ uint32_t group_permuter;
+ uint32_t i;
+ struct createx_data cxd = {0};
+ int est;
+ int num_access_bits = sizeof(cxd.cxd_access1) * BITSINBYTE;
+
+ mem_ctx = talloc_init("createx_dir");
+ if (!mem_ctx)
+ return false;
+
+ if (!torture_setting_bool(tctx, "sacl_support", true))
+ torture_warning(tctx, "Skipping SACL related tests!\n");
+
+ cxd.cxd_test = CXD_TEST_CREATEX_ACCESS;
+
+ /* HACK for progress bar: figure out estimated count. */
+ est = CXD_FLAGS_COUNT * (ACCESS_GROUPS_COUNT + (num_access_bits * 3));
+
+ /* Blank slate. */
+ smbcli_deltree(cli->tree, CREATEX_NAME);
+ smbcli_unlink(cli->tree, CREATEX_NAME);
+
+ for (cxd.cxd_flags = 0; cxd.cxd_flags <= CXD_FLAGS_MASK;
+ cxd.cxd_flags++) {
+ /**
+ * This implements a basic permutation of all elements of
+ * 'bit_group'. group_permuter is a bit field representing
+ * which groups to turn on.
+ */
+ for (group_permuter = 0; group_permuter < (1 <<
+ NUM_ACCESS_GROUPS); group_permuter++) {
+ for (i = 0, cxd.cxd_access1 = 0;
+ i < NUM_ACCESS_GROUPS; i++) {
+ cxd.cxd_access1 |= (group_permuter & (1 << i))
+ ? sec_access_bit_groups[i] : 0;
+ }
+
+ torture_createx_specific(tctx, cli, NULL, mem_ctx,
+ &cxd, est);
+ }
+ for (i = 0; i < num_access_bits; i++) {
+ /* And now run through the single access bits. */
+ cxd.cxd_access1 = 1 << i;
+ torture_createx_specific(tctx, cli, NULL, mem_ctx,
+ &cxd, est);
+
+ /* Does SEC_FLAG_MAXIMUM_ALLOWED override? */
+ cxd.cxd_access1 |= SEC_FLAG_MAXIMUM_ALLOWED;
+ torture_createx_specific(tctx, cli, NULL, mem_ctx,
+ &cxd, est);
+
+ /* What about SEC_FLAG_SYSTEM_SECURITY? */
+ cxd.cxd_access1 |= SEC_FLAG_SYSTEM_SECURITY;
+ torture_createx_specific(tctx, cli, NULL, mem_ctx,
+ &cxd, est);
+ }
+ }
+
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+#define ACCESS_KNOWN_MASK 0xF31F01FFull
+
+bool torture_createx_access_exhaustive(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ char *data_file;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true, first;
+ uint32_t i;
+ struct createx_data cxd = {0};
+
+ mem_ctx = talloc_init("createx_dir");
+ if (!mem_ctx)
+ return false;
+
+ if (!torture_setting_bool(tctx, "sacl_support", true))
+ torture_warning(tctx, "Skipping SACL related tests!\n");
+
+ data_file = getenv("CREATEX_DATA");
+ if (data_file) {
+ data_file_fd = open(data_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (data_file_fd < 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): data file open failed: %s!",
+ __location__, strerror(errno));
+ ret = false;
+ goto done;
+ }
+ }
+
+ /* Blank slate. */
+ smbcli_deltree(cli->tree, CREATEX_NAME);
+ smbcli_unlink(cli->tree, CREATEX_NAME);
+
+ cxd.cxd_test = CXD_TEST_CREATEX_ACCESS_EXHAUSTIVE;
+
+ for (cxd.cxd_flags = 0; cxd.cxd_flags <= CXD_FLAGS_MASK;
+ cxd.cxd_flags++) {
+ for (i = 0, first = true; (i != 0) || first; first = false,
+ i = ((i | ~ACCESS_KNOWN_MASK) + 1) & ACCESS_KNOWN_MASK) {
+ cxd.cxd_access1 = i;
+ ret = torture_createx_specific(tctx, cli, NULL,
+ mem_ctx, &cxd, 0);
+ if (!ret)
+ break;
+ }
+ }
+
+ close(data_file_fd);
+ data_file_fd = -1;
+
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+#define MAXIMUM_ALLOWED_FILE "torture_maximum_allowed"
+bool torture_maximum_allowed(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct security_descriptor *sd, *sd_orig;
+ union smb_open io;
+ static TALLOC_CTX *mem_ctx;
+ int fnum, i;
+ bool ret = true;
+ NTSTATUS status;
+ union smb_fileinfo q;
+ const char *owner_sid;
+ bool has_restore_privilege, has_backup_privilege, has_system_security_privilege;
+
+ mem_ctx = talloc_init("torture_maximum_allowed");
+
+ if (!torture_setting_bool(tctx, "sacl_support", true))
+ torture_warning(tctx, "Skipping SACL related tests!\n");
+
+ sd = security_descriptor_dacl_create(mem_ctx,
+ 0, NULL, NULL,
+ SID_NT_AUTHENTICATED_USERS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ,
+ 0, NULL);
+
+ /* Blank slate */
+ smbcli_unlink(cli->tree, MAXIMUM_ALLOWED_FILE);
+
+ /* create initial file with restrictive SD */
+ memset(&io, 0, sizeof(io));
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = MAXIMUM_ALLOWED_FILE;
+ io.ntcreatex.in.sec_desc = sd;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* the correct answers for this test depends on whether the
+ user has restore privileges. To find that out we first need
+ to know our SID - get it from the owner_sid of the file we
+ just created */
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ torture_comment(tctx, "Checked SEC_PRIV_RESTORE for %s - %s\n",
+ owner_sid,
+ has_restore_privilege?"Yes":"No");
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_BACKUP));
+ has_backup_privilege = NT_STATUS_IS_OK(status);
+ torture_comment(tctx, "Checked SEC_PRIV_BACKUP for %s - %s\n",
+ owner_sid,
+ has_backup_privilege?"Yes":"No");
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_SECURITY));
+ has_system_security_privilege = NT_STATUS_IS_OK(status);
+ torture_comment(tctx, "Checked SEC_PRIV_SECURITY for %s - %s\n",
+ owner_sid,
+ has_system_security_privilege?"Yes":"No");
+
+ smbcli_close(cli->tree, fnum);
+
+ for (i = 0; i < 32; i++) {
+ uint32_t mask = SEC_FLAG_MAXIMUM_ALLOWED | (1u << i);
+ /*
+ * SEC_GENERIC_EXECUTE is a complete subset of
+ * SEC_GENERIC_READ when mapped to specific bits,
+ * so we need to include it in the basic OK mask.
+ */
+ uint32_t ok_mask = SEC_RIGHTS_FILE_READ | SEC_GENERIC_READ | SEC_GENERIC_EXECUTE |
+ SEC_STD_DELETE | SEC_STD_WRITE_DAC;
+
+ /*
+ * Now SEC_RIGHTS_PRIV_RESTORE and SEC_RIGHTS_PRIV_BACKUP
+ * don't include any generic bits (they're used directly
+ * in the fileserver where the generic bits have already
+ * been mapped into file specific bits) we need to add the
+ * generic bits to the ok_mask when we have these privileges.
+ */
+ if (has_restore_privilege) {
+ ok_mask |= SEC_RIGHTS_PRIV_RESTORE|SEC_GENERIC_WRITE;
+ }
+ if (has_backup_privilege) {
+ ok_mask |= SEC_RIGHTS_PRIV_BACKUP|SEC_GENERIC_READ;
+ }
+ if (has_system_security_privilege) {
+ ok_mask |= SEC_FLAG_SYSTEM_SECURITY;
+ }
+
+ /* Skip all SACL related tests. */
+ if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
+ (mask & SEC_FLAG_SYSTEM_SECURITY))
+ continue;
+
+ memset(&io, 0, sizeof(io));
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.access_mask = mask;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation =
+ NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = MAXIMUM_ALLOWED_FILE;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ if (mask & ok_mask ||
+ mask == SEC_FLAG_MAXIMUM_ALLOWED) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ } else {
+ if (mask & SEC_FLAG_SYSTEM_SECURITY) {
+ CHECK_STATUS(status, NT_STATUS_PRIVILEGE_NOT_HELD);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ fnum = io.ntcreatex.out.file.fnum;
+
+ smbcli_close(cli->tree, fnum);
+ }
+
+ done:
+ smbcli_unlink(cli->tree, MAXIMUM_ALLOWED_FILE);
+ return ret;
+}
diff --git a/source4/torture/basic/dir.c b/source4/torture/basic/dir.c
new file mode 100644
index 0000000..2a3d136
--- /dev/null
+++ b/source4/torture/basic/dir.c
@@ -0,0 +1,171 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ directory scanning tests
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "system/filesys.h"
+#include "torture/basic/proto.h"
+
+static void list_fn(struct clilist_file_info *finfo, const char *name, void *state)
+{
+
+}
+
+/*
+ test directory listing speed
+ */
+bool torture_dirtest1(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int i;
+ int fnum;
+ bool correct = true;
+ extern int torture_numops;
+ struct timeval tv;
+ int ret;
+
+ torture_comment(tctx, "Creating %d random filenames\n", torture_numops);
+
+ srandom(0);
+ tv = timeval_current();
+ for (i=0;i<torture_numops;i++) {
+ char *fname;
+ ret = asprintf(&fname, "\\%x", (int)random());
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ fprintf(stderr,"(%s) Failed to open %s\n",
+ __location__, fname);
+ return false;
+ }
+ smbcli_close(cli->tree, fnum);
+ free(fname);
+ }
+
+ torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "a*.*", 0, list_fn, NULL));
+ torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "b*.*", 0, list_fn, NULL));
+ torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "xyzabc", 0, list_fn, NULL));
+
+ torture_comment(tctx, "dirtest core %g seconds\n", timeval_elapsed(&tv));
+
+ srandom(0);
+ for (i=0;i<torture_numops;i++) {
+ char *fname;
+ ret = asprintf(&fname, "\\%x", (int)random());
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ smbcli_unlink(cli->tree, fname);
+ free(fname);
+ }
+
+ return correct;
+}
+
+bool torture_dirtest2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int i;
+ int fnum, num_seen;
+ bool correct = true;
+ extern int torture_entries;
+ int ret;
+
+ if (!torture_setup_dir(cli, "\\LISTDIR")) {
+ return false;
+ }
+
+ torture_comment(tctx, "Creating %d files\n", torture_entries);
+
+ /* Create torture_entries files and torture_entries directories. */
+ for (i=0;i<torture_entries;i++) {
+ char *fname;
+ ret = asprintf(&fname, "\\LISTDIR\\f%d", i);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_ARCHIVE,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+ if (fnum == -1) {
+ fprintf(stderr,"(%s) Failed to open %s, error=%s\n",
+ __location__, fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+ free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+ for (i=0;i<torture_entries;i++) {
+ char *fname;
+ ret = asprintf(&fname, "\\LISTDIR\\d%d", i);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
+ fprintf(stderr,"(%s) Failed to open %s, error=%s\n",
+ __location__, fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+ free(fname);
+ }
+
+ /* Now ensure that doing an old list sees both files and directories. */
+ num_seen = smbcli_list_old(cli->tree, "\\LISTDIR\\*", FILE_ATTRIBUTE_DIRECTORY, list_fn, NULL);
+ torture_comment(tctx, "num_seen = %d\n", num_seen );
+ /* We should see (torture_entries) each of files & directories + . and .. */
+ if (num_seen != (2*torture_entries)+2) {
+ correct = false;
+ fprintf(stderr,"(%s) entry count mismatch, should be %d, was %d\n",
+ __location__, (2*torture_entries)+2, num_seen);
+ }
+
+
+ /* Ensure if we have the "must have" bits we only see the
+ * relevant entries.
+ */
+ num_seen = smbcli_list_old(cli->tree, "\\LISTDIR\\*", (FILE_ATTRIBUTE_DIRECTORY<<8)|FILE_ATTRIBUTE_DIRECTORY, list_fn, NULL);
+ torture_comment(tctx, "num_seen = %d\n", num_seen );
+ if (num_seen != torture_entries+2) {
+ correct = false;
+ fprintf(stderr,"(%s) entry count mismatch, should be %d, was %d\n",
+ __location__, torture_entries+2, num_seen);
+ }
+
+ num_seen = smbcli_list_old(cli->tree, "\\LISTDIR\\*", (FILE_ATTRIBUTE_ARCHIVE<<8)|FILE_ATTRIBUTE_DIRECTORY, list_fn, NULL);
+ torture_comment(tctx, "num_seen = %d\n", num_seen );
+ if (num_seen != torture_entries) {
+ correct = false;
+ fprintf(stderr,"(%s) entry count mismatch, should be %d, was %d\n",
+ __location__, torture_entries, num_seen);
+ }
+
+ /* Delete everything. */
+ if (smbcli_deltree(cli->tree, "\\LISTDIR") == -1) {
+ fprintf(stderr,"(%s) Failed to deltree %s, error=%s\n", "\\LISTDIR",
+ __location__, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+#if 0
+ torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "a*.*", 0, list_fn, NULL));
+ torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "b*.*", 0, list_fn, NULL));
+ torture_comment(tctx, "Matched %d\n", smbcli_list(cli->tree, "xyzabc", 0, list_fn, NULL));
+#endif
+
+ return correct;
+}
diff --git a/source4/torture/basic/disconnect.c b/source4/torture/basic/disconnect.c
new file mode 100644
index 0000000..7fb87d8
--- /dev/null
+++ b/source4/torture/basic/disconnect.c
@@ -0,0 +1,182 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test server handling of unexpected client disconnects
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+#define BASEDIR "\\test_disconnect"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ talloc_free(cli); \
+ return false; \
+ }} while (0)
+
+/*
+ test disconnect after async open
+*/
+static bool test_disconnect_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ struct smbcli_request *req1, *req2;
+ NTSTATUS status;
+
+ printf("trying open/disconnect\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR "\\open.dat";
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.ntcreatex.in.share_access = 0;
+ req1 = smb_raw_open_send(cli->tree, &io);
+ req2 = smb_raw_open_send(cli->tree, &io);
+ if (!req1 || !req2) {
+ printf("test_disconnect_open: smb_raw_open_send() "
+ "returned NULL\n");
+ return false;
+ }
+
+ status = smbcli_chkpath(cli->tree, "\\");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ talloc_free(cli);
+
+ return true;
+}
+
+
+/*
+ test disconnect with timed lock
+*/
+static bool test_disconnect_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ int fnum;
+ struct smbcli_request *req;
+ struct smb_lock_entry lock[1];
+
+ printf("trying disconnect with async lock\n");
+
+ fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat",
+ O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = 0;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.ulock_cnt = 0;
+ lock[0].pid = 1;
+ lock[0].offset = 0;
+ lock[0].count = 4;
+ io.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lock[0].pid = 2;
+ io.lockx.in.timeout = 3000;
+ req = smb_raw_lock_send(cli->tree, &io);
+ if (!req) {
+ printf("test_disconnect_lock: smb_raw_lock_send() "
+ "returned NULL\n");
+ return false;
+ }
+
+ status = smbcli_chkpath(cli->tree, "\\");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ talloc_free(cli);
+
+ return true;
+}
+
+
+
+/*
+ basic testing of disconnects
+*/
+bool torture_disconnect(struct torture_context *torture)
+{
+ bool ret = true;
+ TALLOC_CTX *mem_ctx;
+ int i;
+ extern int torture_numops;
+ struct smbcli_state *cli;
+
+ mem_ctx = talloc_init("torture_raw_mux");
+
+ if (!torture_open_connection(&cli, torture, 0)) {
+ return false;
+ }
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ for (i=0;i<torture_numops;i++) {
+ ret &= test_disconnect_lock(cli, mem_ctx);
+ if (!torture_open_connection(&cli, torture, 0)) {
+ return false;
+ }
+
+ ret &= test_disconnect_open(cli, mem_ctx);
+ if (!torture_open_connection(&cli, torture, 0)) {
+ return false;
+ }
+
+ if (torture_setting_bool(torture, "samba3", false)) {
+ /*
+ * In Samba3 it might happen that the old smbd from
+ * test_disconnect_lock is not scheduled before the
+ * new process comes in. Try to get rid of the random
+ * failures in the build farm.
+ */
+ smb_msleep(200);
+ }
+ }
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/basic/locking.c b/source4/torture/basic/locking.c
new file mode 100644
index 0000000..e0e2971
--- /dev/null
+++ b/source4/torture/basic/locking.c
@@ -0,0 +1,811 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ basic locking tests
+
+ Copyright (C) Andrew Tridgell 2000-2004
+ Copyright (C) Jeremy Allison 2000-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "torture/basic/proto.h"
+
+#define BASEDIR "\\locktest"
+
+/*
+ This test checks for two things:
+
+ 1) correct support for retaining locks over a close (ie. the server
+ must not use posix semantics)
+ 2) support for lock timeouts
+ */
+static bool torture_locktest1(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\lockt1.lck";
+ int fnum1, fnum2, fnum3;
+ time_t t1, t2;
+ unsigned int lock_timeout;
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
+ talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx,
+ "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
+ fnum2 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1, talloc_asprintf(tctx,
+ "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
+ fnum3 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum3 != -1, talloc_asprintf(tctx,
+ "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK),
+ talloc_asprintf(tctx, "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
+ "lock2 succeeded! This is a locking bug\n");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
+ "lock2 succeeded! This is a locking bug\n");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return false;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_lock(cli1->tree, fnum1, 5, 9, 0, WRITE_LOCK),
+ talloc_asprintf(tctx,
+ "lock1 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 5, 9, 0, WRITE_LOCK)),
+ "lock2 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
+ "lock2 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
+ "lock2 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return false;
+
+ lock_timeout = (6 + (random() % 20));
+ torture_comment(tctx, "Testing lock timeout with timeout=%u\n",
+ lock_timeout);
+ t1 = time_mono(NULL);
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, lock_timeout * 1000, WRITE_LOCK)),
+ "lock3 succeeded! This is a locking bug\n");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return false;
+ t2 = time_mono(NULL);
+
+ if (t2 - t1 < 5) {
+ torture_fail(tctx,
+ "error: This server appears not to support timed lock requests");
+ }
+ torture_comment(tctx, "server slept for %u seconds for a %u second timeout\n",
+ (unsigned int)(t2-t1), lock_timeout);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum2),
+ talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
+ "lock4 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli2, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return false;
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum3),
+ talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli2->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
+ talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports multiple locking contexts on the one SMB
+ connection, distinguished by PID.
+
+ 2) the server correctly fails overlapping locks made by the same PID (this
+ goes against POSIX behaviour, which is why it is tricky to implement)
+
+ 3) the server denies unlock requests by an incorrect client PID
+*/
+static bool torture_locktest2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *fname = BASEDIR "\\lockt2.lck";
+ int fnum1, fnum2, fnum3;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
+
+ torture_comment(tctx, "Testing pid context\n");
+
+ cli->session->pid = 1;
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx,
+ "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
+
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1,
+ talloc_asprintf(tctx, "open2 of %s failed (%s)",
+ fname, smbcli_errstr(cli->tree)));
+
+ cli->session->pid = 2;
+
+ fnum3 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum3 != -1,
+ talloc_asprintf(tctx,
+ "open3 of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)));
+
+ cli->session->pid = 1;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK),
+ talloc_asprintf(tctx,
+ "lock1 failed (%s)", smbcli_errstr(cli->tree)));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum1, 0, 4, 0, WRITE_LOCK)),
+ "WRITE lock1 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, WRITE_LOCK)),
+ "WRITE lock2 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli, ERRDOS, ERRlock,
+ NT_STATUS_LOCK_NOT_GRANTED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum2, 0, 4, 0, READ_LOCK)),
+ "READ lock2 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli, ERRDOS, ERRlock,
+ NT_STATUS_FILE_LOCK_CONFLICT)) return false;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_lock(cli->tree, fnum1, 100, 4, 0, WRITE_LOCK),
+ talloc_asprintf(tctx,
+ "lock at 100 failed (%s)", smbcli_errstr(cli->tree)));
+
+ cli->session->pid = 2;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 100, 4)),
+ "unlock at 100 succeeded! This is a locking bug");
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 4)),
+ "unlock1 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli,
+ ERRDOS, ERRnotlocked,
+ NT_STATUS_RANGE_NOT_LOCKED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_unlock(cli->tree, fnum1, 0, 8)),
+ "unlock2 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli,
+ ERRDOS, ERRnotlocked,
+ NT_STATUS_RANGE_NOT_LOCKED)) return false;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli->tree, fnum3, 0, 4, 0, WRITE_LOCK)),
+ "lock3 succeeded! This is a locking bug");
+
+ if (!check_error(__location__, cli, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
+
+ cli->session->pid = 1;
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum1),
+ talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum2),
+ talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli->tree, fnum3),
+ talloc_asprintf(tctx, "close3 failed (%s)", smbcli_errstr(cli->tree)));
+
+ return true;
+}
+
+
+/*
+ This test checks that
+
+ 1) the server supports the full offset range in lock requests
+*/
+static bool torture_locktest3(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\lockt3.lck";
+ int fnum1, fnum2, i;
+ uint32_t offset;
+ extern int torture_numops;
+
+#define NEXT_OFFSET offset += (~(uint32_t)0) / torture_numops
+
+ torture_comment(tctx, "Testing 32 bit offset ranges");
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
+ talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ torture_assert(tctx, fnum1 != -1,
+ talloc_asprintf(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli1->tree)));
+ fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1,
+ talloc_asprintf(tctx, "open2 of %s failed (%s)\n", fname, smbcli_errstr(cli2->tree)));
+
+ torture_comment(tctx, "Establishing %d locks\n", torture_numops);
+
+ for (offset=i=0;i<torture_numops;i++) {
+ NEXT_OFFSET;
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK),
+ talloc_asprintf(tctx, "lock1 %d failed (%s)", i, smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK),
+ talloc_asprintf(tctx, "lock2 %d failed (%s)",
+ i, smbcli_errstr(cli1->tree)));
+ }
+
+ torture_comment(tctx, "Testing %d locks\n", torture_numops);
+
+ for (offset=i=0;i<torture_numops;i++) {
+ NEXT_OFFSET;
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-2, 1, 0, WRITE_LOCK)),
+ talloc_asprintf(tctx, "error: lock1 %d succeeded!", i));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-1, 1, 0, WRITE_LOCK)),
+ talloc_asprintf(tctx, "error: lock2 %d succeeded!", i));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, offset-1, 1, 0, WRITE_LOCK)),
+ talloc_asprintf(tctx, "error: lock3 %d succeeded!", i));
+
+ torture_assert(tctx,
+ !NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, offset-2, 1, 0, WRITE_LOCK)),
+ talloc_asprintf(tctx, "error: lock4 %d succeeded!", i));
+ }
+
+ torture_comment(tctx, "Removing %d locks\n", torture_numops);
+
+ for (offset=i=0;i<torture_numops;i++) {
+ NEXT_OFFSET;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_unlock(cli1->tree, fnum1, offset-1, 1),
+ talloc_asprintf(tctx, "unlock1 %d failed (%s)",
+ i,
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_unlock(cli2->tree, fnum2, offset-2, 1),
+ talloc_asprintf(tctx, "unlock2 %d failed (%s)",
+ i,
+ smbcli_errstr(cli1->tree)));
+ }
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
+ talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
+ talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
+
+ return true;
+}
+
+#define EXPECTED(ret, v) if ((ret) != (v)) { \
+ torture_comment(tctx, "** "); correct = false; \
+ }
+
+/*
+ looks at overlapping locks
+*/
+static bool torture_locktest4(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\lockt4.lck";
+ int fnum1, fnum2, f;
+ bool ret;
+ uint8_t buf[1000];
+ bool correct = true;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ if (smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ torture_comment(tctx, "Failed to create file\n");
+ correct = false;
+ goto fail;
+ }
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 2, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "the same process %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 10, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 12, 4, 0, READ_LOCK));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 20, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 22, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "a different connection %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 30, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 32, 4, 0, READ_LOCK));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "a different connection %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 40, 4, 0, WRITE_LOCK))) &&
+ NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 42, 4, 0, WRITE_LOCK)));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "a different pid %s set overlapping write locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 50, 4, 0, READ_LOCK))) &&
+ NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 52, 4, 0, READ_LOCK)));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "a different pid %s set overlapping read locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 60, 4, 0, READ_LOCK));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s set the same read lock twice\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 70, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "the same process %s set the same write lock twice\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 80, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "the same process %s overlay a read lock with a write lock\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 90, 4, 0, READ_LOCK));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s overlay a write lock with a read lock\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK((cli1->session->pid = 1, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, WRITE_LOCK))) &&
+ NT_STATUS_IS_OK((cli1->session->pid = 2, smbcli_lock(cli1->tree, fnum1, 100, 4, 0, READ_LOCK)));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "a different pid %s overlay a write lock with a read lock\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 110, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 112, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 110, 6));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "the same process %s coalesce read locks\n", ret?"can":"cannot");
+
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 120, 4, 0, WRITE_LOCK)) &&
+ (smbcli_read(cli2->tree, fnum2, buf, 120, 4) == 4);
+ EXPECTED(ret, false);
+ torture_comment(tctx, "this server %s strict write locking\n", ret?"doesn't do":"does");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK)) &&
+ (smbcli_write(cli2->tree, fnum2, 0, buf, 130, 4) == 4);
+ EXPECTED(ret, false);
+ torture_comment(tctx, "this server %s strict read locking\n", ret?"doesn't do":"does");
+
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 140, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 140, 4));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "this server %s do recursive read locking\n", ret?"does":"doesn't");
+
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 150, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4)) &&
+ (smbcli_read(cli2->tree, fnum2, buf, 150, 4) == 4) &&
+ !(smbcli_write(cli2->tree, fnum2, 0, buf, 150, 4) == 4) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 150, 4));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "this server %s do recursive lock overlays\n", ret?"does":"doesn't");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 160, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 160, 4)) &&
+ (smbcli_write(cli2->tree, fnum2, 0, buf, 160, 4) == 4) &&
+ (smbcli_read(cli2->tree, fnum2, buf, 160, 4) == 4);
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 170, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 170, 4)) &&
+ (smbcli_write(cli2->tree, fnum2, 0, buf, 170, 4) == 4) &&
+ (smbcli_read(cli2->tree, fnum2, buf, 170, 4) == 4);
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s remove a write lock using read locking\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 190, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 190, 4)) &&
+ !(smbcli_write(cli2->tree, fnum2, 0, buf, 190, 4) == 4) &&
+ (smbcli_read(cli2->tree, fnum2, buf, 190, 4) == 4);
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s remove the first lock first\n", ret?"does":"doesn't");
+
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli2->tree, fnum2);
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ f = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, f, 0, 1, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_close(cli1->tree, fnum1)) &&
+ ((fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE)) != -1) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
+ smbcli_close(cli1->tree, f);
+ smbcli_close(cli1->tree, fnum1);
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the server %s have the NT byte range lock bug\n", !ret?"does":"doesn't");
+
+ fail:
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli2->tree, fnum2);
+ smbcli_unlink(cli1->tree, fname);
+
+ return correct;
+}
+
+/*
+ looks at lock upgrade/downgrade.
+*/
+static bool torture_locktest5(struct torture_context *tctx, struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\lockt5.lck";
+ int fnum1, fnum2, fnum3;
+ bool ret;
+ uint8_t buf[1000];
+ bool correct = true;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
+ fnum3 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
+ "Failed to create file");
+
+ /* Check for NT bug... */
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 8, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 1, 0, READ_LOCK));
+ smbcli_close(cli1->tree, fnum1);
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 7, 1, 0, WRITE_LOCK));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "this server %s the NT locking bug\n", ret ? "doesn't have" : "has");
+ smbcli_close(cli1->tree, fnum1);
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR, DENY_NONE);
+ smbcli_unlock(cli1->tree, fnum3, 0, 1);
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, WRITE_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 1, 1, 0, READ_LOCK));
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s overlay a write with a read lock\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
+ EXPECTED(ret, false);
+
+ torture_comment(tctx, "a different process %s get a read lock on the first process lock stack\n", ret?"can":"cannot");
+
+ /* Unlock the process 2 lock. */
+ smbcli_unlock(cli2->tree, fnum2, 0, 4);
+
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum3, 0, 4, 0, READ_LOCK));
+ EXPECTED(ret, false);
+
+ torture_comment(tctx, "the same process on a different fnum %s get a read lock\n", ret?"can":"cannot");
+
+ /* Unlock the process 1 fnum3 lock. */
+ smbcli_unlock(cli1->tree, fnum3, 0, 4);
+
+ /* Stack 2 more locks here. */
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli1->tree, fnum1, 0, 4, 0, READ_LOCK));
+
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s stack read locks\n", ret?"can":"cannot");
+
+ /* Unlock the first process lock, then check this was the WRITE lock that was
+ removed. */
+
+ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
+ NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, READ_LOCK));
+
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the first unlock removes the %s lock\n", ret?"WRITE":"READ");
+
+ /* Unlock the process 2 lock. */
+ smbcli_unlock(cli2->tree, fnum2, 0, 4);
+
+ /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
+
+ ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 1, 1)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4)) &&
+ NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
+
+ EXPECTED(ret, true);
+ torture_comment(tctx, "the same process %s unlock the stack of 3 locks\n", ret?"can":"cannot");
+
+ /* Ensure the next unlock fails. */
+ ret = NT_STATUS_IS_OK(smbcli_unlock(cli1->tree, fnum1, 0, 4));
+ EXPECTED(ret, false);
+ torture_comment(tctx, "the same process %s count the lock stack\n", !ret?"can":"cannot");
+
+ /* Ensure connection 2 can get a write lock. */
+ ret = NT_STATUS_IS_OK(smbcli_lock(cli2->tree, fnum2, 0, 4, 0, WRITE_LOCK));
+ EXPECTED(ret, true);
+
+ torture_comment(tctx, "a different process %s get a write lock on the unlocked stack\n", ret?"can":"cannot");
+
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close1 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli2->tree, fnum2),
+ talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum3),
+ talloc_asprintf(tctx, "close2 failed (%s)", smbcli_errstr(cli2->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_unlink(cli1->tree, fname),
+ talloc_asprintf(tctx, "unlink failed (%s)", smbcli_errstr(cli1->tree)));
+
+ return correct;
+}
+
+/*
+ tries the unusual lockingX locktype bits
+*/
+static bool torture_locktest6(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *fname[1] = { "\\lock6.txt" };
+ int i;
+ int fnum;
+ NTSTATUS status;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ for (i=0;i<1;i++) {
+ torture_comment(tctx, "Testing %s\n", fname[i]);
+
+ smbcli_unlink(cli->tree, fname[i]);
+
+ fnum = smbcli_open(cli->tree, fname[i], O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CHANGE_LOCKTYPE);
+ smbcli_close(cli->tree, fnum);
+ torture_comment(tctx, "CHANGE_LOCKTYPE gave %s\n", nt_errstr(status));
+
+ fnum = smbcli_open(cli->tree, fname[i], O_RDWR, DENY_NONE);
+ status = smbcli_locktype(cli->tree, fnum, 0, 8, 0, LOCKING_ANDX_CANCEL_LOCK);
+ smbcli_close(cli->tree, fnum);
+ torture_comment(tctx, "CANCEL_LOCK gave %s\n", nt_errstr(status));
+
+ smbcli_unlink(cli->tree, fname[i]);
+ }
+
+ return true;
+}
+
+static bool torture_locktest7(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *fname = BASEDIR "\\lockt7.lck";
+ int fnum1;
+ int fnum2 = -1;
+ size_t size;
+ uint8_t buf[200];
+ bool correct = false;
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
+ talloc_asprintf(tctx, "Unable to set up %s", BASEDIR));
+
+ fnum1 = smbcli_open(cli1->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+
+ memset(buf, 0, sizeof(buf));
+
+ torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 0, sizeof(buf)) == sizeof(buf),
+ "Failed to create file");
+
+ cli1->session->pid = 1;
+
+ torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, READ_LOCK),
+ talloc_asprintf(tctx, "Unable to apply read lock on range 130:4, error was %s",
+ smbcli_errstr(cli1->tree)));
+
+ torture_comment(tctx, "pid1 successfully locked range 130:4 for READ\n");
+
+ torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
+ talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s)",
+ smbcli_errstr(cli1->tree)));
+
+ torture_comment(tctx, "pid1 successfully read the range 130:4\n");
+
+ if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
+ torture_comment(tctx, "pid1 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
+ torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
+ "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
+ } else {
+ torture_fail(tctx, "pid1 successfully wrote to the range 130:4 (should be denied)");
+ }
+
+ cli1->session->pid = 2;
+
+ if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
+ torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
+ } else {
+ torture_comment(tctx, "pid2 successfully read the range 130:4\n");
+ }
+
+ if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
+ torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n", smbcli_errstr(cli1->tree));
+ torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
+ "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
+ } else {
+ torture_fail(tctx, "pid2 successfully wrote to the range 130:4 (should be denied)");
+ }
+
+ cli1->session->pid = 1;
+ smbcli_unlock(cli1->tree, fnum1, 130, 4);
+
+ torture_assert_ntstatus_ok(tctx, smbcli_lock(cli1->tree, fnum1, 130, 4, 0, WRITE_LOCK),
+ talloc_asprintf(tctx, "Unable to apply write lock on range 130:4, error was %s",
+ smbcli_errstr(cli1->tree)));
+ torture_comment(tctx, "pid1 successfully locked range 130:4 for WRITE\n");
+
+ torture_assert(tctx, smbcli_read(cli1->tree, fnum1, buf, 130, 4) == 4,
+ talloc_asprintf(tctx, "pid1 unable to read the range 130:4, error was %s",
+ smbcli_errstr(cli1->tree)));
+ torture_comment(tctx, "pid1 successfully read the range 130:4\n");
+
+ torture_assert(tctx, smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) == 4,
+ talloc_asprintf(tctx, "pid1 unable to write to the range 130:4, error was %s",
+ smbcli_errstr(cli1->tree)));
+ torture_comment(tctx, "pid1 successfully wrote to the range 130:4\n");
+
+ cli1->session->pid = 2;
+
+ if (smbcli_read(cli1->tree, fnum1, buf, 130, 4) != 4) {
+ torture_comment(tctx, "pid2 unable to read the range 130:4, error was %s\n",
+ smbcli_errstr(cli1->tree));
+ torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT,
+ "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT)");
+ } else {
+ torture_fail(tctx, "pid2 successfully read the range 130:4 (should be denied)");
+ }
+
+ if (smbcli_write(cli1->tree, fnum1, 0, buf, 130, 4) != 4) {
+ torture_comment(tctx, "pid2 unable to write to the range 130:4, error was %s\n",
+ smbcli_errstr(cli1->tree));
+ if (!NT_STATUS_EQUAL(smbcli_nt_error(cli1->tree), NT_STATUS_FILE_LOCK_CONFLICT)) {
+ torture_comment(tctx, "Incorrect error (should be NT_STATUS_FILE_LOCK_CONFLICT) (%s)\n",
+ __location__);
+ goto fail;
+ }
+ } else {
+ torture_comment(tctx, "pid2 successfully wrote to the range 130:4 (should be denied) (%s)\n",
+ __location__);
+ goto fail;
+ }
+
+ torture_comment(tctx, "Testing truncate of locked file.\n");
+
+ fnum2 = smbcli_open(cli1->tree, fname, O_RDWR|O_TRUNC, DENY_NONE);
+
+ torture_assert(tctx, fnum2 != -1, "Unable to truncate locked file");
+
+ torture_comment(tctx, "Truncated locked file.\n");
+
+ torture_assert_ntstatus_ok(tctx, smbcli_getatr(cli1->tree, fname, NULL, &size, NULL),
+ talloc_asprintf(tctx, "getatr failed (%s)", smbcli_errstr(cli1->tree)));
+
+ torture_assert(tctx, size == 0, talloc_asprintf(tctx, "Unable to truncate locked file. Size was %u", (unsigned)size));
+
+ cli1->session->pid = 1;
+
+ smbcli_unlock(cli1->tree, fnum1, 130, 4);
+ correct = true;
+
+fail:
+ smbcli_close(cli1->tree, fnum1);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_unlink(cli1->tree, fname);
+
+ return correct;
+}
+
+struct torture_suite *torture_base_locktest(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
+ torture_suite_add_2smb_test(suite, "LOCK1", torture_locktest1);
+ torture_suite_add_1smb_test(suite, "LOCK2", torture_locktest2);
+ torture_suite_add_2smb_test(suite, "LOCK3", torture_locktest3);
+ torture_suite_add_2smb_test(suite, "LOCK4", torture_locktest4);
+ torture_suite_add_2smb_test(suite, "LOCK5", torture_locktest5);
+ torture_suite_add_1smb_test(suite, "LOCK6", torture_locktest6);
+ torture_suite_add_1smb_test(suite, "LOCK7", torture_locktest7);
+
+ return suite;
+}
diff --git a/source4/torture/basic/mangle_test.c b/source4/torture/basic/mangle_test.c
new file mode 100644
index 0000000..9bd3cf5
--- /dev/null
+++ b/source4/torture/basic/mangle_test.c
@@ -0,0 +1,208 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - mangling test
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include <tdb.h>
+#include "../lib/util/util_tdb.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+#undef strcasecmp
+
+static TDB_CONTEXT *tdb;
+
+#define NAME_LENGTH 20
+
+static unsigned int total, collisions, failures;
+
+static bool test_one(struct torture_context *tctx ,struct smbcli_state *cli,
+ const char *name)
+{
+ int fnum;
+ const char *shortname;
+ const char *name2;
+ NTSTATUS status;
+ TDB_DATA data;
+
+ total++;
+
+ fnum = smbcli_open(cli->tree, name, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
+ printf("close of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ /* get the short name */
+ status = smbcli_qpathinfo_alt_name(cli->tree, name, &shortname);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("query altname of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ name2 = talloc_asprintf(tctx, "\\mangle_test\\%s", shortname);
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, name2))) {
+ printf("unlink of %s (%s) failed (%s)\n",
+ name2, name, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ /* recreate by short name */
+ fnum = smbcli_open(cli->tree, name2, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ printf("open2 of %s failed (%s)\n", name2, smbcli_errstr(cli->tree));
+ return false;
+ }
+ if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
+ printf("close of %s failed (%s)\n", name, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ /* and unlink by long name */
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, name))) {
+ printf("unlink2 of %s (%s) failed (%s)\n",
+ name, name2, smbcli_errstr(cli->tree));
+ failures++;
+ smbcli_unlink(cli->tree, name2);
+ return true;
+ }
+
+ /* see if the short name is already in the tdb */
+ data = tdb_fetch_bystring(tdb, shortname);
+ if (data.dptr) {
+ /* maybe its a duplicate long name? */
+ if (strcasecmp(name, (const char *)data.dptr) != 0) {
+ /* we have a collision */
+ collisions++;
+ printf("Collision between %s and %s -> %s "
+ " (coll/tot: %u/%u)\n",
+ name, data.dptr, shortname, collisions, total);
+ }
+ free(data.dptr);
+ } else {
+ TDB_DATA namedata;
+ /* store it for later */
+ namedata.dptr = discard_const_p(uint8_t, name);
+ namedata.dsize = strlen(name)+1;
+ tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
+ }
+
+ return true;
+}
+
+
+static char *gen_name(TALLOC_CTX *mem_ctx)
+{
+ const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~...";
+ unsigned int max_idx = strlen(chars);
+ unsigned int len;
+ int i;
+ char *p;
+ char *name;
+
+ name = talloc_strdup(mem_ctx, "\\mangle_test\\");
+
+ len = 1 + random() % NAME_LENGTH;
+
+ name = talloc_realloc(mem_ctx, name, char, strlen(name) + len + 6);
+ p = name + strlen(name);
+
+ for (i=0;i<len;i++) {
+ p[i] = chars[random() % max_idx];
+ }
+
+ p[i] = 0;
+
+ if (ISDOT(p) || ISDOTDOT(p)) {
+ p[0] = '_';
+ }
+
+ /* have a high probability of a common lead char */
+ if (random() % 2 == 0) {
+ p[0] = 'A';
+ }
+
+ /* and a medium probability of a common lead string */
+ if ((len > 5) && (random() % 10 == 0)) {
+ strlcpy(p, "ABCDE", 6);
+ }
+
+ /* and a high probability of a good extension length */
+ if (random() % 2 == 0) {
+ char *s = strrchr(p, '.');
+ if (s) {
+ s[4] = 0;
+ }
+ }
+
+ return name;
+}
+
+
+bool torture_mangle(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ extern int torture_numops;
+ int i;
+
+ /* we will use an internal tdb to store the names we have used */
+ tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
+ if (!tdb) {
+ printf("ERROR: Failed to open tdb\n");
+ return false;
+ }
+
+ if (!torture_setup_dir(cli, "\\mangle_test")) {
+ return false;
+ }
+
+ for (i=0;i<torture_numops;i++) {
+ char *name;
+
+ name = gen_name(torture);
+
+ if (!test_one(torture, cli, name)) {
+ break;
+ }
+ if (total && total % 100 == 0) {
+ if (torture_setting_bool(torture, "progress", true)) {
+ printf("collisions %u/%u - %.2f%% (%u failures)\r",
+ collisions, total, (100.0*collisions) / total, failures);
+ }
+ }
+ }
+
+ smbcli_unlink_wcard(cli->tree, "\\mangle_test\\*");
+ if (NT_STATUS_IS_ERR(smbcli_rmdir(cli->tree, "\\mangle_test"))) {
+ printf("ERROR: Failed to remove directory\n");
+ return false;
+ }
+
+ printf("\nTotal collisions %u/%u - %.2f%% (%u failures)\n",
+ collisions, total, (100.0*collisions) / total, failures);
+
+ return (failures == 0);
+}
diff --git a/source4/torture/basic/misc.c b/source4/torture/basic/misc.c
new file mode 100644
index 0000000..60af561
--- /dev/null
+++ b/source4/torture/basic/misc.c
@@ -0,0 +1,1003 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include "../libcli/smb/smb_constants.h"
+#include "libcli/libcli.h"
+#include "lib/events/events.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/composite/composite.h"
+#include "param/param.h"
+#include "torture/basic/proto.h"
+#include "lib/cmdline/cmdline.h"
+
+static bool wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
+{
+ while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
+ if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
+ }
+ return true;
+}
+
+
+static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c)
+{
+ const char *lockfname = "\\torture.lck";
+ char *fname;
+ int fnum;
+ int fnum2;
+ pid_t pid2, pid = getpid();
+ int i, j;
+ uint8_t buf[1024];
+ bool correct = true;
+
+ fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL,
+ DENY_NONE);
+ if (fnum2 == -1)
+ fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ torture_comment(tctx, "open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
+ return false;
+ }
+
+ generate_random_buffer(buf, sizeof(buf));
+
+ for (i=0;i<torture_numops;i++) {
+ unsigned int n = (unsigned int)random()%10;
+ int ret;
+
+ if (i % 10 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%d\r", i);
+ fflush(stdout);
+ }
+ }
+ ret = asprintf(&fname, "\\torture.%u", n);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+
+ if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
+ return false;
+ }
+
+ fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
+ if (fnum == -1) {
+ torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ break;
+ }
+
+ if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
+ torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ }
+
+ for (j=0;j<50;j++) {
+ if (smbcli_write(c->tree, fnum, 0, buf,
+ sizeof(pid)+(j*sizeof(buf)),
+ sizeof(buf)) != sizeof(buf)) {
+ torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ }
+ }
+
+ pid2 = 0;
+
+ if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
+ torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ }
+
+ if (pid2 != pid) {
+ torture_comment(tctx, "data corruption!\n");
+ correct = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
+ torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
+ torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
+ torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree));
+ correct = false;
+ }
+ free(fname);
+ }
+
+ smbcli_close(c->tree, fnum2);
+ smbcli_unlink(c->tree, lockfname);
+
+ torture_comment(tctx, "%d\n", i);
+
+ return correct;
+}
+
+bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
+{
+ return rw_torture(tctx, cli);
+}
+
+
+/*
+ see how many RPC pipes we can open at once
+*/
+bool run_pipe_number(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *pipe_name = "\\WKSSVC";
+ int fnum;
+ int num_pipes = 0;
+
+ while(1) {
+ fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum == -1) {
+ torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
+ break;
+ }
+ num_pipes++;
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%d\r", num_pipes);
+ fflush(stdout);
+ }
+ }
+
+ torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
+ return true;
+}
+
+
+
+
+/*
+ open N connections to the server and just hold them open
+ used for testing performance when there are N idle users
+ already connected
+ */
+bool torture_holdcon(struct torture_context *tctx)
+{
+ int i;
+ struct smbcli_state **cli;
+ int num_dead = 0;
+
+ torture_comment(tctx, "Opening %d connections\n", torture_numops);
+
+ cli = malloc_array_p(struct smbcli_state *, torture_numops);
+
+ for (i=0;i<torture_numops;i++) {
+ if (!torture_open_connection(&cli[i], tctx, i)) {
+ return false;
+ }
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "opened %d connections\r", i+1);
+ fflush(stdout);
+ }
+ }
+
+ torture_comment(tctx, "\nStarting pings\n");
+
+ while (1) {
+ for (i=0;i<torture_numops;i++) {
+ NTSTATUS status;
+ if (cli[i]) {
+ status = smbcli_chkpath(cli[i]->tree, "\\");
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Connection %d is dead\n", i);
+ cli[i] = NULL;
+ num_dead++;
+ }
+ usleep(100);
+ }
+ }
+
+ if (num_dead == torture_numops) {
+ torture_comment(tctx, "All connections dead - finishing\n");
+ break;
+ }
+
+ torture_comment(tctx, ".");
+ fflush(stdout);
+ }
+
+ return true;
+}
+
+/*
+ open a file N times on the server and just hold them open
+ used for testing performance when there are N file handles
+ open
+ */
+bool torture_holdopen(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int i, fnum;
+ const char *fname = "\\holdopen.dat";
+ NTSTATUS status;
+
+ smbcli_unlink(cli->tree, fname);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ smbcli_close(cli->tree, fnum);
+
+ for (i=0;i<torture_numops;i++) {
+ union smb_open op;
+
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &op);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "open %d failed\n", i);
+ continue;
+ }
+
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "opened %d file\r", i);
+ fflush(stdout);
+ }
+ }
+
+ torture_comment(tctx, "\nStarting pings\n");
+
+ while (1) {
+ struct smb_echo ec;
+ ZERO_STRUCT(ec);
+ status = smb_raw_echo(cli->transport, &ec);
+ torture_comment(tctx, ".");
+ fflush(stdout);
+ sleep(15);
+ }
+}
+
+/*
+test how many open files this server supports on the one socket
+*/
+bool torture_maxfid_test(struct torture_context *tctx, struct smbcli_state *cli)
+{
+#define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
+ char *fname;
+ int fnums[0x11000], i;
+ int retries=4, maxfid;
+ bool correct = true;
+ int ret;
+
+ if (retries <= 0) {
+ torture_comment(tctx, "failed to connect\n");
+ return false;
+ }
+
+ if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
+ torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
+ smbcli_errstr(cli->tree));
+ return false;
+ }
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
+ torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n",
+ smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ torture_comment(tctx, "Testing maximum number of open files\n");
+
+ for (i=0; i<0x11000; i++) {
+ if (i % 1000 == 0) {
+ ret = asprintf(&fname, "\\maxfid\\fid%d", i/1000);
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
+ torture_comment(tctx, "Failed to mkdir %s, error=%s\n",
+ fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+ free(fname);
+ }
+ ret = asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ if ((fnums[i] = smbcli_open(cli->tree, fname,
+ O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
+ -1) {
+ torture_comment(tctx, "open of %s failed (%s)\n",
+ fname, smbcli_errstr(cli->tree));
+ torture_comment(tctx, "maximum fnum is %d\n", i);
+ break;
+ }
+ free(fname);
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%6d\r", i);
+ fflush(stdout);
+ }
+ }
+ torture_comment(tctx, "%6d\n", i);
+
+ maxfid = i;
+
+ torture_comment(tctx, "cleaning up\n");
+ for (i=0;i<maxfid;i++) {
+ ret = asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
+ torture_assert(tctx, ret != -1, "asprintf failed");
+ if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
+ torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
+ }
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
+ torture_comment(tctx, "unlink of %s failed (%s)\n",
+ fname, smbcli_errstr(cli->tree));
+ correct = false;
+ }
+ free(fname);
+
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%6d\r", i);
+ fflush(stdout);
+ }
+ }
+ torture_comment(tctx, "%6d\n", 0);
+
+ if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
+ torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
+ smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ torture_comment(tctx, "maxfid test finished\n");
+
+ return correct;
+#undef MAXFID_TEMPLATE
+}
+
+
+
+/*
+ sees what IOCTLs are supported
+ */
+bool torture_ioctl_test(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ uint16_t device, function;
+ int fnum;
+ const char *fname = "\\ioctl.dat";
+ NTSTATUS status;
+ union smb_ioctl parms;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
+
+ smbcli_unlink(cli->tree, fname);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum == -1) {
+ torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ parms.ioctl.level = RAW_IOCTL_IOCTL;
+ parms.ioctl.in.file.fnum = fnum;
+ parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
+ torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
+
+ for (device=0;device<0x100;device++) {
+ torture_comment(tctx, "Testing device=0x%x\n", device);
+ for (function=0;function<0x100;function++) {
+ parms.ioctl.in.request = (device << 16) | function;
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
+
+ if (NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n",
+ device, function, (int)parms.ioctl.out.blob.length);
+ }
+ }
+ }
+
+ return true;
+}
+
+static void benchrw_callback(struct smbcli_request *req);
+enum benchrw_stage {
+ START,
+ OPEN_CONNECTION,
+ CLEANUP_TESTDIR,
+ MK_TESTDIR,
+ OPEN_FILE,
+ INITIAL_WRITE,
+ READ_WRITE_DATA,
+ MAX_OPS_REACHED,
+ ERROR,
+ CLOSE_FILE,
+ CLEANUP,
+ FINISHED
+};
+
+struct bench_params {
+ struct unclist{
+ const char *host;
+ const char *share;
+ } **unc;
+ const char *workgroup;
+ int retry;
+ unsigned int writeblocks;
+ unsigned int blocksize;
+ unsigned int writeratio;
+ int num_parallel_requests;
+};
+
+struct benchrw_state {
+ struct torture_context *tctx;
+ char *dname;
+ char *fname;
+ uint16_t fnum;
+ int nr;
+ struct smbcli_tree *cli;
+ uint8_t *buffer;
+ int writecnt;
+ int readcnt;
+ int completed;
+ int num_parallel_requests;
+ void *req_params;
+ enum benchrw_stage mode;
+ struct bench_params *lpcfg_params;
+};
+
+/*
+ init params using lpcfg_parm_xxx
+ return number of unclist entries
+*/
+static int init_benchrw_params(struct torture_context *tctx,
+ struct bench_params *lpar)
+{
+ char **unc_list = NULL;
+ int num_unc_names = 0, conn_index=0, empty_lines=0;
+ const char *p;
+ lpar->retry = torture_setting_int(tctx, "retry",3);
+ lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
+ lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
+ lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
+ lpar->num_parallel_requests = torture_setting_int(
+ tctx, "parallel_requests", 5);
+ lpar->workgroup = lpcfg_workgroup(tctx->lp_ctx);
+
+ p = torture_setting_string(tctx, "unclist", NULL);
+ if (p) {
+ char *h, *s;
+ unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
+ if (!unc_list || num_unc_names <= 0) {
+ torture_comment(tctx, "Failed to load unc names list "
+ "from '%s'\n", p);
+ exit(1);
+ }
+
+ lpar->unc = talloc_array(tctx, struct unclist *,
+ (num_unc_names-empty_lines));
+ for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
+ /* ignore empty lines */
+ if(strlen(unc_list[conn_index % num_unc_names])==0){
+ empty_lines++;
+ continue;
+ }
+ if (!smbcli_parse_unc(
+ unc_list[conn_index % num_unc_names],
+ NULL, &h, &s)) {
+ torture_comment(
+ tctx, "Failed to parse UNC "
+ "name %s\n",
+ unc_list[conn_index % num_unc_names]);
+ exit(1);
+ }
+ lpar->unc[conn_index-empty_lines] =
+ talloc(tctx, struct unclist);
+ lpar->unc[conn_index-empty_lines]->host = h;
+ lpar->unc[conn_index-empty_lines]->share = s;
+ }
+ return num_unc_names-empty_lines;
+ }else{
+ lpar->unc = talloc_array(tctx, struct unclist *, 1);
+ lpar->unc[0] = talloc(tctx,struct unclist);
+ lpar->unc[0]->host = torture_setting_string(tctx, "host",
+ NULL);
+ lpar->unc[0]->share = torture_setting_string(tctx, "share",
+ NULL);
+ return 1;
+ }
+}
+
+/*
+ Called when the reads & writes are finished. closes the file.
+*/
+static NTSTATUS benchrw_close(struct torture_context *tctx,
+ struct smbcli_request *req,
+ struct benchrw_state *state)
+{
+ union smb_close close_parms;
+
+ NT_STATUS_NOT_OK_RETURN(req->status);
+
+ torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
+ close_parms.close.level = RAW_CLOSE_CLOSE;
+ close_parms.close.in.file.fnum = state->fnum ;
+ close_parms.close.in.write_time = 0;
+ state->mode=CLOSE_FILE;
+
+ req = smb_raw_close_send(state->cli, &close_parms);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+ /*register the callback function!*/
+ req->async.fn = benchrw_callback;
+ req->async.private_data = state;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
+ struct benchrw_state *state);
+static void benchrw_callback(struct smbcli_request *req);
+
+static void benchrw_rw_callback(struct smbcli_request *req)
+{
+ struct benchrw_state *state = req->async.private_data;
+ struct torture_context *tctx = state->tctx;
+
+ if (!NT_STATUS_IS_OK(req->status)) {
+ state->mode = ERROR;
+ return;
+ }
+
+ state->completed++;
+ state->num_parallel_requests--;
+
+ if ((state->completed >= torture_numops)
+ && (state->num_parallel_requests == 0)) {
+ benchrw_callback(req);
+ talloc_free(req);
+ return;
+ }
+
+ talloc_free(req);
+
+ if (state->completed + state->num_parallel_requests
+ < torture_numops) {
+ benchrw_readwrite(tctx, state);
+ }
+}
+
+/*
+ Called when the initial write is completed is done. write or read a file.
+*/
+static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
+ struct benchrw_state *state)
+{
+ struct smbcli_request *req;
+ union smb_read rd;
+ union smb_write wr;
+
+ /* randomize between writes and reads*/
+ if (random() % state->lpcfg_params->writeratio == 0) {
+ torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
+ state->nr,state->completed,torture_numops);
+ wr.generic.level = RAW_WRITE_WRITEX ;
+ wr.writex.in.file.fnum = state->fnum ;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0 ;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = state->lpcfg_params->blocksize;
+ wr.writex.in.data = state->buffer;
+ state->readcnt=0;
+ req = smb_raw_write_send(state->cli,&wr);
+ }
+ else {
+ torture_comment(tctx,
+ "Callback READ file:%d (%d/%d) Offset:%d\n",
+ state->nr,state->completed,torture_numops,
+ (state->readcnt*state->lpcfg_params->blocksize));
+ rd.generic.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = state->fnum ;
+ rd.readx.in.offset = state->readcnt*state->lpcfg_params->blocksize;
+ rd.readx.in.mincnt = state->lpcfg_params->blocksize;
+ rd.readx.in.maxcnt = rd.readx.in.mincnt;
+ rd.readx.in.remaining = 0 ;
+ rd.readx.out.data = state->buffer;
+ rd.readx.in.read_for_execute = false;
+ if(state->readcnt < state->lpcfg_params->writeblocks){
+ state->readcnt++;
+ }else{
+ /*start reading from beginning of file*/
+ state->readcnt=0;
+ }
+ req = smb_raw_read_send(state->cli,&rd);
+ }
+ state->num_parallel_requests += 1;
+ NT_STATUS_HAVE_NO_MEMORY(req);
+ /*register the callback function!*/
+ req->async.fn = benchrw_rw_callback;
+ req->async.private_data = state;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ Called when the open is done. writes to the file.
+*/
+static NTSTATUS benchrw_open(struct torture_context *tctx,
+ struct smbcli_request *req,
+ struct benchrw_state *state)
+{
+ union smb_write wr;
+ if(state->mode == OPEN_FILE){
+ NTSTATUS status;
+ status = smb_raw_open_recv(req,tctx,(
+ union smb_open*)state->req_params);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ state->fnum = ((union smb_open*)state->req_params)
+ ->openx.out.file.fnum;
+ torture_comment(tctx, "File opened (%d)\n",state->fnum);
+ state->mode=INITIAL_WRITE;
+ }
+
+ torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
+ (state->writecnt+1)*state->lpcfg_params->blocksize,
+ (state->lpcfg_params->writeblocks*state->lpcfg_params->blocksize));
+ wr.generic.level = RAW_WRITE_WRITEX ;
+ wr.writex.in.file.fnum = state->fnum ;
+ wr.writex.in.offset = state->writecnt *
+ state->lpcfg_params->blocksize;
+ wr.writex.in.wmode = 0 ;
+ wr.writex.in.remaining = (state->lpcfg_params->writeblocks *
+ state->lpcfg_params->blocksize)-
+ ((state->writecnt+1)*state->
+ lpcfg_params->blocksize);
+ wr.writex.in.count = state->lpcfg_params->blocksize;
+ wr.writex.in.data = state->buffer;
+ state->writecnt++;
+ if(state->writecnt == state->lpcfg_params->writeblocks){
+ state->mode=READ_WRITE_DATA;
+ }
+ req = smb_raw_write_send(state->cli,&wr);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ /*register the callback function!*/
+ req->async.fn = benchrw_callback;
+ req->async.private_data = state;
+ return NT_STATUS_OK;
+}
+
+/*
+ Called when the mkdir is done. Opens a file.
+*/
+static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
+ struct smbcli_request *req,
+ struct benchrw_state *state)
+{
+ union smb_open *open_parms;
+ uint8_t *writedata;
+
+ NT_STATUS_NOT_OK_RETURN(req->status);
+
+ /* open/create the files */
+ torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
+ torture_setting_int(tctx, "nprocs", 4));
+ open_parms=talloc_zero(tctx, union smb_open);
+ NT_STATUS_HAVE_NO_MEMORY(open_parms);
+ open_parms->openx.level = RAW_OPEN_OPENX;
+ open_parms->openx.in.flags = 0;
+ open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ open_parms->openx.in.search_attrs =
+ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ open_parms->openx.in.file_attrs = 0;
+ open_parms->openx.in.write_time = 0;
+ open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
+ open_parms->openx.in.size = 0;
+ open_parms->openx.in.timeout = 0;
+ open_parms->openx.in.fname = state->fname;
+
+ writedata = talloc_size(tctx,state->lpcfg_params->blocksize);
+ NT_STATUS_HAVE_NO_MEMORY(writedata);
+ generate_random_buffer(writedata,state->lpcfg_params->blocksize);
+ state->buffer=writedata;
+ state->writecnt=1;
+ state->readcnt=0;
+ state->req_params=open_parms;
+ state->mode=OPEN_FILE;
+
+ req = smb_raw_open_send(state->cli,open_parms);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ /*register the callback function!*/
+ req->async.fn = benchrw_callback;
+ req->async.private_data = state;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ handler for completion of a sub-request of the bench-rw test
+*/
+static void benchrw_callback(struct smbcli_request *req)
+{
+ struct benchrw_state *state = req->async.private_data;
+ struct torture_context *tctx = state->tctx;
+
+ /*don't send new requests when torture_numops is reached*/
+ if ((state->mode == READ_WRITE_DATA)
+ && (state->completed >= torture_numops)) {
+ state->mode=MAX_OPS_REACHED;
+ }
+
+ switch (state->mode) {
+
+ case MK_TESTDIR:
+ if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
+ torture_comment(tctx, "Failed to create the test "
+ "directory - %s\n",
+ nt_errstr(req->status));
+ state->mode=ERROR;
+ return;
+ }
+ break;
+ case OPEN_FILE:
+ case INITIAL_WRITE:
+ if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
+ torture_comment(tctx, "Failed to open/write the "
+ "file - %s\n",
+ nt_errstr(req->status));
+ state->mode=ERROR;
+ state->readcnt=0;
+ return;
+ }
+ break;
+ case READ_WRITE_DATA:
+ while (state->num_parallel_requests
+ < state->lpcfg_params->num_parallel_requests) {
+ NTSTATUS status;
+ status = benchrw_readwrite(tctx,state);
+ if (!NT_STATUS_IS_OK(status)){
+ torture_comment(tctx, "Failed to read/write "
+ "the file - %s\n",
+ nt_errstr(req->status));
+ state->mode=ERROR;
+ return;
+ }
+ }
+ break;
+ case MAX_OPS_REACHED:
+ if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
+ torture_comment(tctx, "Failed to read/write/close "
+ "the file - %s\n",
+ nt_errstr(req->status));
+ state->mode=ERROR;
+ return;
+ }
+ break;
+ case CLOSE_FILE:
+ torture_comment(tctx, "File %d closed\n",state->nr);
+ if (!NT_STATUS_IS_OK(req->status)) {
+ torture_comment(tctx, "Failed to close the "
+ "file - %s\n",
+ nt_errstr(req->status));
+ state->mode=ERROR;
+ return;
+ }
+ state->mode=CLEANUP;
+ return;
+ default:
+ break;
+ }
+
+}
+
+/* open connection async callback function*/
+static void async_open_callback(struct composite_context *con)
+{
+ struct benchrw_state *state = con->async.private_data;
+ struct torture_context *tctx = state->tctx;
+ int retry = state->lpcfg_params->retry;
+
+ if (NT_STATUS_IS_OK(con->status)) {
+ state->cli=((struct smb_composite_connect*)
+ state->req_params)->out.tree;
+ state->mode=CLEANUP_TESTDIR;
+ }else{
+ if(state->writecnt < retry){
+ torture_comment(tctx, "Failed to open connection: "
+ "%d, Retry (%d/%d)\n",
+ state->nr,state->writecnt,retry);
+ state->writecnt++;
+ state->mode=START;
+ usleep(1000);
+ }else{
+ torture_comment(tctx, "Failed to open connection "
+ "(%d) - %s\n",
+ state->nr, nt_errstr(con->status));
+ state->mode=ERROR;
+ }
+ return;
+ }
+}
+
+/*
+ establishes a smbcli_tree from scratch (async)
+*/
+static struct composite_context *torture_connect_async(
+ struct torture_context *tctx,
+ struct smb_composite_connect *smb,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *host,
+ const char *share,
+ const char *workgroup)
+{
+ torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
+ smb->in.dest_host=talloc_strdup(mem_ctx,host);
+ smb->in.service=talloc_strdup(mem_ctx,share);
+ smb->in.dest_ports=lpcfg_smb_ports(tctx->lp_ctx);
+ smb->in.socket_options = lpcfg_socket_options(tctx->lp_ctx);
+ smb->in.called_name = strupper_talloc(mem_ctx, host);
+ smb->in.service_type=NULL;
+ smb->in.credentials = samba_cmdline_get_creds();
+ smb->in.fallback_to_anonymous=false;
+ smb->in.gensec_settings = lpcfg_gensec_settings(mem_ctx, tctx->lp_ctx);
+ smb->in.workgroup=workgroup;
+ lpcfg_smbcli_options(tctx->lp_ctx, &smb->in.options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &smb->in.session_options);
+
+ return smb_composite_connect_send(smb,mem_ctx,
+ lpcfg_resolve_context(tctx->lp_ctx),ev);
+}
+
+bool run_benchrw(struct torture_context *tctx)
+{
+ struct smb_composite_connect *smb_con;
+ const char *fname = "\\rwtest.dat";
+ struct smbcli_request *req;
+ struct benchrw_state **state;
+ int i , num_unc_names;
+ struct tevent_context *ev ;
+ struct composite_context *req1;
+ struct bench_params lpparams;
+ union smb_mkdir parms;
+ int finished = 0;
+ bool success=true;
+ int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+
+ torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
+ "num_nprocs=%d\n",
+ torture_numops, torture_nprocs);
+
+ /*init talloc context*/
+ ev = tctx->ev;
+ state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
+
+ /* init params using lpcfg_parm_xxx */
+ num_unc_names = init_benchrw_params(tctx,&lpparams);
+
+ /* init private data structs*/
+ for(i = 0; i<torture_nprocs;i++){
+ state[i]=talloc(tctx,struct benchrw_state);
+ state[i]->tctx = tctx;
+ state[i]->completed=0;
+ state[i]->num_parallel_requests=0;
+ state[i]->lpcfg_params=&lpparams;
+ state[i]->nr=i;
+ state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
+ state[i]->fname=talloc_asprintf(tctx,"%s%s",
+ state[i]->dname,fname);
+ state[i]->mode=START;
+ state[i]->writecnt=0;
+ }
+
+ torture_comment(tctx, "Starting async requests\n");
+ while(finished != torture_nprocs){
+ finished=0;
+ for(i = 0; i<torture_nprocs;i++){
+ switch (state[i]->mode){
+ /*open multiple connections with the same userid */
+ case START:
+ smb_con = talloc_zero(
+ tctx,struct smb_composite_connect);
+ state[i]->req_params=smb_con;
+ state[i]->mode=OPEN_CONNECTION;
+ req1 = torture_connect_async(
+ tctx, smb_con, tctx,ev,
+ lpparams.unc[i % num_unc_names]->host,
+ lpparams.unc[i % num_unc_names]->share,
+ lpparams.workgroup);
+ /* register callback fn + private data */
+ req1->async.fn = async_open_callback;
+ req1->async.private_data=state[i];
+ break;
+ /*setup test dirs (sync)*/
+ case CLEANUP_TESTDIR:
+ torture_comment(tctx, "Setup test dir %d\n",i);
+ smb_raw_exit(state[i]->cli->session);
+ if (smbcli_deltree(state[i]->cli,
+ state[i]->dname) == -1) {
+ torture_comment(
+ tctx,
+ "Unable to delete %s - %s\n",
+ state[i]->dname,
+ smbcli_errstr(state[i]->cli));
+ state[i]->mode=ERROR;
+ break;
+ }
+ state[i]->mode=MK_TESTDIR;
+ parms.mkdir.level = RAW_MKDIR_MKDIR;
+ parms.mkdir.in.path = state[i]->dname;
+ req = smb_raw_mkdir_send(state[i]->cli,&parms);
+ /* register callback fn + private data */
+ req->async.fn = benchrw_callback;
+ req->async.private_data=state[i];
+ break;
+ /* error occurred , finish */
+ case ERROR:
+ finished++;
+ success=false;
+ break;
+ /* cleanup , close connection */
+ case CLEANUP:
+ torture_comment(tctx, "Deleting test dir %s "
+ "%d/%d\n",state[i]->dname,
+ i+1,torture_nprocs);
+ smbcli_deltree(state[i]->cli,state[i]->dname);
+ if (NT_STATUS_IS_ERR(smb_tree_disconnect(
+ state[i]->cli))) {
+ torture_comment(tctx, "ERROR: Tree "
+ "disconnect failed");
+ state[i]->mode=ERROR;
+ break;
+ }
+ state[i]->mode=FINISHED;
+
+ FALL_THROUGH;
+ case FINISHED:
+ finished++;
+ break;
+ default:
+ tevent_loop_once(ev);
+ }
+ }
+ }
+
+ return success;
+}
+
diff --git a/source4/torture/basic/properties.c b/source4/torture/basic/properties.c
new file mode 100644
index 0000000..b63acc7
--- /dev/null
+++ b/source4/torture/basic/properties.c
@@ -0,0 +1,118 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ show server properties
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+struct bitmapping {
+ const char *name;
+ uint32_t value;
+};
+
+#define BIT_NAME(x) { #x, x }
+
+const static struct bitmapping fs_attr_bits[] = {
+ BIT_NAME(FS_ATTR_CASE_SENSITIVE_SEARCH),
+ BIT_NAME(FS_ATTR_CASE_PRESERVED_NAMES),
+ BIT_NAME(FS_ATTR_UNICODE_ON_DISK),
+ BIT_NAME(FS_ATTR_PERSISTANT_ACLS),
+ BIT_NAME(FS_ATTR_COMPRESSION),
+ BIT_NAME(FS_ATTR_QUOTAS),
+ BIT_NAME(FS_ATTR_SPARSE_FILES),
+ BIT_NAME(FS_ATTR_REPARSE_POINTS),
+ BIT_NAME(FS_ATTR_REMOTE_STORAGE),
+ BIT_NAME(FS_ATTR_LFN_SUPPORT),
+ BIT_NAME(FS_ATTR_IS_COMPRESSED),
+ BIT_NAME(FS_ATTR_OBJECT_IDS),
+ BIT_NAME(FS_ATTR_ENCRYPTION),
+ BIT_NAME(FS_ATTR_NAMED_STREAMS),
+ { NULL, 0 }
+};
+
+const static struct bitmapping capability_bits[] = {
+ BIT_NAME(CAP_RAW_MODE),
+ BIT_NAME(CAP_MPX_MODE),
+ BIT_NAME(CAP_UNICODE),
+ BIT_NAME(CAP_LARGE_FILES),
+ BIT_NAME(CAP_NT_SMBS),
+ BIT_NAME(CAP_RPC_REMOTE_APIS),
+ BIT_NAME(CAP_STATUS32),
+ BIT_NAME(CAP_LEVEL_II_OPLOCKS),
+ BIT_NAME(CAP_LOCK_AND_READ),
+ BIT_NAME(CAP_NT_FIND),
+ BIT_NAME(CAP_DFS),
+ BIT_NAME(CAP_W2K_SMBS),
+ BIT_NAME(CAP_LARGE_READX),
+ BIT_NAME(CAP_LARGE_WRITEX),
+ BIT_NAME(CAP_UNIX),
+ BIT_NAME(CAP_EXTENDED_SECURITY),
+ { NULL, 0 }
+};
+
+static void show_bits(const struct bitmapping *bm, uint32_t value)
+{
+ int i;
+ for (i=0;bm[i].name;i++) {
+ if (value & bm[i].value) {
+ d_printf("\t%s\n", bm[i].name);
+ value &= ~bm[i].value;
+ }
+ }
+ if (value != 0) {
+ d_printf("\tunknown bits: 0x%08x\n", value);
+ }
+}
+
+
+/*
+ print out server properties
+ */
+bool torture_test_properties(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool correct = true;
+ union smb_fsinfo fs;
+ NTSTATUS status;
+
+ d_printf("Capabilities: 0x%08x\n", cli->transport->negotiate.capabilities);
+ show_bits(capability_bits, cli->transport->negotiate.capabilities);
+ d_printf("\n");
+
+ fs.attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
+ status = smb_raw_fsinfo(cli->tree, cli, &fs);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("qfsinfo failed - %s\n", nt_errstr(status));
+ correct = false;
+ } else {
+ d_printf("Filesystem attributes: 0x%08x\n",
+ fs.attribute_info.out.fs_attr);
+ show_bits(fs_attr_bits, fs.attribute_info.out.fs_attr);
+ d_printf("max_file_component_length: %d\n",
+ fs.attribute_info.out.max_file_component_length);
+ d_printf("fstype: %s\n", fs.attribute_info.out.fs_type.s);
+ }
+
+ return correct;
+}
+
+
diff --git a/source4/torture/basic/rename.c b/source4/torture/basic/rename.c
new file mode 100644
index 0000000..a80dd6e
--- /dev/null
+++ b/source4/torture/basic/rename.c
@@ -0,0 +1,98 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ rename testing
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+/*
+ Test rename on files open with share delete and no share delete.
+ */
+bool torture_test_rename(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *fname = "\\test.txt";
+ const char *fname1 = "\\test1.txt";
+ int fnum1;
+
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_unlink(cli1->tree, fname1);
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "First open failed - %s",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert(tctx, NT_STATUS_IS_ERR(smbcli_rename(cli1->tree, fname, fname1)),
+ "First rename succeeded - this should have failed !");
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 1 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_unlink(cli1->tree, fname1);
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE|NTCREATEX_SHARE_ACCESS_READ,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx,
+ "Second open failed - %s", smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_rename(cli1->tree, fname, fname1),
+ talloc_asprintf(tctx,
+ "Second rename failed - this should have succeeded - %s",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx,
+ "close - 2 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_unlink(cli1->tree, fname1);
+
+ fnum1 = smbcli_nt_create_full(cli1->tree, fname, 0,
+ SEC_STD_READ_CONTROL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OVERWRITE_IF, 0, 0);
+
+ torture_assert(tctx, fnum1 != -1, talloc_asprintf(tctx, "Third open failed - %s",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_rename(cli1->tree, fname, fname1),
+ talloc_asprintf(tctx, "Third rename failed - this should have succeeded - %s",
+ smbcli_errstr(cli1->tree)));
+
+ torture_assert_ntstatus_ok(tctx, smbcli_close(cli1->tree, fnum1),
+ talloc_asprintf(tctx, "close - 3 failed (%s)", smbcli_errstr(cli1->tree)));
+
+ smbcli_unlink(cli1->tree, fname);
+ smbcli_unlink(cli1->tree, fname1);
+
+ return true;
+}
+
diff --git a/source4/torture/basic/scanner.c b/source4/torture/basic/scanner.c
new file mode 100644
index 0000000..144b7d0
--- /dev/null
+++ b/source4/torture/basic/scanner.c
@@ -0,0 +1,623 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - scanning functions
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/filesys.h"
+#include "param/param.h"
+#include "torture/basic/proto.h"
+
+#define VERBOSE 0
+#define OP_MIN 0
+#define OP_MAX 100
+#define PARAM_SIZE 1024
+
+/****************************************************************************
+look for a partial hit
+****************************************************************************/
+static void trans2_check_hit(const char *format, int op, int level, NTSTATUS status)
+{
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ return;
+ }
+#if VERBOSE
+ printf("possible %s hit op=%3d level=%5d status=%s\n",
+ format, op, level, nt_errstr(status));
+#endif
+}
+
+/****************************************************************************
+check for existence of a trans2 call
+****************************************************************************/
+static NTSTATUS try_trans2(struct smbcli_state *cli,
+ int op,
+ uint8_t *param, uint8_t *data,
+ int param_len, int data_len,
+ int *rparam_len, int *rdata_len)
+{
+ NTSTATUS status;
+ struct smb_trans2 t2;
+ uint16_t setup = op;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("try_trans2");
+
+ t2.in.max_param = UINT16_MAX;
+ t2.in.max_data = UINT16_MAX;
+ t2.in.max_setup = 10;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params.data = param;
+ t2.in.params.length = param_len;
+ t2.in.data.data = data;
+ t2.in.data.length = data_len;
+
+ status = smb_raw_trans2(cli->tree, mem_ctx, &t2);
+
+ *rparam_len = t2.out.params.length;
+ *rdata_len = t2.out.data.length;
+
+ talloc_free(mem_ctx);
+
+ return status;
+}
+
+
+static NTSTATUS try_trans2_len(struct smbcli_state *cli,
+ const char *format,
+ int op, int level,
+ uint8_t *param, uint8_t *data,
+ int param_len, int *data_len,
+ int *rparam_len, int *rdata_len)
+{
+ NTSTATUS ret=NT_STATUS_OK;
+
+ ret = try_trans2(cli, op, param, data, param_len,
+ PARAM_SIZE, rparam_len, rdata_len);
+#if VERBOSE
+ printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
+#endif
+ if (!NT_STATUS_IS_OK(ret)) return ret;
+
+ *data_len = 0;
+ while (*data_len < PARAM_SIZE) {
+ ret = try_trans2(cli, op, param, data, param_len,
+ *data_len, rparam_len, rdata_len);
+ if (NT_STATUS_IS_OK(ret)) break;
+ *data_len += 2;
+ }
+ if (NT_STATUS_IS_OK(ret)) {
+ printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
+ format, level, *data_len, *rparam_len, *rdata_len);
+ } else {
+ trans2_check_hit(format, op, level, ret);
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+check whether a trans2 opnum exists at all
+****************************************************************************/
+static bool trans2_op_exists(struct smbcli_state *cli, int op)
+{
+ int data_len = PARAM_SIZE;
+ int param_len = PARAM_SIZE;
+ int rparam_len, rdata_len;
+ uint8_t *param, *data;
+ NTSTATUS status1, status2;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("trans2_op_exists");
+
+ /* try with a info level only */
+
+ param = talloc_array(mem_ctx, uint8_t, param_len);
+ data = talloc_array(mem_ctx, uint8_t, data_len);
+
+ memset(param, 0xFF, param_len);
+ memset(data, 0xFF, data_len);
+
+ status1 = try_trans2(cli, 0xFFFF, param, data, param_len, data_len,
+ &rparam_len, &rdata_len);
+
+ status2 = try_trans2(cli, op, param, data, param_len, data_len,
+ &rparam_len, &rdata_len);
+
+ if (NT_STATUS_EQUAL(status1, status2)) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ printf("Found op %d (status=%s)\n", op, nt_errstr(status2));
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+/****************************************************************************
+check for existence of a trans2 call
+****************************************************************************/
+static bool scan_trans2(
+ struct smbcli_state *cli, int op, int level,
+ int fnum, int dnum, int qfnum, const char *fname)
+{
+ int data_len = 0;
+ int param_len = 0;
+ int rparam_len, rdata_len;
+ uint8_t *param, *data;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("scan_trans2");
+
+ data = talloc_array(mem_ctx, uint8_t, PARAM_SIZE);
+ param = talloc_array(mem_ctx, uint8_t, PARAM_SIZE);
+
+ memset(data, 0, PARAM_SIZE);
+ data_len = 4;
+
+ /* try with a info level only */
+ param_len = 2;
+ SSVAL(param, 0, level);
+ status = try_trans2_len(cli, "void", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_trans2_len(cli, "fnum", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a quota file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, qfnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_trans2_len(cli, "qfnum", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a notify style */
+ param_len = 6;
+ SSVAL(param, 0, dnum);
+ SSVAL(param, 2, dnum);
+ SSVAL(param, 4, level);
+ status = try_trans2_len(cli, "notify", op, level, param, data,
+ param_len, &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += push_string(
+ &param[6], fname, PARAM_SIZE-7,
+ STR_TERMINATE|STR_UNICODE);
+
+ status = try_trans2_len(cli, "fname", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a new file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += push_string(
+ &param[6], "\\newfile.dat", PARAM_SIZE-7,
+ STR_TERMINATE|STR_UNICODE);
+
+ status = try_trans2_len(cli, "newfile", op, level, param, data,
+ param_len, &data_len, &rparam_len, &rdata_len);
+ smbcli_unlink(cli->tree, "\\newfile.dat");
+ smbcli_rmdir(cli->tree, "\\newfile.dat");
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try dfs style */
+ smbcli_mkdir(cli->tree, "\\testdir");
+ param_len = 2;
+ SSVAL(param, 0, level);
+ param_len += push_string(
+ &param[2], "\\testdir", PARAM_SIZE-3,
+ STR_TERMINATE|STR_UNICODE);
+
+ status = try_trans2_len(cli, "dfs", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ smbcli_rmdir(cli->tree, "\\testdir");
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ talloc_free(mem_ctx);
+ return false;
+}
+
+bool torture_trans2_scan(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ int op, level;
+ const char *fname = "\\scanner.dat";
+ int fnum, dnum, qfnum;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ printf("file open failed - %s\n", smbcli_errstr(cli->tree));
+ }
+ dnum = smbcli_nt_create_full(cli->tree, "\\",
+ 0,
+ SEC_RIGHTS_FILE_READ,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OPEN,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ if (dnum == -1) {
+ printf("directory open failed - %s\n", smbcli_errstr(cli->tree));
+ }
+ qfnum = smbcli_nt_create_full(cli->tree, "\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION",
+ NTCREATEX_FLAGS_EXTENDED,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ 0,
+ NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OPEN,
+ 0, 0);
+ if (qfnum == -1) {
+ printf("quota open failed - %s\n", smbcli_errstr(cli->tree));
+ }
+
+ for (op=OP_MIN; op<=OP_MAX; op++) {
+
+ if (!trans2_op_exists(cli, op)) {
+ continue;
+ }
+
+ for (level = 0; level <= 50; level++) {
+ scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
+ }
+
+ for (level = 0x100; level <= 0x130; level++) {
+ scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
+ }
+
+ for (level = 1000; level < 1050; level++) {
+ scan_trans2(cli, op, level, fnum, dnum, qfnum, fname);
+ }
+ }
+
+ return true;
+}
+
+
+
+
+/****************************************************************************
+look for a partial hit
+****************************************************************************/
+static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
+{
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ return;
+ }
+#if VERBOSE
+ printf("possible %s hit op=%3d level=%5d status=%s\n",
+ format, op, level, nt_errstr(status));
+#endif
+}
+
+/****************************************************************************
+check for existence of a nttrans call
+****************************************************************************/
+static NTSTATUS try_nttrans(struct smbcli_state *cli,
+ int op,
+ uint8_t *param, uint8_t *data,
+ int param_len, int data_len,
+ int *rparam_len, int *rdata_len)
+{
+ struct smb_nttrans parms;
+ DATA_BLOB ntparam_blob, ntdata_blob;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("try_nttrans");
+
+ ntparam_blob.length = param_len;
+ ntparam_blob.data = param;
+ ntdata_blob.length = data_len;
+ ntdata_blob.data = data;
+
+ parms.in.max_param = UINT32_MAX;
+ parms.in.max_data = UINT32_MAX;
+ parms.in.max_setup = 0;
+ parms.in.setup_count = 0;
+ parms.in.function = op;
+ parms.in.params = ntparam_blob;
+ parms.in.data = ntdata_blob;
+
+ status = smb_raw_nttrans(cli->tree, mem_ctx, &parms);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(1,("Failed to send NT_TRANS\n"));
+ talloc_free(mem_ctx);
+ return status;
+ }
+ *rparam_len = parms.out.params.length;
+ *rdata_len = parms.out.data.length;
+
+ talloc_free(mem_ctx);
+
+ return status;
+}
+
+
+static NTSTATUS try_nttrans_len(struct smbcli_state *cli,
+ const char *format,
+ int op, int level,
+ uint8_t *param, uint8_t *data,
+ int param_len, int *data_len,
+ int *rparam_len, int *rdata_len)
+{
+ NTSTATUS ret=NT_STATUS_OK;
+
+ ret = try_nttrans(cli, op, param, data, param_len,
+ PARAM_SIZE, rparam_len, rdata_len);
+#if VERBOSE
+ printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
+#endif
+ if (!NT_STATUS_IS_OK(ret)) return ret;
+
+ *data_len = 0;
+ while (*data_len < PARAM_SIZE) {
+ ret = try_nttrans(cli, op, param, data, param_len,
+ *data_len, rparam_len, rdata_len);
+ if (NT_STATUS_IS_OK(ret)) break;
+ *data_len += 2;
+ }
+ if (NT_STATUS_IS_OK(ret)) {
+ printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
+ format, level, *data_len, *rparam_len, *rdata_len);
+ } else {
+ nttrans_check_hit(format, op, level, ret);
+ }
+ return ret;
+}
+
+/****************************************************************************
+check for existence of a nttrans call
+****************************************************************************/
+static bool scan_nttrans(struct smbcli_state *cli, int op, int level,
+ int fnum, int dnum, const char *fname)
+{
+ int data_len = 0;
+ int param_len = 0;
+ int rparam_len, rdata_len;
+ uint8_t *param, *data;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("scan_nttrans");
+
+ param = talloc_array(mem_ctx, uint8_t, PARAM_SIZE);
+ data = talloc_array(mem_ctx, uint8_t, PARAM_SIZE);
+ memset(data, 0, PARAM_SIZE);
+ data_len = 4;
+
+ /* try with a info level only */
+ param_len = 2;
+ SSVAL(param, 0, level);
+ status = try_nttrans_len(cli, "void", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a file descriptor */
+ param_len = 6;
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+ SSVAL(param, 4, 0);
+ status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a notify style */
+ param_len = 6;
+ SSVAL(param, 0, dnum);
+ SSVAL(param, 2, dnum);
+ SSVAL(param, 4, level);
+ status = try_nttrans_len(cli, "notify", op, level, param, data,
+ param_len, &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += push_string(
+ &param[6], fname, PARAM_SIZE,
+ STR_TERMINATE | STR_UNICODE);
+
+ status = try_nttrans_len(cli, "fname", op, level, param, data,
+ param_len, &data_len, &rparam_len, &rdata_len);
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try with a new file name */
+ param_len = 6;
+ SSVAL(param, 0, level);
+ SSVAL(param, 2, 0);
+ SSVAL(param, 4, 0);
+ param_len += push_string(
+ &param[6], "\\newfile.dat", PARAM_SIZE,
+ STR_TERMINATE | STR_UNICODE);
+
+ status = try_nttrans_len(cli, "newfile", op, level, param, data,
+ param_len, &data_len, &rparam_len, &rdata_len);
+ smbcli_unlink(cli->tree, "\\newfile.dat");
+ smbcli_rmdir(cli->tree, "\\newfile.dat");
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /* try dfs style */
+ smbcli_mkdir(cli->tree, "\\testdir");
+ param_len = 2;
+ SSVAL(param, 0, level);
+ param_len += push_string(&param[2], "\\testdir", PARAM_SIZE,
+ STR_TERMINATE | STR_UNICODE);
+
+ status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len,
+ &data_len, &rparam_len, &rdata_len);
+ smbcli_rmdir(cli->tree, "\\testdir");
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ talloc_free(mem_ctx);
+ return false;
+}
+
+
+bool torture_nttrans_scan(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ int op, level;
+ const char *fname = "\\scanner.dat";
+ int fnum, dnum;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ dnum = smbcli_open(cli->tree, "\\", O_RDONLY, DENY_NONE);
+
+ for (op=OP_MIN; op<=OP_MAX; op++) {
+ printf("Scanning op=%d\n", op);
+ for (level = 0; level <= 50; level++) {
+ scan_nttrans(cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 0x100; level <= 0x130; level++) {
+ scan_nttrans(cli, op, level, fnum, dnum, fname);
+ }
+
+ for (level = 1000; level < 1050; level++) {
+ scan_nttrans(cli, op, level, fnum, dnum, fname);
+ }
+ }
+
+ printf("nttrans scan finished\n");
+ return true;
+}
+
+
+/* scan for valid base SMB requests */
+bool torture_smb_scan(struct torture_context *torture)
+{
+ static struct smbcli_state *cli;
+ int op;
+ struct smbcli_request *req;
+ NTSTATUS status;
+
+ for (op=0x0;op<=0xFF;op++) {
+ if (op == SMBreadbraw) continue;
+
+ if (!torture_open_connection(&cli, torture, 0)) {
+ return false;
+ }
+
+ req = smbcli_request_setup(cli->tree, op, 0, 0);
+
+ if (!smbcli_request_send(req)) {
+ smbcli_request_destroy(req);
+ break;
+ }
+
+ usleep(10000);
+ smbcli_transport_process(cli->transport);
+ if (req->state > SMBCLI_REQUEST_RECV) {
+ status = smbcli_request_simple_recv(req);
+ printf("op=0x%x status=%s\n", op, nt_errstr(status));
+ torture_close_connection(cli);
+ continue;
+ }
+
+ sleep(1);
+ smbcli_transport_process(cli->transport);
+ if (req->state > SMBCLI_REQUEST_RECV) {
+ status = smbcli_request_simple_recv(req);
+ printf("op=0x%x status=%s\n", op, nt_errstr(status));
+ } else {
+ printf("op=0x%x no reply\n", op);
+ smbcli_request_destroy(req);
+ continue; /* don't attempt close! */
+ }
+
+ torture_close_connection(cli);
+ }
+
+
+ printf("smb scan finished\n");
+ return true;
+}
diff --git a/source4/torture/basic/secleak.c b/source4/torture/basic/secleak.c
new file mode 100644
index 0000000..9db9f54
--- /dev/null
+++ b/source4/torture/basic/secleak.c
@@ -0,0 +1,77 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ find security related memory leaks
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "system/time.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+#include "torture/basic/proto.h"
+
+static bool try_failed_login(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ struct smb_composite_sesssetup setup;
+ struct smbcli_session *session;
+ struct smbcli_session_options options;
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+
+ session = smbcli_session_init(cli->transport, cli, false, options);
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities;
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ setup.in.credentials = cli_credentials_init(session);
+ setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+
+ cli_credentials_set_conf(setup.in.credentials, tctx->lp_ctx);
+ cli_credentials_set_domain(setup.in.credentials, "INVALID-DOMAIN", CRED_SPECIFIED);
+ cli_credentials_set_username(setup.in.credentials, "INVALID-USERNAME", CRED_SPECIFIED);
+ cli_credentials_set_password(setup.in.credentials, "INVALID-PASSWORD", CRED_SPECIFIED);
+
+ status = smb_composite_sesssetup(session, &setup);
+ talloc_free(session);
+ if (NT_STATUS_IS_OK(status)) {
+ printf("Allowed session setup with invalid credentials?!\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool torture_sec_leak(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ time_t t1 = time_mono(NULL);
+ int timelimit = torture_setting_int(tctx, "timelimit", 20);
+
+ while (time_mono(NULL) < t1+timelimit) {
+ if (!try_failed_login(tctx, cli)) {
+ return false;
+ }
+ talloc_report(NULL, stdout);
+ }
+
+ return true;
+}
diff --git a/source4/torture/basic/unlink.c b/source4/torture/basic/unlink.c
new file mode 100644
index 0000000..dee71bd
--- /dev/null
+++ b/source4/torture/basic/unlink.c
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ unlink tester
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+
+#define BASEDIR "\\unlinktest"
+
+/*
+ This test checks that
+
+ 1) the server does not allow an unlink on a file that is open
+*/
+bool torture_unlinktest(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ const char *fname = BASEDIR "\\unlink.tst";
+ int fnum;
+ bool correct = true;
+ union smb_open io;
+ NTSTATUS status;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ talloc_asprintf(tctx, "Failed setting up %s", BASEDIR));
+
+ cli->session->pid = 1;
+
+ torture_comment(tctx, "Opening a file\n");
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ torture_assert(tctx, fnum != -1, talloc_asprintf(tctx, "open of %s failed (%s)", fname, smbcli_errstr(cli->tree)));
+
+ torture_comment(tctx, "Unlinking a open file\n");
+
+ torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlink(cli->tree, fname)),
+ "server allowed unlink on an open file");
+
+ correct = check_error(__location__, cli, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ torture_comment(tctx, "Testing unlink after ntcreatex with DELETE access\n");
+
+ io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+
+ status = smb_raw_open(cli->tree, cli, &io);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "failed to open %s", fname));
+
+ torture_assert(tctx, !NT_STATUS_IS_OK(smbcli_unlink(cli->tree, fname)),
+ "server allowed unlink on an open file");
+
+ correct = check_error(__location__, cli, ERRDOS, ERRbadshare,
+ NT_STATUS_SHARING_VIOLATION);
+
+ return correct;
+}
+
+
diff --git a/source4/torture/basic/utable.c b/source4/torture/basic/utable.c
new file mode 100644
index 0000000..a3ddf1a
--- /dev/null
+++ b/source4/torture/basic/utable.c
@@ -0,0 +1,202 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - unicode table dumper
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "param/param.h"
+#include "torture/basic/proto.h"
+#include "lib/util/sys_rw.h"
+
+bool torture_utable(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ char fname[256];
+ const char *alt_name;
+ int fnum;
+ uint8_t c2[4];
+ int c, fd;
+ size_t len;
+ int chars_allowed=0, alt_allowed=0;
+ uint8_t valid[0x10000];
+
+ torture_comment(tctx, "Generating valid character table\n");
+
+ memset(valid, 0, sizeof(valid));
+
+ torture_assert(tctx, torture_setup_dir(cli, "\\utable"),
+ "Setting up dir \\utable failed");
+
+ for (c=1; c < 0x10000; c++) {
+ char *p;
+
+ SSVAL(c2, 0, c);
+ strncpy(fname, "\\utable\\x", sizeof(fname)-1);
+ p = fname+strlen(fname);
+ len = 0;
+ if (!convert_string(CH_UTF16, CH_UNIX,
+ c2, 2,
+ p, sizeof(fname)-strlen(fname), &len)) {
+ torture_comment(tctx, "convert_string failed [%s]\n",
+ fname);
+ continue;
+ }
+
+ p[len] = 0;
+ strncat(fname,"_a_long_extension",sizeof(fname)-1);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR | O_CREAT | O_TRUNC,
+ DENY_NONE);
+ if (fnum == -1) continue;
+
+ chars_allowed++;
+
+ smbcli_qpathinfo_alt_name(cli->tree, fname, &alt_name);
+
+ if (strncmp(alt_name, "X_A_L", 5) != 0) {
+ alt_allowed++;
+ valid[c] = 1;
+ torture_comment(tctx, "fname=[%s] alt_name=[%s]\n", fname, alt_name);
+ }
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ if (c % 100 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%d (%d/%d)\r", c, chars_allowed, alt_allowed);
+ fflush(stdout);
+ }
+ }
+ }
+ torture_comment(tctx, "%d (%d/%d)\n", c, chars_allowed, alt_allowed);
+
+ smbcli_rmdir(cli->tree, "\\utable");
+
+ torture_comment(tctx, "%d chars allowed %d alt chars allowed\n", chars_allowed, alt_allowed);
+
+ fd = open("valid.dat", O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ torture_assert(tctx, fd != -1,
+ talloc_asprintf(tctx,
+ "Failed to create valid.dat - %s", strerror(errno)));
+ sys_write_v(fd, valid, 0x10000);
+ close(fd);
+ torture_comment(tctx, "wrote valid.dat\n");
+
+ return true;
+}
+
+
+static char *form_name(int c)
+{
+ static char fname[256];
+ uint8_t c2[4];
+ char *p;
+ size_t len = 0;
+
+ strncpy(fname, "\\utable\\", sizeof(fname)-1);
+ p = fname+strlen(fname);
+ SSVAL(c2, 0, c);
+
+ if (!convert_string(CH_UTF16, CH_UNIX,
+ c2, 2,
+ p, sizeof(fname)-strlen(fname), &len)) {
+ return NULL;
+ }
+ p[len] = 0;
+ return fname;
+}
+
+bool torture_casetable(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ char *fname;
+ int fnum;
+ int c, i;
+#define MAX_EQUIVALENCE 8
+ codepoint_t equiv[0x10000][MAX_EQUIVALENCE];
+
+ torture_comment(tctx, "Determining upper/lower case table\n");
+
+ memset(equiv, 0, sizeof(equiv));
+
+ torture_assert(tctx, torture_setup_dir(cli, "\\utable"),
+ "Error setting up dir \\utable");
+
+ for (c=1; c < 0x10000; c++) {
+ size_t size;
+
+ if (c == '.' || c == '\\') continue;
+
+ torture_comment(tctx, "%04x (%c)\n", c, isprint(c)?c:'.');
+
+ fname = form_name(c);
+ if (fname == NULL) continue;
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+#if 0
+ SEC_RIGHT_MAXIMUM_ALLOWED,
+#else
+ SEC_RIGHTS_FILE_ALL,
+#endif
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OPEN_IF, 0, 0);
+
+ if (fnum == -1) {
+ torture_comment(tctx, "Failed to create file with char %04x\n", c);
+ continue;
+ }
+
+ size = 0;
+
+ if (NT_STATUS_IS_ERR(smbcli_qfileinfo(cli->tree, fnum, NULL, &size,
+ NULL, NULL, NULL, NULL, NULL))) continue;
+
+ if (size > 0) {
+ /* found a character equivalence! */
+ int c2[MAX_EQUIVALENCE];
+
+ if (size/sizeof(int) >= MAX_EQUIVALENCE) {
+ torture_comment(tctx, "too many chars match?? size=%d c=0x%04x\n",
+ (int)size, c);
+ smbcli_close(cli->tree, fnum);
+ return false;
+ }
+
+ smbcli_read(cli->tree, fnum, c2, 0, size);
+ torture_comment(tctx, "%04x: ", c);
+ equiv[c][0] = c;
+ for (i=0; i<size/sizeof(int); i++) {
+ torture_comment(tctx, "%04x ", c2[i]);
+ equiv[c][i+1] = c2[i];
+ }
+ torture_comment(tctx, "\n");
+ }
+
+ smbcli_write(cli->tree, fnum, 0, &c, size, sizeof(c));
+ smbcli_close(cli->tree, fnum);
+ }
+
+ smbcli_unlink_wcard(cli->tree, "\\utable\\*");
+ smbcli_rmdir(cli->tree, "\\utable");
+
+ return true;
+}
diff --git a/source4/torture/dfs/common.c b/source4/torture/dfs/common.c
new file mode 100644
index 0000000..5772c0d
--- /dev/null
+++ b/source4/torture/dfs/common.c
@@ -0,0 +1,71 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various Domain DFS
+ Copyright (C) Matthieu Patou 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "../librpc/gen_ndr/ndr_dfsblobs.h"
+#include "librpc/ndr/libndr.h"
+#include "param/param.h"
+#include "torture/torture.h"
+#include "torture/dfs/proto.h"
+#include "libcli/raw/raw_proto.h"
+
+NTSTATUS dfs_cli_do_call(struct smbcli_tree *tree,
+ struct dfs_GetDFSReferral *ref)
+{
+ NTSTATUS result;
+ enum ndr_err_code ndr_err;
+ uint16_t setup = TRANSACT2_GET_DFS_REFERRAL;
+ struct smb_trans2 trans;
+
+ ZERO_STRUCT(trans);
+ trans.in.max_param = 0;
+ trans.in.max_data = 4096;
+ trans.in.max_setup = 0;
+ trans.in.flags = 0;
+ trans.in.timeout = 0;
+ trans.in.setup_count = 1;
+ trans.in.setup = &setup;
+ trans.in.trans_name = NULL;
+
+ ndr_err = ndr_push_struct_blob(&trans.in.params, tree,
+ &ref->in.req,
+ (ndr_push_flags_fn_t)ndr_push_dfs_GetDFSReferral_in);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ trans.in.data = data_blob(NULL, 0);
+
+ result = smb_raw_trans2(tree, tree, &trans);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ ndr_err = ndr_pull_struct_blob(&trans.out.data, tree,
+ ref->out.resp,
+ (ndr_pull_flags_fn_t)ndr_pull_dfs_referral_resp);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/torture/dfs/domaindfs.c b/source4/torture/dfs/domaindfs.c
new file mode 100644
index 0000000..e9d9ce4
--- /dev/null
+++ b/source4/torture/dfs/domaindfs.c
@@ -0,0 +1,540 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various Domain DFS
+ Copyright (C) Matthieu Patou 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "../librpc/gen_ndr/ndr_dfsblobs.h"
+#include "librpc/ndr/libndr.h"
+#include "param/param.h"
+#include "torture/torture.h"
+#include "torture/dfs/proto.h"
+
+static bool test_getdomainreferral(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct dfs_GetDFSReferral r;
+ struct dfs_referral_resp resp;
+
+ r.in.req.max_referral_level = 3;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ "Get Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp.path_consumed, 0,
+ "Path consumed not equal to 0");
+ torture_assert_int_equal(tctx, resp.nb_referrals != 0, 1,
+ "0 domains referrals returned");
+ torture_assert_int_equal(tctx, resp.header_flags, 0,
+ "Header flag different it's not a referral server");
+ torture_assert_int_equal(tctx, resp.referral_entries[1].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 1 got %d expected 3",
+ resp.referral_entries[1].version));
+ torture_assert_int_equal(tctx, resp.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3",
+ resp.referral_entries[0].version));
+ torture_assert_int_equal(tctx, resp.referral_entries[0].referral.v3.server_type,
+ DFS_SERVER_NON_ROOT,
+ talloc_asprintf(tctx,
+ "Wrong server type, expected non root server and got %d",
+ resp.referral_entries[0].referral.v3.server_type));
+ torture_assert_int_equal(tctx, resp.referral_entries[0].referral.v3.entry_flags,
+ DFS_FLAG_REFERRAL_DOMAIN_RESP,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a domain response and got %d",
+ resp.referral_entries[0].referral.v3.entry_flags));
+ torture_assert_int_equal(tctx, strlen(
+ resp.referral_entries[0].referral.v3.referrals.r2.special_name) > 0,
+ 1,
+ "Length of domain is 0 or less");
+ torture_assert_int_equal(tctx,
+ resp.referral_entries[0].referral.v3.referrals.r2.special_name[0] == '\\',
+ 1,
+ "domain didn't start with a \\");
+ return true;
+}
+
+static bool test_getdcreferral(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct dfs_GetDFSReferral r, r2, r3;
+ struct dfs_referral_resp resp, resp2, resp3;
+ const char* str;
+ const char* str2;
+
+ r.in.req.max_referral_level = 3;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ "Get Domain referral failed");
+
+ str = resp.referral_entries[0].referral.v3.referrals.r2.special_name;
+ if( strchr(str, '.') == NULL ) {
+ str = resp.referral_entries[1].referral.v3.referrals.r2.special_name;
+ }
+
+ r2.in.req.max_referral_level = 3;
+ r2.in.req.servername = str;
+ r2.out.resp = &resp2;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r2),
+ "Get DC Domain referral failed");
+
+
+ torture_assert_int_equal(tctx, resp2.path_consumed, 0,
+ "Path consumed not equal to 0");
+ torture_assert_int_equal(tctx, resp2.nb_referrals , 1,
+ "We do not received only 1 referral");
+ torture_assert_int_equal(tctx, resp2.header_flags, 0,
+ "Header flag different it's not a referral server");
+ torture_assert_int_equal(tctx, resp2.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3",
+ resp2.referral_entries[0].version));
+ torture_assert_int_equal(tctx, resp2.referral_entries[0].referral.v3.server_type,
+ DFS_SERVER_NON_ROOT,
+ talloc_asprintf(tctx,
+ "Wrong server type, expected non root server and got %d",
+ resp2.referral_entries[0].referral.v3.server_type));
+ torture_assert_int_equal(tctx, resp2.referral_entries[0].referral.v3.entry_flags,
+ DFS_FLAG_REFERRAL_DOMAIN_RESP,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a domain response and got %d",
+ resp2.referral_entries[0].referral.v3.entry_flags));
+ torture_assert_int_equal(tctx, strlen(
+ resp2.referral_entries[0].referral.v3.referrals.r2.special_name) > 0,
+ 1,
+ "Length of domain is 0 or less");
+ torture_assert_int_equal(tctx, strlen(
+ resp2.referral_entries[0].referral.v3.referrals.r2.expanded_names[0]) > 0,
+ 1,
+ "Length of first dc is less than 0");
+ str = strchr(resp2.referral_entries[0].referral.v3.referrals.r2.expanded_names[0], '.');
+ str2 = resp2.referral_entries[0].referral.v3.referrals.r2.special_name;
+ if (str2[0] == '\\') {
+ str2++;
+ }
+ torture_assert_int_equal(tctx, strlen(str) >0, 1 ,"Length of domain too short");
+ str++;
+ torture_assert_int_equal(tctx, strcmp(str,str2), 0,
+ talloc_asprintf(tctx, "Pb domain of the dc is not "\
+ "the same as the requested: domain was = %s got =%s",str2 ,str));
+ torture_assert_int_equal(tctx,
+ resp.referral_entries[0].referral.v3.referrals.r2.special_name[0] == '\\',
+ 1,
+ "dc name didn't start with a \\");
+
+ r3.in.req.max_referral_level = 3;
+ /*
+ * Windows 7 and at least windows 2008 server sends domain.fqdn instead of \domain.fqdn
+ * (as it is specified in the spec)
+ * Let's check that we are able to support it too
+ */
+ r3.in.req.servername = str;
+ r3.out.resp = &resp3;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r3),
+ "Get DC Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp3.path_consumed, 0,
+ "Path consumed not equal to 0");
+ torture_assert_int_equal(tctx, resp3.nb_referrals , 1,
+ "We do not received only 1 referral");
+ torture_assert_int_equal(tctx, resp3.header_flags, 0,
+ "Header flag different it's not a referral server");
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3",
+ resp3.referral_entries[0].version));
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v3.server_type,
+ DFS_SERVER_NON_ROOT,
+ talloc_asprintf(tctx,
+ "Wrong server type, expected non root server and got %d",
+ resp3.referral_entries[0].referral.v3.server_type));
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v3.entry_flags,
+ DFS_FLAG_REFERRAL_DOMAIN_RESP,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a domain response and got %d",
+ resp3.referral_entries[0].referral.v3.entry_flags));
+ torture_assert_int_equal(tctx, strlen(
+ resp3.referral_entries[0].referral.v3.referrals.r2.special_name) > 0,
+ 1,
+ "Length of domain is 0 or less");
+ torture_assert_int_equal(tctx, strlen(
+ resp3.referral_entries[0].referral.v3.referrals.r2.expanded_names[0]) > 0,
+ 1,
+ "Length of first dc is less than 0");
+ return true;
+}
+
+static bool test_getdcreferral_netbios(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct dfs_GetDFSReferral r, r2, r3;
+ struct dfs_referral_resp resp, resp2, resp3;
+ const char* str;
+
+ r.in.req.max_referral_level = 3;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ "Get Domain referral failed");
+
+ r2.in.req.max_referral_level = 3;
+
+ str = resp.referral_entries[0].referral.v3.referrals.r2.special_name;
+ if( strchr(str, '.') != NULL ) {
+ str = resp.referral_entries[1].referral.v3.referrals.r2.special_name;
+ }
+
+ r2.in.req.servername = str;
+ r2.out.resp = &resp2;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r2),
+ "Get DC Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp2.path_consumed, 0,
+ "Path consumed not equal to 0");
+ torture_assert_int_equal(tctx, resp2.nb_referrals , 1,
+ "We do not received only 1 referral");
+ torture_assert_int_equal(tctx, resp2.header_flags, 0,
+ "Header flag different it's not a referral server");
+ torture_assert_int_equal(tctx, resp2.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3",
+ resp2.referral_entries[0].version));
+ torture_assert_int_equal(tctx, resp2.referral_entries[0].referral.v3.server_type,
+ DFS_SERVER_NON_ROOT,
+ talloc_asprintf(tctx,
+ "Wrong server type, expected non root server and got %d",
+ resp2.referral_entries[0].referral.v3.server_type));
+ torture_assert_int_equal(tctx, resp2.referral_entries[0].referral.v3.entry_flags,
+ DFS_FLAG_REFERRAL_DOMAIN_RESP,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a domain response and got %d",
+ resp2.referral_entries[0].referral.v3.entry_flags));
+ torture_assert_int_equal(tctx, strlen(
+ resp2.referral_entries[0].referral.v3.referrals.r2.special_name) > 0,
+ 1,
+ "Length of domain is 0 or less");
+ torture_assert_int_equal(tctx, strlen(
+ resp2.referral_entries[0].referral.v3.referrals.r2.expanded_names[0]) > 0,
+ 1,
+ "Length of first dc is less than 0");
+ torture_assert(tctx, strchr(
+ resp2.referral_entries[0].referral.v3.referrals.r2.expanded_names[0],'.') == NULL,
+ "referral contains dots it's not a netbios name");
+
+ r3.in.req.max_referral_level = 3;
+ /*
+ * Windows 7 and at least windows 2008 server sends domain.fqdn instead of \domain.fqdn
+ * (as it is specified in the spec)
+ * Let's check that we are able to support it too
+ */
+ r3.in.req.servername = str + 1;
+ r3.out.resp = &resp3;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r3),
+ "Get DC Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp3.path_consumed, 0,
+ "Path consumed not equal to 0");
+ torture_assert_int_equal(tctx, resp3.nb_referrals , 1,
+ "We do not received only 1 referral");
+ torture_assert_int_equal(tctx, resp3.header_flags, 0,
+ "Header flag different it's not a referral server");
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3",
+ resp3.referral_entries[0].version));
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v3.server_type,
+ DFS_SERVER_NON_ROOT,
+ talloc_asprintf(tctx,
+ "Wrong server type, expected non root server and got %d",
+ resp3.referral_entries[0].referral.v3.server_type));
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v3.entry_flags,
+ DFS_FLAG_REFERRAL_DOMAIN_RESP,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a domain response and got %d",
+ resp3.referral_entries[0].referral.v3.entry_flags));
+ torture_assert_int_equal(tctx, strlen(
+ resp3.referral_entries[0].referral.v3.referrals.r2.special_name) > 0,
+ 1,
+ "Length of domain is 0 or less");
+ torture_assert_int_equal(tctx, strlen(
+ resp3.referral_entries[0].referral.v3.referrals.r2.expanded_names[0]) > 0,
+ 1,
+ "Length of first dc is less than 0");
+ torture_assert(tctx, strchr(
+ resp3.referral_entries[0].referral.v3.referrals.r2.expanded_names[0],'.') == NULL,
+ "referral contains dots it's not a netbios name");
+ return true;
+}
+
+static bool test_getsysvolreferral(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char* str;
+ struct dfs_GetDFSReferral r, r2, r3;
+ struct dfs_referral_resp resp, resp2, resp3;
+
+ r.in.req.max_referral_level = 3;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ "Get Domain referral failed");
+
+ str = resp.referral_entries[0].referral.v3.referrals.r2.special_name;
+ if( strchr(str, '.') == NULL ) {
+ str = resp.referral_entries[1].referral.v3.referrals.r2.special_name;
+ }
+
+ r2.in.req.max_referral_level = 3;
+ r2.in.req.servername = str;
+ r2.out.resp = &resp2;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r2),
+ "Get DC Domain referral failed");
+
+ r3.in.req.max_referral_level = 3;
+ r3.in.req.servername = talloc_asprintf(tctx, "%s\\sysvol", str);
+ r3.out.resp = &resp3;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r3),
+ "Get sysvol Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp3.path_consumed, 2*strlen(r3.in.req.servername),
+ "Path consumed not equal to length of the request");
+ torture_assert_int_equal(tctx, resp3.nb_referrals != 0, 1,
+ "We do not receive at least 1 referral");
+ torture_assert_int_equal(tctx, resp3.header_flags, DFS_HEADER_FLAG_STORAGE_SVR,
+ "Header flag different it's not a referral for a storage");
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3",
+ resp3.referral_entries[0].version));
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v3.server_type,
+ DFS_SERVER_NON_ROOT,
+ talloc_asprintf(tctx,
+ "Wrong server type, expected non root server and got %d",
+ resp3.referral_entries[0].referral.v3.server_type));
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v3.entry_flags,
+ 0,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a non domain response and got %d",
+ resp3.referral_entries[0].referral.v3.entry_flags));
+ torture_assert_int_equal(tctx, strlen(
+ resp3.referral_entries[0].referral.v3.referrals.r1.DFS_path) > 0,
+ 1,
+ "Length of domain is 0 or less");
+ torture_assert_int_equal(tctx, strstr(resp3.referral_entries[0].referral.v3.referrals.r1.DFS_path,
+ str+1) != NULL, 1,
+ talloc_asprintf(tctx,
+ "Wrong DFS_path %s unable to find substring %s in it",
+ resp3.referral_entries[0].referral.v3.referrals.r1.DFS_path,
+ str+1));
+ torture_assert_int_equal(tctx, strlen(
+ resp3.referral_entries[0].referral.v3.referrals.r1.netw_address) > 0,
+ 1,
+ "Length of first referral is less than 0");
+ torture_assert_int_equal(tctx, strstr(resp3.referral_entries[0].referral.v3.referrals.r1.netw_address,
+ str+1) != NULL, 1,
+ talloc_asprintf(tctx,
+ "Wrong DFS_path %s unable to find substring %s in it",
+ resp3.referral_entries[0].referral.v3.referrals.r1.netw_address,
+ str+1));
+ /*
+ * Due to strange behavior with XP and level 4
+ * we are obliged to degrade to level 3 ...
+ */
+ r3.in.req.max_referral_level = 4;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r3),
+ "Get sysvol Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].version, 4,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 4",
+ resp3.referral_entries[0].version));
+ torture_assert(tctx, all_zero(resp3.referral_entries[0].referral.v3.service_site_guid.value, 16),
+ talloc_asprintf(tctx,
+ "Service_site_guid is not NULL as expected"));
+#if 0
+ /* Shouldn't be needed anymore*/
+ r3.in.req.max_referral_level = 4;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r3),
+ "Get sysvol Domain referral failed");
+
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].version, 3,
+ talloc_asprintf(tctx,
+ "Not expected version for referral entry 0 got %d expected 3 in degraded mode",
+ resp3.referral_entries[0].version));
+ /*
+ * We do not support fallback indication for the moment
+ */
+ torture_assert_int_equal(tctx, resp3.header_flags,
+ DFS_HEADER_FLAG_STORAGE_SVR | DFS_HEADER_FLAG_TARGET_BCK,
+ "Header flag different it's not a referral for a storage with fallback");
+ torture_assert_int_equal(tctx, resp3.referral_entries[0].referral.v4.entry_flags,
+ DFS_FLAG_REFERRAL_FIRST_TARGET_SET,
+ talloc_asprintf(tctx,
+ "Wrong entry flag expected to have a non domain response and got %d",
+ resp3.referral_entries[0].referral.v4.entry_flags));
+#endif
+ return true;
+}
+
+static bool test_unknowndomain(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct dfs_GetDFSReferral r, r2;
+ struct dfs_referral_resp resp, resp2;
+
+ r.in.req.max_referral_level = 3;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ "Get Domain referral failed");
+
+ r2.in.req.max_referral_level = 3;
+ r2.in.req.servername = "foobar.none.net";
+ r2.out.resp = &resp2;
+
+ torture_assert_ntstatus_equal(tctx,
+ dfs_cli_do_call(cli->tree, &r2),
+ NT_STATUS_INVALID_PARAMETER,
+ "Get DC Domain didn't return expected error code");
+
+ return true;
+}
+
+static bool test_getsysvolplusreferral(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char* str;
+ struct dfs_GetDFSReferral r, r2, r3;
+ struct dfs_referral_resp resp, resp2, resp3;
+
+ r.in.req.max_referral_level = 3;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ "Get Domain referral failed");
+
+ r2.in.req.max_referral_level = 3;
+ r2.in.req.servername = resp.referral_entries[0].referral.v3.referrals.r2.special_name;
+ r2.out.resp = &resp2;
+
+ torture_assert_ntstatus_ok(tctx,
+ dfs_cli_do_call(cli->tree, &r2),
+ "Get DC Domain referral failed");
+
+ str = resp2.referral_entries[0].referral.v3.referrals.r2.special_name;
+ r3.in.req.max_referral_level = 3;
+ r3.in.req.servername = talloc_asprintf(tctx, "%s\\sysvol\\foo", str);
+ r3.out.resp = &resp3;
+
+ torture_assert_ntstatus_equal(tctx,
+ dfs_cli_do_call(cli->tree, &r3),
+ NT_STATUS_NOT_FOUND,
+ "Bad behavior with subtree sysvol referral");
+
+ return true;
+}
+
+static bool test_low_referral_level(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct dfs_GetDFSReferral r;
+ struct dfs_referral_resp resp;
+
+ r.in.req.max_referral_level = 2;
+ r.in.req.servername = "";
+ r.out.resp = &resp;
+
+ torture_assert_ntstatus_equal(tctx,
+ dfs_cli_do_call(cli->tree, &r),
+ NT_STATUS_UNSUCCESSFUL,
+ "Unexpected STATUS for invalid referral request");
+
+ return true;
+}
+
+NTSTATUS torture_dfs_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dfs");
+ struct torture_suite *suite_basic = torture_suite_create(suite, "domain");
+
+ torture_suite_add_suite(suite, suite_basic);
+
+ torture_suite_add_1smb_test(suite_basic, "domain referral",
+ test_getdomainreferral);
+ torture_suite_add_1smb_test(suite_basic, "dc referral",
+ test_getdcreferral);
+ torture_suite_add_1smb_test(suite_basic, "dc referral netbios",
+ test_getdcreferral_netbios);
+
+ torture_suite_add_1smb_test(suite_basic, "sysvol referral",
+ test_getsysvolreferral);
+
+ /* Non standard case */
+
+ torture_suite_add_1smb_test(suite_basic, "dc referral on unknown domain",
+ test_unknowndomain);
+ torture_suite_add_1smb_test(suite_basic, "sysvol with subtree referral",
+ test_getsysvolplusreferral);
+ torture_suite_add_1smb_test(suite_basic, "referral with a level 2",
+ test_low_referral_level);
+
+ /*
+ * test with invalid level
+ * test with netbios
+ */
+
+ suite->description = talloc_strdup(suite, "DFS referrals calls");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/dns/dlz_bind9.c b/source4/torture/dns/dlz_bind9.c
new file mode 100644
index 0000000..32725b7
--- /dev/null
+++ b/source4/torture/dns/dlz_bind9.c
@@ -0,0 +1,2514 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Bartlett 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "system/network.h"
+#include "dns_server/dlz_minimal.h"
+#include <talloc.h>
+#include <ldb.h>
+#include "lib/param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
+#include "auth/session.h"
+#include "auth/gensec/gensec.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "system/network.h"
+#include "dns_server/dnsserver_common.h"
+#include "librpc/gen_ndr/ndr_dnsserver.h"
+#include "librpc/gen_ndr/ndr_dnsserver_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_proto.h"
+
+/* Tests that configure multiple DLZs will use this. Increase to add stress. */
+#define NUM_DLZS_TO_CONFIGURE 4
+
+struct torture_context *tctx_static;
+
+static void dlz_bind9_log_wrapper(int level, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+
+static void dlz_bind9_log_wrapper(int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+ va_start(ap, fmt);
+ msg = talloc_vasprintf(NULL, fmt, ap);
+ torture_comment(tctx_static, "%s\n", msg);
+ TALLOC_FREE(msg);
+ va_end(ap);
+}
+
+static bool test_dlz_bind9_version(struct torture_context *tctx)
+{
+ unsigned int flags = 0;
+ torture_assert_int_equal(tctx, dlz_version(&flags),
+ DLZ_DLOPEN_VERSION, "got wrong DLZ version");
+ return true;
+}
+
+static char *dlz_bind9_binddns_dir(struct torture_context *tctx,
+ const char *file)
+{
+ return talloc_asprintf(tctx,
+ "ldb://%s/%s",
+ lpcfg_binddns_dir(tctx->lp_ctx),
+ file);
+}
+
+static bool test_dlz_bind9_create(struct torture_context *tctx)
+{
+ void *dbdata;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper, NULL), ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ dlz_destroy(dbdata);
+
+ return true;
+}
+
+static bool calls_zone_hook = false;
+
+static isc_result_t dlz_bind9_writeable_zone_hook(dns_view_t *view,
+ dns_dlzdb_t *dlzdb,
+ const char *zone_name)
+{
+ struct torture_context *tctx = talloc_get_type((void *)view, struct torture_context);
+ struct ldb_context *samdb = NULL;
+ char *errstring = NULL;
+ int ret = samdb_connect_url(
+ tctx,
+ NULL,
+ tctx->lp_ctx,
+ system_session(tctx->lp_ctx),
+ 0,
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL,
+ &samdb,
+ &errstring);
+ struct ldb_message *msg;
+ const char *attrs[] = {
+ NULL
+ };
+ if (ret != LDB_SUCCESS) {
+ torture_comment(tctx, "Failed to connect to samdb");
+ return ISC_R_FAILURE;
+ }
+
+ ret = dsdb_search_one(samdb, tctx, &msg, NULL,
+ LDB_SCOPE_SUBTREE, attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
+ "(&(objectClass=dnsZone)(name=%s))", zone_name);
+ if (ret != LDB_SUCCESS) {
+ torture_comment(tctx,
+ "Failed to search for %s: %s",
+ zone_name,
+ ldb_errstring(samdb));
+ return ISC_R_FAILURE;
+ }
+ talloc_free(msg);
+
+ calls_zone_hook = true;
+
+ return ISC_R_SUCCESS;
+}
+
+static bool test_dlz_bind9_configure(struct torture_context *tctx)
+{
+ void *dbdata = NULL;
+ dns_dlzdb_t *dlzdb = NULL;
+ int ret;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ tctx_static = tctx;
+ ret = dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ NULL);
+ torture_assert_int_equal(tctx,
+ ret,
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ calls_zone_hook = false;
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx,
+ dlzdb,
+ dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ dlz_destroy(dbdata);
+
+ torture_assert_int_equal(tctx, calls_zone_hook, 1, "Hasn't called zone hook");
+
+ return true;
+}
+
+static bool test_dlz_bind9_multiple_configure(struct torture_context *tctx)
+{
+ int i;
+ for(i = 0; i < NUM_DLZS_TO_CONFIGURE; i++){
+ test_dlz_bind9_configure(tctx);
+ }
+ return true;
+}
+
+static bool configure_multiple_dlzs(struct torture_context *tctx,
+ void **dbdata, int count)
+{
+ int i, res;
+ dns_dlzdb_t *dlzdb = NULL;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+
+ tctx_static = tctx;
+ for(i = 0; i < count; i++){
+ res = dlz_create("samba_dlz", 3, argv, &(dbdata[i]),
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone",
+ dlz_bind9_writeable_zone_hook, NULL);
+ torture_assert_int_equal(tctx, res, ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ res = dlz_configure((void*)tctx, dlzdb, dbdata[i]);
+ torture_assert_int_equal(tctx, res, ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+ }
+
+ return true;
+}
+
+static bool test_dlz_bind9_destroy_oldest_first(struct torture_context *tctx)
+{
+ void *dbdata[NUM_DLZS_TO_CONFIGURE];
+ int i;
+ bool ret = configure_multiple_dlzs(tctx,
+ dbdata,
+ NUM_DLZS_TO_CONFIGURE);
+ if (ret == false) {
+ /* failure: has already been printed */
+ return false;
+ }
+
+ /* Reload faults are reported to happen on the first destroy */
+ dlz_destroy(dbdata[0]);
+
+ for(i = 1; i < NUM_DLZS_TO_CONFIGURE; i++){
+ dlz_destroy(dbdata[i]);
+ }
+
+ return true;
+}
+
+static bool test_dlz_bind9_destroy_newest_first(struct torture_context *tctx)
+{
+ void *dbdata[NUM_DLZS_TO_CONFIGURE];
+ int i;
+ bool ret = configure_multiple_dlzs(tctx,
+ dbdata,
+ NUM_DLZS_TO_CONFIGURE);
+ if (ret == false) {
+ /* failure: has already been printed */
+ return false;
+ }
+
+ for(i = NUM_DLZS_TO_CONFIGURE - 1; i >= 0; i--) {
+ dlz_destroy(dbdata[i]);
+ }
+
+ return true;
+}
+
+/*
+ * Test that a ticket obtained for the DNS service will be accepted on the Samba DLZ side
+ *
+ */
+static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech)
+{
+ NTSTATUS status;
+ dns_dlzdb_t *dlzdb = NULL;
+
+ struct gensec_security *gensec_client_context;
+
+ DATA_BLOB client_to_server, server_to_client;
+
+ void *dbdata;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook, NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx,
+ dlzdb, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ /*
+ * dlz_bind9 use the special dns/host.domain account
+ */
+ status = gensec_set_target_hostname(gensec_client_context,
+ talloc_asprintf(tctx,
+ "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx)));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
+
+ status = gensec_set_target_service(gensec_client_context, "dns");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed");
+
+ status = gensec_set_credentials(gensec_client_context,
+ samba_cmdline_get_creds());
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, mech);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ /* Do one step of the client-server update dance */
+ status = gensec_update(gensec_client_context, tctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ torture_assert_int_equal(tctx, dlz_ssumatch(
+ cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ lpcfg_dnsdomain(tctx->lp_ctx),
+ "127.0.0.1", "type", "key",
+ client_to_server.length,
+ client_to_server.data,
+ dbdata),
+ ISC_TRUE,
+ "Failed to check key for update rights samba_dlz");
+
+ dlz_destroy(dbdata);
+
+ return true;
+}
+
+static bool test_dlz_bind9_gssapi(struct torture_context *tctx)
+{
+ return test_dlz_bind9_gensec(tctx, "GSSAPI");
+}
+
+static bool test_dlz_bind9_spnego(struct torture_context *tctx)
+{
+ return test_dlz_bind9_gensec(tctx, "GSS-SPNEGO");
+}
+
+struct test_expected_record {
+ const char *name;
+ const char *type;
+ const char *data;
+ int ttl;
+ bool printed;
+ const char *rdata;
+};
+
+struct test_expected_rr {
+ struct torture_context *tctx;
+ const char *query_name;
+ size_t num_records;
+ struct test_expected_record *records;
+ size_t num_rr;
+};
+
+static bool dlz_bind9_putnamedrr_torture_hook(struct test_expected_rr *expected,
+ const char *name,
+ const char *type,
+ dns_ttl_t ttl,
+ const char *data)
+{
+ size_t i;
+
+ torture_assert(expected->tctx, name != NULL,
+ talloc_asprintf(expected->tctx,
+ "Got unnamed record type[%s] data[%s]\n",
+ type, data));
+
+ expected->num_rr++;
+ torture_comment(expected->tctx, "%u: name[%s] type[%s] ttl[%u] data[%s]\n",
+ (unsigned)expected->num_rr, name, type, (unsigned)ttl, data);
+
+ for (i = 0; i < expected->num_records; i++) {
+ if (expected->records[i].name != NULL) {
+ if (strcmp(name, expected->records[i].name) != 0) {
+ continue;
+ }
+ }
+
+ if (strcmp(type, expected->records[i].type) != 0) {
+ continue;
+ }
+
+ if (expected->records[i].data != NULL) {
+ /*
+ * For most types the data will have been reformatted
+ * or normalised, so we need to do approximately the
+ * same to compare.
+ */
+ const char *data2 = expected->records[i].data;
+ if (strcmp(type, "aaaa") == 0) {
+ struct in6_addr adr1;
+ struct in6_addr adr2;
+ int ret;
+ ret = inet_pton(AF_INET6, data, &adr1);
+ if (ret != 1) {
+ continue;
+ }
+ ret = inet_pton(AF_INET6, data2, &adr2);
+ if (ret != 1) {
+ continue;
+ }
+ if (memcmp(&adr1, &adr2, sizeof(adr1)) != 0) {
+ continue;
+ }
+ } else if (strcmp(type, "cname") == 0 ||
+ strcmp(type, "ptr") == 0 ||
+ strcmp(type, "ns") == 0) {
+ if (!samba_dns_name_equal(data, data2)) {
+ continue;
+ }
+ } else if (strcmp(type, "mx") == 0) {
+ /*
+ * samba_dns_name_equal works for MX records
+ * because the space in "10 example.com." is
+ * theoretically OK as a DNS character. And we
+ * need it because dlz will add the trailing
+ * dot.
+ */
+ if (!samba_dns_name_equal(data, data2)) {
+ continue;
+ }
+ } else if (strcmp(data, data2) != 0) {
+ /* default, works for A records */
+ continue;
+ }
+ }
+
+ torture_assert_int_equal(expected->tctx, ttl,
+ expected->records[i].ttl,
+ talloc_asprintf(expected->tctx,
+ "TTL did not match expectations for type %s",
+ type));
+
+ expected->records[i].printed = true;
+ }
+
+ return true;
+}
+
+/*
+ * Lookups in these tests end up coming round to run this function.
+ */
+static isc_result_t dlz_bind9_putrr_hook(dns_sdlzlookup_t *lookup,
+ const char *type,
+ dns_ttl_t ttl,
+ const char *data)
+{
+ struct test_expected_rr *expected =
+ talloc_get_type_abort(lookup, struct test_expected_rr);
+ bool ok;
+
+ ok = dlz_bind9_putnamedrr_torture_hook(expected, expected->query_name,
+ type, ttl, data);
+ if (!ok) {
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t dlz_bind9_putnamedrr_hook(dns_sdlzallnodes_t *allnodes,
+ const char *name,
+ const char *type,
+ dns_ttl_t ttl,
+ const char *data)
+{
+ struct test_expected_rr *expected =
+ talloc_get_type_abort(allnodes, struct test_expected_rr);
+ bool ok;
+
+ ok = dlz_bind9_putnamedrr_torture_hook(expected, name, type, ttl, data);
+ if (!ok) {
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+/*
+ * Tests some lookups
+ */
+static bool test_dlz_bind9_lookup(struct torture_context *tctx)
+{
+ size_t i;
+ void *dbdata = NULL;
+ dns_clientinfomethods_t *methods = NULL;
+ dns_clientinfo_t *clientinfo = NULL;
+ dns_dlzdb_t *dlzdb = NULL;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ struct test_expected_rr *expected1 = NULL;
+ struct test_expected_rr *expected2 = NULL;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx,
+ dlz_configure((void*)tctx, dlzdb, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ expected1 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected1 != NULL, "talloc failed");
+ expected1->tctx = tctx;
+
+ expected1->query_name = "@";
+
+ expected1->num_records = 4;
+ expected1->records = talloc_zero_array(expected1,
+ struct test_expected_record,
+ expected1->num_records);
+ torture_assert(tctx, expected1->records != NULL, "talloc failed");
+
+ expected1->records[0].name = expected1->query_name;
+ expected1->records[0].type = "soa";
+ expected1->records[0].ttl = 3600;
+ expected1->records[0].data = talloc_asprintf(expected1->records,
+ "%s.%s. hostmaster.%s. 1 900 600 86400 3600",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[0].data != NULL, "talloc failed");
+
+ expected1->records[1].name = expected1->query_name;
+ expected1->records[1].type = "ns";
+ expected1->records[1].ttl = 900;
+ expected1->records[1].data = talloc_asprintf(expected1->records, "%s.%s.",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[1].data != NULL, "talloc failed");
+
+ expected1->records[2].name = expected1->query_name;
+ expected1->records[2].type = "aaaa";
+ expected1->records[2].ttl = 900;
+
+ expected1->records[3].name = expected1->query_name;
+ expected1->records[3].type = "a";
+ expected1->records[3].ttl = 900;
+
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Failed to lookup @");
+ for (i = 0; i < expected1->num_records; i++) {
+ torture_assert(tctx, expected1->records[i].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run for type %s",
+ expected1->records[i].type));
+ }
+ torture_assert_int_equal(tctx, expected1->num_rr,
+ expected1->num_records,
+ "Got too much data");
+
+ expected2 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected2 != NULL, "talloc failed");
+ expected2->tctx = tctx;
+
+ expected2->query_name = torture_setting_string(tctx, "host", NULL);
+ torture_assert(tctx, expected2->query_name != NULL, "unknown host");
+
+ expected2->num_records = 2;
+ expected2->records = talloc_zero_array(expected2,
+ struct test_expected_record,
+ expected2->num_records);
+ torture_assert(tctx, expected2->records != NULL, "talloc failed");
+
+ expected2->records[0].name = expected2->query_name;
+ expected2->records[0].type = "aaaa";
+ expected2->records[0].ttl = 900;
+
+ expected2->records[1].name = expected2->query_name;
+ expected2->records[1].type = "a";
+ expected2->records[1].ttl = 900;
+
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected2->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected2,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Failed to lookup hostname");
+ for (i = 0; i < expected2->num_records; i++) {
+ torture_assert(tctx, expected2->records[i].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected2->records[i].name,
+ expected2->records[i].type));
+ }
+ torture_assert_int_equal(tctx, expected2->num_rr,
+ expected2->num_records,
+ "Got too much data");
+
+ dlz_destroy(dbdata);
+
+ return true;
+}
+
+/*
+ * Test some zone dumps
+ */
+static bool test_dlz_bind9_zonedump(struct torture_context *tctx)
+{
+ size_t i;
+ void *dbdata = NULL;
+ dns_dlzdb_t *dlzdb = NULL;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ struct test_expected_rr *expected1 = NULL;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dlzdb, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ expected1 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected1 != NULL, "talloc failed");
+ expected1->tctx = tctx;
+
+ expected1->num_records = 7;
+ expected1->records = talloc_zero_array(expected1,
+ struct test_expected_record,
+ expected1->num_records);
+ torture_assert(tctx, expected1->records != NULL, "talloc failed");
+
+ expected1->records[0].name = talloc_asprintf(expected1->records,
+ "%s.", lpcfg_dnsdomain(tctx->lp_ctx));
+ expected1->records[0].type = "soa";
+ expected1->records[0].ttl = 3600;
+ expected1->records[0].data = talloc_asprintf(expected1->records,
+ "%s.%s. hostmaster.%s. 1 900 600 86400 3600",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[0].data != NULL, "talloc failed");
+
+ expected1->records[1].name = talloc_asprintf(expected1->records,
+ "%s.", lpcfg_dnsdomain(tctx->lp_ctx));
+ expected1->records[1].type = "ns";
+ expected1->records[1].ttl = 900;
+ expected1->records[1].data = talloc_asprintf(expected1->records, "%s.%s.",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[1].data != NULL, "talloc failed");
+
+ expected1->records[2].name = talloc_asprintf(expected1->records,
+ "%s.", lpcfg_dnsdomain(tctx->lp_ctx));
+ expected1->records[2].type = "aaaa";
+ expected1->records[2].ttl = 900;
+
+ expected1->records[3].name = talloc_asprintf(expected1->records,
+ "%s.", lpcfg_dnsdomain(tctx->lp_ctx));
+ expected1->records[3].type = "a";
+ expected1->records[3].ttl = 900;
+
+ expected1->records[4].name = talloc_asprintf(expected1->records, "%s.%s.",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[4].name != NULL, "unknown host");
+ expected1->records[4].type = "aaaa";
+ expected1->records[4].ttl = 900;
+
+ expected1->records[5].name = talloc_asprintf(expected1->records, "%s.%s.",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, expected1->records[5].name != NULL, "unknown host");
+ expected1->records[5].type = "a";
+ expected1->records[5].ttl = 900;
+
+ /*
+ * We expect multiple srv records
+ */
+ expected1->records[6].name = NULL;
+ expected1->records[6].type = "srv";
+ expected1->records[6].ttl = 900;
+
+ torture_assert_int_equal(tctx, dlz_allnodes(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, (dns_sdlzallnodes_t *)expected1),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+ for (i = 0; i < expected1->num_records; i++) {
+ torture_assert(tctx, expected1->records[i].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[i].name,
+ expected1->records[i].type));
+ }
+ torture_assert_int_equal(tctx, expected1->num_rr, 24,
+ "Got wrong record count");
+
+ dlz_destroy(dbdata);
+
+ return true;
+}
+
+/*
+ * Test some updates
+ */
+static bool test_dlz_bind9_update01(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct gensec_security *gensec_client_context;
+ DATA_BLOB client_to_server, server_to_client;
+ void *dbdata = NULL;
+ dns_dlzdb_t *dlzdb = NULL;
+ void *version = NULL;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ struct test_expected_rr *expected1 = NULL;
+ char *name = NULL;
+ char *data0 = NULL;
+ char *data1 = NULL;
+ char *data2 = NULL;
+ bool ret = false;
+ dns_clientinfomethods_t *methods = NULL;
+ dns_clientinfo_t *clientinfo = NULL;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dlzdb, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ expected1 = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, expected1 != NULL, "talloc failed");
+ expected1->tctx = tctx;
+
+ expected1->query_name = __func__;
+
+ name = talloc_asprintf(expected1, "%s.%s",
+ expected1->query_name,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, name != NULL, "talloc failed");
+
+ expected1->num_records = 2;
+ expected1->records = talloc_zero_array(expected1,
+ struct test_expected_record,
+ expected1->num_records);
+ torture_assert(tctx, expected1->records != NULL, "talloc failed");
+
+ expected1->records[0].name = expected1->query_name;
+ expected1->records[0].type = "a";
+ expected1->records[0].ttl = 3600;
+ expected1->records[0].data = "127.1.2.3";
+ expected1->records[0].printed = false;
+
+ data0 = talloc_asprintf(expected1,
+ "%s.\t" "%u\t" "%s\t" "%s\t" "%s",
+ name,
+ (unsigned)expected1->records[0].ttl,
+ "in",
+ expected1->records[0].type,
+ expected1->records[0].data);
+ torture_assert(tctx, data0 != NULL, "talloc failed");
+
+ expected1->records[1].name = expected1->query_name;
+ expected1->records[1].type = "a";
+ expected1->records[1].ttl = 3600;
+ expected1->records[1].data = "127.3.2.1";
+ expected1->records[1].printed = false;
+
+ data1 = talloc_asprintf(expected1,
+ "%s.\t" "%u\t" "%s\t" "%s\t" "%s",
+ name,
+ (unsigned)expected1->records[1].ttl,
+ "in",
+ expected1->records[1].type,
+ expected1->records[1].data);
+ torture_assert(tctx, data1 != NULL, "talloc failed");
+
+ data2 = talloc_asprintf(expected1,
+ "%s.\t" "0\t" "in\t" "a\t" "127.3.3.3",
+ name);
+ torture_assert(tctx, data2 != NULL, "talloc failed");
+
+ /*
+ * Prepare session info
+ */
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ /*
+ * dlz_bind9 use the special dns/host.domain account
+ */
+ status = gensec_set_target_hostname(gensec_client_context,
+ talloc_asprintf(tctx,
+ "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx)));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
+
+ status = gensec_set_target_service(gensec_client_context, "dns");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed");
+
+ status = gensec_set_credentials(gensec_client_context,
+ samba_cmdline_get_creds());
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSS-SPNEGO");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ /* Do one step of the client-server update dance */
+ status = gensec_update(gensec_client_context, tctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ torture_assert_int_equal(tctx, dlz_ssumatch(
+ cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ name,
+ "127.0.0.1",
+ expected1->records[0].type,
+ "key",
+ client_to_server.length,
+ client_to_server.data,
+ dbdata),
+ ISC_TRUE,
+ "Failed to check key for update rights samba_dlz");
+
+ /*
+ * We test the following:
+ *
+ * 1. lookup the records => NOT_FOUND
+ * 2. delete all records => NOT_FOUND
+ * 3. delete 1st record => NOT_FOUND
+ * 4. create 1st record => SUCCESS
+ * 5. lookup the records => found 1st
+ * 6. create 2nd record => SUCCESS
+ * 7. lookup the records => found 1st and 2nd
+ * 8. delete unknown record => NOT_FOUND
+ * 9. lookup the records => found 1st and 2nd
+ * 10. delete 1st record => SUCCESS
+ * 11. lookup the records => found 2nd
+ * 12. delete 2nd record => SUCCESS
+ * 13. lookup the records => NOT_FOUND
+ * 14. create 1st record => SUCCESS
+ * 15. lookup the records => found 1st
+ * 16. create 2nd record => SUCCESS
+ * 17. lookup the records => found 1st and 2nd
+ * 18. update 1st record => SUCCESS
+ * 19. lookup the records => found 1st and 2nd
+ * 20. delete all unknown type records => NOT_FOUND
+ * 21. lookup the records => found 1st and 2nd
+ * 22. delete all records => SUCCESS
+ * 23. lookup the records => NOT_FOUND
+ */
+
+ /* Step 1. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, expected1->num_rr, 0,
+ "Got wrong record count");
+
+ /* Step 2. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_delrdataset(name,
+ expected1->records[0].type,
+ dbdata, version),
+ ISC_R_NOTFOUND, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n",
+ name, expected1->records[0].type));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+
+ /* Step 3. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data0, dbdata, version),
+ ISC_R_NOTFOUND, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+
+ /* Step 4. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 5. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 1,
+ "Got wrong record count");
+
+ /* Step 6. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data1, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data1));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 7. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 8. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data2, dbdata, version),
+ ISC_R_NOTFOUND, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n",
+ name, data2));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 9. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 10. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 11. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 1,
+ "Got wrong record count");
+
+ /* Step 12. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_subrdataset(name, data1, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n",
+ name, data1));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 13. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, expected1->num_rr, 0,
+ "Got wrong record count");
+
+ /* Step 14. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 15. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 1,
+ "Got wrong record count");
+
+ /* Step 16. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data1, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
+ name, data1));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 17. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 18. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_addrdataset(name, data0, dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to update name[%s] data[%s]\n",
+ name, data0));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 19. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 20. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_delrdataset(name, "txt", dbdata, version),
+ ISC_R_FAILURE, ret, cancel_version,
+ talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n",
+ name, "txt"));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+
+ /* Step 21. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert(tctx, expected1->records[0].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[0].name,
+ expected1->records[0].type));
+ torture_assert(tctx, expected1->records[1].printed,
+ talloc_asprintf(tctx,
+ "Failed to have putrr callback run name[%s] for type %s",
+ expected1->records[1].name,
+ expected1->records[1].type));
+ torture_assert_int_equal(tctx, expected1->num_rr, 2,
+ "Got wrong record count");
+
+ /* Step 22. */
+ torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
+ dbdata, &version),
+ ISC_R_SUCCESS,
+ "Failed to start transaction");
+ torture_assert_int_equal_goto(tctx,
+ dlz_delrdataset(name,
+ expected1->records[0].type,
+ dbdata, version),
+ ISC_R_SUCCESS, ret, cancel_version,
+ talloc_asprintf(tctx, "Failed to delete name[%s] type[%s]\n",
+ name, expected1->records[0].type));
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);
+
+ /* Step 23. */
+ expected1->num_rr = 0;
+ expected1->records[0].printed = false;
+ expected1->records[1].printed = false;
+ torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
+ expected1->query_name, dbdata,
+ (dns_sdlzlookup_t *)expected1,
+ methods, clientinfo),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, expected1->num_rr, 0,
+ "Got wrong record count");
+
+ dlz_destroy(dbdata);
+
+ return true;
+
+cancel_version:
+ dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
+ return ret;
+}
+
+/*
+ * Test zone transfer requests restrictions
+ *
+ * 1: test that zone transfer is denied by default
+ * 2: with an authorized list of IPs set in smb.conf, test that zone transfer
+ * is accepted only for selected IPs.
+ */
+static bool test_dlz_bind9_allowzonexfr(struct torture_context *tctx)
+{
+ void *dbdata;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+ isc_result_t ret;
+ dns_dlzdb_t *dlzdb = NULL;
+ bool ok;
+
+ tctx_static = tctx;
+ torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL),
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dlzdb, dbdata),
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ /* Ask for zone transfer with no specific config => expect denied */
+ ret = dlz_allowzonexfr(dbdata, lpcfg_dnsdomain(tctx->lp_ctx), "127.0.0.1");
+ torture_assert_int_equal(tctx, ret, ISC_R_NOPERM,
+ "Zone transfer accepted with default settings");
+
+ /* Ask for zone transfer with authorizations set */
+ ok = lpcfg_set_option(tctx->lp_ctx, "dns zone transfer clients allow=127.0.0.1,1234:5678::1,192.168.0.");
+ torture_assert(tctx, ok, "Failed to set dns zone transfer clients allow option.");
+
+ ok = lpcfg_set_option(tctx->lp_ctx, "dns zone transfer clients deny=192.168.0.2");
+ torture_assert(tctx, ok, "Failed to set dns zone transfer clients deny option.");
+
+ ret = dlz_allowzonexfr(dbdata, lpcfg_dnsdomain(tctx->lp_ctx), "127.0.0.1");
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Zone transfer refused for authorized IPv4 address");
+
+ ret = dlz_allowzonexfr(dbdata, lpcfg_dnsdomain(tctx->lp_ctx), "1234:5678::1");
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Zone transfer refused for authorized IPv6 address.");
+
+ ret = dlz_allowzonexfr(dbdata, lpcfg_dnsdomain(tctx->lp_ctx), "10.0.0.1");
+ torture_assert_int_equal(tctx, ret, ISC_R_NOPERM,
+ "Zone transfer accepted for unauthorized IP");
+
+ ret = dlz_allowzonexfr(dbdata, lpcfg_dnsdomain(tctx->lp_ctx), "192.168.0.1");
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Zone transfer refused for address in authorized IPv4 subnet.");
+
+ ret = dlz_allowzonexfr(dbdata, lpcfg_dnsdomain(tctx->lp_ctx), "192.168.0.2");
+ torture_assert_int_equal(tctx, ret, ISC_R_NOPERM,
+ "Zone transfer allowed for denied client.");
+
+ dlz_destroy(dbdata);
+ return true;
+}
+
+
+static int init_dlz(struct torture_context *tctx,
+ void **dbdata)
+{
+ isc_result_t ret;
+ const char *argv[] = {
+ "samba_dlz",
+ "-H",
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL
+ };
+
+ ret = dlz_create("samba_dlz", 3, argv, dbdata,
+ "log", dlz_bind9_log_wrapper,
+ "writeable_zone", dlz_bind9_writeable_zone_hook,
+ "putrr", dlz_bind9_putrr_hook,
+ "putnamedrr", dlz_bind9_putnamedrr_hook,
+ NULL);
+
+ torture_assert_int_equal(tctx,
+ ret,
+ ISC_R_SUCCESS,
+ "Failed to create samba_dlz");
+
+ ret = dlz_configure((void*)tctx, NULL, *dbdata);
+ torture_assert_int_equal(tctx,
+ ret,
+ ISC_R_SUCCESS,
+ "Failed to configure samba_dlz");
+
+ return true;
+}
+
+
+static int init_gensec(struct torture_context *tctx,
+ struct gensec_security **gensec_client_context)
+{
+ NTSTATUS status;
+ /*
+ * Prepare session info
+ */
+ status = gensec_client_start(tctx, gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status,
+ "gensec_client_start (client) failed");
+
+ /*
+ * dlz_bind9 use the special dns/host.domain account
+ */
+ status = gensec_set_target_hostname(*gensec_client_context,
+ talloc_asprintf(tctx,
+ "%s.%s",
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_dnsdomain(tctx->lp_ctx)));
+ torture_assert_ntstatus_ok(tctx, status,
+ "gensec_set_target_hostname (client) failed");
+
+ status = gensec_set_target_service(*gensec_client_context, "dns");
+ torture_assert_ntstatus_ok(tctx, status,
+ "gensec_set_target_service failed");
+
+ status = gensec_set_credentials(*gensec_client_context,
+ samba_cmdline_get_creds());
+ torture_assert_ntstatus_ok(tctx, status,
+ "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(*gensec_client_context,
+ "GSS-SPNEGO");
+ torture_assert_ntstatus_ok(tctx, status,
+ "gensec_start_mech_by_sasl_name (client) failed");
+
+
+ return true;
+}
+
+
+
+static bool expected_record(TALLOC_CTX *mem_ctx,
+ struct test_expected_record *r,
+ const char *name,
+ const char *type,
+ const char *data)
+{
+ unsigned int ttl = 3600;
+ const char *rdata = talloc_asprintf(
+ mem_ctx,
+ "%s.\t" "%u\t" "in\t" "%s\t" "%s",
+ name, ttl, type, data);
+ if (rdata == NULL) {
+ return false;
+ }
+
+ *r = (struct test_expected_record){
+ .name = name,
+ .type = type,
+ .data = data,
+ .ttl = ttl,
+ .printed = false,
+ .rdata = rdata
+ };
+ return true;
+}
+
+
+struct dlz_test_handle {
+ struct dcerpc_pipe *p;
+};
+
+
+static bool set_zone_aging(struct torture_context *tctx,
+ const char *zone,
+ int value)
+{
+ int ret;
+ char *cmd = talloc_asprintf(tctx,
+ "bin/samba-tool dns zoneoptions "
+ "$SERVER %s -U$USERNAME%%$PASSWORD "
+ "--aging %d", zone, value);
+
+ if (cmd == NULL) {
+ return false;
+ }
+
+ ret = system(cmd);
+ if (ret != 0) {
+ TALLOC_FREE(cmd);
+ return false;
+ }
+ TALLOC_FREE(cmd);
+ return true;
+}
+
+
+static struct ldb_context* get_samdb(struct torture_context *tctx)
+{
+ struct ldb_context *samdb = NULL;
+ char *errstring;
+ int ret = samdb_connect_url(
+ tctx,
+ NULL,
+ tctx->lp_ctx,
+ system_session(tctx->lp_ctx),
+ 0,
+ dlz_bind9_binddns_dir(tctx, "dns/sam.ldb"),
+ NULL,
+ &samdb,
+ &errstring);
+ if (ret != LDB_SUCCESS) {
+ return NULL;
+ }
+ return samdb;
+}
+
+
+static void print_node_records(struct torture_context *tctx,
+ struct ldb_context *samdb,
+ struct ldb_dn *node_dn,
+ const char *msg)
+{
+ int ret;
+ struct ldb_result *result = NULL;
+ struct dnsp_DnssrvRpcRecord rec;
+ struct ldb_message_element *el = NULL;
+ size_t i;
+
+ if (msg != NULL) {
+ torture_comment(tctx,
+ "\033[1;32m%s\033[0m\n",
+ msg);
+ }
+
+ ret = dsdb_search(samdb, tctx, &result, node_dn,
+ LDB_SCOPE_SUBTREE, NULL,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_comment(tctx,
+ "Failed to find node: %s",
+ ldb_errstring(samdb));
+ }
+
+ el = ldb_msg_find_element(result->msgs[0], "dnsRecord");
+
+ for (i = 0; i < el->num_values; i++) {
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ result,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ret)) {
+ DBG_ERR("Failed to pull dns rec blob [%zu].\n",
+ i);
+ TALLOC_FREE(result);
+ }
+ torture_comment(tctx, "record[%zu]:\n", i);
+ torture_comment(tctx, "type: %d\n", rec.wType);
+ torture_comment(tctx, "timestamp: %u\n", rec.dwTimeStamp);
+ torture_comment(tctx, "%s\n",
+ NDR_PRINT_STRUCT_STRING(result,
+ dnsp_DnssrvRpcRecord,
+ &rec));
+ }
+}
+
+
+
+/*
+ * Test some MORE updates, this time focussing on more record types and aging.
+ */
+static bool test_dlz_bind9_aging(struct torture_context *tctx)
+{
+ struct gensec_security *gensec_client_context = NULL;
+ DATA_BLOB client_to_server, server_to_client;
+ NTSTATUS status;
+ void *dbdata = NULL;
+ void *version = NULL;
+ struct test_expected_rr *testdata = NULL;
+ bool ok = false;
+ struct ldb_context *samdb = NULL;
+ isc_result_t ret;
+ size_t i, j;
+ const char *domain = lpcfg_dnsdomain(tctx->lp_ctx);
+ struct ldb_dn *domain_dn = NULL;
+ struct ldb_dn *node_dn = NULL;
+ struct ldb_result *result = NULL;
+ uint32_t dns_timestamp_before;
+ uint32_t dns_timestamp_after;
+ const char *name = NULL;
+ const char *attrs[] = {"dnsrecord", NULL};
+ const char *node_dn_str = NULL;
+ struct ldb_message_element *el = NULL;
+ struct ldb_message *msg = NULL;
+
+ tctx_static = tctx;
+
+ /* Step 0. set things up */
+
+ ok = init_dlz(tctx, &dbdata);
+ if (! ok) {
+ torture_fail(tctx, "Failed to init_dlz");
+ }
+ ok = init_gensec(tctx, &gensec_client_context);
+ if (! ok) {
+ torture_fail(tctx, "Failed to init_gensec");
+ }
+
+ samdb = get_samdb(tctx);
+ if (samdb == NULL) {
+ torture_fail(tctx, "Failed to connect to samdb");
+ }
+
+ domain_dn = ldb_get_default_basedn(samdb);
+ testdata = talloc_zero(tctx, struct test_expected_rr);
+ torture_assert(tctx, testdata != NULL, "talloc failed");
+ testdata->tctx = tctx;
+
+ testdata->query_name = __func__;
+
+ name = talloc_asprintf(testdata, "%s.%s",
+ testdata->query_name,
+ domain);
+ torture_assert(tctx, name != NULL, "talloc failed");
+
+ testdata->num_records = 6;
+ testdata->records = talloc_zero_array(testdata,
+ struct test_expected_record,
+ testdata->num_records);
+ torture_assert(tctx, testdata->records != NULL, "talloc failed");
+
+ torture_assert(tctx,
+ expected_record(testdata->records,
+ &testdata->records[0],
+ testdata->query_name,
+ "aaaa",
+ "::1"),
+ "failed to add record");
+
+ torture_assert(tctx,
+ expected_record(testdata->records,
+ &testdata->records[1],
+ testdata->query_name,
+ "a",
+ "127.11.12.13"),
+ "failed to add record");
+ torture_assert(tctx,
+ expected_record(testdata->records,
+ &testdata->records[2],
+ testdata->query_name,
+ "a",
+ "127.11.12.14"),
+ "failed to add record");
+
+ torture_assert(tctx,
+ expected_record(testdata->records,
+ &testdata->records[3],
+ testdata->query_name,
+ "ptr",
+ "samba.example.com"),
+ "failed to add record");
+
+ /*
+ * NOTE: Here we add the MX record with the priority before the name,
+ * rather than the other way around which you are more likely to see
+ * ("samba.example.com 11" e.g. in samba-tool dns), because this is
+ * how it goes in BIND9 configuration.
+ */
+ torture_assert(tctx,
+ expected_record(testdata->records,
+ &testdata->records[4],
+ testdata->query_name,
+ "mx",
+ "11 samba.example.com."),
+ "failed to add record");
+
+ torture_assert(tctx,
+ expected_record(testdata->records,
+ &testdata->records[5],
+ testdata->query_name,
+ "cname",
+ "samba.example.com"),
+ "failed to add record");
+
+
+ server_to_client = data_blob(NULL, 0);
+
+ /* Do one step of the client-server update dance */
+ status = gensec_update(gensec_client_context, tctx, server_to_client,
+ &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status,
+ "gensec_update (client) failed");
+ }
+
+ torture_assert_int_equal(tctx, dlz_ssumatch(
+ cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ domain,
+ "127.0.0.1",
+ testdata->records[0].type,
+ "key",
+ client_to_server.length,
+ client_to_server.data,
+ dbdata),
+ ISC_TRUE,
+ "Failed to check key for update rights samba_dlz");
+
+ /* remember the DN for use below */
+ node_dn = ldb_dn_copy(testdata, domain_dn);
+ if (node_dn == NULL) {
+ torture_fail(tctx, "Failed to make node dn");
+ }
+
+ ok = ldb_dn_add_child_fmt(
+ node_dn,
+ "DC=%s,DC=%s,CN=MicrosoftDNS,DC=DomainDnsZones",
+ testdata->query_name,
+ domain);
+ if (! ok) {
+ torture_fail(tctx, "Failed to make node dn");
+ }
+ node_dn_str = ldb_dn_get_linearized(node_dn);
+ if (node_dn_str == NULL) {
+ torture_fail(tctx, "Failed to linearise node dn");
+ }
+
+ /* LOOK: we are chopping off the last one (the CNAME) for now */
+ testdata->num_records = 5;
+
+ /*
+ * We test the following:
+ *
+ * Step 1. Ensure we are starting with an empty node.
+ * Step 2. Add all the records (with aging off).
+ * Step 3. Check the timestamps are now-ish.
+ * Step 4. Add all the records AGAIN.
+ * Step 5: Turn aging on.
+ * Step 6. Add all the records again.
+ * Step 7. Check the timestamps are still now-ish.
+ * Step 8. Wind back the timestamps in the database.
+ * Step 9. Do another update, changing some timestamps
+ * Step 10. Check that the timestamps are right.
+ * Step 11. Set one record to be static.
+ * Step 12. Do updates on some records, zeroing their timestamps
+ * Step 13. Check that the record timeouts are *mostly* zero.
+ * Step 14. Turn aging off
+ * Step 15. Update, setting timestamps to zero
+ * Step 16. Check that the timestamps are all zero.
+ * Step 17. Reset to non-zero via ldb, with aging still off.
+ * Step 18. Update with aging off. Nothing should change.
+ * Step 19. Check that the timestamps didn't change.
+ * Step 20. Delete all the records, 1 by 1.
+ */
+
+
+ /*
+ * Step 1. Ensure we are starting with an empty node.
+ */
+ torture_comment(tctx, "step 1: %s records are not there\n",
+ testdata->query_name);
+ testdata->num_rr = 0;
+ torture_assert_int_equal(tctx, dlz_lookup(domain,
+ testdata->query_name,
+ dbdata,
+ (dns_sdlzlookup_t *)testdata,
+ NULL, NULL),
+ ISC_R_NOTFOUND,
+ "Found hostname");
+ torture_assert_int_equal(tctx, testdata->num_rr, 0,
+ "Got records when there should be none");
+
+
+ dns_timestamp_before = unix_to_dns_timestamp(time(NULL));
+
+ /*
+ * Step 2. Add all the records (with aging off).
+ * After adding each one, expect to find it and earlier ones.
+ */
+ torture_comment(tctx,
+ "step 2: add %zu records\n",
+ testdata->num_records);
+
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(name, r.rdata, dbdata, version);
+ torture_assert_int_equal_goto(
+ tctx, ret, ISC_R_SUCCESS, ok,
+ cancel_version,
+ talloc_asprintf(tctx,
+ "Failed to add record %zu «%s»\n",
+ i, r.rdata));
+
+ dlz_closeversion(domain, true, dbdata, &version);
+
+ testdata->num_rr = 0;
+
+ ret = dlz_lookup(domain, testdata->query_name, dbdata,
+ (dns_sdlzlookup_t *)testdata, NULL, NULL);
+
+ torture_assert_int_equal(tctx, ret,
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert_int_equal(tctx, testdata->num_rr, i + 1,
+ "Got wrong record count");
+
+ for (j = 0; j < testdata->num_records; j++) {
+ struct test_expected_record *r2 = &testdata->records[j];
+ if (j <= i) {
+ torture_assertf(
+ tctx,
+ r2->printed,
+ "putrr callback not run on %s «%s»",
+ r2->type, r2->name);
+ } else {
+ torture_assertf(
+ tctx,
+ ! r2->printed,
+ "putrr callback should not see %s «%s»",
+ r2->type, r2->name);
+ }
+ r2->printed = false;
+ }
+ }
+
+ dns_timestamp_after = unix_to_dns_timestamp(time(NULL));
+ /*
+ * Step 3. Check the timestamps are now-ish.
+ *
+ * Those records should have DNS timestamps between
+ * dns_timestamp_before and dns_timestamp_after (the resolution is
+ * hourly, so probably both are equal).
+ */
+ ret = dsdb_search(samdb, tctx, &result, node_dn,
+ LDB_SCOPE_SUBTREE, NULL,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+ torture_assert_int_equal(tctx, result->count, 1,
+ "Should be one node");
+
+ el = ldb_msg_find_element(result->msgs[0], "dnsRecord");
+ torture_assert_not_null(tctx, el, "el");
+ torture_assert(tctx, dns_timestamp_before <= dns_timestamp_after, "<");
+ torture_assert_int_equal(tctx, el->num_values, testdata->num_records,
+ "num_values != num_records");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ result,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ret)) {
+ DBG_ERR("Failed to pull dns rec blob [%zu].\n",
+ i);
+ TALLOC_FREE(result);
+ torture_fail(tctx, "Failed to pull dns rec blob");
+ }
+ torture_comment(tctx, "record[%zu]:\n", i);
+ torture_comment(tctx, "type: %d\n", rec.wType);
+ torture_comment(tctx, "timestamp: %u\n", rec.dwTimeStamp);
+ torture_comment(tctx, "%s\n",
+ NDR_PRINT_STRUCT_STRING(result,
+ dnsp_DnssrvRpcRecord,
+ &rec));
+
+ torture_assert(tctx, rec.dwTimeStamp >= dns_timestamp_before,
+ "timestamp < dns_timestamp_before");
+ torture_assert(tctx, rec.dwTimeStamp <= dns_timestamp_after,
+ "timestamp > dns_timestamp_after");
+ }
+
+ talloc_free(result);
+
+ /*
+ * Step 4. Add all the records AGAIN.
+ *
+ * After adding each one, we expect no change in the number or nature
+ * of records.
+ */
+ torture_comment(tctx, "step 4: add the records again\n");
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(name, r.rdata, dbdata, version);
+ torture_assert_int_equal_goto(
+ tctx, ret, ISC_R_SUCCESS, ok,
+ cancel_version,
+ talloc_asprintf(tctx,
+ "Failed to add record %zu «%s»\n",
+ i, r.rdata));
+
+ dlz_closeversion(domain, true, dbdata, &version);
+
+ testdata->num_rr = 0;
+
+ ret = dlz_lookup(domain, testdata->query_name, dbdata,
+ (dns_sdlzlookup_t *)testdata, NULL, NULL);
+
+ torture_assert_int_equal(tctx, ret,
+ ISC_R_SUCCESS,
+ "Not found hostname");
+ torture_assert_int_equal(tctx,
+ testdata->num_rr,
+ testdata->num_records,
+ "Got wrong record count");
+
+ for (j = 0; j <= i; j++) {
+ /* these ones are printed again. */
+ struct test_expected_record *r2 = &testdata->records[j];
+ torture_assert(
+ tctx,
+ r2->printed,
+ talloc_asprintf(
+ tctx,
+ "putrr callback not run on %s «%s»",
+ r2->type, r2->name));
+ r2->printed = false;
+ }
+ }
+
+ print_node_records(tctx, samdb, node_dn, "after adding again");
+
+
+ /*
+ * Step 5: Turn aging on.
+ */
+ torture_comment(tctx, "step 5: turn aging on\n");
+ ok = set_zone_aging(tctx, domain, 1);
+ torture_assert(tctx, ok, "failed to enable aging");
+
+ print_node_records(tctx, samdb, node_dn, "aging on");
+
+ /*
+ * Step 6. Add all the records again.
+ *
+ * We expect no change in the number or nature of records, even with
+ * aging on, because the default noRefreshInterval is 7 days (also,
+ * there should be no change because almost no time has passed).
+ */
+ torture_comment(tctx, "step 6: add records again\n");
+
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(domain, r.rdata, dbdata, version);
+ torture_assert_int_equal_goto(
+ tctx, ret, ISC_R_SUCCESS, ok,
+ cancel_version,
+ talloc_asprintf(tctx,
+ "Failed to add record %zu «%s»\n",
+ i, r.rdata));
+
+ dlz_closeversion(domain, true, dbdata, &version);
+ }
+
+ print_node_records(tctx, samdb, node_dn, "add again");
+
+
+ /*
+ * Step 7. Check the timestamps are still now-ish.
+ *
+ */
+ ret = dsdb_search(samdb, tctx, &result, node_dn,
+ LDB_SCOPE_SUBTREE, NULL,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+ torture_assert_int_equal(tctx, result->count, 1,
+ "Should be one node");
+
+ el = ldb_msg_find_element(result->msgs[0], "dnsRecord");
+ torture_assert_not_null(tctx, el, "el");
+ torture_assert(tctx, dns_timestamp_before <= dns_timestamp_after, "<");
+ torture_assert_int_equal(tctx, el->num_values, testdata->num_records,
+ "num_values != num_records");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ result,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ret)) {
+ DBG_ERR("Failed to pull dns rec blob [%zu].\n",
+ i);
+ TALLOC_FREE(result);
+ torture_fail(tctx, "Failed to pull dns rec blob");
+ }
+ torture_comment(tctx, "record[%zu]:\n", i);
+ torture_comment(tctx, "type: %d\n", rec.wType);
+ torture_comment(tctx, "timestamp: %u\n", rec.dwTimeStamp);
+ torture_comment(tctx, "%s\n",
+ NDR_PRINT_STRUCT_STRING(result,
+ dnsp_DnssrvRpcRecord,
+ &rec));
+
+ torture_assert(tctx, rec.dwTimeStamp >= dns_timestamp_before,
+ "timestamp < dns_timestamp_before");
+ torture_assert(tctx, rec.dwTimeStamp <= dns_timestamp_after,
+ "timestamp > dns_timestamp_after");
+ }
+
+ talloc_free(result);
+
+ /*
+ * Step 8. Wind back the timestamps in the database.
+ *
+ * We use a different number of days for each record, so that some
+ * should be refreshed, and some shouldn't.
+ */
+ torture_comment(tctx, "step 8: alter timestamps\n");
+ ret = dsdb_search_one(samdb, tctx, &msg, node_dn,
+ LDB_SCOPE_BASE, attrs,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ torture_assert_not_null(tctx, el, "el");
+ torture_assert_int_equal(tctx, el->num_values,
+ testdata->num_records,
+ "num_values != num_records");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to pull record");
+
+ rec.dwTimeStamp = dns_timestamp_after + 3 - 24 * (i + 5);
+
+ ret = ndr_push_struct_blob(
+ &el->values[i],
+ msg,
+ &rec,
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to PUSH record");
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_modify(samdb, msg);
+ torture_assert_int_equal(tctx, ret, 0, "failed to ldb_modify");
+ print_node_records(tctx, samdb, node_dn, "after ldb_modify");
+
+
+ /*
+ * Step 9. Do another update, changing some timestamps
+ */
+
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(name, r.rdata, dbdata, version);
+ dlz_closeversion(domain, ret == ISC_R_SUCCESS, dbdata,
+ &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to update record\n");
+ }
+ print_node_records(tctx, samdb, node_dn, "after update");
+
+ /*
+ * Step 10. Check that the timestamps are right.
+ *
+ * The formula was
+ * (i + 5) days + 3 hours
+ * so 1 is 6 days + 3 hours, and should not be renewed.
+ * 2 is 7 days + 3 hours, and should be renewed
+ *
+ * NOTE: the ldb record order is different from the insertion order,
+ * but it should stay the same between searches.
+ */
+ ret = dsdb_search_one(samdb, tctx, &msg, node_dn,
+ LDB_SCOPE_BASE, attrs,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ torture_assert_not_null(tctx, el, "el");
+ torture_assert_int_equal(tctx, el->num_values,
+ testdata->num_records,
+ "num_values != num_records");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to pull record");
+ if (i < 3) {
+ /* records 0 and 1 should not have been renewed */
+ int old_ts = dns_timestamp_after + 3 - 24 * (i + 5);
+ torture_assertf(
+ tctx,
+ rec.dwTimeStamp == old_ts,
+ "record[%zu] timestamp should not be altered."
+ " diff is %d\n",
+ i, rec.dwTimeStamp - old_ts);
+ } else {
+ /* records 3+ should have a now-ish timestamp */
+ int old_ts = dns_timestamp_after + 3 - 24 * (i + 5);
+ torture_assertf(
+ tctx,
+ rec.dwTimeStamp >= dns_timestamp_before,
+ "record[%zu] should have altered timestamp "
+ "now ~= %d, then ~= %d, has %d, diff %d\n", i,
+ dns_timestamp_before, old_ts, rec.dwTimeStamp,
+ dns_timestamp_before - rec.dwTimeStamp
+ );
+ }
+ }
+
+ /*
+ * Step 11. Set one record to be static.
+ *
+ * This should make the node static, but it won't "know" that until we
+ * force it with an update.
+ */
+ torture_comment(tctx, "step 11: alter one timestamp to be 0\n");
+ ret = dsdb_search_one(samdb, tctx, &msg, node_dn,
+ LDB_SCOPE_BASE, attrs,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ torture_assert_not_null(tctx, el, "el");
+ torture_assert_int_equal(tctx, el->num_values,
+ testdata->num_records,
+ "num_values != num_records");
+
+ {
+ /* we're arbitrarily picking on record 3 */
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[3]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to pull record");
+
+ rec.dwTimeStamp = 0;
+
+ ret = ndr_push_struct_blob(
+ &el->values[3],
+ msg,
+ &rec,
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to PUSH record");
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_modify(samdb, msg);
+ torture_assert_int_equal(tctx, ret, 0, "failed to ldb_modify");
+ print_node_records(tctx, samdb, node_dn, "after ldb_modify");
+
+
+ /*
+ * Step 12. Do updates on some records, zeroing their timestamps
+ *
+ * Zero means static. A single zero timestamp is infectious, so other
+ * records get it when they are updated.
+ */
+
+ for (i = 0; i < testdata->num_records - 2; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(name, r.rdata, dbdata, version);
+ dlz_closeversion(domain, ret == ISC_R_SUCCESS, dbdata,
+ &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to update record\n");
+ }
+ print_node_records(tctx, samdb, node_dn, "after update to static");
+
+
+ /*
+ * Step 13. Check that the record timeouts are *mostly* zero.
+ *
+ * one or two will be non-zero: we updated all but two, but one of
+ * excluded ones might be the el->records[3] that we explicitly set to
+ * zero.
+ */
+ ret = dsdb_search_one(samdb, tctx, &msg, node_dn,
+ LDB_SCOPE_BASE, attrs,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ {
+ unsigned n_zero = 0;
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t)\
+ ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret,
+ "failed to pull record");
+ if (rec.dwTimeStamp == 0) {
+ n_zero++;
+ }
+ }
+ if (n_zero != el->num_values - 1 &&
+ n_zero != el->num_values - 2) {
+ torture_comment(tctx, "got %u zeros, expected %u or %u",
+ n_zero,
+ el->num_values - 2,
+ el->num_values - 1);
+ torture_fail(tctx,
+ "static node not setting zero timestamps\n");
+
+ }
+ }
+
+
+ /*
+ * Step 14. Turn aging off.
+ */
+ torture_comment(tctx, "step 14: turn aging off\n");
+ ok = set_zone_aging(tctx, domain, 0);
+ torture_assert(tctx, ok, "failed to disable aging");
+ print_node_records(tctx, samdb, node_dn, "aging off");
+
+ /*
+ * Step 15. Update, setting timestamps to zero.
+ *
+ * Even with aging off, timestamps are still changed to static.
+ */
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(name, r.rdata, dbdata, version);
+ dlz_closeversion(domain, ret == ISC_R_SUCCESS, dbdata,
+ &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to update record\n");
+ }
+ print_node_records(tctx, samdb, node_dn, "after update with aging off");
+
+
+ /*
+ * Step 16. Check that the timestamps are all zero.
+ */
+ ret = dsdb_search_one(samdb, tctx, &msg, node_dn,
+ LDB_SCOPE_BASE, attrs,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t) ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret,
+ "failed to pull record");
+ torture_assertf(tctx, rec.dwTimeStamp == 0,
+ "record[%zu].dwTimeStamp is %u, expected 0\n",
+ i, rec.dwTimeStamp);
+
+ }
+
+
+ /*
+ * Step 17. Reset to non-zero via ldb, with aging still off.
+ *
+ * We chose timestamps in the distant past that would all be updated
+ * if aging was on.
+ */
+ torture_comment(tctx, "step 17: reset to non-zero timestamps\n");
+ ret = dsdb_search_one(samdb, tctx, &msg, node_dn,
+ LDB_SCOPE_BASE, attrs,
+ 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(
+ tctx,
+ "Failed to find %s node: %s",
+ name, ldb_errstring(samdb)));
+ }
+
+ el = ldb_msg_find_element(msg, "dnsRecord");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to pull record");
+
+ rec.dwTimeStamp = 10000 + i; /* a long time ago */
+
+ ret = ndr_push_struct_blob(
+ &el->values[i],
+ msg,
+ &rec,
+ (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to PUSH record");
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_modify(samdb, msg);
+ torture_assert_int_equal(tctx, ret, 0, "failed to ldb_modify");
+ print_node_records(tctx, samdb, node_dn, "timestamps no-zero, aging off");
+
+
+ /*
+ * Step 18. Update with aging off. Nothing should change.
+ *
+ */
+
+ /* now, with another update, some will be updated and some won't */
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_addrdataset(name, r.rdata, dbdata, version);
+ dlz_closeversion(domain, ret == ISC_R_SUCCESS, dbdata,
+ &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to update record\n");
+ }
+ print_node_records(tctx, samdb, node_dn, "after update");
+
+
+ /*
+ * Step 19. Check that the timestamps didn't change.
+ */
+ el = ldb_msg_find_element(msg, "dnsRecord");
+ torture_assert_not_null(tctx, el, "el");
+ torture_assert_int_equal(tctx, el->num_values,
+ testdata->num_records,
+ "num_values != num_records");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dnsp_DnssrvRpcRecord rec;
+ ret = ndr_pull_struct_blob(
+ &(el->values[i]),
+ msg,
+ &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
+ torture_assert_ndr_success(tctx, ret, "failed to pull record");
+ torture_assertf(
+ tctx,
+ rec.dwTimeStamp == 10000 + i,
+ "record[%zu] timestamp should not be altered.\n",
+ i);
+ }
+
+
+ /*
+ * Step 20. Delete all the records, 1 by 1.
+ *
+ */
+ torture_comment(tctx, "step 20: delete the records\n");
+
+ for (i = 0; i < testdata->num_records; i++) {
+ struct test_expected_record r = testdata->records[i];
+
+ ret = dlz_newversion(domain, dbdata, &version);
+ torture_assert_int_equal(tctx, ret, ISC_R_SUCCESS,
+ "Failed to start transaction");
+
+ ret = dlz_subrdataset(name, r.rdata, dbdata, version);
+ torture_assert_int_equal_goto(
+ tctx, ret, ISC_R_SUCCESS, ok,
+ cancel_version,
+ talloc_asprintf(tctx,
+ "Failed to delete record %zu «%s»\n",
+ i, r.rdata));
+
+ dlz_closeversion(domain, true, dbdata, &version);
+
+ testdata->num_rr = 0;
+
+ ret = dlz_lookup(domain, testdata->query_name, dbdata,
+ (dns_sdlzlookup_t *)testdata, NULL, NULL);
+
+ if (i == testdata->num_records - 1) {
+ torture_assert_int_equal(tctx, ret,
+ ISC_R_NOTFOUND,
+ "no records should exist");
+ } else {
+ torture_assert_int_equal(tctx, ret,
+ ISC_R_SUCCESS,
+ "records not found");
+ }
+
+ torture_assert_int_equal(tctx,
+ testdata->num_rr,
+ testdata->num_records - 1 - i,
+ "Got wrong record count");
+
+ for (j = 0; j < testdata->num_records; j++) {
+ struct test_expected_record *r2 = &testdata->records[j];
+ if (j > i) {
+ torture_assert(
+ tctx,
+ r2->printed,
+ talloc_asprintf(tctx,
+ "putrr callback not run on %s «%s»",
+ r2->type, r2->name));
+ } else {
+ torture_assert(
+ tctx,
+ ! r2->printed,
+ talloc_asprintf(tctx,
+ "putrr callback should not see %s «%s»",
+ r2->type, r2->name));
+ }
+ r2->printed = false;
+ }
+ }
+
+ dlz_destroy(dbdata);
+
+ return true;
+
+cancel_version:
+ DBG_ERR("exiting with %d\n", ret);
+ dlz_closeversion(domain, false, dbdata, &version);
+ return ret;
+}
+
+
+static struct torture_suite *dlz_bind9_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dlz_bind9");
+
+ suite->description = talloc_strdup(suite,
+ "Tests for the BIND 9 DLZ module");
+ torture_suite_add_simple_test(suite, "version", test_dlz_bind9_version);
+ torture_suite_add_simple_test(suite, "create", test_dlz_bind9_create);
+ torture_suite_add_simple_test(suite, "configure", test_dlz_bind9_configure);
+ torture_suite_add_simple_test(suite, "destroyoldestfirst",
+ test_dlz_bind9_destroy_oldest_first);
+ torture_suite_add_simple_test(suite, "destroynewestfirst",
+ test_dlz_bind9_destroy_newest_first);
+ torture_suite_add_simple_test(suite, "multipleconfigure",
+ test_dlz_bind9_multiple_configure);
+
+ torture_suite_add_simple_test(suite, "gssapi", test_dlz_bind9_gssapi);
+ torture_suite_add_simple_test(suite, "spnego", test_dlz_bind9_spnego);
+ torture_suite_add_simple_test(suite, "lookup", test_dlz_bind9_lookup);
+ torture_suite_add_simple_test(suite, "zonedump", test_dlz_bind9_zonedump);
+ torture_suite_add_simple_test(suite, "update01", test_dlz_bind9_update01);
+ torture_suite_add_simple_test(suite, "aging", test_dlz_bind9_aging);
+ torture_suite_add_simple_test(suite, "allowzonexfr", test_dlz_bind9_allowzonexfr);
+ return suite;
+}
+
+/**
+ * DNS torture module initialization
+ */
+NTSTATUS torture_bind_dns_init(TALLOC_CTX *);
+NTSTATUS torture_bind_dns_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ /* register DNS related test cases */
+ suite = dlz_bind9_suite(ctx);
+ if (!suite) return NT_STATUS_NO_MEMORY;
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/dns/internal_dns.c b/source4/torture/dns/internal_dns.c
new file mode 100644
index 0000000..2ccc7ed
--- /dev/null
+++ b/source4/torture/dns/internal_dns.c
@@ -0,0 +1,189 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Kai Blin 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include <talloc.h>
+#include "lib/addns/dns.h"
+
+static struct dns_connection *setup_connection(struct torture_context *tctx)
+{
+ DNS_ERROR err;
+ struct dns_connection *conn;
+
+ err = dns_open_connection(getenv("DC_SERVER_IP"), DNS_TCP, tctx, &conn);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to open connection to DNS server\n");
+ return NULL;
+ }
+
+ return conn;
+}
+
+static char *get_dns_domain(struct torture_context *tctx)
+{
+ return strlower_talloc(tctx, getenv("REALM"));
+}
+
+static struct sockaddr_storage *str_to_sockaddr(TALLOC_CTX *mem_ctx, const char *ip_string)
+{
+ struct sockaddr_storage *ss = talloc_zero(mem_ctx, struct sockaddr_storage);
+ int ret;
+
+ if (ss == NULL) {
+ return NULL;
+ }
+
+ ss->ss_family = AF_INET;
+
+ ret = inet_pton(AF_INET, ip_string, &(((struct sockaddr_in *)ss)->sin_addr));
+ if (ret != 1) {
+ return NULL;
+ }
+
+ return ss;
+}
+
+static bool test_internal_dns_query_self(struct torture_context *tctx)
+{
+ struct dns_connection *conn;
+ struct dns_request *req, *resp;
+ char *host;
+ DNS_ERROR err;
+
+ conn = setup_connection(tctx);
+ if (conn == NULL) {
+ return false;
+ }
+
+ host = talloc_asprintf(tctx, "%s.%s", getenv("DC_SERVER"), get_dns_domain(tctx));
+ if (host == NULL) {
+ return false;
+ }
+
+ err = dns_create_query(conn, host, QTYPE_A, DNS_CLASS_IN, &req);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to create A record query\n");
+ return false;
+ }
+
+ err = dns_transaction(conn, conn, req, &resp);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to query DNS server\n");
+ return false;
+ }
+
+ if (dns_response_code(resp->flags) != DNS_NO_ERROR) {
+ printf("Query returned %u\n", dns_response_code(resp->flags));
+ return false;
+ }
+
+ /* FIXME: is there _any_ way to unmarshal the response to check this? */
+
+ return true;
+}
+
+static bool test_internal_dns_update_self(struct torture_context *tctx)
+{
+ struct dns_connection *conn;
+ struct dns_update_request *req, *resp;
+ struct dns_rrec *rec = NULL;
+ char *host;
+ DNS_ERROR err;
+ struct sockaddr_storage *ss;
+
+ conn = setup_connection(tctx);
+ if (conn == NULL) {
+ return false;
+ }
+
+ host = talloc_asprintf(tctx, "%s.%s", getenv("DC_SERVER"), get_dns_domain(tctx));
+ if (host == NULL) {
+ return false;
+ }
+
+ err = dns_create_update(conn, get_dns_domain(tctx), &req);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to update packet\n");
+ return false;
+ }
+
+ ss = str_to_sockaddr(conn, getenv("DC_SERVER_IP"));
+ if (ss == NULL) {
+ printf("Converting '%s' to sockaddr_storage failed\n", getenv("DC_SERVER_IP"));
+ return false;
+ }
+
+ err = dns_create_a_record(req, host, 300, ss, &rec);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to create A update record\n");
+ return false;
+ }
+
+ err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to add A update record to update packet\n");
+ return false;
+ }
+
+ err = dns_update_transaction(conn, conn, req, &resp);
+ if (!ERR_DNS_IS_OK(err)) {
+ printf("Failed to send update\n");
+ return false;
+ }
+
+ if (dns_response_code(resp->flags) != DNS_REFUSED) {
+ printf("Update returned %u\n", dns_response_code(resp->flags));
+ return false;
+ }
+
+ /* FIXME: is there _any_ way to unmarshal the response to check this? */
+
+ return true;
+}
+
+static struct torture_suite *internal_dns_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dns_internal");
+
+ suite->description = talloc_strdup(suite,
+ "Tests for the internal DNS server");
+ torture_suite_add_simple_test(suite, "queryself", test_internal_dns_query_self);
+ torture_suite_add_simple_test(suite, "updateself", test_internal_dns_update_self);
+ return suite;
+}
+
+
+/* Silence silly compiler warning */
+NTSTATUS torture_internal_dns_init(TALLOC_CTX *);
+
+/**
+ * DNS torture module initialization
+ */
+NTSTATUS torture_internal_dns_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ /* register internal DNS torture test cases */
+ suite = internal_dns_suite(ctx);
+ if (!suite) return NT_STATUS_NO_MEMORY;
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/dns/wscript_build b/source4/torture/dns/wscript_build
new file mode 100644
index 0000000..0b40e03
--- /dev/null
+++ b/source4/torture/dns/wscript_build
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+if bld.AD_DC_BUILD_IS_ENABLED():
+ bld.SAMBA_MODULE('TORTURE_BIND_DNS',
+ source='dlz_bind9.c',
+ subsystem='smbtorture',
+ init_function='torture_bind_dns_init',
+ cflags='-DBIND_VERSION_9_16',
+ deps='torture talloc torturemain dlz_bind9_for_torture',
+ internal_module=True
+ )
+
+ bld.SAMBA_MODULE('TORTURE_INTERNAL_DNS',
+ source='internal_dns.c',
+ subsystem='smbtorture',
+ init_function='torture_internal_dns_init',
+ deps='torture talloc torturemain',
+ internal_module=True
+ )
diff --git a/source4/torture/drs/drs_init.c b/source4/torture/drs/drs_init.c
new file mode 100644
index 0000000..bbe246d
--- /dev/null
+++ b/source4/torture/drs/drs_init.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUAPI utility functions to be used in torture tests
+
+ Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/rpc/drsuapi.h"
+#include "dsdb/samdb/samdb.h"
+#include "torture/drs/proto.h"
+
+/**
+ * DRSUAPI tests to be executed remotely
+ */
+static struct torture_suite * torture_drs_rpc_suite(TALLOC_CTX *mem_ctx,
+ const char *suite_name)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, suite_name);
+
+ torture_drs_rpc_dssync_tcase(suite);
+ torture_drs_rpc_dsintid_tcase(suite);
+
+ suite->description = talloc_strdup(suite,
+ "DRSUAPI RPC Tests Suite");
+
+ return suite;
+}
+
+/**
+ * DRSUAPI tests to be executed remotely
+ */
+static struct torture_suite * torture_drs_unit_suite(TALLOC_CTX *mem_ctx,
+ const char *suite_name)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, suite_name);
+
+ torture_drs_unit_prefixmap(suite);
+ torture_drs_unit_schemainfo(suite);
+
+ suite->description = talloc_strdup(suite,
+ "DRSUAPI Unit Tests Suite");
+
+ return suite;
+}
+
+/**
+ * DRSUAPI torture module initialization
+ */
+NTSTATUS torture_drs_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ /* register RPC related test cases */
+ suite = torture_drs_rpc_suite(ctx, "drs.rpc");
+ if (!suite) return NT_STATUS_NO_MEMORY;
+ torture_register_suite(ctx, suite);
+
+ /* register DRS Unit test cases */
+ suite = torture_drs_unit_suite(ctx, "drs.unit");
+ if (!suite) return NT_STATUS_NO_MEMORY;
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/drs/drs_util.c b/source4/torture/drs/drs_util.c
new file mode 100644
index 0000000..c43836e
--- /dev/null
+++ b/source4/torture/drs/drs_util.c
@@ -0,0 +1,167 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUAPI utility functions to be used in torture tests
+
+ Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "dsdb/samdb/samdb.h"
+#include "torture/rpc/drsuapi.h"
+#include "../lib/util/asn1.h"
+#include "torture/drs/proto.h"
+
+/**
+ * Decode Attribute OID based on MS documentation
+ * See MS-DRSR.pdf - 5.16.4
+ *
+ * On success returns decoded OID and
+ * corresponding prefix_map index (if requested)
+ */
+bool drs_util_oid_from_attid(struct torture_context *tctx,
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *prefix_map,
+ uint32_t attid,
+ const char **_oid,
+ int *map_idx)
+{
+ uint32_t i, hi_word, lo_word;
+ DATA_BLOB bin_oid = {NULL, 0};
+ char *oid;
+ struct drsuapi_DsReplicaOIDMapping *map_entry = NULL;
+ TALLOC_CTX *mem_ctx = talloc_named(tctx, 0, "util_drsuapi_oid_from_attid");
+
+ /* crack attid value */
+ hi_word = attid >> 16;
+ lo_word = attid & 0xFFFF;
+
+ /* check last entry in the prefix map is the special one */
+ map_entry = &prefix_map->mappings[prefix_map->num_mappings-1];
+ torture_assert(tctx,
+ (map_entry->id_prefix == 0)
+ && (*map_entry->oid.binary_oid == 0xFF),
+ "Last entry in Prefix Map is not the special one!");
+
+ /* locate corresponding prefixMap entry */
+ map_entry = NULL;
+ for (i = 0; i < prefix_map->num_mappings - 1; i++) {
+
+ if (hi_word == prefix_map->mappings[i].id_prefix) {
+ map_entry = &prefix_map->mappings[i];
+ if (map_idx) *map_idx = i;
+ break;
+ }
+ }
+
+ torture_assert(tctx, map_entry, "Unable to locate corresponding Prefix Map entry");
+
+ /* copy partial oid making enough room */
+ bin_oid.length = map_entry->oid.length + 2;
+ bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length);
+ torture_assert(tctx, bin_oid.data, "Not enough memory");
+ memcpy(bin_oid.data, map_entry->oid.binary_oid, map_entry->oid.length);
+
+ if (lo_word < 128) {
+ bin_oid.length = bin_oid.length - 1;
+ bin_oid.data[bin_oid.length-1] = lo_word;
+ }
+ else {
+ if (lo_word >= 32768) {
+ lo_word -= 32768;
+ }
+ bin_oid.data[bin_oid.length-2] = ((lo_word / 128) % 128) + 128; /* (0x80 | ((lo_word>>7) & 0x7f)) */
+ bin_oid.data[bin_oid.length-1] = lo_word % 128; /* lo_word & 0x7f */
+ }
+
+ torture_assert(tctx,
+ ber_read_OID_String(tctx, bin_oid, &oid),
+ "Failed to decode binary OID");
+ talloc_free(mem_ctx);
+
+ *_oid = oid;
+
+ return true;
+}
+
+
+/**
+ * Loads dsdb_schema from ldb connection using remote prefixMap.
+ * Schema will be loaded only if:
+ * - ldb has no attached schema
+ * - reload_schema is true
+ *
+ * This function is to be used in tests that use GetNCChanges() function
+ */
+bool drs_util_dsdb_schema_load_ldb(struct torture_context *tctx,
+ struct ldb_context *ldb,
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
+ bool reload_schema)
+{
+ int ret;
+ WERROR werr;
+ char *err_msg;
+ struct ldb_result *res;
+ struct ldb_dn *schema_dn;
+ struct dsdb_schema *ldap_schema;
+
+ ldap_schema = dsdb_get_schema(ldb, NULL);
+ if (ldap_schema && !reload_schema) {
+ return true;
+ }
+
+ schema_dn = ldb_get_schema_basedn(ldb);
+ torture_assert(tctx, schema_dn != NULL,
+ talloc_asprintf(tctx, "ldb_get_schema_basedn() failed: %s", ldb_errstring(ldb)));
+
+ ldap_schema = dsdb_new_schema(ldb);
+ torture_assert(tctx, ldap_schema != NULL, "dsdb_new_schema() failed!");
+
+ werr = dsdb_load_prefixmap_from_drsuapi(ldap_schema, mapping_ctr);
+ torture_assert_werr_ok(tctx, werr,
+ "Failed to construct prefixMap from drsuapi data");
+
+ /*
+ * load the attribute and objectClass definitions
+ */
+ ret = ldb_search(ldb, ldap_schema, &res,
+ schema_dn, LDB_SCOPE_ONELEVEL, NULL,
+ "(|(objectClass=attributeSchema)(objectClass=classSchema))");
+ if (ret != LDB_SUCCESS) {
+ err_msg = talloc_asprintf(tctx,
+ "failed to search attributeSchema or classSchema objects: %s",
+ ldb_errstring(ldb));
+ torture_fail(tctx, err_msg);
+ }
+
+ ret = dsdb_load_ldb_results_into_schema(tctx, ldb, ldap_schema, res, &err_msg);
+ if (ret != LDB_SUCCESS) {
+ err_msg = talloc_asprintf(tctx,
+ "dsdb_load_ldb_results_into_schema failed: %s",
+ err_msg);
+ torture_fail(tctx, err_msg);
+ }
+
+ talloc_free(res);
+
+ ret = dsdb_set_schema(ldb, ldap_schema, SCHEMA_WRITE);
+ if (ret != LDB_SUCCESS) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx, "dsdb_set_schema() failed: %s", ldb_strerror(ret)));
+ }
+
+ return true;
+}
diff --git a/source4/torture/drs/python/cracknames.py b/source4/torture/drs/python/cracknames.py
new file mode 100644
index 0000000..f244605
--- /dev/null
+++ b/source4/torture/drs/python/cracknames.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) Catalyst .Net Ltd 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import samba.tests
+import ldb
+import drs_base
+
+from samba.dcerpc import drsuapi
+
+
+class DrsCracknamesTestCase(drs_base.DrsBaseTestCase):
+ def setUp(self):
+ super(DrsCracknamesTestCase, self).setUp()
+ (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
+
+ self.ou = "ou=Cracknames_ou,%s" % self.ldb_dc1.get_default_basedn()
+ self.username = "Cracknames_user"
+ self.user = "cn=%s,%s" % (self.username, self.ou)
+
+ self.ldb_dc1.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+
+ self.user_record = {
+ "dn": self.user,
+ "objectclass": "user",
+ "sAMAccountName": self.username,
+ "userPrincipalName": "test@test.com",
+ "servicePrincipalName": "test/%s" % self.ldb_dc1.get_default_basedn(),
+ "displayName": "test"}
+
+ self.ldb_dc1.add(self.user_record)
+ self.ldb_dc1.delete(self.user_record["dn"])
+ self.ldb_dc1.add(self.user_record)
+
+ # The formats specified in MS-DRSR 4.1.4.13; DS_NAME_FORMAT
+ # We don't support any of the ones specified in 4.1.4.1.2.
+ self.formats = {
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ # This format is not supported by Windows (or us)
+ # drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN,
+ }
+
+ def tearDown(self):
+ self.ldb_dc1.delete(self.user)
+ self.ldb_dc1.delete(self.ou)
+ super(DrsCracknamesTestCase, self).tearDown()
+
+ def test_Cracknames(self):
+ """
+ Verifies that we can cracknames any of the standard formats
+ (DS_NAME_FORMAT) to a GUID, and that we can cracknames a
+ GUID to any of the standard formats.
+
+ GUID was chosen just so that we don't have to do an n^2 loop.
+ """
+ (result, ctr) = self._do_cracknames(self.user,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
+
+ user_guid = ctr.array[0].result_name
+
+ for name_format in self.formats:
+ (result, ctr) = self._do_cracknames(user_guid,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+ name_format)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
+ "Expected 0, got %s, desired format is %s"
+ % (ctr.array[0].status, name_format))
+
+ (result, ctr) = self._do_cracknames(ctr.array[0].result_name,
+ name_format,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
+ "Expected 0, got %s, offered format is %s"
+ % (ctr.array[0].status, name_format))
+
+ def test_MultiValuedAttribute(self):
+ """
+ Verifies that, if we try and cracknames with the desired output
+ being a multi-valued attribute, it returns
+ DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
+ """
+ username = "Cracknames_user_MVA"
+ user = "cn=%s,%s" % (username, self.ou)
+
+ user_record = {
+ "dn": user,
+ "objectclass": "user",
+ "sAMAccountName": username,
+ "userPrincipalName": "test2@test.com",
+ "servicePrincipalName": ["test2/%s" % self.ldb_dc1.get_default_basedn(),
+ "test3/%s" % self.ldb_dc1.get_default_basedn()],
+ "displayName": "test2"}
+
+ self.ldb_dc1.add(user_record)
+
+ (result, ctr) = self._do_cracknames(user,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
+
+ user_guid = ctr.array[0].result_name
+
+ (result, ctr) = self._do_cracknames(user_guid,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE)
+
+ self.ldb_dc1.delete(user)
+
+ def test_NoSPNAttribute(self):
+ """
+ Verifies that, if we try and cracknames with the desired output
+ being an SPN, it returns
+ DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
+ """
+ username = "Cracknames_no_SPN"
+ user = "cn=%s,%s" % (username, self.ou)
+
+ user_record = {
+ "dn": user,
+ "objectclass": "user",
+ "sAMAccountName" : username,
+ "userPrincipalName" : "test4@test.com",
+ "displayName" : "test4"}
+
+ self.ldb_dc1.add(user_record)
+
+ (result, ctr) = self._do_cracknames(user,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
+
+ user_guid = ctr.array[0].result_name
+
+ (result, ctr) = self._do_cracknames(user_guid,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+ drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
+
+ self.assertEqual(ctr.count, 1)
+ self.assertEqual(ctr.array[0].status,
+ drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_FOUND)
+
+ self.ldb_dc1.delete(user)
+
+ def _do_cracknames(self, name, format_offered, format_desired):
+ req = drsuapi.DsNameRequest1()
+ names = drsuapi.DsNameString()
+ names.str = name
+
+ req.codepage = 1252 # German, but it doesn't really matter here
+ req.language = 1033
+ req.format_flags = 0
+ req.format_offered = format_offered
+ req.format_desired = format_desired
+ req.count = 1
+ req.names = [names]
+
+ (result, ctr) = self.drs.DsCrackNames(self.drs_handle, 1, req)
+ return (result, ctr)
diff --git a/source4/torture/drs/python/delete_object.py b/source4/torture/drs/python/delete_object.py
new file mode 100644
index 0000000..5f2f703
--- /dev/null
+++ b/source4/torture/drs/python/delete_object.py
@@ -0,0 +1,376 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN delete_object -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import time
+
+
+from ldb import (
+ SCOPE_SUBTREE,
+)
+
+import drs_base
+import ldb
+
+
+class DrsDeleteObjectTestCase(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(DrsDeleteObjectTestCase, self).setUp()
+ # disable automatic replication temporary
+ self._disable_all_repl(self.dnsname_dc1)
+ self._disable_all_repl(self.dnsname_dc2)
+ # make sure DCs are synchronized before the test
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ def tearDown(self):
+ self._enable_all_repl(self.dnsname_dc1)
+ self._enable_all_repl(self.dnsname_dc2)
+ super(DrsDeleteObjectTestCase, self).tearDown()
+
+ def _make_username(self):
+ return "DrsDelObjUser_" + time.strftime("%s", time.gmtime())
+
+ # now also used to check the group
+ def _check_obj(self, sam_ldb, obj_orig, is_deleted):
+ # search the user by guid as it may be deleted
+ guid_str = self._GUID_string(obj_orig["objectGUID"][0])
+ expression = "(objectGUID=%s)" % guid_str
+ res = sam_ldb.search(base=self.domain_dn,
+ expression=expression,
+ controls=["show_deleted:1"])
+ self.assertEqual(len(res), 1)
+ user_cur = res[0]
+ # Deleted Object base DN
+ dodn = self._deleted_objects_dn(sam_ldb)
+ # now check properties of the user
+ cn_orig = str(obj_orig["cn"][0])
+ cn_cur = str(user_cur["cn"][0])
+ name_orig = str(obj_orig["name"][0])
+ name_cur = str(user_cur["name"][0])
+ if is_deleted:
+ self.assertEqual(str(user_cur["isDeleted"][0]), "TRUE")
+ self.assertFalse("objectCategory" in user_cur)
+ self.assertFalse("sAMAccountType" in user_cur)
+ self.assertFalse("description" in user_cur)
+ self.assertFalse("memberOf" in user_cur)
+ self.assertFalse("member" in user_cur)
+ self.assertTrue(dodn in str(user_cur["dn"]),
+ "User %s is deleted but it is not located under %s (found at %s)!" % (name_orig, dodn, user_cur["dn"]))
+ self.assertEqual(name_cur, name_orig + "\nDEL:" + guid_str)
+ self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
+ self.assertEqual(cn_cur, cn_orig + "\nDEL:" + guid_str)
+ self.assertEqual(name_cur, cn_cur)
+ else:
+ self.assertFalse("isDeleted" in user_cur)
+ self.assertEqual(name_cur, name_orig)
+ self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
+ self.assertEqual(cn_cur, cn_orig)
+ self.assertEqual(name_cur, cn_cur)
+ self.assertEqual(obj_orig["dn"], user_cur["dn"])
+ self.assertTrue(dodn not in str(user_cur["dn"]))
+ return user_cur
+
+ def test_ReplicateDeletedObject1(self):
+ """Verifies how a deleted-object is replicated between two DCs.
+ This test should verify that:
+ - deleted-object is replicated properly
+ - We verify that after replication,
+ object's state to conform to a tombstone-object state
+ - This test replicates the object modifications to
+ the server with the user deleted first
+
+ TODO: It will also be great if check replPropertyMetaData.
+ TODO: Check for deleted-object state, depending on DC's features
+ when recycle-bin is enabled
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username, password="P@sswOrd!")
+ ldb_res = self.ldb_dc1.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # delete user on DC1
+ self.ldb_dc1.delete(user_dn)
+ # check user info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
+
+ # The user should not have a description or memberOf yet
+ self.assertFalse("description" in user_cur)
+ self.assertFalse("memberOf" in user_cur)
+
+ self.ldb_dc2.newgroup("group_%s" % username)
+
+ self.ldb_dc2.newgroup("group2_%s" % username)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertTrue("sAMAccountName" in ldb_res[0])
+ group_orig = ldb_res[0]
+ group_dn = ldb_res[0]["dn"]
+
+ # modify user on DC2 to have a description and be a member of the group
+ m = ldb.Message()
+ m.dn = user_dn
+ m["description"] = ldb.MessageElement("a description",
+ ldb.FLAG_MOD_ADD, "description")
+ self.ldb_dc2.modify(m)
+ m = ldb.Message()
+ m.dn = group_dn
+ m["member"] = ldb.MessageElement(str(user_dn),
+ ldb.FLAG_MOD_ADD, "member")
+ self.ldb_dc2.modify(m)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group2_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertTrue("sAMAccountName" in ldb_res[0])
+ group2_dn = ldb_res[0]["dn"]
+ group2_orig = ldb_res[0]
+
+ m = ldb.Message()
+ m.dn = group2_dn
+ m["member"] = ldb.MessageElement(str(group_dn),
+ ldb.FLAG_MOD_ADD, "member")
+ self.ldb_dc2.modify(m)
+
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
+
+ # The user should not have a description yet
+ self.assertTrue("description" in user_cur)
+ self.assertTrue("memberOf" in user_cur)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+
+ # This group is a member of another group
+ self.assertTrue("memberOf" in ldb_res[0])
+
+ # The user was deleted on DC1, but check the modify we just did on DC2
+ self.assertTrue("member" in ldb_res[0])
+
+ # trigger replication from DC2 to DC1
+ # to check if deleted object gets restored
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True)
+ # check user info on DC2 - should be valid user
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
+
+ ldb_res = self.ldb_dc1.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+
+ # This group is a member of another group
+ self.assertTrue("memberOf" in ldb_res[0])
+
+ # The user was deleted on DC1, but the modify we did on DC2, check it never replicated in
+ self.assertFalse("member" in ldb_res[0])
+
+ # trigger replication from DC1 to DC2
+ # to check if deleted object is replicated
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True)
+ # check user info on DC2 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=True)
+
+ # delete group on DC1
+ self.ldb_dc1.delete(group_dn)
+
+ # trigger replication from DC1 to DC2
+ # to check if deleted object is replicated
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check group info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=group_orig, is_deleted=True)
+ # check group info on DC2 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=group_orig, is_deleted=True)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group2_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertFalse("member" in ldb_res[0])
+
+ # delete group on DC1
+ self.ldb_dc1.delete(group2_dn)
+
+ # trigger replication from DC1 to DC2
+ # to check if deleted object is replicated
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check group info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=group2_orig, is_deleted=True)
+ # check group info on DC2 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=group2_orig, is_deleted=True)
+
+ def test_ReplicateDeletedObject2(self):
+ """Verifies how a deleted-object is replicated between two DCs.
+ This test should verify that:
+ - deleted-object is replicated properly
+ - We verify that after replication,
+ object's state to conform to a tombstone-object state
+ - This test replicates the delete to the server with the
+ object modifications first
+
+ TODO: It will also be great if check replPropertyMetaData.
+ TODO: Check for deleted-object state, depending on DC's features
+ when recycle-bin is enabled
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username, password="P@sswOrd!")
+ ldb_res = self.ldb_dc1.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # delete user on DC1
+ self.ldb_dc1.delete(user_dn)
+ # check user info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
+
+ # The user should not have a description or memberOf yet
+ self.assertFalse("description" in user_cur)
+ self.assertFalse("memberOf" in user_cur)
+
+ self.ldb_dc2.newgroup("group_%s" % username)
+
+ self.ldb_dc2.newgroup("group2_%s" % username)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertTrue("sAMAccountName" in ldb_res[0])
+ group_dn = ldb_res[0]["dn"]
+
+ # modify user on DC2 to have a description and be a member of the group
+ m = ldb.Message()
+ m.dn = user_dn
+ m["description"] = ldb.MessageElement("a description",
+ ldb.FLAG_MOD_ADD, "description")
+ self.ldb_dc2.modify(m)
+ m = ldb.Message()
+ m.dn = group_dn
+ m["member"] = ldb.MessageElement(str(user_dn),
+ ldb.FLAG_MOD_ADD, "member")
+ self.ldb_dc2.modify(m)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group2_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertTrue("sAMAccountName" in ldb_res[0])
+ group2_dn = ldb_res[0]["dn"]
+
+ m = ldb.Message()
+ m.dn = group2_dn
+ m["member"] = ldb.MessageElement(str(group_dn),
+ ldb.FLAG_MOD_ADD, "member")
+ self.ldb_dc2.modify(m)
+
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
+
+ # The user should not have a description yet
+ self.assertTrue("description" in user_cur)
+ self.assertTrue("memberOf" in user_cur)
+
+ # trigger replication from DC1 to DC2
+ # to check if deleted object gets restored
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True)
+ # check user info on DC2 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=True)
+
+ ldb_res = self.ldb_dc2.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertTrue("memberOf" in ldb_res[0])
+ self.assertFalse("member" in ldb_res[0])
+
+ # trigger replication from DC2 to DC1
+ # to check if deleted object is replicated
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC1 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True)
+ # check user info on DC2 - should be deleted
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=True)
+
+ ldb_res = self.ldb_dc1.search(base=self.domain_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=group_%s)" % username)
+ self.assertTrue(len(ldb_res) == 1)
+ self.assertTrue("memberOf" in ldb_res[0])
+ self.assertFalse("member" in ldb_res[0])
+
+ # delete group on DC1
+ self.ldb_dc1.delete(group_dn)
+ self.ldb_dc1.delete(group2_dn)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
new file mode 100644
index 0000000..bf98e59
--- /dev/null
+++ b/source4/torture/drs/python/drs_base.py
@@ -0,0 +1,632 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+# Copyright (C) Catalyst IT Ltd. 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import time
+import os
+import ldb
+
+sys.path.insert(0, "bin/python")
+import samba.tests
+from samba.tests.samba_tool.base import SambaToolCmdTest
+from samba import dsdb
+from samba.dcerpc import drsuapi, misc, drsblobs, security
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.drs_utils import drs_DsBind
+from samba import gensec
+from ldb import (
+ SCOPE_BASE,
+ Message,
+ FLAG_MOD_REPLACE,
+)
+from samba.common import cmp
+from samba.common import get_string
+
+
+class DrsBaseTestCase(SambaToolCmdTest):
+ """Base class implementation for all DRS python tests.
+ It is intended to provide common initialization and
+ and functionality used by all DRS tests in drs/python
+ test package. For instance, DC1 and DC2 are always used
+ to pass URLs for DCs to test against"""
+
+ def setUp(self):
+ super(DrsBaseTestCase, self).setUp()
+ creds = self.get_credentials()
+ creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
+
+ # connect to DCs
+ self.url_dc1 = samba.tests.env_get_var_value("DC1")
+ (self.ldb_dc1, self.info_dc1) = samba.tests.connect_samdb_ex(self.url_dc1,
+ ldap_only=True)
+ self.url_dc2 = samba.tests.env_get_var_value("DC2")
+ (self.ldb_dc2, self.info_dc2) = samba.tests.connect_samdb_ex(self.url_dc2,
+ ldap_only=True)
+ self.test_ldb_dc = self.ldb_dc1
+
+ # cache some of RootDSE props
+ self.schema_dn = str(self.info_dc1["schemaNamingContext"][0])
+ self.domain_dn = str(self.info_dc1["defaultNamingContext"][0])
+ self.config_dn = str(self.info_dc1["configurationNamingContext"][0])
+ self.forest_level = int(self.info_dc1["forestFunctionality"][0])
+
+ # we will need DCs DNS names for 'samba-tool drs' command
+ self.dnsname_dc1 = str(self.info_dc1["dnsHostName"][0])
+ self.dnsname_dc2 = str(self.info_dc2["dnsHostName"][0])
+
+ # for debugging the test code
+ self._debug = False
+
+ def tearDown(self):
+ super(DrsBaseTestCase, self).tearDown()
+
+ def set_test_ldb_dc(self, ldb_dc):
+ """Sets which DC's LDB we perform operations on during the test"""
+ self.test_ldb_dc = ldb_dc
+
+ def _GUID_string(self, guid):
+ return get_string(self.test_ldb_dc.schema_format_value("objectGUID", guid))
+
+ def _ldap_schemaUpdateNow(self, sam_db):
+ rec = {"dn": "",
+ "schemaUpdateNow": "1"}
+ m = Message.from_dict(sam_db, rec, FLAG_MOD_REPLACE)
+ sam_db.modify(m)
+
+ def _deleted_objects_dn(self, sam_ldb):
+ wkdn = "<WKGUID=18E2EA80684F11D2B9AA00C04F79F805,%s>" % self.domain_dn
+ res = sam_ldb.search(base=wkdn,
+ scope=SCOPE_BASE,
+ controls=["show_deleted:1"])
+ self.assertEqual(len(res), 1)
+ return str(res[0]["dn"])
+
+ def _lost_and_found_dn(self, sam_ldb, nc):
+ wkdn = "<WKGUID=%s,%s>" % (dsdb.DS_GUID_LOSTANDFOUND_CONTAINER, nc)
+ res = sam_ldb.search(base=wkdn,
+ scope=SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+ return str(res[0]["dn"])
+
+ def _make_obj_name(self, prefix):
+ return prefix + time.strftime("%s", time.gmtime())
+
+ def _samba_tool_cmd_list(self, drs_command):
+ # make command line credentials string
+
+ # If test runs on windows then it can provide its own auth string
+ if hasattr(self, 'cmdline_auth'):
+ cmdline_auth = self.cmdline_auth
+ else:
+ ccache_name = self.get_creds_ccache_name()
+
+ # Tunnel the command line credentials down to the
+ # subcommand to avoid a new kinit
+ cmdline_auth = "--use-krb5-ccache=%s" % ccache_name
+
+ # bin/samba-tool drs <drs_command> <cmdline_auth>
+ return ["drs", drs_command, cmdline_auth]
+
+ def _net_drs_replicate(self, DC, fromDC, nc_dn=None, forced=True,
+ local=False, full_sync=False, single=False):
+ if nc_dn is None:
+ nc_dn = self.domain_dn
+ # make base command line
+ samba_tool_cmdline = self._samba_tool_cmd_list("replicate")
+ # bin/samba-tool drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>
+ samba_tool_cmdline += [DC, fromDC, nc_dn]
+
+ if forced:
+ samba_tool_cmdline += ["--sync-forced"]
+ if local:
+ samba_tool_cmdline += ["--local"]
+ if full_sync:
+ samba_tool_cmdline += ["--full-sync"]
+ if single:
+ samba_tool_cmdline += ["--single-object"]
+
+ (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ def _enable_inbound_repl(self, DC):
+ # make base command line
+ samba_tool_cmd = self._samba_tool_cmd_list("options")
+ # disable replication
+ samba_tool_cmd += [DC, "--dsa-option=-DISABLE_INBOUND_REPL"]
+ (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ def _disable_inbound_repl(self, DC):
+ # make base command line
+ samba_tool_cmd = self._samba_tool_cmd_list("options")
+ # disable replication
+ samba_tool_cmd += [DC, "--dsa-option=+DISABLE_INBOUND_REPL"]
+ (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ def _enable_all_repl(self, DC):
+ self._enable_inbound_repl(DC)
+ # make base command line
+ samba_tool_cmd = self._samba_tool_cmd_list("options")
+ # enable replication
+ samba_tool_cmd += [DC, "--dsa-option=-DISABLE_OUTBOUND_REPL"]
+ (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ def _disable_all_repl(self, DC):
+ self._disable_inbound_repl(DC)
+ # make base command line
+ samba_tool_cmd = self._samba_tool_cmd_list("options")
+ # disable replication
+ samba_tool_cmd += [DC, "--dsa-option=+DISABLE_OUTBOUND_REPL"]
+ (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ def _get_highest_hwm_utdv(self, ldb_conn):
+ res = ldb_conn.search("", scope=ldb.SCOPE_BASE, attrs=["highestCommittedUSN"])
+ hwm = drsuapi.DsReplicaHighWaterMark()
+ hwm.tmp_highest_usn = int(res[0]["highestCommittedUSN"][0])
+ hwm.reserved_usn = 0
+ hwm.highest_usn = hwm.tmp_highest_usn
+
+ utdv = drsuapi.DsReplicaCursorCtrEx()
+ cursors = []
+ c1 = drsuapi.DsReplicaCursor()
+ c1.source_dsa_invocation_id = misc.GUID(ldb_conn.get_invocation_id())
+ c1.highest_usn = hwm.highest_usn
+ cursors.append(c1)
+ utdv.count = len(cursors)
+ utdv.cursors = cursors
+ return (hwm, utdv)
+
+ def _get_identifier(self, ldb_conn, dn):
+ res = ldb_conn.search(dn, scope=ldb.SCOPE_BASE,
+ attrs=["objectGUID", "objectSid"])
+ id = drsuapi.DsReplicaObjectIdentifier()
+ id.guid = ndr_unpack(misc.GUID, res[0]['objectGUID'][0])
+ if "objectSid" in res[0]:
+ id.sid = ndr_unpack(security.dom_sid, res[0]['objectSid'][0])
+ id.dn = str(res[0].dn)
+ return id
+
+ def _get_ctr6_links(self, ctr6):
+ """
+ Unpacks the linked attributes from a DsGetNCChanges response
+ and returns them as a list.
+ """
+ ctr6_links = []
+ for lidx in range(0, ctr6.linked_attributes_count):
+ l = ctr6.linked_attributes[lidx]
+ try:
+ target = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+ l.value.blob)
+ except:
+ target = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3Binary,
+ l.value.blob)
+ al = AbstractLink(l.attid, l.flags,
+ l.identifier.guid,
+ target.guid, target.dn)
+ ctr6_links.append(al)
+
+ return ctr6_links
+
+ def _get_ctr6_object_guids(self, ctr6):
+ """Returns all the object GUIDs in a GetNCChanges response"""
+ guid_list = []
+
+ obj = ctr6.first_object
+ for i in range(0, ctr6.object_count):
+ guid_list.append(str(obj.object.identifier.guid))
+ obj = obj.next_object
+
+ return guid_list
+
+ def _ctr6_debug(self, ctr6):
+ """
+ Displays basic info contained in a DsGetNCChanges response.
+ Having this debug code allows us to see the difference in behaviour
+ between Samba and Windows easier. Turn on the self._debug flag to see it.
+ """
+
+ if self._debug:
+ print("------------ recvd CTR6 -------------")
+
+ next_object = ctr6.first_object
+ for i in range(0, ctr6.object_count):
+ print("Obj %d: %s %s" % (i, next_object.object.identifier.dn[:25],
+ next_object.object.identifier.guid))
+ next_object = next_object.next_object
+
+ print("Linked Attributes: %d" % ctr6.linked_attributes_count)
+ for lidx in range(0, ctr6.linked_attributes_count):
+ l = ctr6.linked_attributes[lidx]
+ try:
+ target = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+ l.value.blob)
+ except:
+ target = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3Binary,
+ l.value.blob)
+
+ print("Link Tgt %s... <-- Src %s"
+ % (target.dn[:25], l.identifier.guid))
+ state = "Del"
+ if l.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE:
+ state = "Act"
+ print(" v%u %s changed %u" % (l.meta_data.version, state,
+ l.meta_data.originating_change_time))
+
+ print("HWM: %d" % (ctr6.new_highwatermark.highest_usn))
+ print("Tmp HWM: %d" % (ctr6.new_highwatermark.tmp_highest_usn))
+ print("More data: %d" % (ctr6.more_data))
+
+ def _get_replication(self, replica_flags,
+ drs_error=drsuapi.DRSUAPI_EXOP_ERR_NONE, drs=None, drs_handle=None,
+ highwatermark=None, uptodateness_vector=None,
+ more_flags=0, max_objects=133, exop=0,
+ dest_dsa=drsuapi.DRSUAPI_DS_BIND_GUID_W2K3,
+ source_dsa=None, invocation_id=None, nc_dn_str=None):
+ """
+ Builds a DsGetNCChanges request based on the information provided
+ and returns the response received from the DC.
+ """
+ if source_dsa is None:
+ source_dsa = self.test_ldb_dc.get_ntds_GUID()
+ if invocation_id is None:
+ invocation_id = self.test_ldb_dc.get_invocation_id()
+ if nc_dn_str is None:
+ nc_dn_str = self.test_ldb_dc.domain_dn()
+
+ if highwatermark is None:
+ if self.default_hwm is None:
+ (highwatermark, _) = self._get_highest_hwm_utdv(self.test_ldb_dc)
+ else:
+ highwatermark = self.default_hwm
+
+ if drs is None:
+ drs = self.drs
+ if drs_handle is None:
+ drs_handle = self.drs_handle
+
+ req10 = self._getnc_req10(dest_dsa=dest_dsa,
+ invocation_id=invocation_id,
+ nc_dn_str=nc_dn_str,
+ exop=exop,
+ max_objects=max_objects,
+ replica_flags=replica_flags,
+ more_flags=more_flags)
+ req10.highwatermark = highwatermark
+ if uptodateness_vector is not None:
+ uptodateness_vector_v1 = drsuapi.DsReplicaCursorCtrEx()
+ cursors = []
+ for i in range(0, uptodateness_vector.count):
+ c = uptodateness_vector.cursors[i]
+ c1 = drsuapi.DsReplicaCursor()
+ c1.source_dsa_invocation_id = c.source_dsa_invocation_id
+ c1.highest_usn = c.highest_usn
+ cursors.append(c1)
+ uptodateness_vector_v1.count = len(cursors)
+ uptodateness_vector_v1.cursors = cursors
+ req10.uptodateness_vector = uptodateness_vector_v1
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 10, req10)
+ self._ctr6_debug(ctr)
+
+ self.assertEqual(level, 6, "expected level 6 response!")
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(source_dsa))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(invocation_id))
+ self.assertEqual(ctr.extended_ret, drs_error)
+
+ return ctr
+
+ def _check_replication(self, expected_dns, replica_flags, expected_links=None,
+ drs_error=drsuapi.DRSUAPI_EXOP_ERR_NONE, drs=None, drs_handle=None,
+ highwatermark=None, uptodateness_vector=None,
+ more_flags=0, more_data=False,
+ dn_ordered=True, links_ordered=True,
+ max_objects=133, exop=0,
+ dest_dsa=drsuapi.DRSUAPI_DS_BIND_GUID_W2K3,
+ source_dsa=None, invocation_id=None, nc_dn_str=None,
+ nc_object_count=0, nc_linked_attributes_count=0):
+ """
+ Makes sure that replication returns the specific error given.
+ """
+ if expected_links is None:
+ expected_links = []
+
+ # send a DsGetNCChanges to the DC
+ ctr6 = self._get_replication(replica_flags,
+ drs_error, drs, drs_handle,
+ highwatermark, uptodateness_vector,
+ more_flags, max_objects, exop, dest_dsa,
+ source_dsa, invocation_id, nc_dn_str)
+
+ # check the response is what we expect
+ self._check_ctr6(ctr6, expected_dns, expected_links,
+ nc_object_count=nc_object_count, more_data=more_data,
+ dn_ordered=dn_ordered)
+ return (ctr6.new_highwatermark, ctr6.uptodateness_vector)
+
+ def _get_ctr6_dn_list(self, ctr6):
+ """
+ Returns the DNs contained in a DsGetNCChanges response.
+ """
+ dn_list = []
+ next_object = ctr6.first_object
+ for i in range(0, ctr6.object_count):
+ dn_list.append(next_object.object.identifier.dn)
+ next_object = next_object.next_object
+ self.assertEqual(next_object, None)
+
+ return dn_list
+
+ def _check_ctr6(self, ctr6, expected_dns=None, expected_links=None,
+ dn_ordered=True, links_ordered=True,
+ more_data=False, nc_object_count=0,
+ nc_linked_attributes_count=0, drs_error=0):
+ """
+ Check that a ctr6 matches the specified parameters.
+ """
+ if expected_dns is None:
+ expected_dns = []
+
+ if expected_links is None:
+ expected_links = []
+
+ ctr6_raw_dns = self._get_ctr6_dn_list(ctr6)
+
+ # filter out changes to the RID Set objects, as these can happen
+ # intermittently and mess up the test assertions
+ ctr6_dns = []
+ for dn in ctr6_raw_dns:
+ if "CN=RID Set," in dn or "CN=RID Manager$," in dn:
+ print("Removing {0} from GetNCChanges reply".format(dn))
+ else:
+ ctr6_dns.append(dn)
+
+ self.assertEqual(len(ctr6_dns), len(expected_dns),
+ "Received unexpected objects (%s)" % ctr6_dns)
+ self.assertEqual(ctr6.object_count, len(ctr6_raw_dns))
+ self.assertEqual(ctr6.linked_attributes_count, len(expected_links))
+ self.assertEqual(ctr6.more_data, more_data)
+ self.assertEqual(ctr6.nc_object_count, nc_object_count)
+ self.assertEqual(ctr6.nc_linked_attributes_count, nc_linked_attributes_count)
+ self.assertEqual(ctr6.drs_error[0], drs_error)
+
+ i = 0
+ for dn in expected_dns:
+ # Expect them back in the exact same order as specified.
+ if dn_ordered:
+ self.assertNotEqual(ctr6_dns[i], None)
+ self.assertEqual(ctr6_dns[i], dn)
+ i = i + 1
+ # Don't care what order
+ else:
+ self.assertTrue(dn in ctr6_dns, "Couldn't find DN '%s' anywhere in ctr6 response." % dn)
+
+ # Extract the links from the response
+ ctr6_links = self._get_ctr6_links(ctr6)
+ expected_links.sort()
+
+ lidx = 0
+ for el in expected_links:
+ if links_ordered:
+ self.assertEqual(el, ctr6_links[lidx])
+ lidx += 1
+ else:
+ self.assertTrue(el in ctr6_links, "Couldn't find link '%s' anywhere in ctr6 response." % el)
+
+ def _exop_req8(self, dest_dsa, invocation_id, nc_dn_str, exop,
+ replica_flags=0, max_objects=0, partial_attribute_set=None,
+ partial_attribute_set_ex=None, mapping_ctr=None, nc_guid=None):
+ req8 = drsuapi.DsGetNCChangesRequest8()
+
+ req8.destination_dsa_guid = misc.GUID(dest_dsa) if dest_dsa else misc.GUID()
+ req8.source_dsa_invocation_id = misc.GUID(invocation_id)
+ req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
+ req8.naming_context.dn = str(nc_dn_str)
+ if nc_guid is not None:
+ req8.naming_context.guid = nc_guid
+ req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
+ req8.highwatermark.tmp_highest_usn = 0
+ req8.highwatermark.reserved_usn = 0
+ req8.highwatermark.highest_usn = 0
+ req8.uptodateness_vector = None
+ req8.replica_flags = replica_flags
+ req8.max_object_count = max_objects
+ req8.max_ndr_size = 402116
+ req8.extended_op = exop
+ req8.fsmo_info = 0
+ req8.partial_attribute_set = partial_attribute_set
+ req8.partial_attribute_set_ex = partial_attribute_set_ex
+ if mapping_ctr:
+ req8.mapping_ctr = mapping_ctr
+ else:
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+
+ return req8
+
+ def _getnc_req10(self, dest_dsa, invocation_id, nc_dn_str, exop,
+ replica_flags=0, max_objects=0, partial_attribute_set=None,
+ partial_attribute_set_ex=None, mapping_ctr=None,
+ more_flags=0, nc_guid=None):
+ req10 = drsuapi.DsGetNCChangesRequest10()
+
+ req10.destination_dsa_guid = misc.GUID(dest_dsa) if dest_dsa else misc.GUID()
+ req10.source_dsa_invocation_id = misc.GUID(invocation_id)
+ req10.naming_context = drsuapi.DsReplicaObjectIdentifier()
+ req10.naming_context.dn = str(nc_dn_str)
+ if nc_guid is not None:
+ req10.naming_context.guid = nc_guid
+ req10.highwatermark = drsuapi.DsReplicaHighWaterMark()
+ req10.highwatermark.tmp_highest_usn = 0
+ req10.highwatermark.reserved_usn = 0
+ req10.highwatermark.highest_usn = 0
+ req10.uptodateness_vector = None
+ req10.replica_flags = replica_flags
+ req10.max_object_count = max_objects
+ req10.max_ndr_size = 402116
+ req10.extended_op = exop
+ req10.fsmo_info = 0
+ req10.partial_attribute_set = partial_attribute_set
+ req10.partial_attribute_set_ex = partial_attribute_set_ex
+ if mapping_ctr:
+ req10.mapping_ctr = mapping_ctr
+ else:
+ req10.mapping_ctr.num_mappings = 0
+ req10.mapping_ctr.mappings = None
+ req10.more_flags = more_flags
+
+ return req10
+
+ def _ds_bind(self, server_name, creds=None, ip=None):
+ if ip is None:
+ binding_str = f"ncacn_ip_tcp:{server_name}[seal]"
+ else:
+ binding_str = f"ncacn_ip_tcp:{ip}[seal,target_hostname={server_name}]"
+
+ if creds is None:
+ creds = self.get_credentials()
+ drs = drsuapi.drsuapi(binding_str, self.get_loadparm(), creds)
+ (drs_handle, supported_extensions) = drs_DsBind(drs)
+ return (drs, drs_handle)
+
+ def get_partial_attribute_set(self, attids=None):
+ if attids is None:
+ attids = [drsuapi.DRSUAPI_ATTID_objectClass]
+ partial_attribute_set = drsuapi.DsPartialAttributeSet()
+ partial_attribute_set.attids = attids
+ partial_attribute_set.num_attids = len(attids)
+ return partial_attribute_set
+
+
+class AbstractLink:
+ def __init__(self, attid, flags, identifier, targetGUID,
+ targetDN=""):
+ self.attid = attid
+ self.flags = flags
+ self.identifier = str(identifier)
+ self.selfGUID_blob = ndr_pack(identifier)
+ self.targetGUID = str(targetGUID)
+ self.targetGUID_blob = ndr_pack(targetGUID)
+ self.targetDN = targetDN
+
+ def __repr__(self):
+ return "AbstractLink(0x%08x, 0x%08x, %s, %s)" % (
+ self.attid, self.flags, self.identifier, self.targetGUID)
+
+ def __internal_cmp__(self, other, verbose=False):
+ """See CompareLinks() in MS-DRSR section 4.1.10.5.17"""
+ if not isinstance(other, AbstractLink):
+ if verbose:
+ print("AbstractLink.__internal_cmp__(%r, %r) => wrong type" % (self, other))
+ return NotImplemented
+
+ c = cmp(self.selfGUID_blob, other.selfGUID_blob)
+ if c != 0:
+ if verbose:
+ print("AbstractLink.__internal_cmp__(%r, %r) => %d different identifier" % (self, other, c))
+ return c
+
+ c = other.attid - self.attid
+ if c != 0:
+ if verbose:
+ print("AbstractLink.__internal_cmp__(%r, %r) => %d different attid" % (self, other, c))
+ return c
+
+ self_active = self.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+ other_active = other.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+
+ c = self_active - other_active
+ if c != 0:
+ if verbose:
+ print("AbstractLink.__internal_cmp__(%r, %r) => %d different FLAG_ACTIVE" % (self, other, c))
+ return c
+
+ c = cmp(self.targetGUID_blob, other.targetGUID_blob)
+ if c != 0:
+ if verbose:
+ print("AbstractLink.__internal_cmp__(%r, %r) => %d different target" % (self, other, c))
+ return c
+
+ c = self.flags - other.flags
+ if c != 0:
+ if verbose:
+ print("AbstractLink.__internal_cmp__(%r, %r) => %d different flags" % (self, other, c))
+ return c
+
+ return 0
+
+ def __lt__(self, other):
+ c = self.__internal_cmp__(other)
+ if c == NotImplemented:
+ return NotImplemented
+ if c < 0:
+ return True
+ return False
+
+ def __le__(self, other):
+ c = self.__internal_cmp__(other)
+ if c == NotImplemented:
+ return NotImplemented
+ if c <= 0:
+ return True
+ return False
+
+ def __eq__(self, other):
+ c = self.__internal_cmp__(other, verbose=True)
+ if c == NotImplemented:
+ return NotImplemented
+ if c == 0:
+ return True
+ return False
+
+ def __ne__(self, other):
+ c = self.__internal_cmp__(other)
+ if c == NotImplemented:
+ return NotImplemented
+ if c != 0:
+ return True
+ return False
+
+ def __gt__(self, other):
+ c = self.__internal_cmp__(other)
+ if c == NotImplemented:
+ return NotImplemented
+ if c > 0:
+ return True
+ return False
+
+ def __ge__(self, other):
+ c = self.__internal_cmp__(other)
+ if c == NotImplemented:
+ return NotImplemented
+ if c >= 0:
+ return True
+ return False
+
+ def __hash__(self):
+ return hash((self.attid, self.flags, self.identifier, self.targetGUID))
diff --git a/source4/torture/drs/python/fsmo.py b/source4/torture/drs/python/fsmo.py
new file mode 100644
index 0000000..55805b9
--- /dev/null
+++ b/source4/torture/drs/python/fsmo.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Anatoliy Atanasov <anatoliy.atanasov@postpath.com> 2010
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN fsmo -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import sys
+import time
+import os
+
+sys.path.insert(0, "bin/python")
+
+from ldb import SCOPE_BASE
+
+import drs_base
+
+
+class DrsFsmoTestCase(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(DrsFsmoTestCase, self).setUp()
+
+ # we have to wait for the replication before we make the check
+ self.fsmo_wait_max_time = 20
+ self.fsmo_wait_sleep_time = 0.2
+
+ # cache some of RootDSE props
+ self.dsServiceName_dc1 = self.info_dc1["dsServiceName"][0]
+ self.dsServiceName_dc2 = self.info_dc2["dsServiceName"][0]
+ self.infrastructure_dn = "CN=Infrastructure," + self.domain_dn
+ self.naming_dn = "CN=Partitions," + self.config_dn
+ self.rid_dn = "CN=RID Manager$,CN=System," + self.domain_dn
+ self.domain_dns_dn = (
+ "CN=Infrastructure,DC=DomainDnsZones, %s" % self.domain_dn )
+ self.forest_dns_dn = (
+ "CN=Infrastructure,DC=ForestDnsZones, %s" % self.domain_dn )
+
+ def tearDown(self):
+ super(DrsFsmoTestCase, self).tearDown()
+
+ def _net_fsmo_role_transfer(self, DC, role, noop=False):
+ # make command line credentials string
+ ccache_name = self.get_creds_ccache_name()
+ cmd_line_auth = "--use-krb5-ccache=%s" % ccache_name
+ (result, out, err) = self.runsubcmd("fsmo", "transfer",
+ "--role=%s" % role,
+ "-H", "ldap://%s:389" % DC,
+ cmd_line_auth)
+
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+ if not noop:
+ self.assertTrue("FSMO transfer of '%s' role successful" % role in out)
+ else:
+ self.assertTrue("This DC already has the '%s' FSMO role" % role in out)
+
+ def _wait_for_role_transfer(self, ldb_dc, role_dn, master):
+ """Wait for role transfer for certain amount of time
+
+ :return: (Result=True|False, CurrentMasterDnsName) tuple
+ """
+ cur_master = ''
+ retries = int(self.fsmo_wait_max_time / self.fsmo_wait_sleep_time) + 1
+ for i in range(0, retries):
+ # check if master has been transferred
+ res = ldb_dc.search(role_dn,
+ scope=SCOPE_BASE, attrs=["fSMORoleOwner"])
+ assert len(res) == 1, "Only one fSMORoleOwner value expected!"
+ cur_master = res[0]["fSMORoleOwner"][0]
+ if master == cur_master:
+ return (True, cur_master)
+ # skip last sleep, if no need to wait anymore
+ if i != (retries - 1):
+ # wait a little bit before next retry
+ time.sleep(self.fsmo_wait_sleep_time)
+ return (False, cur_master)
+
+ def _role_transfer(self, role, role_dn):
+ """Triggers transfer of role from DC1 to DC2
+ and vice versa so the role goes back to the original dc"""
+ # dc2 gets the role from dc1
+ print("Testing for %s role transfer from %s to %s" % (role, self.dnsname_dc1, self.dnsname_dc2))
+
+ self._net_fsmo_role_transfer(DC=self.dnsname_dc2, role=role)
+ # check if the role is transferred
+ (res, master) = self._wait_for_role_transfer(ldb_dc=self.ldb_dc2,
+ role_dn=role_dn,
+ master=self.dsServiceName_dc2)
+ self.assertTrue(res,
+ "Transferring %s role to %s has failed, master is: %s!" % (role, self.dsServiceName_dc2, master))
+
+ # dc1 gets back the role from dc2
+ print("Testing for %s role transfer from %s to %s" % (role, self.dnsname_dc2, self.dnsname_dc1))
+ self._net_fsmo_role_transfer(DC=self.dnsname_dc1, role=role)
+ # check if the role is transferred
+ (res, master) = self._wait_for_role_transfer(ldb_dc=self.ldb_dc1,
+ role_dn=role_dn,
+ master=self.dsServiceName_dc1)
+ self.assertTrue(res,
+ "Transferring %s role to %s has failed, master is: %s!" % (role, self.dsServiceName_dc1, master))
+
+ # dc1 keeps the role
+ print("Testing for no-op %s role transfer from %s to %s" % (role, self.dnsname_dc2, self.dnsname_dc1))
+ self._net_fsmo_role_transfer(DC=self.dnsname_dc1, role=role, noop=True)
+ # check if the role is transferred
+ (res, master) = self._wait_for_role_transfer(ldb_dc=self.ldb_dc1,
+ role_dn=role_dn,
+ master=self.dsServiceName_dc1)
+ self.assertTrue(res,
+ "Transferring %s role to %s has failed, master is: %s!" % (role, self.dsServiceName_dc1, master))
+
+ def test_SchemaMasterTransfer(self):
+ self._role_transfer(role="schema", role_dn=self.schema_dn)
+
+ def test_InfrastructureMasterTransfer(self):
+ self._role_transfer(role="infrastructure", role_dn=self.infrastructure_dn)
+
+ def test_PDCMasterTransfer(self):
+ self._role_transfer(role="pdc", role_dn=self.domain_dn)
+
+ def test_RIDMasterTransfer(self):
+ self._role_transfer(role="rid", role_dn=self.rid_dn)
+
+ def test_NamingMasterTransfer(self):
+ self._role_transfer(role="naming", role_dn=self.naming_dn)
+
+ def test_DomainDnsZonesMasterTransfer(self):
+ self._role_transfer(role="domaindns", role_dn=self.domain_dns_dn)
+
+ def test_ForestDnsZonesMasterTransfer(self):
+ self._role_transfer(role="forestdns", role_dn=self.forest_dns_dn)
diff --git a/source4/torture/drs/python/getnc_exop.py b/source4/torture/drs/python/getnc_exop.py
new file mode 100644
index 0000000..0f12d9b
--- /dev/null
+++ b/source4/torture/drs/python/getnc_exop.py
@@ -0,0 +1,1304 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests various schema replication scenarios
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN getnc_exop -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import random
+
+import drs_base
+from drs_base import AbstractLink
+
+import samba.tests
+from samba import werror, WERRORError
+
+import ldb
+from ldb import SCOPE_BASE
+
+from samba.dcerpc import drsuapi, misc, drsblobs
+from samba.drs_utils import drs_DsBind
+from samba.ndr import ndr_unpack, ndr_pack
+from functools import cmp_to_key
+from samba.common import cmp
+
+
+def _linked_attribute_compare(la1, la2):
+ """See CompareLinks() in MS-DRSR section 4.1.10.5.17"""
+ la1, la1_target = la1
+ la2, la2_target = la2
+
+ # Ascending host object GUID
+ c = cmp(ndr_pack(la1.identifier.guid), ndr_pack(la2.identifier.guid))
+ if c != 0:
+ return c
+
+ # Ascending attribute ID
+ if la1.attid != la2.attid:
+ return -1 if la1.attid < la2.attid else 1
+
+ la1_active = la1.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+ la2_active = la2.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+
+ # Ascending 'is present'
+ if la1_active != la2_active:
+ return 1 if la1_active else -1
+
+ # Ascending target object GUID
+ return cmp(ndr_pack(la1_target), ndr_pack(la2_target))
+
+
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
+ """Intended as a semi-black box test case for DsGetNCChanges
+ implementation for extended operations. It should be testing
+ how DsGetNCChanges handles different input params (mostly invalid).
+ Final goal is to make DsGetNCChanges as binary compatible to
+ Windows implementation as possible"""
+
+ def setUp(self):
+ super(DrsReplicaSyncTestCase, self).setUp()
+ self.base_dn = self.ldb_dc1.get_default_basedn()
+ self.ou = "OU=test_getncchanges%d,%s" % (random.randint(0, 4294967295),
+ self.base_dn)
+ self.ldb_dc1.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+ (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+ (self.default_hwm, self.default_utdv) = self._get_highest_hwm_utdv(self.ldb_dc1)
+
+ def tearDown(self):
+ try:
+ self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+ except ldb.LdbError as e:
+ (enum, string) = e.args
+ if enum == ldb.ERR_NO_SUCH_OBJECT:
+ pass
+ super(DrsReplicaSyncTestCase, self).tearDown()
+
+ def _determine_fSMORoleOwner(self, fsmo_obj_dn):
+ """Returns (owner, not_owner) pair where:
+ owner: dns name for FSMO owner
+ not_owner: dns name for DC not owning the FSMO"""
+ # collect info to return later
+ fsmo_info_1 = {"dns_name": self.dnsname_dc1,
+ "invocation_id": self.ldb_dc1.get_invocation_id(),
+ "ntds_guid": self.ldb_dc1.get_ntds_GUID(),
+ "server_dn": self.ldb_dc1.get_serverName()}
+ fsmo_info_2 = {"dns_name": self.dnsname_dc2,
+ "invocation_id": self.ldb_dc2.get_invocation_id(),
+ "ntds_guid": self.ldb_dc2.get_ntds_GUID(),
+ "server_dn": self.ldb_dc2.get_serverName()}
+
+ msgs = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=fsmo_info_1["server_dn"], attrs=["serverReference"])
+ fsmo_info_1["server_acct_dn"] = ldb.Dn(self.ldb_dc1, msgs[0]["serverReference"][0].decode('utf8'))
+ fsmo_info_1["rid_set_dn"] = ldb.Dn(self.ldb_dc1, "CN=RID Set") + fsmo_info_1["server_acct_dn"]
+
+ msgs = self.ldb_dc2.search(scope=ldb.SCOPE_BASE, base=fsmo_info_2["server_dn"], attrs=["serverReference"])
+ fsmo_info_2["server_acct_dn"] = ldb.Dn(self.ldb_dc2, msgs[0]["serverReference"][0].decode('utf8'))
+ fsmo_info_2["rid_set_dn"] = ldb.Dn(self.ldb_dc2, "CN=RID Set") + fsmo_info_2["server_acct_dn"]
+
+ # determine the owner dc
+ res = self.ldb_dc1.search(fsmo_obj_dn,
+ scope=SCOPE_BASE, attrs=["fSMORoleOwner"])
+ assert len(res) == 1, "Only one fSMORoleOwner value expected for %s!" % fsmo_obj_dn
+ fsmo_owner = res[0]["fSMORoleOwner"][0]
+ if fsmo_owner == self.info_dc1["dsServiceName"][0]:
+ return (fsmo_info_1, fsmo_info_2)
+ return (fsmo_info_2, fsmo_info_1)
+
+ def _check_exop_failed(self, ctr6, expected_failure):
+ self.assertEqual(ctr6.extended_ret, expected_failure)
+ #self.assertEqual(ctr6.object_count, 0)
+ #self.assertEqual(ctr6.first_object, None)
+ self.assertEqual(ctr6.more_data, False)
+ self.assertEqual(ctr6.nc_object_count, 0)
+ self.assertEqual(ctr6.nc_linked_attributes_count, 0)
+ self.assertEqual(ctr6.linked_attributes_count, 0)
+ self.assertEqual(ctr6.linked_attributes, [])
+ self.assertEqual(ctr6.drs_error[0], 0)
+
+ def test_do_single_repl(self):
+ """
+ Make sure that DRSUAPI_EXOP_REPL_OBJ never replicates more than
+ one object, even when we use DRS_GET_ANC/GET_TGT.
+ """
+
+ ou1 = "OU=get_anc1,%s" % self.ou
+ self.ldb_dc1.add({
+ "dn": ou1,
+ "objectclass": "organizationalUnit"
+ })
+ ou1_id = self._get_identifier(self.ldb_dc1, ou1)
+ ou2 = "OU=get_anc2,%s" % ou1
+ self.ldb_dc1.add({
+ "dn": ou2,
+ "objectclass": "organizationalUnit"
+ })
+ ou2_id = self._get_identifier(self.ldb_dc1, ou2)
+ dc3 = "CN=test_anc_dc_%u,%s" % (random.randint(0, 4294967295), ou2)
+ self.ldb_dc1.add({
+ "dn": dc3,
+ "objectclass": "computer",
+ "userAccountControl": "%d" % (samba.dsdb.UF_ACCOUNTDISABLE | samba.dsdb.UF_SERVER_TRUST_ACCOUNT)
+ })
+ dc3_id = self._get_identifier(self.ldb_dc1, dc3)
+
+ # Add some linked attributes (for checking GET_TGT behaviour)
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc2, ou1)
+ m["managedBy"] = ldb.MessageElement(ou2, ldb.FLAG_MOD_ADD, "managedBy")
+ self.ldb_dc1.modify(m)
+ ou1_link = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ ou1_id.guid, ou2_id.guid)
+
+ m.dn = ldb.Dn(self.ldb_dc2, dc3)
+ m["managedBy"] = ldb.MessageElement(ou2, ldb.FLAG_MOD_ADD, "managedBy")
+ self.ldb_dc1.modify(m)
+ dc3_link = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ dc3_id.guid, ou2_id.guid)
+
+ req = self._getnc_req10(dest_dsa=None,
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=ou1,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req)
+ self._check_ctr6(ctr, [ou1], expected_links=[ou1_link])
+
+ # DRSUAPI_DRS_WRIT_REP means that we should only replicate the dn we give (dc3).
+ # DRSUAPI_DRS_GET_ANC means that we should also replicate its ancestors, but
+ # Windows doesn't do this if we use both.
+ req = self._getnc_req10(dest_dsa=None,
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=dc3,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req)
+ self._check_ctr6(ctr, [dc3], expected_links=[dc3_link])
+
+ # Even though the ancestor of ou2 (ou1) has changed since last hwm, and we're
+ # sending DRSUAPI_DRS_GET_ANC, the expected response is that it will only try
+ # and replicate the single object still.
+ req = self._getnc_req10(dest_dsa=None,
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=ou2,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ replica_flags=drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req)
+ self._check_ctr6(ctr, [ou2])
+
+ def test_do_full_repl_on_ou(self):
+ """
+ Make sure that a full replication on a not-an-nc fails with
+ the right error code
+ """
+
+ non_nc_ou = "OU=not-an-NC,%s" % self.ou
+ self.ldb_dc1.add({
+ "dn": non_nc_ou,
+ "objectclass": "organizationalUnit"
+ })
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=non_nc_ou,
+ exop=drsuapi.DRSUAPI_EXOP_NONE,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ try:
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 8, req8)
+ self.fail("Expected DsGetNCChanges to fail with WERR_DS_CANT_FIND_EXPECTED_NC")
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.assertEqual(enum, werror.WERR_DS_CANT_FIND_EXPECTED_NC)
+
+ def test_InvalidNC_DummyDN_InvalidGUID_REPL_OBJ(self):
+ """Test single object replication on a totally invalid GUID fails with the right error code"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str="DummyDN",
+ nc_guid=misc.GUID("c2d2f745-1610-4e93-964b-d4ba73eb32f8"),
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ (drs, drs_handle) = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.assertEqual(enum, werror.WERR_DS_DRA_BAD_DN)
+
+ def test_InvalidNC_DummyDN_InvalidGUID_REPL_SECRET(self):
+ """Test single object replication on a totally invalid GUID fails with the right error code"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str="DummyDN",
+ nc_guid=misc.GUID("c2d2f745-1610-4e93-964b-d4ba73eb32f8"),
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ (drs, drs_handle) = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.assertEqual(enum, werror.WERR_DS_DRA_BAD_DN)
+
+ def test_InvalidNC_DummyDN_InvalidGUID_RID_ALLOC(self):
+ """Test RID Allocation on a totally invalid GUID fails with the right error code"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str="DummyDN",
+ nc_guid=misc.GUID("c2d2f745-1610-4e93-964b-d4ba73eb32f8"),
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_RID_ALLOC)
+
+ (drs, drs_handle) = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.assertEqual(enum, werror.WERR_DS_DRA_BAD_NC)
+
+ def test_valid_GUID_only_REPL_OBJ(self):
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ res = self.ldb_dc1.search(base=self.ou, scope=SCOPE_BASE,
+ attrs=["objectGUID"])
+
+ guid = misc.GUID(res[0]["objectGUID"][0])
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str="",
+ nc_guid=guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.fail(f"Failed to call GetNCChanges with EXOP_REPL_OBJ and a GUID: {estr}")
+
+ self.assertEqual(ctr.first_object.object.identifier.guid, guid)
+
+ def test_DummyDN_valid_GUID_REPL_OBJ(self):
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ res = self.ldb_dc1.search(base=self.ou, scope=SCOPE_BASE,
+ attrs=["objectGUID"])
+
+ guid = misc.GUID(res[0]["objectGUID"][0])
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str="DummyDN",
+ nc_guid=guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.fail(f"Failed to call GetNCChanges with EXOP_REPL_OBJ, DummyDN and a GUID: {estr}")
+
+ self.assertEqual(ctr.first_object.object.identifier.guid, guid)
+
+ def test_DummyDN_valid_GUID_REPL_SECRET(self):
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ res = self.ldb_dc1.search(base=self.ou, scope=SCOPE_BASE,
+ attrs=["objectGUID"])
+
+ guid = misc.GUID(res[0]["objectGUID"][0])
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str="DummyDN",
+ nc_guid=guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET)
+
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+
+ # We expect to get as far as failing on the missing dest_dsa
+ self.assertEqual(enum, werror.WERR_DS_DRA_DB_ERROR)
+
+ def test_link_utdv_hwm(self):
+ """Test verify the DRS_GET_ANC behavior."""
+
+ ou1 = "OU=get_anc1,%s" % self.ou
+ self.ldb_dc1.add({
+ "dn": ou1,
+ "objectclass": "organizationalUnit"
+ })
+ ou1_id = self._get_identifier(self.ldb_dc1, ou1)
+ ou2 = "OU=get_anc2,%s" % ou1
+ self.ldb_dc1.add({
+ "dn": ou2,
+ "objectclass": "organizationalUnit"
+ })
+ ou2_id = self._get_identifier(self.ldb_dc1, ou2)
+ dc3 = "CN=test_anc_dc_%u,%s" % (random.randint(0, 4294967295), ou2)
+ self.ldb_dc1.add({
+ "dn": dc3,
+ "objectclass": "computer",
+ "userAccountControl": "%d" % (samba.dsdb.UF_ACCOUNTDISABLE | samba.dsdb.UF_SERVER_TRUST_ACCOUNT)
+ })
+ dc3_id = self._get_identifier(self.ldb_dc1, dc3)
+
+ (hwm1, utdv1) = self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
+
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, ou1)
+ m["displayName"] = ldb.MessageElement("OU1", ldb.FLAG_MOD_ADD, "displayName")
+ self.ldb_dc1.modify(m)
+
+ (hwm2, utdv2) = self._check_replication([ou2, dc3, ou1],
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
+
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([ou1],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ highwatermark=hwm1)
+
+ self._check_replication([ou1],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ highwatermark=hwm1)
+
+ self._check_replication([ou1],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ uptodateness_vector=utdv1)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, ou2)
+ m["displayName"] = ldb.MessageElement("OU2", ldb.FLAG_MOD_ADD, "displayName")
+ self.ldb_dc1.modify(m)
+
+ (hwm3, utdv3) = self._check_replication([dc3, ou1, ou2],
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
+
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([ou1, ou2],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ highwatermark=hwm1)
+
+ self._check_replication([ou1, ou2],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ highwatermark=hwm1)
+
+ self._check_replication([ou1, ou2],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ uptodateness_vector=utdv1)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, self.ou)
+ m["displayName"] = ldb.MessageElement("OU", ldb.FLAG_MOD_ADD, "displayName")
+ self.ldb_dc1.modify(m)
+
+ (hwm4, utdv4) = self._check_replication([dc3, ou1, ou2, self.ou],
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ self._check_replication([self.ou, ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
+
+ self._check_replication([self.ou, ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([self.ou, ou2],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ uptodateness_vector=utdv2)
+
+ cn3 = "CN=get_anc3,%s" % ou2
+ self.ldb_dc1.add({
+ "dn": cn3,
+ "objectclass": "container",
+ })
+
+ (hwm5, utdv5) = self._check_replication([dc3, ou1, ou2, self.ou, cn3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ self._check_replication([self.ou, ou1, ou2, dc3, cn3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
+
+ self._check_replication([self.ou, ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, ou2)
+ m["managedBy"] = ldb.MessageElement(dc3, ldb.FLAG_MOD_ADD, "managedBy")
+ self.ldb_dc1.modify(m)
+ ou2_managedBy_dc3 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ ou2_id.guid, dc3_id.guid)
+
+ (hwm6, utdv6) = self._check_replication([dc3, ou1, self.ou, cn3, ou2],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ expected_links=[ou2_managedBy_dc3])
+
+ # Can fail against Windows due to equal precedence of dc3, cn3
+ self._check_replication([self.ou, ou1, ou2, dc3, cn3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[ou2_managedBy_dc3])
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
+
+ self._check_replication([self.ou, ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ uptodateness_vector=utdv5,
+ expected_links=[ou2_managedBy_dc3])
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ uptodateness_vector=utdv5)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ uptodateness_vector=utdv5)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, dc3)
+ m["managedBy"] = ldb.MessageElement(ou1, ldb.FLAG_MOD_ADD, "managedBy")
+ self.ldb_dc1.modify(m)
+ dc3_managedBy_ou1 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ dc3_id.guid, ou1_id.guid)
+
+ (hwm7, utdv7) = self._check_replication([ou1, self.ou, cn3, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ expected_links=[ou2_managedBy_dc3, dc3_managedBy_ou1])
+
+ # Can fail against Windows due to equal precedence of dc3, cn3
+ # self._check_replication([self.ou,ou1,ou2,dc3,cn3],
+ # drsuapi.DRSUAPI_DRS_WRIT_REP|
+ # drsuapi.DRSUAPI_DRS_GET_ANC,
+ # expected_links=[ou2_managedBy_dc3,dc3_managedBy_ou1])
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ expected_links=[dc3_managedBy_ou1])
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ expected_links=[dc3_managedBy_ou1])
+
+ self._check_replication([self.ou, ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[dc3_managedBy_ou1])
+
+ # GET_TGT seems to override DRS_CRITICAL_ONLY and also returns any
+ # object(s) that relate to the linked attributes (similar to GET_ANC)
+ self._check_replication([ou1, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT,
+ expected_links=[dc3_managedBy_ou1], dn_ordered=False)
+
+ # Change DC3's managedBy to OU2 instead of OU1
+ # Note that the OU1 managedBy linked attribute will still exist as
+ # a tombstone object (and so will be returned in the replication still)
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, dc3)
+ m["managedBy"] = ldb.MessageElement(ou2, ldb.FLAG_MOD_REPLACE, "managedBy")
+ self.ldb_dc1.modify(m)
+ dc3_managedBy_ou1.flags &= ~drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+ dc3_managedBy_ou2 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ dc3_id.guid, ou2_id.guid)
+
+ (hwm8, utdv8) = self._check_replication([ou1, self.ou, cn3, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ expected_links=[ou2_managedBy_dc3, dc3_managedBy_ou1, dc3_managedBy_ou2])
+
+ # Can fail against Windows due to equal precedence of dc3, cn3
+ # self._check_replication([self.ou,ou1,ou2,dc3,cn3],
+ # drsuapi.DRSUAPI_DRS_WRIT_REP|
+ # drsuapi.DRSUAPI_DRS_GET_ANC,
+ # expected_links=[ou2_managedBy_dc3,dc3_managedBy_ou1,dc3_managedBy_ou2])
+
+ self._check_replication([dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2])
+
+ self._check_replication([self.ou, ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2])
+
+ # GET_TGT will also return any DNs referenced by the linked attributes
+ # (including the Tombstone attribute)
+ self._check_replication([ou1, ou2, dc3],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2], dn_ordered=False)
+
+ # Use the highwater-mark prior to changing ManagedBy - this should
+ # only return the old/Tombstone and new linked attributes (we already
+ # know all the DNs)
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ highwatermark=hwm7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ highwatermark=hwm7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ highwatermark=hwm7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ highwatermark=hwm7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ highwatermark=hwm7)
+
+ # Repeat the above set of tests using the uptodateness_vector
+ # instead of the highwater-mark
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ uptodateness_vector=utdv7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ uptodateness_vector=utdv7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ uptodateness_vector=utdv7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ uptodateness_vector=utdv7)
+
+ self._check_replication([],
+ drsuapi.DRSUAPI_DRS_CRITICAL_ONLY,
+ more_flags=drsuapi.DRSUAPI_DRS_GET_TGT,
+ expected_links=[dc3_managedBy_ou1, dc3_managedBy_ou2],
+ uptodateness_vector=utdv7)
+
+ def test_FSMONotOwner(self):
+ """Test role transfer with against DC not owner of the role"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa=fsmo_owner["ntds_guid"],
+ invocation_id=fsmo_not_owner["invocation_id"],
+ nc_dn_str=fsmo_dn,
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_REQ_ROLE)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_not_owner["dns_name"])
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER)
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_not_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_not_owner["invocation_id"]))
+
+ def test_InvalidDestDSA(self):
+ """Test role transfer with invalid destination DSA guid"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str=fsmo_dn,
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_REQ_ROLE)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_owner["dns_name"])
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_UNKNOWN_CALLER)
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_owner["invocation_id"]))
+
+ def test_InvalidDestDSA_and_GUID(self):
+ """Test role transfer with invalid destination DSA guid"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str="DummyDN",
+ nc_guid=misc.GUID("c2d2f745-1610-4e93-964b-d4ba73eb32f8"),
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_REQ_ROLE)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_owner["dns_name"])
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.fail(f"DsGetNCChanges failed with {estr}")
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_UNKNOWN_CALLER)
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_owner["invocation_id"]))
+
+ def test_InvalidDestDSA_and_GUID_RID_ALLOC(self):
+ """Test role transfer with invalid destination DSA guid"""
+ fsmo_dn = self.ldb_dc1.get_schema_basedn()
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str="DummyDN",
+ nc_guid=misc.GUID("c2d2f745-1610-4e93-964b-d4ba73eb32f8"),
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_RID_ALLOC)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_owner["dns_name"])
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.fail(f"DsGetNCChanges failed with {estr}")
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_UNKNOWN_CALLER)
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_owner["invocation_id"]))
+
+
+class DrsReplicaPrefixMapTestCase(drs_base.DrsBaseTestCase):
+ def setUp(self):
+ super(DrsReplicaPrefixMapTestCase, self).setUp()
+ self.base_dn = self.ldb_dc1.get_default_basedn()
+ self.ou = "ou=pfm_exop%d,%s" % (random.randint(0, 4294967295),
+ self.base_dn)
+ self.ldb_dc1.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+ self.user = "cn=testuser,%s" % self.ou
+ self.ldb_dc1.add({
+ "dn": self.user,
+ "objectclass": "user"})
+
+ def tearDown(self):
+ super(DrsReplicaPrefixMapTestCase, self).tearDown()
+ try:
+ self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+ except ldb.LdbError as e2:
+ (enum, string) = e2.args
+ if enum == ldb.ERR_NO_SUCH_OBJECT:
+ pass
+
+ def test_missing_prefix_map_dsa(self):
+ partial_attribute_set = self.get_partial_attribute_set()
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set)
+
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(ctr.extended_ret, drsuapi.DRSUAPI_EXOP_ERR_SUCCESS)
+ except RuntimeError:
+ self.fail("Missing prefixmap shouldn't have triggered an error")
+
+ def test_invalid_prefix_map_attid(self):
+ # Request for invalid attid
+ partial_attribute_set = self.get_partial_attribute_set([99999])
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ try:
+ pfm = self._samdb_fetch_pfm_and_schi()
+ except KeyError:
+ # On Windows, prefixMap isn't available over LDAP
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ pfm = ctr.mapping_ctr
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ mapping_ctr=pfm)
+
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.fail("Invalid attid (99999) should have triggered an error")
+ except RuntimeError as e3:
+ (ecode, emsg) = e3.args
+ self.assertEqual(ecode, 0x000020E2, "Error code should have been "
+ "WERR_DS_DRA_SCHEMA_MISMATCH")
+
+ def test_secret_prefix_map_attid(self):
+ # Request for a secret attid
+ partial_attribute_set = self.get_partial_attribute_set([drsuapi.DRSUAPI_ATTID_unicodePwd])
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ try:
+ pfm = self._samdb_fetch_pfm_and_schi()
+ except KeyError:
+ # On Windows, prefixMap isn't available over LDAP
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ pfm = ctr.mapping_ctr
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ mapping_ctr=pfm)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_unicodePwd:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the unicodePwd attribute back")
+
+ for i, mapping in enumerate(pfm.mappings):
+ # OID: 2.5.4.*
+ # objectClass: 2.5.4.0
+ if mapping.oid.binary_oid == [85, 4]:
+ idx1 = i
+ # OID: 1.2.840.113556.1.4.*
+ # unicodePwd: 1.2.840.113556.1.4.90
+ elif mapping.oid.binary_oid == [42, 134, 72, 134, 247, 20, 1, 4]:
+ idx2 = i
+
+ (pfm.mappings[idx1].id_prefix,
+ pfm.mappings[idx2].id_prefix) = (pfm.mappings[idx2].id_prefix,
+ pfm.mappings[idx1].id_prefix)
+
+ tmp = pfm.mappings
+ tmp[idx1], tmp[idx2] = tmp[idx2], tmp[idx1]
+ pfm.mappings = tmp
+
+ # 90 for unicodePwd (with new prefix = 0)
+ # 589824, 589827 for objectClass and CN
+ # Use of three ensures sorting is correct
+ partial_attribute_set = self.get_partial_attribute_set([90, 589824, 589827])
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ mapping_ctr=pfm)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_unicodePwd:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the unicodePwd attribute back")
+
+ def test_regular_prefix_map_attid(self):
+ # Request for a regular (non-secret) attid
+ partial_attribute_set = self.get_partial_attribute_set([drsuapi.DRSUAPI_ATTID_name])
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ try:
+ pfm = self._samdb_fetch_pfm_and_schi()
+ except KeyError:
+ # On Windows, prefixMap isn't available over LDAP
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ pfm = ctr.mapping_ctr
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ mapping_ctr=pfm)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_name:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the name attribute back")
+
+ for i, mapping in enumerate(pfm.mappings):
+ # OID: 2.5.4.*
+ # objectClass: 2.5.4.0
+ if mapping.oid.binary_oid == [85, 4]:
+ idx1 = i
+ # OID: 1.2.840.113556.1.4.*
+ # name: 1.2.840.113556.1.4.1
+ elif mapping.oid.binary_oid == [42, 134, 72, 134, 247, 20, 1, 4]:
+ idx2 = i
+
+ (pfm.mappings[idx1].id_prefix,
+ pfm.mappings[idx2].id_prefix) = (pfm.mappings[idx2].id_prefix,
+ pfm.mappings[idx1].id_prefix)
+
+ tmp = pfm.mappings
+ tmp[idx1], tmp[idx2] = tmp[idx2], tmp[idx1]
+ pfm.mappings = tmp
+
+ # 1 for name (with new prefix = 0)
+ partial_attribute_set = self.get_partial_attribute_set([1])
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ mapping_ctr=pfm)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_name:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the name attribute back")
+
+ def test_regular_prefix_map_ex_attid(self):
+ # Request for a regular (non-secret) attid
+ partial_attribute_set = self.get_partial_attribute_set([drsuapi.DRSUAPI_ATTID_name])
+ partial_attribute_set_ex = self.get_partial_attribute_set([drsuapi.DRSUAPI_ATTID_unicodePwd])
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ try:
+ pfm = self._samdb_fetch_pfm_and_schi()
+ except KeyError:
+ # On Windows, prefixMap isn't available over LDAP
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ pfm = ctr.mapping_ctr
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ partial_attribute_set_ex=partial_attribute_set_ex,
+ mapping_ctr=pfm)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_name:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the name attribute back")
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_unicodePwd:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the unicodePwd attribute back")
+
+ for i, mapping in enumerate(pfm.mappings):
+ # OID: 2.5.4.*
+ # objectClass: 2.5.4.0
+ if mapping.oid.binary_oid == [85, 4]:
+ idx1 = i
+ # OID: 1.2.840.113556.1.4.*
+ # name: 1.2.840.113556.1.4.1
+ # unicodePwd: 1.2.840.113556.1.4.90
+ elif mapping.oid.binary_oid == [42, 134, 72, 134, 247, 20, 1, 4]:
+ idx2 = i
+
+ (pfm.mappings[idx1].id_prefix,
+ pfm.mappings[idx2].id_prefix) = (pfm.mappings[idx2].id_prefix,
+ pfm.mappings[idx1].id_prefix)
+
+ tmp = pfm.mappings
+ tmp[idx1], tmp[idx2] = tmp[idx2], tmp[idx1]
+ pfm.mappings = tmp
+
+ # 1 for name (with new prefix = 0)
+ partial_attribute_set = self.get_partial_attribute_set([1])
+ # 90 for unicodePwd (with new prefix = 0)
+ # HOWEVER: Windows doesn't seem to respect incoming maps for PartialAttrSetEx
+ partial_attribute_set_ex = self.get_partial_attribute_set([drsuapi.DRSUAPI_ATTID_unicodePwd])
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.user,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ partial_attribute_set=partial_attribute_set,
+ partial_attribute_set_ex=partial_attribute_set_ex,
+ mapping_ctr=pfm)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_name:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the name attribute back")
+
+ found = False
+ for attr in ctr.first_object.object.attribute_ctr.attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_unicodePwd:
+ found = True
+ break
+
+ self.assertTrue(found, "Ensure we get the unicodePwd attribute back")
+
+ def _samdb_fetch_pfm_and_schi(self):
+ """Fetch prefixMap and schemaInfo stored in SamDB using LDB connection"""
+ samdb = self.ldb_dc1
+ res = samdb.search(base=samdb.get_schema_basedn(), scope=SCOPE_BASE,
+ attrs=["prefixMap", "schemaInfo"])
+
+ pfm = ndr_unpack(drsblobs.prefixMapBlob,
+ res[0]['prefixMap'][0])
+
+ schi = drsuapi.DsReplicaOIDMapping()
+ schi.id_prefix = 0
+ if 'schemaInfo' in res[0]:
+ binary_oid = [x if isinstance(x, int) else ord(x) for x in res[0]['schemaInfo'][0]]
+ schi.oid.length = len(binary_oid)
+ schi.oid.binary_oid = binary_oid
+ else:
+ schema_info = drsblobs.schemaInfoBlob()
+ schema_info.revision = 0
+ schema_info.marker = 0xFF
+ schema_info.invocation_id = misc.GUID(samdb.get_invocation_id())
+
+ binary_oid = [x if isinstance(x, int) else ord(x) for x in ndr_pack(schema_info)]
+ # you have to set the length before setting binary_oid
+ schi.oid.length = len(binary_oid)
+ schi.oid.binary_oid = binary_oid
+
+ pfm.ctr.mappings = pfm.ctr.mappings + [schi]
+ pfm.ctr.num_mappings += 1
+ return pfm.ctr
+
+
+class DrsReplicaSyncSortTestCase(drs_base.DrsBaseTestCase):
+ def setUp(self):
+ super(DrsReplicaSyncSortTestCase, self).setUp()
+ self.base_dn = self.ldb_dc1.get_default_basedn()
+ self.ou = "ou=sort_exop%d,%s" % (random.randint(0, 4294967295),
+ self.base_dn)
+ self.ldb_dc1.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+
+ def tearDown(self):
+ super(DrsReplicaSyncSortTestCase, self).tearDown()
+ # tidyup groups and users
+ try:
+ self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+ except ldb.LdbError as e4:
+ (enum, string) = e4.args
+ if enum == ldb.ERR_NO_SUCH_OBJECT:
+ pass
+
+ def add_linked_attribute(self, src, dest, attr='member'):
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, src)
+ m[attr] = ldb.MessageElement(dest, ldb.FLAG_MOD_ADD, attr)
+ self.ldb_dc1.modify(m)
+
+ def remove_linked_attribute(self, src, dest, attr='member'):
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, src)
+ m[attr] = ldb.MessageElement(dest, ldb.FLAG_MOD_DELETE, attr)
+ self.ldb_dc1.modify(m)
+
+ def test_sort_behaviour_single_object(self):
+ """Testing sorting behaviour on single objects"""
+
+ user1_dn = "cn=test_user1,%s" % self.ou
+ user2_dn = "cn=test_user2,%s" % self.ou
+ user3_dn = "cn=test_user3,%s" % self.ou
+ group_dn = "cn=test_group,%s" % self.ou
+
+ self.ldb_dc1.add({"dn": user1_dn, "objectclass": "user"})
+ self.ldb_dc1.add({"dn": user2_dn, "objectclass": "user"})
+ self.ldb_dc1.add({"dn": user3_dn, "objectclass": "user"})
+ self.ldb_dc1.add({"dn": group_dn, "objectclass": "group"})
+
+ u1_guid = misc.GUID(self.ldb_dc1.search(base=user1_dn,
+ attrs=["objectGUID"])[0]['objectGUID'][0])
+ u2_guid = misc.GUID(self.ldb_dc1.search(base=user2_dn,
+ attrs=["objectGUID"])[0]['objectGUID'][0])
+ u3_guid = misc.GUID(self.ldb_dc1.search(base=user3_dn,
+ attrs=["objectGUID"])[0]['objectGUID'][0])
+ g_guid = misc.GUID(self.ldb_dc1.search(base=group_dn,
+ attrs=["objectGUID"])[0]['objectGUID'][0])
+
+ self.add_linked_attribute(group_dn, user1_dn,
+ attr='member')
+ self.add_linked_attribute(group_dn, user2_dn,
+ attr='member')
+ self.add_linked_attribute(group_dn, user3_dn,
+ attr='member')
+ self.add_linked_attribute(group_dn, user1_dn,
+ attr='managedby')
+ self.add_linked_attribute(group_dn, user2_dn,
+ attr='nonSecurityMember')
+ self.add_linked_attribute(group_dn, user3_dn,
+ attr='nonSecurityMember')
+
+ set_inactive = AbstractLink(drsuapi.DRSUAPI_ATTID_nonSecurityMember,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ g_guid, u3_guid)
+
+ expected_links = set([set_inactive,
+ AbstractLink(drsuapi.DRSUAPI_ATTID_member,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ g_guid,
+ u1_guid),
+ AbstractLink(drsuapi.DRSUAPI_ATTID_member,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ g_guid,
+ u2_guid),
+ AbstractLink(drsuapi.DRSUAPI_ATTID_member,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ g_guid,
+ u3_guid),
+ AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ g_guid,
+ u1_guid),
+ AbstractLink(drsuapi.DRSUAPI_ATTID_nonSecurityMember,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ g_guid,
+ u2_guid),
+ ])
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=group_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ no_inactive = []
+ for link in ctr.linked_attributes:
+ target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+ link.value.blob).guid
+ no_inactive.append((link, target_guid))
+ self.assertTrue(AbstractLink(link.attid, link.flags,
+ link.identifier.guid,
+ target_guid) in expected_links)
+
+ no_inactive.sort(key=cmp_to_key(_linked_attribute_compare))
+
+ # assert the two arrays are the same
+ self.assertEqual(len(expected_links), ctr.linked_attributes_count)
+ self.assertEqual([x[0] for x in no_inactive], ctr.linked_attributes)
+
+ self.remove_linked_attribute(group_dn, user3_dn,
+ attr='nonSecurityMember')
+
+ # Set the link inactive
+ expected_links.remove(set_inactive)
+ set_inactive.flags = 0
+ expected_links.add(set_inactive)
+
+ has_inactive = []
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ for link in ctr.linked_attributes:
+ target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+ link.value.blob).guid
+ has_inactive.append((link, target_guid))
+ self.assertTrue(AbstractLink(link.attid, link.flags,
+ link.identifier.guid,
+ target_guid) in expected_links)
+
+ has_inactive.sort(key=cmp_to_key(_linked_attribute_compare))
+
+ # assert the two arrays are the same
+ self.assertEqual(len(expected_links), ctr.linked_attributes_count)
+ self.assertEqual([x[0] for x in has_inactive], ctr.linked_attributes)
+
+ def test_sort_behaviour_ncchanges(self):
+ """Testing sorting behaviour on a group of objects."""
+ user1_dn = "cn=test_user1,%s" % self.ou
+ group_dn = "cn=test_group,%s" % self.ou
+ self.ldb_dc1.add({"dn": user1_dn, "objectclass": "user"})
+ self.ldb_dc1.add({"dn": group_dn, "objectclass": "group"})
+
+ self.add_linked_attribute(group_dn, user1_dn,
+ attr='member')
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ # Make sure the max objects count is high enough
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.base_dn,
+ replica_flags=0,
+ max_objects=100,
+ exop=drsuapi.DRSUAPI_EXOP_NONE)
+
+ # Loop until we get linked attributes, or we get to the end.
+ # Samba sends linked attributes at the end, unlike Windows.
+ while True:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ if ctr.more_data == 0 or ctr.linked_attributes_count != 0:
+ break
+ req8.highwatermark = ctr.new_highwatermark
+
+ self.assertTrue(ctr.linked_attributes_count != 0)
+
+ no_inactive = []
+ for link in ctr.linked_attributes:
+ try:
+ target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+ link.value.blob).guid
+ except:
+ target_guid = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3Binary,
+ link.value.blob).guid
+ no_inactive.append((link, target_guid))
+
+ no_inactive.sort(key=cmp_to_key(_linked_attribute_compare))
+
+ # assert the two arrays are the same
+ self.assertEqual([x[0] for x in no_inactive], ctr.linked_attributes)
diff --git a/source4/torture/drs/python/getnc_schema.py b/source4/torture/drs/python/getnc_schema.py
new file mode 100644
index 0000000..60062f9
--- /dev/null
+++ b/source4/torture/drs/python/getnc_schema.py
@@ -0,0 +1,304 @@
+import drs_base
+import ldb
+import time
+import random
+import os
+
+break_me = os.getenv("PLEASE_BREAK_MY_WINDOWS") == "1"
+assert break_me, ("This test breaks Windows active directory after "
+ "a few runs. Set PLEASE_BREAK_MY_WINDOWS=1 to run.")
+
+# This test runs against Windows. To run, set up two Windows AD DCs, join one
+# to the other, and make sure the passwords are the same. SMB_CONF_PATH must
+# also be set to any smb.conf file. Set DC1 to the PDC's hostname, and DC2 to
+# the join'd DC's hostname. Example:
+# PLEASE_BREAK_MY_WINDOWS=1
+# DC1=pdc DC2=joindc
+# SMB_CONF_PATH=st/ad_dc/etc/smb.conf
+# PYTHONPATH=$PYTHONPATH:./source4/torture/drs/python
+# python3 ./source4/scripting/bin/subunitrun getnc_schema
+# -UAdministrator%Password
+
+class SchemaReplicationTests(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(SchemaReplicationTests, self).setUp()
+ self.creds = self.get_credentials()
+ self.cmdline_auth = "-U{}%{}".format(self.creds.get_username(),
+ self.creds.get_password())
+
+ self.from_ldb = self.ldb_dc1
+ self.dest_ldb = self.ldb_dc2
+ self._disable_inbound_repl(self.url_dc1)
+ self._disable_all_repl(self.url_dc1)
+ self.free_offset = 0
+
+ def tearDown(self):
+ self._enable_inbound_repl(self.url_dc1)
+ self._enable_all_repl(self.url_dc1)
+
+ def do_repl(self, partition_dn):
+ self._enable_inbound_repl(self.url_dc1)
+ self._enable_all_repl(self.url_dc1)
+
+ samba_tool_cmd = ["drs", "replicate", self.url_dc2, self.url_dc1]
+ samba_tool_cmd += [partition_dn]
+ username = self.creds.get_username()
+ password = self.creds.get_password()
+ samba_tool_cmd += ["-U{0}%{1}".format(username, password)]
+
+ (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+
+ try:
+ self.assertCmdSuccess(result, out, err)
+ except AssertionError:
+ print("Failed repl, retrying in 10s")
+ time.sleep(10)
+ (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+
+ self._disable_inbound_repl(self.url_dc1)
+ self._disable_all_repl(self.url_dc1)
+
+ self.assertCmdSuccess(result, out, err)
+
+ # Get a unique prefix for some search expression like "([att]=[pref]{i}*)"
+ def get_unique(self, expr_templ):
+ found = True
+ while found:
+ i = random.randint(0, 65535)
+ res = self.from_ldb.search(base=self.schema_dn,
+ scope=ldb.SCOPE_SUBTREE,
+ expression=expr_templ.format(i=i))
+ found = len(res) > 0
+
+ return str(i)
+
+ def unique_gov_id_prefix(self):
+ prefix = "1.3.6.1.4.1.7165.4.6.2.8."
+ return prefix + self.get_unique("(governsId=" + prefix + "{i}.*)")
+
+ def unique_cn_prefix(self, prefix="testobj"):
+ return prefix + self.get_unique("(cn=" + prefix + "{i}x*)") + "x"
+
+ # Make test schema classes linked to each other in a line, then modify
+ # them in reverse order so when we repl, a link crosses the chunk
+ # boundary. Chunk size is 133 by default so we do 150.
+ def test_poss_superiors_across_chunk(self):
+ num_schema_objects_to_add = 150
+ class_name = self.unique_cn_prefix()
+
+ ldif_template = """
+dn: CN={class_name}{i},{schema_dn}
+objectClass: top
+objectClass: classSchema
+adminDescription: {class_name}{i}
+adminDisplayName: {class_name}{i}
+cn: {class_name}{i}
+governsId: {gov_id}.{i}
+instanceType: 4
+objectClassCategory: 1
+systemFlags: 16
+systemOnly: FALSE
+"""
+
+ ldif_kwargs = {'class_name': class_name,
+ 'schema_dn': self.schema_dn}
+ gov_id = self.unique_gov_id_prefix()
+ ldif = ldif_template.format(i=0, gov_id=gov_id, **ldif_kwargs)
+ self.from_ldb.add_ldif(ldif)
+
+ ldif_template += "systemPossSuperiors: {possSup}\n"
+
+ ids = list(range(num_schema_objects_to_add))
+ got_no_such_attrib = False
+ for i in ids[1:]:
+ last_class_name = class_name + str(i-1)
+ ldif = ldif_template.format(i=i, gov_id=gov_id,
+ possSup=last_class_name,
+ **ldif_kwargs)
+
+ try:
+ self.from_ldb.add_ldif(ldif)
+ if got_no_such_attrib:
+ self.from_ldb.set_schema_update_now()
+ except ldb.LdbError as e:
+ if e.args[0] != ldb.ERR_NO_SUCH_ATTRIBUTE:
+ self.fail(e)
+ if got_no_such_attrib:
+ self.fail(("got NO_SUCH_ATTRIB even after "
+ "setting schemaUpdateNow", str(e)))
+ print("got NO_SUCH_ATTRIB, trying schemaUpdateNow")
+ got_no_such_attrib = True
+ self.from_ldb.set_schema_update_now()
+ self.from_ldb.add_ldif(ldif)
+ self.from_ldb.set_schema_update_now()
+
+ ldif_template = """
+dn: CN={class_name}{i},{schema_dn}
+changetype: modify
+replace: adminDescription
+adminDescription: new_description
+"""
+
+ for i in reversed(ids):
+ ldif = ldif_template.format(i=i, **ldif_kwargs)
+ self.from_ldb.modify_ldif(ldif)
+
+ self.do_repl(self.schema_dn)
+
+ dn_templ = "CN={class_name}{i},{schema_dn}"
+ for i in ids:
+ dn = dn_templ.format(i=i, **ldif_kwargs)
+ res = self.dest_ldb.search(base=dn, scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+
+ # Test for method of adding linked attributes in schema partition
+ # required by other tests.
+ def test_create_linked_attribute_in_schema(self):
+ # Make an object outside of the schema partition that we can link to
+ user_name = self.unique_cn_prefix("user")
+ user_dn = "CN={},CN=Users,{}".format(user_name, self.domain_dn)
+
+ ldif_template = """
+dn: {user_dn}
+objectClass: person
+objectClass: user"""
+ ldif = ldif_template.format(user_dn=user_dn)
+ self.from_ldb.add_ldif(ldif)
+
+ # Make test class name unique so test can run multiple times
+ class_name = self.unique_cn_prefix("class")
+
+ kwargs = {'class_name': class_name,
+ 'schema_dn': self.schema_dn,
+ 'user_dn': user_dn}
+
+ # Add an auxiliary schemaClass (cat 3) class and give it managedBy
+ # so we can create schema objects with linked attributes.
+ ldif_template = """
+dn: CN={class_name},{schema_dn}
+objectClass: classSchema
+governsId: {gov_id}.0
+instanceType: 4
+systemFlags: 16
+systemOnly: FALSE
+objectClassCategory: 3
+mayContain: managedBy
+"""
+
+ gov_id = self.unique_gov_id_prefix()
+ ldif = ldif_template.format(gov_id=gov_id, **kwargs)
+ self.from_ldb.add_ldif(ldif)
+
+ # Now make an instance that points back to the user with managedBy,
+ # thus creating an object in the schema with a linked attribute
+ ldif_template = """
+dn: CN=link{class_name},{schema_dn}
+objectClass: classSchema
+objectClass: {class_name}
+instanceType: 4
+governsId: {gov_id}.0
+systemFlags: 16
+managedBy: {user_dn}
+"""
+
+ gov_id = self.unique_gov_id_prefix()
+ ldif = ldif_template.format(gov_id=gov_id, **kwargs)
+ self.from_ldb.add_ldif(ldif)
+
+ # Check link exists on test schema object
+ dn_templ = "CN=link{class_name},{schema_dn}"
+ dn = dn_templ.format(**kwargs)
+ res = self.from_ldb.search(base=dn, scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+ self.assertIsNotNone(res[0].get("managedBy"))
+ self.assertEqual(str(res[0].get("managedBy")[0]), user_dn)
+
+ # Check backlink on user object
+ res = self.from_ldb.search(base=user_dn, scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+ managed_objs = res[0].get("managedObjects")
+ self.assertEqual(len(managed_objs), 1)
+ managed_objs = [str(o) for o in managed_objs]
+ self.assertEqual(managed_objs, [dn_templ.format(**kwargs)])
+
+ def test_schema_linked_attributes(self):
+ num_test_objects = 9
+
+ # Make an object outside of the schema partition that we can link to
+ user_name = self.unique_cn_prefix("user")
+ user_dn = "CN={},CN=Users,{}".format(user_name, self.domain_dn)
+
+ ldif_template = """
+dn: {user_dn}
+objectClass: person
+objectClass: user"""
+ ldif = ldif_template.format(user_dn=user_dn)
+ self.from_ldb.add_ldif(ldif)
+
+ self.do_repl(self.domain_dn)
+
+ # Make test object name prefixes unique so test can run multiple times
+ # in a single testenv (can't delete schema objects)
+ class_name = self.unique_cn_prefix("class")
+ link_class_name = self.unique_cn_prefix("linkClass")
+
+ kwargs = {'class_name': class_name,
+ 'schema_dn': self.schema_dn,
+ 'link_class_name': link_class_name,
+ 'user_dn': user_dn}
+
+ # Add an auxiliary schemaClass (cat 3) class and give it managedBy
+ # so we can create schema objects with linked attributes.
+ ldif_template = """
+dn: CN={class_name},{schema_dn}
+objectClass: classSchema
+governsId: {gov_id}.0
+instanceType: 4
+systemFlags: 16
+systemOnly: FALSE
+objectClassCategory: 3
+mayContain: managedBy
+"""
+
+ gov_id = self.unique_gov_id_prefix()
+ ldif = ldif_template.format(gov_id=gov_id, **kwargs)
+ self.from_ldb.add_ldif(ldif)
+
+ # Now make instances that point back to the user with managedBy,
+ # thus creating objects in the schema with linked attributes
+ ldif_template = """
+dn: CN={link_class_name}{i},{schema_dn}
+objectClass: classSchema
+objectClass: {class_name}
+instanceType: 4
+governsId: {gov_id}.0
+systemFlags: 16
+managedBy: {user_dn}
+"""
+
+ id_range = list(range(num_test_objects))
+ for i in id_range:
+ gov_id = self.unique_gov_id_prefix()
+ ldif = ldif_template.format(i=i, gov_id=gov_id, **kwargs)
+ self.from_ldb.add_ldif(ldif)
+
+ self.do_repl(self.schema_dn)
+
+ # Check link exists in each test schema objects at destination DC
+ dn_templ = "CN={link_class_name}{i},{schema_dn}"
+ for i in id_range:
+ dn = dn_templ.format(i=i, **kwargs)
+ res = self.dest_ldb.search(base=dn, scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+ self.assertIsNotNone(res[0].get("managedBy"))
+ self.assertEqual(str(res[0].get("managedBy")[0]), user_dn)
+
+ # Check backlinks list on user object contains DNs of test objects.
+ res = self.dest_ldb.search(base=user_dn, scope=ldb.SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+ managed_objs = res[0].get("managedObjects")
+ self.assertIsNotNone(managed_objs)
+ managed_objs_set = {str(el) for el in managed_objs}
+ expected = {dn_templ.format(i=i, **kwargs) for i in id_range}
+ self.assertEqual(managed_objs_set, expected)
diff --git a/source4/torture/drs/python/getnc_unpriv.py b/source4/torture/drs/python/getnc_unpriv.py
new file mode 100644
index 0000000..c53906a
--- /dev/null
+++ b/source4/torture/drs/python/getnc_unpriv.py
@@ -0,0 +1,306 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests replication scenarios with different user privileges.
+# We want to test every replication scenario we can think of against:
+# - users with only GET_CHANGES privileges
+# - users with only GET_ALL_CHANGES privileges
+# - users with both GET_CHANGES and GET_ALL_CHANGES privileges
+# - users with no privileges
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN getnc_unpriv -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+from samba import werror, WERRORError
+
+from samba import sd_utils
+import ldb
+from ldb import SCOPE_BASE
+import random
+
+from samba.dcerpc import drsuapi, security
+from samba.credentials import DONT_USE_KERBEROS
+
+
+class DrsReplicaSyncUnprivTestCase(drs_base.DrsBaseTestCase):
+ """Confirm the behaviour of DsGetNCChanges for unprivileged users"""
+
+ def setUp(self):
+ super(DrsReplicaSyncUnprivTestCase, self).setUp()
+ self.get_changes_user = "get-changes-user"
+ self.base_dn = self.ldb_dc1.get_default_basedn()
+ self.user_pass = samba.generate_random_password(12, 16)
+
+ # add some randomness to the test OU. (Deletion of the last test's
+ # objects can be slow to replicate out. So the OU created by a previous
+ # testenv may still exist at this point).
+ rand = random.randint(1, 10000000)
+ test_ou = "OU=test_getnc_unpriv%d" % rand
+ self.ou = "%s,%s" % (test_ou, self.base_dn)
+ self.ldb_dc1.add({
+ "dn": self.ou,
+ "objectclass": "organizationalUnit"})
+ self.ldb_dc1.newuser(self.get_changes_user, self.user_pass,
+ userou=test_ou)
+ (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
+
+ self.sd_utils = sd_utils.SDUtils(self.ldb_dc1)
+ self.user_dn = "cn=%s,%s" % (self.get_changes_user, self.ou)
+ user_sid = self.sd_utils.get_object_sid(self.user_dn)
+ self.acl_mod_get_changes = "(OA;;CR;%s;;%s)" % (security.GUID_DRS_GET_CHANGES,
+ str(user_sid))
+ self.acl_mod_get_all_changes = "(OA;;CR;%s;;%s)" % (security.GUID_DRS_GET_ALL_CHANGES,
+ str(user_sid))
+ self.desc_sddl = self.sd_utils.get_sd_as_sddl(self.base_dn)
+
+ # We set DONT_USE_KERBEROS to avoid a race with getting the
+ # user replicated to our selected KDC
+ self.user_creds = self.insta_creds(template=self.get_credentials(),
+ username=self.get_changes_user,
+ userpass=self.user_pass,
+ kerberos_state=DONT_USE_KERBEROS)
+ (self.user_drs, self.user_drs_handle) = self._ds_bind(self.dnsname_dc1,
+ self.user_creds)
+
+ def tearDown(self):
+ self.sd_utils.modify_sd_on_dn(self.base_dn, self.desc_sddl)
+ try:
+ self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+ except ldb.LdbError as e1:
+ (enum, string) = e1.args
+ if enum == ldb.ERR_NO_SUCH_OBJECT:
+ pass
+ super(DrsReplicaSyncUnprivTestCase, self).tearDown()
+
+ def _test_repl_exop(self, exop, repl_obj, expected_error, dest_dsa=None,
+ partial_attribute_set=None):
+ """
+ Common function to send a replication request and check the result
+ matches what's expected.
+ """
+ req8 = self._exop_req8(dest_dsa=dest_dsa,
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=repl_obj,
+ exop=exop,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP,
+ partial_attribute_set=partial_attribute_set)
+
+ if expected_error is None:
+ # user is OK, request should be accepted without throwing an error
+ (level, ctr) = self.user_drs.DsGetNCChanges(self.user_drs_handle,
+ 8, req8)
+ else:
+ # check the request is rejected (with the error we're expecting)
+ try:
+ (level, ctr) = self.user_drs.DsGetNCChanges(self.user_drs_handle,
+ 8, req8)
+ self.fail("Should have failed with user denied access")
+ except WERRORError as e:
+ (enum, estr) = e.args
+ self.assertTrue(enum in expected_error,
+ "Got unexpected error: %s" % estr)
+
+ def _test_repl_single_obj(self, repl_obj, expected_error,
+ partial_attribute_set=None):
+ """
+ Checks that replication on a single object either succeeds or fails as
+ expected (based on the user's access rights)
+ """
+ self._test_repl_exop(exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ repl_obj=repl_obj,
+ expected_error=expected_error,
+ partial_attribute_set=partial_attribute_set)
+
+ def _test_repl_secret(self, repl_obj, expected_error, dest_dsa=None):
+ """
+ Checks that REPL_SECRET on an object either succeeds or fails as
+ expected (based on the user's access rights)
+ """
+ self._test_repl_exop(exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ repl_obj=repl_obj,
+ expected_error=expected_error,
+ dest_dsa=dest_dsa)
+
+ def _test_repl_full(self, expected_error, partial_attribute_set=None):
+ """
+ Checks that a full replication either succeeds or fails as expected
+ (based on the user's access rights)
+ """
+ self._test_repl_exop(exop=drsuapi.DRSUAPI_EXOP_NONE,
+ repl_obj=self.ldb_dc1.get_default_basedn(),
+ expected_error=expected_error,
+ partial_attribute_set=partial_attribute_set)
+
+ def _test_repl_full_on_ou(self, repl_obj, expected_error):
+ """
+ Full replication on a specific OU should always fail (it should be done
+ against a base NC). The error may vary based on the user's access rights
+ """
+ # Just try against the OU created in the test setup
+ self._test_repl_exop(exop=drsuapi.DRSUAPI_EXOP_NONE,
+ repl_obj=repl_obj,
+ expected_error=expected_error)
+
+ def test_repl_getchanges_userpriv(self):
+ """
+ Tests various replication requests made by a user with only GET_CHANGES
+ rights. Some requests will be accepted, but most will be rejected.
+ """
+
+ # Assign the user GET_CHANGES rights
+ self.sd_utils.dacl_add_ace(self.base_dn, self.acl_mod_get_changes)
+
+ self._test_repl_single_obj(repl_obj=self.ou,
+ expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+ bad_ou = "OU=bad_obj,%s" % self.ou
+ self._test_repl_single_obj(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_DN,
+ werror.WERR_DS_DRA_ACCESS_DENIED])
+
+ self._test_repl_secret(repl_obj=self.ou,
+ expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_secret(repl_obj=self.user_dn,
+ expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_secret(repl_obj=self.user_dn,
+ dest_dsa=self.ldb_dc1.get_ntds_GUID(),
+ expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_secret(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_DN])
+
+ self._test_repl_full(expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_full_on_ou(repl_obj=self.ou,
+ expected_error=[werror.WERR_DS_CANT_FIND_EXPECTED_NC,
+ werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_full_on_ou(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_NC,
+ werror.WERR_DS_DRA_ACCESS_DENIED])
+
+ # Partial Attribute Sets don't require GET_ALL_CHANGES rights, so we
+ # expect the following to succeed
+ self._test_repl_single_obj(repl_obj=self.ou,
+ expected_error=None,
+ partial_attribute_set=self.get_partial_attribute_set())
+ self._test_repl_full(expected_error=None,
+ partial_attribute_set=self.get_partial_attribute_set())
+
+ def test_repl_getallchanges_userpriv(self):
+ """
+ Tests various replication requests made by a user with only
+ GET_ALL_CHANGES rights. Note that assigning these rights is possible,
+ but doesn't make a lot of sense. We test it anyway for consistency.
+ """
+
+ # Assign the user GET_ALL_CHANGES rights
+ self.sd_utils.dacl_add_ace(self.base_dn, self.acl_mod_get_all_changes)
+
+ # We can expect to get the same responses as an unprivileged user,
+ # i.e. we have permission to see the results, but don't have permission
+ # to ask
+ self.test_repl_no_userpriv()
+
+ def test_repl_both_userpriv(self):
+ """
+ Tests various replication requests made by a privileged user (i.e. has
+ both GET_CHANGES and GET_ALL_CHANGES). We expect any valid requests
+ to be accepted.
+ """
+
+ # Assign the user both GET_CHANGES and GET_ALL_CHANGES rights
+ both_rights = self.acl_mod_get_changes + self.acl_mod_get_all_changes
+ self.sd_utils.dacl_add_ace(self.base_dn, both_rights)
+
+ self._test_repl_single_obj(repl_obj=self.ou,
+ expected_error=None)
+ bad_ou = "OU=bad_obj,%s" % self.ou
+ self._test_repl_single_obj(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_DN])
+
+ # Microsoft returns DB_ERROR, Samba returns ACCESS_DENIED
+ self._test_repl_secret(repl_obj=self.ou,
+ expected_error=[werror.WERR_DS_DRA_DB_ERROR,
+ werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_secret(repl_obj=self.user_dn,
+ expected_error=[werror.WERR_DS_DRA_DB_ERROR,
+ werror.WERR_DS_DRA_ACCESS_DENIED])
+ # Note that Windows accepts this but Samba rejects it
+ self._test_repl_secret(repl_obj=self.user_dn,
+ dest_dsa=self.ldb_dc1.get_ntds_GUID(),
+ expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+
+ self._test_repl_secret(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_DN])
+
+ self._test_repl_full(expected_error=None)
+ self._test_repl_full_on_ou(repl_obj=self.ou,
+ expected_error=[werror.WERR_DS_CANT_FIND_EXPECTED_NC])
+ self._test_repl_full_on_ou(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_NC,
+ werror.WERR_DS_DRA_BAD_DN])
+
+ self._test_repl_single_obj(repl_obj=self.ou,
+ expected_error=None,
+ partial_attribute_set=self.get_partial_attribute_set())
+ self._test_repl_full(expected_error=None,
+ partial_attribute_set=self.get_partial_attribute_set())
+
+ def test_repl_no_userpriv(self):
+ """
+ Tests various replication requests made by a unprivileged user.
+ We expect all these requests to be rejected.
+ """
+
+ # Microsoft usually returns BAD_DN, Samba returns ACCESS_DENIED
+ usual_error = [werror.WERR_DS_DRA_BAD_DN, werror.WERR_DS_DRA_ACCESS_DENIED]
+
+ self._test_repl_single_obj(repl_obj=self.ou,
+ expected_error=usual_error)
+ bad_ou = "OU=bad_obj,%s" % self.ou
+ self._test_repl_single_obj(repl_obj=bad_ou,
+ expected_error=usual_error)
+
+ self._test_repl_secret(repl_obj=self.ou,
+ expected_error=usual_error)
+ self._test_repl_secret(repl_obj=self.user_dn,
+ expected_error=usual_error)
+ self._test_repl_secret(repl_obj=self.user_dn,
+ dest_dsa=self.ldb_dc1.get_ntds_GUID(),
+ expected_error=usual_error)
+ self._test_repl_secret(repl_obj=bad_ou,
+ expected_error=usual_error)
+
+ self._test_repl_full(expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED])
+ self._test_repl_full_on_ou(repl_obj=self.ou,
+ expected_error=usual_error)
+ self._test_repl_full_on_ou(repl_obj=bad_ou,
+ expected_error=[werror.WERR_DS_DRA_BAD_NC,
+ werror.WERR_DS_DRA_ACCESS_DENIED])
+
+ self._test_repl_single_obj(repl_obj=self.ou,
+ expected_error=usual_error,
+ partial_attribute_set=self.get_partial_attribute_set())
+ self._test_repl_full(expected_error=[werror.WERR_DS_DRA_ACCESS_DENIED],
+ partial_attribute_set=self.get_partial_attribute_set())
diff --git a/source4/torture/drs/python/getncchanges.py b/source4/torture/drs/python/getncchanges.py
new file mode 100644
index 0000000..6b5456a
--- /dev/null
+++ b/source4/torture/drs/python/getncchanges.py
@@ -0,0 +1,1427 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests various schema replication scenarios
+#
+# Copyright (C) Catalyst.Net Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN \
+# getncchanges -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+import ldb
+from ldb import SCOPE_BASE
+import random
+
+from samba.dcerpc import drsuapi, misc
+from samba import WERRORError
+from samba import werror
+
+class DrsReplicaSyncIntegrityTestCase(drs_base.DrsBaseTestCase):
+ def setUp(self):
+ super(DrsReplicaSyncIntegrityTestCase, self).setUp()
+
+ self.init_test_state()
+
+ # Note that DC2 is the DC with the testenv-specific quirks (e.g. it's
+ # the vampire_dc), so we point this test directly at that DC
+ self.set_test_ldb_dc(self.ldb_dc2)
+
+ self.ou = str(samba.tests.create_test_ou(self.test_ldb_dc,
+ "getncchanges." + self.id().rsplit(".", 1)[1]))
+
+ self.addCleanup(self.ldb_dc2.delete, self.ou, ["tree_delete:1"])
+
+ self.base_dn = self.test_ldb_dc.get_default_basedn()
+
+ self.default_conn = DcConnection(self, self.ldb_dc2, self.dnsname_dc2)
+ self.set_dc_connection(self.default_conn)
+
+ def init_test_state(self):
+ self.rxd_dn_list = []
+ self.rxd_links = []
+ self.rxd_guids = []
+ self.last_ctr = None
+
+ # 100 is the minimum max_objects that Microsoft seems to honour
+ # (the max honoured is 400ish), so we use that in these tests
+ self.max_objects = 100
+
+ # store whether we used GET_TGT/GET_ANC flags in the requests
+ self.used_get_tgt = False
+ self.used_get_anc = False
+
+ def add_object(self, dn, objectclass="organizationalunit"):
+ """Adds an OU object"""
+ self.test_ldb_dc.add({"dn": dn, "objectclass": objectclass})
+ res = self.test_ldb_dc.search(base=dn, scope=SCOPE_BASE)
+ self.assertEqual(len(res), 1)
+
+ def modify_object(self, dn, attr, value):
+ """Modifies an object's USN by adding an attribute value to it"""
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.test_ldb_dc, dn)
+ m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_ADD, attr)
+ self.test_ldb_dc.modify(m)
+
+ def delete_attribute(self, dn, attr, value):
+ """Deletes an attribute from an object"""
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.test_ldb_dc, dn)
+ m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_DELETE, attr)
+ self.test_ldb_dc.modify(m)
+
+ def start_new_repl_cycle(self):
+ """Resets enough state info to start a new replication cycle"""
+ # reset rxd_links, but leave rxd_guids and rxd_dn_list alone so we know
+ # whether a parent/target is unknown and needs GET_ANC/GET_TGT to
+ # resolve
+ self.rxd_links = []
+
+ self.used_get_tgt = False
+ self.used_get_anc = False
+ # mostly preserve self.last_ctr, so that we use the last HWM
+ if self.last_ctr is not None:
+ self.last_ctr.more_data = True
+
+ def create_object_range(self, start, end, prefix="",
+ children=None, parent_list=None):
+ """
+ Creates a block of objects. Object names are numbered sequentially,
+ using the optional prefix supplied. If the children parameter is
+ supplied it will create a parent-child hierarchy and return the
+ top-level parents separately.
+ """
+ dn_list = []
+
+ # Use dummy/empty lists if we're not creating a parent/child hierarchy
+ if children is None:
+ children = []
+
+ if parent_list is None:
+ parent_list = []
+
+ # Create the parents first, then the children.
+ # This makes it easier to see in debug when GET_ANC takes effect
+ # because the parent/children become interleaved (by default,
+ # this approach means the objects are organized into blocks of
+ # parents and blocks of children together)
+ for x in range(start, end):
+ ou = "OU=test_ou_%s%d,%s" % (prefix, x, self.ou)
+ self.add_object(ou)
+ dn_list.append(ou)
+
+ # keep track of the top-level parents (if needed)
+ parent_list.append(ou)
+
+ # create the block of children (if needed)
+ for x in range(start, end):
+ for child in children:
+ ou = "OU=test_ou_child%s%d,%s" % (child, x, parent_list[x])
+ self.add_object(ou)
+ dn_list.append(ou)
+
+ return dn_list
+
+ def assert_expected_data(self, expected_list):
+ """
+ Asserts that we received all the DNs that we expected and
+ none are missing.
+ """
+ received_list = self.rxd_dn_list
+
+ # Note that with GET_ANC Windows can end up sending the same parent
+ # object multiple times, so this might be noteworthy but doesn't
+ # warrant failing the test
+ num_received = len(received_list)
+ num_expected = len(expected_list)
+ if num_received != num_expected:
+ print("Note: received %d objects but expected %d" % (num_received,
+ num_expected))
+
+ # Check that we received every object that we were expecting
+ for dn in expected_list:
+ self.assertTrue(dn in received_list,
+ "DN '%s' missing from replication." % dn)
+
+ def test_repl_integrity(self):
+ """
+ Modify the objects being replicated while the replication is still
+ in progress and check that no object loss occurs.
+ """
+
+ # The server behaviour differs between samba and Windows. Samba returns
+ # the objects in the original order (up to the pre-modify HWM). Windows
+ # incorporates the modified objects and returns them in the new order
+ # (i.e. modified objects last), up to the post-modify HWM. The
+ # Microsoft docs state the Windows behaviour is optional.
+
+ # Create a range of objects to replicate.
+ expected_dn_list = self.create_object_range(0, 400)
+ (orig_hwm, unused) = self._get_highest_hwm_utdv(self.test_ldb_dc)
+
+ # We ask for the first page of 100 objects.
+ # For this test, we don't care what order we receive the objects in,
+ # so long as by the end we've received everything
+ self.repl_get_next()
+
+ # Modify some of the second page of objects. This should bump the
+ # highwatermark
+ for x in range(100, 200):
+ self.modify_object(expected_dn_list[x], "displayName", "OU%d" % x)
+
+ (post_modify_hwm, _) = self._get_highest_hwm_utdv(self.test_ldb_dc)
+ self.assertTrue(post_modify_hwm.highest_usn > orig_hwm.highest_usn)
+
+ # Get the remaining blocks of data
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ # Check we still receive all the objects we're expecting
+ self.assert_expected_data(expected_dn_list)
+
+ def is_parent_known(self, dn, known_dn_list):
+ """
+ Returns True if the parent of the dn specified is in known_dn_list
+ """
+
+ # we can sometimes get system objects like the RID Manager returned.
+ # Ignore anything that is not under the test OU we created
+ if self.ou not in dn:
+ return True
+
+ # Remove the child portion from the name to get the parent's DN
+ name_substrings = dn.split(",")
+ del name_substrings[0]
+
+ parent_dn = ",".join(name_substrings)
+
+ # check either this object is a parent (it's parent is the top-level
+ # test object), or its parent has been seen previously
+ return parent_dn == self.ou or parent_dn in known_dn_list
+
+ def _repl_send_request(self, get_anc=False, get_tgt=False):
+ """
+ Sends a GetNCChanges request for the next block of replication data.
+ """
+
+ # we're just trying to mimic regular client behaviour here, so just
+ # use the highwatermark in the last response we received
+ if self.last_ctr:
+ highwatermark = self.last_ctr.new_highwatermark
+ uptodateness_vector = self.last_ctr.uptodateness_vector
+ else:
+ # this is the first replication chunk
+ highwatermark = None
+ uptodateness_vector = None
+
+ # Ask for the next block of replication data
+ replica_flags = drsuapi.DRSUAPI_DRS_WRIT_REP
+ more_flags = 0
+
+ if get_anc:
+ replica_flags |= drsuapi.DRSUAPI_DRS_GET_ANC
+ self.used_get_anc = True
+
+ if get_tgt:
+ more_flags = drsuapi.DRSUAPI_DRS_GET_TGT
+ self.used_get_tgt = True
+
+ # return the response from the DC
+ return self._get_replication(replica_flags,
+ max_objects=self.max_objects,
+ highwatermark=highwatermark,
+ uptodateness_vector=uptodateness_vector,
+
+ more_flags=more_flags)
+
+ def repl_get_next(self, get_anc=False, get_tgt=False, assert_links=False):
+ """
+ Requests the next block of replication data. This tries to simulate
+ client behaviour - if we receive a replicated object that we don't know
+ the parent of, then re-request the block with the GET_ANC flag set.
+ If we don't know the target object for a linked attribute, then
+ re-request with GET_TGT.
+ """
+
+ # send a request to the DC and get the response
+ ctr6 = self._repl_send_request(get_anc=get_anc, get_tgt=get_tgt)
+
+ # extract the object DNs and their GUIDs from the response
+ rxd_dn_list = self._get_ctr6_dn_list(ctr6)
+ rxd_guid_list = self._get_ctr6_object_guids(ctr6)
+
+ # we'll add new objects as we discover them, so take a copy of the
+ # ones we already know about, so we can modify these lists safely
+ known_objects = self.rxd_dn_list[:]
+ known_guids = self.rxd_guids[:]
+
+ # check that we know the parent for every object received
+ for i in range(0, len(rxd_dn_list)):
+
+ dn = rxd_dn_list[i]
+ guid = rxd_guid_list[i]
+
+ if self.is_parent_known(dn, known_objects):
+
+ # the new DN is now known so add it to the list.
+ # It may be the parent of another child in this block
+ known_objects.append(dn)
+ known_guids.append(guid)
+ else:
+ # If we've already set the GET_ANC flag then it should mean
+ # we receive the parents before the child
+ self.assertFalse(get_anc, "Unknown parent for object %s" % dn)
+
+ print("Unknown parent for %s - try GET_ANC" % dn)
+
+ # try the same thing again with the GET_ANC flag set this time
+ return self.repl_get_next(get_anc=True, get_tgt=get_tgt,
+ assert_links=assert_links)
+
+ # check we know about references to any objects in the linked attrs
+ received_links = self._get_ctr6_links(ctr6)
+
+ # This is so that older versions of Samba fail - we want the links to
+ # be sent roughly with the objects, rather than getting all links at
+ # the end
+ if assert_links:
+ self.assertTrue(len(received_links) > 0,
+ "Links were expected in the GetNCChanges response")
+
+ for link in received_links:
+
+ # skip any links that aren't part of the test
+ if self.ou not in link.targetDN:
+ continue
+
+ # check the source object is known (Windows can actually send links
+ # where we don't know the source object yet). Samba shouldn't ever
+ # hit this case because it gets the links based on the source
+ if link.identifier not in known_guids:
+
+ # If we've already set the GET_ANC flag then it should mean
+ # this case doesn't happen
+ self.assertFalse(get_anc, "Unknown source object for GUID %s"
+ % link.identifier)
+
+ print("Unknown source GUID %s - try GET_ANC" % link.identifier)
+
+ # try the same thing again with the GET_ANC flag set this time
+ return self.repl_get_next(get_anc=True, get_tgt=get_tgt,
+ assert_links=assert_links)
+
+ # check we know the target object
+ if link.targetGUID not in known_guids:
+
+ # If we've already set the GET_TGT flag then we should have
+ # already received any objects we need to know about
+ self.assertFalse(get_tgt, "Unknown linked target for object %s"
+ % link.targetDN)
+
+ print("Unknown target for %s - try GET_TGT" % link.targetDN)
+
+ # try the same thing again with the GET_TGT flag set this time
+ return self.repl_get_next(get_anc=get_anc, get_tgt=True,
+ assert_links=assert_links)
+
+ # store the last successful result so we know what HWM to request next
+ self.last_ctr = ctr6
+
+ # store the objects, GUIDs, and links we received
+ self.rxd_dn_list += self._get_ctr6_dn_list(ctr6)
+ self.rxd_links += self._get_ctr6_links(ctr6)
+ self.rxd_guids += self._get_ctr6_object_guids(ctr6)
+
+ return ctr6
+
+ def replication_complete(self):
+ """Returns True if the current/last replication cycle is complete"""
+
+ if self.last_ctr is None or self.last_ctr.more_data:
+ return False
+ else:
+ return True
+
+ def test_repl_integrity_get_anc(self):
+ """
+ Modify the parent objects being replicated while the replication is
+ still in progress (using GET_ANC) and check that no object loss occurs.
+ """
+
+ # Note that GET_ANC behaviour varies between Windows and Samba.
+ # On Samba GET_ANC results in the replication restarting from the very
+ # beginning. After that, Samba remembers GET_ANC and also sends the
+ # parents in subsequent requests (regardless of whether GET_ANC is
+ # specified in the later request).
+ # Windows only sends the parents if GET_ANC was specified in the last
+ # request. It will also resend a parent, even if it's already sent the
+ # parent in a previous response (whereas Samba doesn't).
+
+ # Create a small block of 50 parents, each with 2 children (A and B)
+ # This is so that we receive some children in the first block, so we
+ # can resend with GET_ANC before we learn too many parents
+ parent_dn_list = []
+ expected_dn_list = self.create_object_range(0, 50, prefix="parent",
+ children=("A", "B"),
+ parent_list=parent_dn_list)
+
+ # create the remaining parents and children
+ expected_dn_list += self.create_object_range(50, 150, prefix="parent",
+ children=("A", "B"),
+ parent_list=parent_dn_list)
+
+ # We've now got objects in the following order:
+ # [50 parents][100 children][100 parents][200 children]
+
+ # Modify the first parent so that it's now ordered last by USN
+ # This means we set the GET_ANC flag pretty much straight away
+ # because we receive the first child before the first parent
+ self.modify_object(parent_dn_list[0], "displayName", "OU0")
+
+ # modify a later block of parents so they also get reordered
+ for x in range(50, 100):
+ self.modify_object(parent_dn_list[x], "displayName", "OU%d" % x)
+
+ # Get the first block of objects - this should resend the request with
+ # GET_ANC set because we won't know about the first child's parent.
+ # On samba GET_ANC essentially starts the sync from scratch again, so
+ # we get this over with early before we learn too many parents
+ self.repl_get_next()
+
+ # modify the last chunk of parents. They should now have a USN higher
+ # than the highwater-mark for the replication cycle
+ for x in range(100, 150):
+ self.modify_object(parent_dn_list[x], "displayName", "OU%d" % x)
+
+ # Get the remaining blocks of data - this will resend the request with
+ # GET_ANC if it encounters an object it doesn't have the parent for.
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ # The way the test objects have been created should force
+ # self.repl_get_next() to use the GET_ANC flag. If this doesn't
+ # actually happen, then the test isn't doing its job properly
+ self.assertTrue(self.used_get_anc,
+ "Test didn't use the GET_ANC flag as expected")
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(expected_dn_list)
+
+ def assert_expected_links(self, objects_with_links, link_attr="managedBy",
+ num_expected=None):
+ """
+ Asserts that a GetNCChanges response contains any expected links
+ for the objects it contains.
+ """
+ received_links = self.rxd_links
+
+ if num_expected is None:
+ num_expected = len(objects_with_links)
+
+ self.assertTrue(len(received_links) == num_expected,
+ "Received %d links but expected %d"
+ % (len(received_links), num_expected))
+
+ for dn in objects_with_links:
+ self.assert_object_has_link(dn, link_attr, received_links)
+
+ def assert_object_has_link(self, dn, link_attr, received_links):
+ """
+ Queries the object in the DB and asserts there is a link in the
+ GetNCChanges response that matches.
+ """
+
+ # Look up the link attribute in the DB
+ # The extended_dn option will dump the GUID info for the link
+ # attribute (as a hex blob)
+ res = self.test_ldb_dc.search(ldb.Dn(self.test_ldb_dc, dn),
+ attrs=[link_attr],
+ controls=['extended_dn:1:0'],
+ scope=ldb.SCOPE_BASE)
+
+ # We didn't find the expected link attribute in the DB for the object.
+ # Something has gone wrong somewhere...
+ self.assertTrue(link_attr in res[0],
+ "%s in DB doesn't have attribute %s" % (dn, link_attr))
+
+ # find the received link in the list and assert that the target and
+ # source GUIDs match what's in the DB
+ for val in [str(val) for val in res[0][link_attr]]:
+ # Work out the expected source and target GUIDs for the DB link
+ target_dn = ldb.Dn(self.test_ldb_dc, val)
+ targetGUID_blob = target_dn.get_extended_component("GUID")
+ sourceGUID_blob = res[0].dn.get_extended_component("GUID")
+
+ found = False
+
+ for link in received_links:
+ if link.selfGUID_blob == sourceGUID_blob and \
+ link.targetGUID_blob == targetGUID_blob:
+
+ found = True
+
+ if self._debug:
+ print("Link %s --> %s" % (dn[:25], link.targetDN[:25]))
+ break
+
+ self.assertTrue(found,
+ "Did not receive expected link for DN %s" % dn)
+
+ def test_repl_get_tgt(self):
+ """
+ Creates a scenario where we should receive the linked attribute before
+ we know about the target object, and therefore need to use GET_TGT.
+ Note: Samba currently avoids this problem by sending all its links last
+ """
+
+ # create the test objects
+ reportees = self.create_object_range(0, 100, prefix="reportee")
+ managers = self.create_object_range(0, 100, prefix="manager")
+ all_objects = managers + reportees
+ expected_links = reportees
+
+ # add a link attribute to each reportee object that points to the
+ # corresponding manager object as the target
+ for i in range(0, 100):
+ self.modify_object(reportees[i], "managedBy", managers[i])
+
+ # touch the managers (the link-target objects) again to make sure the
+ # reportees (link source objects) get returned first by the replication
+ for i in range(0, 100):
+ self.modify_object(managers[i], "displayName", "OU%d" % i)
+
+ links_expected = True
+
+ # Get all the replication data - this code should resend the requests
+ # with GET_TGT
+ while not self.replication_complete():
+
+ # get the next block of replication data (this sets GET_TGT
+ # if needed)
+ self.repl_get_next(assert_links=links_expected)
+ links_expected = len(self.rxd_links) < len(expected_links)
+
+ # The way the test objects have been created should force
+ # self.repl_get_next() to use the GET_TGT flag. If this doesn't
+ # actually happen, then the test isn't doing its job properly
+ self.assertTrue(self.used_get_tgt,
+ "Test didn't use the GET_TGT flag as expected")
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(all_objects)
+
+ # Check we received links for all the reportees
+ self.assert_expected_links(expected_links)
+
+ def test_repl_get_tgt_chain(self):
+ """
+ Tests the behaviour of GET_TGT with a more complicated scenario.
+ Here we create a chain of objects linked together, so if we follow
+ the link target, then we'd traverse ~200 objects each time.
+ """
+
+ # create the test objects
+ objectsA = self.create_object_range(0, 100, prefix="AAA")
+ objectsB = self.create_object_range(0, 100, prefix="BBB")
+ objectsC = self.create_object_range(0, 100, prefix="CCC")
+
+ # create a complex set of object links:
+ # A0-->B0-->C1-->B2-->C3-->B4-->and so on...
+ # Basically each object-A should link to a circular chain of 200 B/C
+ # objects. We create the links in separate chunks here, as it makes it
+ # clearer what happens with the USN (links on Windows have their own
+ # USN, so this approach means the A->B/B->C links aren't interleaved)
+ for i in range(0, 100):
+ self.modify_object(objectsA[i], "managedBy", objectsB[i])
+
+ for i in range(0, 100):
+ self.modify_object(objectsB[i], "managedBy",
+ objectsC[(i + 1) % 100])
+
+ for i in range(0, 100):
+ self.modify_object(objectsC[i], "managedBy",
+ objectsB[(i + 1) % 100])
+
+ all_objects = objectsA + objectsB + objectsC
+ expected_links = all_objects
+
+ # the default order the objects now get returned in should be:
+ # [A0-A99][B0-B99][C0-C99]
+
+ links_expected = True
+
+ # Get all the replication data - this code should resend the requests
+ # with GET_TGT
+ while not self.replication_complete():
+
+ # get the next block of replication data (this sets GET_TGT
+ # if needed)
+ self.repl_get_next(assert_links=links_expected)
+ links_expected = len(self.rxd_links) < len(expected_links)
+
+ # The way the test objects have been created should force
+ # self.repl_get_next() to use the GET_TGT flag. If this doesn't
+ # actually happen, then the test isn't doing its job properly
+ self.assertTrue(self.used_get_tgt,
+ "Test didn't use the GET_TGT flag as expected")
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(all_objects)
+
+ # Check we received links for all the reportees
+ self.assert_expected_links(expected_links)
+
+ def test_repl_integrity_link_attr(self):
+ """
+ Tests adding links to new objects while a replication is in progress.
+ """
+
+ # create some source objects for the linked attributes, sandwiched
+ # between 2 blocks of filler objects
+ filler = self.create_object_range(0, 100, prefix="filler")
+ reportees = self.create_object_range(0, 100, prefix="reportee")
+ filler += self.create_object_range(100, 200, prefix="filler")
+
+ # Start the replication and get the first block of filler objects
+ # (We're being mean here and setting the GET_TGT flag right from the
+ # start. On earlier Samba versions, if the client encountered an
+ # unknown target object and retried with GET_TGT, it would restart the
+ # replication cycle from scratch, which avoids the problem).
+ self.repl_get_next(get_tgt=True)
+
+ # create the target objects and add the links. These objects should be
+ # outside the scope of the Samba replication cycle, but the links
+ # should still get sent with the source object
+ managers = self.create_object_range(0, 100, prefix="manager")
+
+ for i in range(0, 100):
+ self.modify_object(reportees[i], "managedBy", managers[i])
+
+ expected_objects = managers + reportees + filler
+ expected_links = reportees
+
+ # complete the replication
+ while not self.replication_complete():
+ self.repl_get_next(get_tgt=True)
+
+ # If we didn't receive the most recently created objects in the last
+ # replication cycle, then kick off another replication to get them
+ if len(self.rxd_dn_list) < len(expected_objects):
+ self.repl_get_next()
+
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(expected_objects)
+
+ # Check we received links for all the parents
+ self.assert_expected_links(expected_links)
+
+ def test_repl_get_anc_link_attr(self):
+ """
+ A basic GET_ANC test where the parents have linked attributes
+ """
+
+ # Create a block of 100 parents and 100 children
+ parent_dn_list = []
+ expected_dn_list = self.create_object_range(0, 100, prefix="parent",
+ children=("A"),
+ parent_list=parent_dn_list)
+
+ # Add links from the parents to the children
+ for x in range(0, 100):
+ self.modify_object(parent_dn_list[x], "managedBy",
+ expected_dn_list[x + 100])
+
+ # add some filler objects at the end. This allows us to easily see
+ # which chunk the links get sent in
+ expected_dn_list += self.create_object_range(0, 100, prefix="filler")
+
+ # We've now got objects in the following order:
+ # [100 x children][100 x parents][100 x filler]
+
+ # Get the replication data - because the block of children come first,
+ # this should retry the request with GET_ANC
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ self.assertTrue(self.used_get_anc,
+ "Test didn't use the GET_ANC flag as expected")
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(expected_dn_list)
+
+ # Check we received links for all the parents
+ self.assert_expected_links(parent_dn_list)
+
+ def test_repl_get_tgt_and_anc(self):
+ """
+ Check we can resolve an unknown ancestor when fetching the link target,
+ i.e. tests using GET_TGT and GET_ANC in combination
+ """
+
+ # Create some parent/child objects (the child will be the link target)
+ parents = []
+ all_objects = self.create_object_range(0, 100, prefix="parent",
+ children=["la_tgt"],
+ parent_list=parents)
+
+ children = [item for item in all_objects if item not in parents]
+
+ # create the link source objects and link them to the child/target
+ la_sources = self.create_object_range(0, 100, prefix="la_src")
+ all_objects += la_sources
+
+ for i in range(0, 100):
+ self.modify_object(la_sources[i], "managedBy", children[i])
+
+ expected_links = la_sources
+
+ # modify the children/targets so they come after the link source
+ for x in range(0, 100):
+ self.modify_object(children[x], "displayName", "OU%d" % x)
+
+ # modify the parents, so they now come last in the replication
+ for x in range(0, 100):
+ self.modify_object(parents[x], "displayName", "OU%d" % x)
+
+ # We've now got objects in the following order:
+ # [100 la_source][100 la_target][100 parents (of la_target)]
+
+ links_expected = True
+
+ # Get all the replication data - this code should resend the requests
+ # with GET_TGT and GET_ANC
+ while not self.replication_complete():
+
+ # get the next block of replication data (this sets
+ # GET_TGT/GET_ANC)
+ self.repl_get_next(assert_links=links_expected)
+ links_expected = len(self.rxd_links) < len(expected_links)
+
+ # The way the test objects have been created should force
+ # self.repl_get_next() to use the GET_TGT/GET_ANC flags. If this
+ # doesn't actually happen, then the test isn't doing its job properly
+ self.assertTrue(self.used_get_tgt,
+ "Test didn't use the GET_TGT flag as expected")
+ self.assertTrue(self.used_get_anc,
+ "Test didn't use the GET_ANC flag as expected")
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(all_objects)
+
+ # Check we received links for all the link sources
+ self.assert_expected_links(expected_links)
+
+ # Second part of test. Add some extra objects and kick off another
+ # replication. The test code will use the HWM from the last replication
+ # so we'll only receive the objects we modify below
+ self.start_new_repl_cycle()
+
+ # add an extra level of grandchildren that hang off a child
+ # that got created last time
+ new_parent = "OU=test_new_parent,%s" % children[0]
+ self.add_object(new_parent)
+ new_children = []
+
+ for x in range(0, 50):
+ dn = "OU=test_new_la_tgt%d,%s" % (x, new_parent)
+ self.add_object(dn)
+ new_children.append(dn)
+
+ # replace half of the links to point to the new children
+ for x in range(0, 50):
+ self.delete_attribute(la_sources[x], "managedBy", children[x])
+ self.modify_object(la_sources[x], "managedBy", new_children[x])
+
+ # add some filler objects to fill up the 1st chunk
+ filler = self.create_object_range(0, 100, prefix="filler")
+
+ # modify the new children/targets so they come after the link source
+ for x in range(0, 50):
+ self.modify_object(new_children[x], "displayName", "OU-%d" % x)
+
+ # modify the parent, so it now comes last in the replication
+ self.modify_object(new_parent, "displayName", "OU%d" % x)
+
+ # We should now get the modified objects in the following order:
+ # [50 links (x 2)][100 filler][50 new children][new parent]
+ # Note that the link sources aren't actually sent (their new linked
+ # attributes are sent, but apart from that, nothing has changed)
+ all_objects = filler + new_children + [new_parent]
+ expected_links = la_sources[:50]
+
+ links_expected = True
+
+ while not self.replication_complete():
+ self.repl_get_next(assert_links=links_expected)
+ links_expected = len(self.rxd_links) < len(expected_links)
+
+ self.assertTrue(self.used_get_tgt,
+ "Test didn't use the GET_TGT flag as expected")
+ self.assertTrue(self.used_get_anc,
+ "Test didn't use the GET_ANC flag as expected")
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(all_objects)
+
+ # Check we received links (50 deleted links and 50 new)
+ self.assert_expected_links(expected_links, num_expected=100)
+
+ def _repl_integrity_obj_deletion(self, delete_link_source=True):
+ """
+ Tests deleting link objects while a replication is in progress.
+ """
+
+ # create some objects and link them together, with some filler
+ # object in between the link sources
+ la_sources = self.create_object_range(0, 100, prefix="la_source")
+ la_targets = self.create_object_range(0, 100, prefix="la_targets")
+
+ for i in range(0, 50):
+ self.modify_object(la_sources[i], "managedBy", la_targets[i])
+
+ filler = self.create_object_range(0, 100, prefix="filler")
+
+ for i in range(50, 100):
+ self.modify_object(la_sources[i], "managedBy", la_targets[i])
+
+ # touch the targets so that the sources get replicated first
+ for i in range(0, 100):
+ self.modify_object(la_targets[i], "displayName", "OU%d" % i)
+
+ # objects should now be in the following USN order:
+ # [50 la_source][100 filler][50 la_source][100 la_target]
+
+ # Get the first block containing 50 link sources
+ self.repl_get_next()
+
+ # delete either the link targets or link source objects
+ if delete_link_source:
+ objects_to_delete = la_sources
+ # in GET_TGT testenvs we only receive the first 50 source objects
+ expected_objects = la_sources[:50] + la_targets + filler
+ else:
+ objects_to_delete = la_targets
+ expected_objects = la_sources + filler
+
+ for obj in objects_to_delete:
+ self.ldb_dc2.delete(obj)
+
+ # complete the replication
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ # Check we get all the objects we're expecting
+ self.assert_expected_data(expected_objects)
+
+ # we can't use assert_expected_links() here because it tries to check
+ # against the deleted objects on the DC. (Although we receive some
+ # links from the first block processed, the Samba client should end up
+ # deleting these, as the source/target object involved is deleted)
+ self.assertTrue(len(self.rxd_links) == 50,
+ "Expected 50 links, not %d" % len(self.rxd_links))
+
+ def test_repl_integrity_src_obj_deletion(self):
+ self._repl_integrity_obj_deletion(delete_link_source=True)
+
+ def test_repl_integrity_tgt_obj_deletion(self):
+ self._repl_integrity_obj_deletion(delete_link_source=False)
+
+ def restore_deleted_object(self, guid, new_dn):
+ """Re-animates a deleted object"""
+
+ guid_str = self._GUID_string(guid)
+ res = self.test_ldb_dc.search(base="<GUID=%s>" % guid_str,
+ attrs=["isDeleted"],
+ controls=['show_deleted:1'],
+ scope=ldb.SCOPE_BASE)
+ if len(res) != 1:
+ return
+
+ msg = ldb.Message()
+ msg.dn = res[0].dn
+ msg["isDeleted"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE,
+ "isDeleted")
+ msg["distinguishedName"] = ldb.MessageElement([new_dn],
+ ldb.FLAG_MOD_REPLACE,
+ "distinguishedName")
+ self.test_ldb_dc.modify(msg, ["show_deleted:1"])
+
+ def sync_DCs(self, nc_dn=None):
+ # make sure DC1 has all the changes we've made to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2,
+ nc_dn=nc_dn)
+
+ def get_object_guid(self, dn):
+ res = self.test_ldb_dc.search(base=dn, attrs=["objectGUID"],
+ scope=ldb.SCOPE_BASE)
+ return res[0]['objectGUID'][0]
+
+ def set_dc_connection(self, conn):
+ """
+ Switches over the connection state info that the underlying drs_base
+ class uses so that we replicate with a different DC.
+ """
+ self.default_hwm = conn.default_hwm
+ self.default_utdv = conn.default_utdv
+ self.drs = conn.drs
+ self.drs_handle = conn.drs_handle
+ self.set_test_ldb_dc(conn.ldb_dc)
+
+ def assert_DCs_replication_is_consistent(self, peer_conn, all_objects,
+ expected_links):
+ """
+ Replicates against both the primary and secondary DCs in the testenv
+ and checks that both return the expected results.
+ """
+ print("Checking replication against primary test DC...")
+
+ # get the replication data from the test DC first
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ # Check we get all the objects and links we're expecting
+ self.assert_expected_data(all_objects)
+ self.assert_expected_links(expected_links)
+
+ # switch over the DC state info so we now talk to the peer DC
+ self.set_dc_connection(peer_conn)
+ self.init_test_state()
+
+ print("Checking replication against secondary test DC...")
+
+ # check that we get the same information from the 2nd DC
+ while not self.replication_complete():
+ self.repl_get_next()
+
+ self.assert_expected_data(all_objects)
+ self.assert_expected_links(expected_links)
+
+ # switch back to using the default connection
+ self.set_dc_connection(self.default_conn)
+
+ def test_repl_integrity_obj_reanimation(self):
+ """
+ Checks receiving links for a re-animated object doesn't lose links.
+ We test this against the peer DC to make sure it doesn't drop links.
+ """
+
+ # This test is a little different in that we're particularly interested
+ # in exercising the replmd client code on the second DC.
+ # First, make sure the peer DC has the base OU, then connect to it (so
+ # we store its initial HWM)
+ self.sync_DCs()
+ peer_conn = DcConnection(self, self.ldb_dc1, self.dnsname_dc1)
+
+ # create the link source/target objects
+ la_sources = self.create_object_range(0, 100, prefix="la_src")
+ la_targets = self.create_object_range(0, 100, prefix="la_tgt")
+
+ # store the target object's GUIDs (we need to know these to
+ # reanimate them)
+ target_guids = []
+
+ for dn in la_targets:
+ target_guids.append(self.get_object_guid(dn))
+
+ # delete the link target
+ for x in range(0, 100):
+ self.ldb_dc2.delete(la_targets[x])
+
+ # sync the DCs, then disable replication. We want the peer DC to get
+ # all the following changes in a single replication cycle
+ self.sync_DCs()
+ self._disable_all_repl(self.dnsname_dc2)
+
+ # restore the target objects for the linked attributes again
+ for x in range(0, 100):
+ self.restore_deleted_object(target_guids[x], la_targets[x])
+
+ # add the links
+ for x in range(0, 100):
+ self.modify_object(la_sources[x], "managedBy", la_targets[x])
+
+ # create some additional filler objects
+ filler = self.create_object_range(0, 100, prefix="filler")
+
+ # modify the targets so they now come last
+ for x in range(0, 100):
+ self.modify_object(la_targets[x], "displayName", "OU-%d" % x)
+
+ # the objects should now be sent in the following order:
+ # [la sources + links][filler][la targets]
+ all_objects = la_sources + la_targets + filler
+ expected_links = la_sources
+
+ # Enable replication again make sure the 2 DCs are back in sync
+ self._enable_all_repl(self.dnsname_dc2)
+ self.sync_DCs()
+
+ # Get the replication data from each DC in turn.
+ # Check that both give us all the objects and links we're expecting,
+ # i.e. no links were lost
+ self.assert_DCs_replication_is_consistent(peer_conn, all_objects,
+ expected_links)
+
+ def _test_repl_integrity_cross_partition_links(self, get_tgt=False):
+ """
+ Checks that a cross-partition link to an unknown target object does
+ not result in missing links.
+ """
+
+ # check the peer DC is up-to-date, then connect (storing its HWM)
+ self.sync_DCs()
+ peer_conn = DcConnection(self, self.ldb_dc1, self.dnsname_dc1)
+
+ # stop replication so the peer gets the following objects in one go
+ self._disable_all_repl(self.dnsname_dc2)
+
+ # optionally force the client-side to use GET_TGT locally, by adding a
+ # one-way link to a missing/deleted target object
+ if get_tgt:
+ missing_target = "OU=missing_tgt,%s" % self.ou
+ self.add_object(missing_target)
+ get_tgt_source = "CN=get_tgt_src,%s" % self.ou
+ self.add_object(get_tgt_source,
+ objectclass="msExchConfigurationContainer")
+ self.modify_object(get_tgt_source, "addressBookRoots2",
+ missing_target)
+ self.test_ldb_dc.delete(missing_target)
+
+ # create a link source object in the main NC
+ la_source = "OU=cross_nc_src,%s" % self.ou
+ self.add_object(la_source)
+
+ # create the link target (a server object) in the config NC
+ sites_dn = "CN=Sites,%s" % self.config_dn
+ servers_dn = "CN=Servers,CN=Default-First-Site-Name,%s" % sites_dn
+ rand = random.randint(1, 10000000)
+ la_target = "CN=getncchanges-%d,%s" % (rand, servers_dn)
+ self.add_object(la_target, objectclass="server")
+
+ # add a cross-partition link between the two
+ self.modify_object(la_source, "managedBy", la_target)
+
+ # First, sync to the peer the NC containing the link source object
+ self.sync_DCs()
+
+ # Now, before the peer has received the partition containing the target
+ # object, try replicating from the peer. It will only know about half
+ # of the link at this point, but it should be a valid scenario
+ self.set_dc_connection(peer_conn)
+
+ while not self.replication_complete():
+ # pretend we've received other link targets out of order and that's
+ # forced us to use GET_TGT. This checks the peer doesn't fail
+ # trying to fetch a cross-partition target object that doesn't
+ # exist
+ self.repl_get_next(get_tgt=True)
+
+ self.set_dc_connection(self.default_conn)
+
+ # delete the GET_TGT test object. We're not interested in asserting its
+ # links - it was just there to make the client use GET_TGT (and it
+ # creates an inconsistency because one DC correctly ignores the link,
+ # because it points to a deleted object)
+ if get_tgt:
+ self.test_ldb_dc.delete(get_tgt_source)
+
+ self.init_test_state()
+
+ # Now sync across the partition containing the link target object
+ self.sync_DCs(nc_dn=self.config_dn)
+ self._enable_all_repl(self.dnsname_dc2)
+
+ # Get the replication data from each DC in turn.
+ # Check that both return the cross-partition link (note we're not
+ # checking the config domain NC here for simplicity)
+ self.assert_DCs_replication_is_consistent(peer_conn,
+ all_objects=[la_source],
+ expected_links=[la_source])
+
+ # the cross-partition linked attribute has a missing backlink. Check
+ # that we can still delete it successfully
+ self.delete_attribute(la_source, "managedBy", la_target)
+ self.sync_DCs()
+
+ res = self.test_ldb_dc.search(ldb.Dn(self.ldb_dc1, la_source),
+ attrs=["managedBy"],
+ controls=['extended_dn:1:0'],
+ scope=ldb.SCOPE_BASE)
+ self.assertFalse("managedBy" in res[0],
+ "%s in DB still has managedBy attribute" % la_source)
+ res = self.test_ldb_dc.search(ldb.Dn(self.ldb_dc2, la_source),
+ attrs=["managedBy"],
+ controls=['extended_dn:1:0'],
+ scope=ldb.SCOPE_BASE)
+ self.assertFalse("managedBy" in res[0],
+ "%s in DB still has managedBy attribute" % la_source)
+
+ # Check receiving a cross-partition link to a deleted target.
+ # Delete the target and make sure the deletion is sync'd between DCs
+ target_guid = self.get_object_guid(la_target)
+ self.test_ldb_dc.delete(la_target)
+ self.sync_DCs(nc_dn=self.config_dn)
+ self._disable_all_repl(self.dnsname_dc2)
+
+ # re-animate the target
+ self.restore_deleted_object(target_guid, la_target)
+ self.modify_object(la_source, "managedBy", la_target)
+
+ # now sync the link - because the target is in another partition, the
+ # peer DC receives a link for a deleted target, which it should accept
+ self.sync_DCs()
+ res = self.test_ldb_dc.search(ldb.Dn(self.ldb_dc1, la_source),
+ attrs=["managedBy"],
+ controls=['extended_dn:1:0'],
+ scope=ldb.SCOPE_BASE)
+ self.assertTrue("managedBy" in res[0],
+ "%s in DB missing managedBy attribute" % la_source)
+
+ # cleanup the server object we created in the Configuration partition
+ self.test_ldb_dc.delete(la_target)
+ self._enable_all_repl(self.dnsname_dc2)
+
+ def test_repl_integrity_cross_partition_links(self):
+ self._test_repl_integrity_cross_partition_links(get_tgt=False)
+
+ def test_repl_integrity_cross_partition_links_with_tgt(self):
+ self._test_repl_integrity_cross_partition_links(get_tgt=True)
+
+ def test_repl_get_tgt_multivalued_links(self):
+ """Tests replication with multi-valued link attributes."""
+
+ # create the target/source objects and link them together
+ la_targets = self.create_object_range(0, 500, prefix="la_tgt")
+ la_source = "CN=la_src,%s" % self.ou
+ self.add_object(la_source, objectclass="msExchConfigurationContainer")
+
+ for tgt in la_targets:
+ self.modify_object(la_source, "addressBookRoots2", tgt)
+
+ filler = self.create_object_range(0, 100, prefix="filler")
+
+ # We should receive the objects/links in the following order:
+ # [500 targets + 1 source][500 links][100 filler]
+ expected_objects = la_targets + [la_source] + filler
+ link_only_chunk = False
+
+ # First do the replication without needing GET_TGT
+ while not self.replication_complete():
+ ctr6 = self.repl_get_next()
+
+ if ctr6.object_count == 0 and ctr6.linked_attributes_count != 0:
+ link_only_chunk = True
+
+ # we should receive one chunk that contains only links
+ self.assertTrue(link_only_chunk,
+ "Expected to receive a chunk containing only links")
+
+ # check we received all the expected objects/links
+ self.assert_expected_data(expected_objects)
+ self.assert_expected_links([la_source], link_attr="addressBookRoots2",
+ num_expected=500)
+
+ # Do the replication again, forcing the use of GET_TGT this time
+ self.init_test_state()
+
+ for x in range(0, 500):
+ self.modify_object(la_targets[x], "displayName", "OU-%d" % x)
+
+ # The objects/links should get sent in the following order:
+ # [1 source][500 targets][500 links][100 filler]
+
+ while not self.replication_complete():
+ ctr6 = self.repl_get_next()
+
+ self.assertTrue(self.used_get_tgt,
+ "Test didn't use the GET_TGT flag as expected")
+
+ # check we received all the expected objects/links
+ self.assert_expected_data(expected_objects)
+ self.assert_expected_links([la_source], link_attr="addressBookRoots2",
+ num_expected=500)
+
+
+ def test_InvalidNC_DummyDN_InvalidGUID_full_repl(self):
+ """Test full replication on a totally invalid GUID fails with the right error code"""
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=dc_guid_1,
+ nc_dn_str="DummyDN",
+ nc_guid=misc.GUID("c2d2f745-1610-4e93-964b-d4ba73eb32f8"),
+ exop=drsuapi.DRSUAPI_EXOP_NONE,
+ max_objects=1)
+
+ (drs, drs_handle) = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.assertEqual(enum, werror.WERR_DS_DRA_BAD_NC)
+
+ def test_DummyDN_valid_GUID_full_repl(self):
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ res = self.ldb_dc1.search(base=self.base_dn, scope=SCOPE_BASE,
+ attrs=["objectGUID"])
+
+ guid = misc.GUID(res[0]["objectGUID"][0])
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str="DummyDN",
+ nc_guid=guid,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP |
+ drsuapi.DRSUAPI_DRS_GET_ANC,
+ exop=drsuapi.DRSUAPI_EXOP_NONE,
+ max_objects=1)
+
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.fail(f"Failed to call GetNCChanges with DummyDN and a GUID: {estr}")
+
+ # The NC should be the first object returned due to GET_ANC
+ self.assertEqual(ctr.first_object.object.identifier.guid, guid)
+
+ def _test_do_full_repl_no_overlap(self, mix=True, get_anc=False):
+ self.default_hwm = drsuapi.DsReplicaHighWaterMark()
+
+ # We set get_anc=True so we can assert the BASE DN will be the
+ # first object
+ ctr6 = self._repl_send_request(get_anc=get_anc)
+ guid_list_1 = self._get_ctr6_object_guids(ctr6)
+
+ if mix:
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=self.ldb_dc1.get_default_basedn(),
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ (level, ctr_repl_obj) = self.drs.DsGetNCChanges(self.drs_handle, 8, req8)
+
+ self.assertEqual(ctr_repl_obj.extended_ret, drsuapi.DRSUAPI_EXOP_ERR_SUCCESS)
+
+ repl_obj_guid_list = self._get_ctr6_object_guids(ctr_repl_obj)
+
+ self.assertEqual(len(repl_obj_guid_list), 1)
+
+ # This should be the first object in the main replication due
+ # to get_anc=True above in one case, and a rule that the NC must be first regardless otherwise
+ self.assertEqual(repl_obj_guid_list[0], guid_list_1[0])
+
+ self.last_ctr = ctr6
+ ctr6 = self._repl_send_request(get_anc=True)
+ guid_list_2 = self._get_ctr6_object_guids(ctr6)
+
+ self.assertNotEqual(guid_list_1, guid_list_2)
+
+ def test_do_full_repl_no_overlap_get_anc(self):
+ """
+ Make sure that a full replication on an nc succeeds to the goal despite needing multiple passes
+ """
+ self._test_do_full_repl_no_overlap(mix=False, get_anc=True)
+
+ def test_do_full_repl_no_overlap(self):
+ """
+ Make sure that a full replication on an nc succeeds to the goal despite needing multiple passes
+ """
+ self._test_do_full_repl_no_overlap(mix=False)
+
+ def test_do_full_repl_mix_no_overlap(self):
+ """
+ Make sure that a full replication on an nc succeeds to the goal despite needing multiple passes
+
+ Assert this is true even if we do a REPL_OBJ in between the replications
+
+ """
+ self._test_do_full_repl_no_overlap(mix=True)
+
+ def nc_change(self):
+ old_base_msg = self.default_conn.ldb_dc.search(base=self.base_dn,
+ scope=SCOPE_BASE,
+ attrs=["oEMInformation"])
+ rec_cleanup = {"dn": self.base_dn,
+ "oEMInformation": old_base_msg[0]["oEMInformation"][0]}
+ m_cleanup = ldb.Message.from_dict(self.default_conn.ldb_dc,
+ rec_cleanup,
+ ldb.FLAG_MOD_REPLACE)
+
+ self.addCleanup(self.default_conn.ldb_dc.modify, m_cleanup)
+
+ rec = {"dn": self.base_dn,
+ "oEMInformation": f"Tortured by Samba's getncchanges.py {self.id()} against {self.default_conn.dnsname_dc}"}
+ m = ldb.Message.from_dict(self.default_conn.ldb_dc, rec, ldb.FLAG_MOD_REPLACE)
+ self.default_conn.ldb_dc.modify(m)
+
+ def _test_repl_nc_is_first(self, start_at_zero=True, nc_change=True, ou_change=True, mid_change=False):
+ """Tests that the NC is always replicated first, but does not move the
+ tmp_highest_usn at that point, just like 'early' GET_ANC objects.
+ """
+
+ # create objects, twice more than the page size of 133
+ objs = self.create_object_range(0, 300, prefix="obj")
+
+ if nc_change:
+ self.nc_change()
+
+ if mid_change:
+ # create even more objects
+ objs = self.create_object_range(301, 450, prefix="obj2")
+
+ base_msg = self.default_conn.ldb_dc.search(base=self.base_dn,
+ scope=SCOPE_BASE,
+ attrs=["uSNChanged",
+ "objectGUID"])
+
+ base_guid = misc.GUID(base_msg[0]["objectGUID"][0])
+ base_usn = int(base_msg[0]["uSNChanged"][0])
+
+ if ou_change:
+ # Make one more modification. We want to assert we have
+ # caught up to the base DN, but Windows both promotes the NC
+ # to the front and skips including it in the tmp_highest_usn,
+ # so we make a later modification that will be to show we get
+ # this change.
+ rec = {"dn": self.ou,
+ "postalCode": "0"}
+ m = ldb.Message.from_dict(self.default_conn.ldb_dc, rec, ldb.FLAG_MOD_REPLACE)
+ self.default_conn.ldb_dc.modify(m)
+
+ ou_msg = self.default_conn.ldb_dc.search(base=self.ou,
+ scope=SCOPE_BASE,
+ attrs=["uSNChanged",
+ "objectGUID"])
+
+ ou_guid = misc.GUID(ou_msg[0]["objectGUID"][0])
+ ou_usn = int(ou_msg[0]["uSNChanged"][0])
+
+ # Check some predicates about USN ordering that the below tests will rely on
+ if ou_change and nc_change:
+ self.assertGreater(ou_usn, base_usn)
+ elif not ou_change and nc_change:
+ self.assertGreater(base_usn, ou_usn)
+
+ ctr6 = self.repl_get_next()
+
+ guid_list_1 = self._get_ctr6_object_guids(ctr6)
+ if nc_change or start_at_zero:
+ self.assertEqual(base_guid, misc.GUID(guid_list_1[0]))
+ self.assertIn(str(base_guid), guid_list_1)
+ self.assertNotIn(str(base_guid), guid_list_1[1:])
+ else:
+ self.assertNotEqual(base_guid, misc.GUID(guid_list_1[0]))
+ self.assertNotIn(str(base_guid), guid_list_1)
+
+ self.assertTrue(ctr6.more_data)
+
+ if not ou_change and nc_change:
+ self.assertLess(ctr6.new_highwatermark.tmp_highest_usn, base_usn)
+
+ i = 0
+ while not self.replication_complete():
+ i = i + 1
+ last_tmp_highest_usn = ctr6.new_highwatermark.tmp_highest_usn
+ ctr6 = self.repl_get_next()
+ guid_list_2 = self._get_ctr6_object_guids(ctr6)
+ if len(guid_list_2) > 0:
+ self.assertNotEqual(last_tmp_highest_usn, ctr6.new_highwatermark.tmp_highest_usn)
+
+ if (nc_change or start_at_zero) and base_usn > last_tmp_highest_usn:
+ self.assertEqual(base_guid, misc.GUID(guid_list_2[0]),
+ f"pass={i} more_data={ctr6.more_data} base_usn={base_usn} tmp_highest_usn={ctr6.new_highwatermark.tmp_highest_usn} last_tmp_highest_usn={last_tmp_highest_usn}")
+ self.assertIn(str(base_guid), guid_list_2,
+ f"pass {i}·more_data={ctr6.more_data} base_usn={base_usn} tmp_highest_usn={ctr6.new_highwatermark.tmp_highest_usn} last_tmp_highest_usn={last_tmp_highest_usn}")
+ else:
+ self.assertNotIn(str(base_guid), guid_list_2,
+ f"pass {i}·more_data={ctr6.more_data} base_usn={base_usn} tmp_highest_usn={ctr6.new_highwatermark.tmp_highest_usn} last_tmp_highest_usn={last_tmp_highest_usn}")
+
+ if ou_change:
+ # The modification to the base OU should be in the final chunk
+ self.assertIn(str(ou_guid), guid_list_2)
+ self.assertGreaterEqual(ctr6.new_highwatermark.highest_usn,
+ ou_usn)
+ else:
+ # Show that the NC root change does not show up in the
+ # highest_usn. We either get the change before or after
+ # it.
+ self.assertNotEqual(ctr6.new_highwatermark.highest_usn,
+ base_usn)
+ self.assertEqual(ctr6.new_highwatermark.highest_usn,
+ ctr6.new_highwatermark.tmp_highest_usn)
+
+ self.assertFalse(ctr6.more_data)
+
+ def test_repl_nc_is_first_start_zero_nc_change(self):
+ self.default_hwm = drsuapi.DsReplicaHighWaterMark()
+ self._test_repl_nc_is_first(start_at_zero=True, nc_change=True, ou_change=True)
+
+ def test_repl_nc_is_first_start_zero(self):
+ # Get the NC change in the middle of the replication stream, certainly not at the start or end
+ self.nc_change()
+ self.default_hwm = drsuapi.DsReplicaHighWaterMark()
+ self._test_repl_nc_is_first(start_at_zero=True, nc_change=False, ou_change=False)
+
+ def test_repl_nc_is_first_mid(self):
+ # This is a modification of the next test, that Samba
+ # will pass as it will always include the NC in the
+ # tmp_highest_usn at the point where it belongs
+ self._test_repl_nc_is_first(start_at_zero=False,
+ nc_change=True,
+ ou_change=True,
+ mid_change=True)
+
+ def test_repl_nc_is_first(self):
+ # This is a modification of the next test, that Samba
+ # will pass as it will always include the NC in the
+ # tmp_highest_usn at the point where it belongs
+ self._test_repl_nc_is_first(start_at_zero=False, nc_change=True, ou_change=True)
+
+ def test_repl_nc_is_first_nc_change_only(self):
+ # This shows that the NC change is not reflected in the tmp_highest_usn
+ self._test_repl_nc_is_first(start_at_zero=False, nc_change=True, ou_change=False)
+
+ def test_repl_nc_is_first_no_change(self):
+ # The NC should not be present in this replication
+ self._test_repl_nc_is_first(start_at_zero=False, nc_change=False, ou_change=False)
+
+class DcConnection:
+ """Helper class to track a connection to another DC"""
+
+ def __init__(self, drs_base, ldb_dc, dnsname_dc):
+ self.ldb_dc = ldb_dc
+ (self.drs, self.drs_handle) = drs_base._ds_bind(dnsname_dc)
+ (self.default_hwm, utdv) = drs_base._get_highest_hwm_utdv(ldb_dc)
+ self.default_utdv = utdv
+ self.dnsname_dc = dnsname_dc
diff --git a/source4/torture/drs/python/link_conflicts.py b/source4/torture/drs/python/link_conflicts.py
new file mode 100644
index 0000000..d344b7e
--- /dev/null
+++ b/source4/torture/drs/python/link_conflicts.py
@@ -0,0 +1,763 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests replication scenarios that involve conflicting linked attribute
+# information between the 2 DCs.
+#
+# Copyright (C) Catalyst.Net Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN \
+# link_conflicts -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+import ldb
+from ldb import SCOPE_BASE
+import random
+import time
+
+from drs_base import AbstractLink
+from samba.dcerpc import drsuapi, misc
+from samba.dcerpc.drsuapi import DRSUAPI_EXOP_ERR_SUCCESS
+
+# specifies the order to sync DCs in
+DC1_TO_DC2 = 1
+DC2_TO_DC1 = 2
+
+
+class DrsReplicaLinkConflictTestCase(drs_base.DrsBaseTestCase):
+ def setUp(self):
+ super(DrsReplicaLinkConflictTestCase, self).setUp()
+
+ self.ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "test_link_conflict")
+ self.base_dn = self.ldb_dc1.get_default_basedn()
+
+ (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
+ (self.drs2, self.drs2_handle) = self._ds_bind(self.dnsname_dc2)
+
+ # disable replication for the tests so we can control at what point
+ # the DCs try to replicate
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ def tearDown(self):
+ # re-enable replication
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self._enable_inbound_repl(self.dnsname_dc2)
+ self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+ super(DrsReplicaLinkConflictTestCase, self).tearDown()
+
+ def get_guid(self, samdb, dn):
+ """Returns an object's GUID (in string format)"""
+ res = samdb.search(base=dn, attrs=["objectGUID"], scope=ldb.SCOPE_BASE)
+ return self._GUID_string(res[0]['objectGUID'][0])
+
+ def add_object(self, samdb, dn, objectclass="organizationalunit"):
+ """Adds an object"""
+ samdb.add({"dn": dn, "objectclass": objectclass})
+ return self.get_guid(samdb, dn)
+
+ def modify_object(self, samdb, dn, attr, value):
+ """Modifies an attribute for an object"""
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, dn)
+ m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_ADD, attr)
+ samdb.modify(m)
+
+ def add_link_attr(self, samdb, source_dn, attr, target_dn):
+ """Adds a linked attribute between 2 objects"""
+ # add the specified attribute to the source object
+ self.modify_object(samdb, source_dn, attr, target_dn)
+
+ def del_link_attr(self, samdb, src, attr, target):
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, src)
+ m[attr] = ldb.MessageElement(target, ldb.FLAG_MOD_DELETE, attr)
+ samdb.modify(m)
+
+ def sync_DCs(self, sync_order=DC1_TO_DC2):
+ """Manually syncs the 2 DCs to ensure they're in sync"""
+ if sync_order == DC1_TO_DC2:
+ # sync DC1-->DC2, then DC2-->DC1
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1)
+ self._net_drs_replicate(DC=self.dnsname_dc1,
+ fromDC=self.dnsname_dc2)
+ else:
+ # sync DC2-->DC1, then DC1-->DC2
+ self._net_drs_replicate(DC=self.dnsname_dc1,
+ fromDC=self.dnsname_dc2)
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1)
+
+ def ensure_unique_timestamp(self):
+ """Waits a second to ensure a unique timestamp between 2 objects"""
+ time.sleep(1)
+
+ def unique_dn(self, obj_name):
+ """Returns a unique object DN"""
+ # Because we run each test case twice, we need to create a unique DN so
+ # that the 2nd run doesn't hit objects that already exist. Add some
+ # randomness to the object DN to make it unique
+ rand = random.randint(1, 10000000)
+ return "%s-%d,%s" % (obj_name, rand, self.ou)
+
+ def assert_attrs_match(self, res1, res2, attr, expected_count):
+ """
+ Asserts that the search results contain the expected number of
+ attributes and the results match on both DCs
+ """
+ actual_len = len(res1[0][attr])
+ self.assertTrue(actual_len == expected_count,
+ "Expected %u %s attributes, got %u" % (expected_count,
+ attr,
+ actual_len))
+ actual_len = len(res2[0][attr])
+ self.assertTrue(actual_len == expected_count,
+ "Expected %u %s attributes, got %u" % (expected_count,
+ attr,
+ actual_len))
+
+ # check DCs both agree on the same linked attributes
+ for val in res1[0][attr]:
+ self.assertTrue(val in res2[0][attr],
+ "%s '%s' not found on DC2" % (attr, val))
+
+ def zero_highwatermark(self):
+ """Returns a zeroed highwatermark so that all DRS data gets returned"""
+ hwm = drsuapi.DsReplicaHighWaterMark()
+ hwm.tmp_highest_usn = 0
+ hwm.reserved_usn = 0
+ hwm.highest_usn = 0
+ return hwm
+
+ def _check_replicated_links(self, src_obj_dn, expected_links):
+ """Checks that replication sends back the expected linked attributes"""
+ self._check_replication([src_obj_dn],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ dest_dsa=None,
+ drs_error=drsuapi.DRSUAPI_EXOP_ERR_SUCCESS,
+ nc_dn_str=src_obj_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ expected_links=expected_links,
+ highwatermark=self.zero_highwatermark())
+
+ # Check DC2 as well
+ self.set_test_ldb_dc(self.ldb_dc2)
+
+ self._check_replication([src_obj_dn],
+ drsuapi.DRSUAPI_DRS_WRIT_REP,
+ dest_dsa=None,
+ drs_error=drsuapi.DRSUAPI_EXOP_ERR_SUCCESS,
+ nc_dn_str=src_obj_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ expected_links=expected_links,
+ highwatermark=self.zero_highwatermark(),
+ drs=self.drs2, drs_handle=self.drs2_handle)
+ self.set_test_ldb_dc(self.ldb_dc1)
+
+ def _test_conflict_single_valued_link(self, sync_order):
+ """
+ Tests a simple single-value link conflict, i.e. each DC adds a link to
+ the same source object but linking to different targets.
+ """
+ src_ou = self.unique_dn("OU=src")
+ src_guid = self.add_object(self.ldb_dc1, src_ou)
+ self.sync_DCs()
+
+ # create a unique target on each DC
+ target1_ou = self.unique_dn("OU=target1")
+ target2_ou = self.unique_dn("OU=target2")
+
+ target1_guid = self.add_object(self.ldb_dc1, target1_ou)
+ target2_guid = self.add_object(self.ldb_dc2, target2_ou)
+
+ # link the test OU to the respective targets created
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_ou, "managedBy", target2_ou)
+
+ # sync the 2 DCs
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+
+ # check the object has only have one occurrence of the single-valued
+ # attribute and it matches on both DCs
+ self.assert_attrs_match(res1, res2, "managedBy", 1)
+
+ self.assertTrue(str(res1[0]["managedBy"][0]) == target2_ou,
+ "Expected most recent update to win conflict")
+
+ # we can't query the deleted links over LDAP, but we can check DRS
+ # to make sure the DC kept a copy of the conflicting link
+ link1 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy, 0,
+ misc.GUID(src_guid), misc.GUID(target1_guid))
+ link2 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ misc.GUID(src_guid), misc.GUID(target2_guid))
+ self._check_replicated_links(src_ou, [link1, link2])
+
+ def test_conflict_single_valued_link(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_conflict_single_valued_link(sync_order=DC1_TO_DC2)
+ self._test_conflict_single_valued_link(sync_order=DC2_TO_DC1)
+
+ def _test_duplicate_single_valued_link(self, sync_order):
+ """
+ Adds the same single-valued link on 2 DCs and checks we don't end up
+ with 2 copies of the link.
+ """
+ # create unique objects for the link
+ target_ou = self.unique_dn("OU=target")
+ self.add_object(self.ldb_dc1, target_ou)
+ src_ou = self.unique_dn("OU=src")
+ src_guid = self.add_object(self.ldb_dc1, src_ou)
+ self.sync_DCs()
+
+ # link the same test OU to the same target on both DCs
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target_ou)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_ou, "managedBy", target_ou)
+
+ # sync the 2 DCs
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+
+ # check the object has only have one occurrence of the single-valued
+ # attribute and it matches on both DCs
+ self.assert_attrs_match(res1, res2, "managedBy", 1)
+
+ def test_duplicate_single_valued_link(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_duplicate_single_valued_link(sync_order=DC1_TO_DC2)
+ self._test_duplicate_single_valued_link(sync_order=DC2_TO_DC1)
+
+ def _test_conflict_multi_valued_link(self, sync_order):
+ """
+ Tests a simple multi-valued link conflict. This adds 2 objects with the
+ same username on 2 different DCs and checks their group membership is
+ preserved after the conflict is resolved.
+ """
+
+ # create a common link source
+ src_dn = self.unique_dn("CN=src")
+ src_guid = self.add_object(self.ldb_dc1, src_dn, objectclass="group")
+ self.sync_DCs()
+
+ # create the same user (link target) on each DC.
+ # Note that the GUIDs will differ between the DCs
+ target_dn = self.unique_dn("CN=target")
+ target1_guid = self.add_object(self.ldb_dc1, target_dn,
+ objectclass="user")
+ self.ensure_unique_timestamp()
+ target2_guid = self.add_object(self.ldb_dc2, target_dn,
+ objectclass="user")
+
+ # link the src group to the respective target created
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+
+ # sync the 2 DCs. We expect the more recent target2 object to win
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+ target1_conflict = False
+
+ # we expect exactly 2 members in our test group (both DCs should agree)
+ self.assert_attrs_match(res1, res2, "member", 2)
+
+ for val in [str(val) for val in res1[0]["member"]]:
+ # check the expected conflicting object was renamed
+ self.assertFalse("CNF:%s" % target2_guid in val)
+ if "CNF:%s" % target1_guid in val:
+ target1_conflict = True
+
+ self.assertTrue(target1_conflict,
+ "Expected link to conflicting target object not found")
+
+ def test_conflict_multi_valued_link(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_conflict_multi_valued_link(sync_order=DC1_TO_DC2)
+ self._test_conflict_multi_valued_link(sync_order=DC2_TO_DC1)
+
+ def _test_duplicate_multi_valued_link(self, sync_order):
+ """
+ Adds the same multivalued link on 2 DCs and checks we don't end up
+ with 2 copies of the link.
+ """
+
+ # create the link source/target objects
+ src_dn = self.unique_dn("CN=src")
+ src_guid = self.add_object(self.ldb_dc1, src_dn, objectclass="group")
+ target_dn = self.unique_dn("CN=target")
+ self.add_object(self.ldb_dc1, target_dn, objectclass="user")
+ self.sync_DCs()
+
+ # link the src group to the same target user separately on each DC
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+
+ # we expect to still have only 1 member in our test group
+ self.assert_attrs_match(res1, res2, "member", 1)
+
+ def test_duplicate_multi_valued_link(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_duplicate_multi_valued_link(sync_order=DC1_TO_DC2)
+ self._test_duplicate_multi_valued_link(sync_order=DC2_TO_DC1)
+
+ def _test_conflict_backlinks(self, sync_order):
+ """
+ Tests that resolving a source object conflict fixes up any backlinks,
+ e.g. the same user is added to a conflicting group.
+ """
+
+ # create a common link target
+ target_dn = self.unique_dn("CN=target")
+ target_guid = self.add_object(self.ldb_dc1, target_dn,
+ objectclass="user")
+ self.sync_DCs()
+
+ # create the same group (link source) on each DC.
+ # Note that the GUIDs will differ between the DCs
+ src_dn = self.unique_dn("CN=src")
+ src1_guid = self.add_object(self.ldb_dc1, src_dn, objectclass="group")
+ self.ensure_unique_timestamp()
+ src2_guid = self.add_object(self.ldb_dc2, src_dn, objectclass="group")
+
+ # link the src group to the respective target created
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+
+ # sync the 2 DCs. We expect the more recent src2 object to win
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % target_guid,
+ scope=SCOPE_BASE, attrs=["memberOf"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % target_guid,
+ scope=SCOPE_BASE, attrs=["memberOf"])
+ src1_backlink = False
+
+ # our test user should still be a member of 2 groups (check both
+ # DCs agree)
+ self.assert_attrs_match(res1, res2, "memberOf", 2)
+
+ for val in [str(val) for val in res1[0]["memberOf"]]:
+ # check the conflicting object was renamed
+ self.assertFalse("CNF:%s" % src2_guid in val)
+ if "CNF:%s" % src1_guid in val:
+ src1_backlink = True
+
+ self.assertTrue(src1_backlink,
+ "Backlink to conflicting source object not found")
+
+ def test_conflict_backlinks(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_conflict_backlinks(sync_order=DC1_TO_DC2)
+ self._test_conflict_backlinks(sync_order=DC2_TO_DC1)
+
+ def _test_link_deletion_conflict(self, sync_order):
+ """
+ Checks that a deleted link conflicting with an active link is
+ resolved correctly.
+ """
+
+ # Add the link objects
+ target_dn = self.unique_dn("CN=target")
+ self.add_object(self.ldb_dc1, target_dn, objectclass="user")
+ src_dn = self.unique_dn("CN=src")
+ src_guid = self.add_object(self.ldb_dc1, src_dn, objectclass="group")
+ self.sync_DCs()
+
+ # add the same link on both DCs, and resolve any conflict
+ self.add_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+ self.sync_DCs(sync_order=sync_order)
+
+ # delete and re-add the link on one DC
+ self.del_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+
+ # just delete it on the other DC
+ self.ensure_unique_timestamp()
+ self.del_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+ # sanity-check the link is gone on this DC
+ res1 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+ self.assertFalse("member" in res1[0], "Couldn't delete member attr")
+
+ # sync the 2 DCs. We expect the more older DC1 attribute to win
+ # because it has a higher version number (even though it's older)
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+
+ # our test user should still be a member of the group (check both
+ # DCs agree)
+ self.assertTrue("member" in res1[0],
+ "Expected member attribute missing")
+ self.assert_attrs_match(res1, res2, "member", 1)
+
+ def test_link_deletion_conflict(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_link_deletion_conflict(sync_order=DC1_TO_DC2)
+ self._test_link_deletion_conflict(sync_order=DC2_TO_DC1)
+
+ def _test_obj_deletion_conflict(self, sync_order, del_target):
+ """
+ Checks that a receiving a new link for a deleted object gets
+ resolved correctly.
+ """
+
+ target_dn = self.unique_dn("CN=target")
+ target_guid = self.add_object(self.ldb_dc1, target_dn,
+ objectclass="user")
+ src_dn = self.unique_dn("CN=src")
+ src_guid = self.add_object(self.ldb_dc1, src_dn, objectclass="group")
+
+ self.sync_DCs()
+
+ # delete the object on one DC
+ if del_target:
+ search_guid = src_guid
+ self.ldb_dc2.delete(target_dn)
+ else:
+ search_guid = target_guid
+ self.ldb_dc2.delete(src_dn)
+
+ # add a link on the other DC
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+
+ self.sync_DCs(sync_order=sync_order)
+
+ # the object deletion should trump the link addition.
+ # Check the link no longer exists on the remaining object
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % search_guid,
+ scope=SCOPE_BASE,
+ attrs=["member", "memberOf"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % search_guid,
+ scope=SCOPE_BASE,
+ attrs=["member", "memberOf"])
+
+ self.assertFalse("member" in res1[0], "member attr shouldn't exist")
+ self.assertFalse("member" in res2[0], "member attr shouldn't exist")
+ self.assertFalse("memberOf" in res1[0], "member attr shouldn't exist")
+ self.assertFalse("memberOf" in res2[0], "member attr shouldn't exist")
+
+ def test_obj_deletion_conflict(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_obj_deletion_conflict(sync_order=DC1_TO_DC2,
+ del_target=True)
+ self._test_obj_deletion_conflict(sync_order=DC2_TO_DC1,
+ del_target=True)
+
+ # and also try deleting the source object instead of the link target
+ self._test_obj_deletion_conflict(sync_order=DC1_TO_DC2,
+ del_target=False)
+ self._test_obj_deletion_conflict(sync_order=DC2_TO_DC1,
+ del_target=False)
+
+ def _test_full_sync_link_conflict(self, sync_order):
+ """
+ Checks that doing a full sync doesn't affect how conflicts get resolved
+ """
+
+ # create the objects for the linked attribute
+ src_dn = self.unique_dn("CN=src")
+ src_guid = self.add_object(self.ldb_dc1, src_dn, objectclass="group")
+ target_dn = self.unique_dn("CN=target")
+ self.add_object(self.ldb_dc1, target_dn, objectclass="user")
+ self.sync_DCs()
+
+ # add the same link on both DCs
+ self.add_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+
+ # Do a couple of full syncs which should resolve the conflict
+ # (but only for one DC)
+ if sync_order == DC1_TO_DC2:
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ full_sync=True)
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ full_sync=True)
+ else:
+ self._net_drs_replicate(DC=self.dnsname_dc1,
+ fromDC=self.dnsname_dc2,
+ full_sync=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1,
+ fromDC=self.dnsname_dc2,
+ full_sync=True)
+
+ # delete and re-add the link on one DC
+ self.del_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc1, src_dn, "member", target_dn)
+
+ # just delete the link on the 2nd DC
+ self.ensure_unique_timestamp()
+ self.del_link_attr(self.ldb_dc2, src_dn, "member", target_dn)
+
+ # sync the 2 DCs. We expect DC1 to win based on version number
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["member"])
+
+ # check the membership still exits (and both DCs agree)
+ self.assertTrue("member" in res1[0],
+ "Expected member attribute missing")
+ self.assert_attrs_match(res1, res2, "member", 1)
+
+ def test_full_sync_link_conflict(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_full_sync_link_conflict(sync_order=DC1_TO_DC2)
+ self._test_full_sync_link_conflict(sync_order=DC2_TO_DC1)
+
+ def _singleval_link_conflict_deleted_winner(self, sync_order):
+ """
+ Tests a single-value link conflict where the more-up-to-date link value
+ is deleted.
+ """
+ src_ou = self.unique_dn("OU=src")
+ src_guid = self.add_object(self.ldb_dc1, src_ou)
+ self.sync_DCs()
+
+ # create a unique target on each DC
+ target1_ou = self.unique_dn("OU=target1")
+ target2_ou = self.unique_dn("OU=target2")
+
+ target1_guid = self.add_object(self.ldb_dc1, target1_ou)
+ target2_guid = self.add_object(self.ldb_dc2, target2_ou)
+
+ # add the links for the respective targets, and delete one of the links
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.add_link_attr(self.ldb_dc2, src_ou, "managedBy", target2_ou)
+ self.ensure_unique_timestamp()
+ self.del_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+
+ # sync the 2 DCs
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+
+ # Although the more up-to-date link value is deleted, this shouldn't
+ # trump DC1's active link
+ self.assert_attrs_match(res1, res2, "managedBy", 1)
+
+ self.assertTrue(str(res1[0]["managedBy"][0]) == target2_ou,
+ "Expected active link win conflict")
+
+ # we can't query the deleted links over LDAP, but we can check that
+ # the deleted links exist using DRS
+ link1 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy, 0,
+ misc.GUID(src_guid), misc.GUID(target1_guid))
+ link2 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ misc.GUID(src_guid), misc.GUID(target2_guid))
+ self._check_replicated_links(src_ou, [link1, link2])
+
+ def test_conflict_single_valued_link_deleted_winner(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._singleval_link_conflict_deleted_winner(sync_order=DC1_TO_DC2)
+ self._singleval_link_conflict_deleted_winner(sync_order=DC2_TO_DC1)
+
+ def _singleval_link_conflict_deleted_loser(self, sync_order):
+ """
+ Tests a single-valued link conflict, where the losing link value is
+ deleted.
+ """
+ src_ou = self.unique_dn("OU=src")
+ src_guid = self.add_object(self.ldb_dc1, src_ou)
+ self.sync_DCs()
+
+ # create a unique target on each DC
+ target1_ou = self.unique_dn("OU=target1")
+ target2_ou = self.unique_dn("OU=target2")
+
+ target1_guid = self.add_object(self.ldb_dc1, target1_ou)
+ target2_guid = self.add_object(self.ldb_dc2, target2_ou)
+
+ # add the links - we want the link to end up deleted on DC2, but active
+ # on DC1. DC1 has the better version and DC2 has the better timestamp -
+ # the better version should win
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.del_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_ou, "managedBy", target2_ou)
+ self.del_link_attr(self.ldb_dc2, src_ou, "managedBy", target2_ou)
+
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+
+ # check the object has only have one occurrence of the single-valued
+ # attribute and it matches on both DCs
+ self.assert_attrs_match(res1, res2, "managedBy", 1)
+
+ self.assertTrue(str(res1[0]["managedBy"][0]) == target1_ou,
+ "Expected most recent update to win conflict")
+
+ # we can't query the deleted links over LDAP, but we can check DRS
+ # to make sure the DC kept a copy of the conflicting link
+ link1 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ misc.GUID(src_guid), misc.GUID(target1_guid))
+ link2 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy, 0,
+ misc.GUID(src_guid), misc.GUID(target2_guid))
+ self._check_replicated_links(src_ou, [link1, link2])
+
+ def test_conflict_single_valued_link_deleted_loser(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._singleval_link_conflict_deleted_loser(sync_order=DC1_TO_DC2)
+ self._singleval_link_conflict_deleted_loser(sync_order=DC2_TO_DC1)
+
+ def _test_conflict_existing_single_valued_link(self, sync_order):
+ """
+ Tests a single-valued link conflict, where the conflicting link value
+ already exists (as inactive) on both DCs.
+ """
+ # create the link objects
+ src_ou = self.unique_dn("OU=src")
+ src_guid = self.add_object(self.ldb_dc1, src_ou)
+
+ target1_ou = self.unique_dn("OU=target1")
+ target2_ou = self.unique_dn("OU=target2")
+ target1_guid = self.add_object(self.ldb_dc1, target1_ou)
+ target2_guid = self.add_object(self.ldb_dc1, target2_ou)
+
+ # add the links, but then delete them
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.del_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target2_ou)
+ self.del_link_attr(self.ldb_dc1, src_ou, "managedBy", target2_ou)
+ self.sync_DCs()
+
+ # re-add the links independently on each DC
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+ self.ensure_unique_timestamp()
+ self.add_link_attr(self.ldb_dc2, src_ou, "managedBy", target2_ou)
+
+ # try to sync the 2 DCs
+ self.sync_DCs(sync_order=sync_order)
+
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % src_guid,
+ scope=SCOPE_BASE, attrs=["managedBy"])
+
+ # check the object has only have one occurrence of the single-valued
+ # attribute and it matches on both DCs
+ self.assert_attrs_match(res1, res2, "managedBy", 1)
+
+ # here we expect DC2 to win because it has the more recent link
+ self.assertTrue(str(res1[0]["managedBy"][0]) == target2_ou,
+ "Expected most recent update to win conflict")
+
+ # we can't query the deleted links over LDAP, but we can check DRS
+ # to make sure the DC kept a copy of the conflicting link
+ link1 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy, 0,
+ misc.GUID(src_guid), misc.GUID(target1_guid))
+ link2 = AbstractLink(drsuapi.DRSUAPI_ATTID_managedBy,
+ drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE,
+ misc.GUID(src_guid), misc.GUID(target2_guid))
+ self._check_replicated_links(src_ou, [link1, link2])
+
+ def test_conflict_existing_single_valued_link(self):
+ # repeat the test twice, to give each DC a chance to resolve
+ # the conflict
+ self._test_conflict_existing_single_valued_link(sync_order=DC1_TO_DC2)
+ self._test_conflict_existing_single_valued_link(sync_order=DC2_TO_DC1)
+
+ def test_link_attr_version(self):
+ """
+ Checks the link attribute version starts from the correct value
+ """
+ # create some objects and add a link
+ src_ou = self.unique_dn("OU=src")
+ self.add_object(self.ldb_dc1, src_ou)
+ target1_ou = self.unique_dn("OU=target1")
+ self.add_object(self.ldb_dc1, target1_ou)
+ self.add_link_attr(self.ldb_dc1, src_ou, "managedBy", target1_ou)
+
+ # get the link info via replication
+ ctr6 = self._get_replication(drsuapi.DRSUAPI_DRS_WRIT_REP,
+ dest_dsa=None,
+ drs_error=DRSUAPI_EXOP_ERR_SUCCESS,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ highwatermark=self.zero_highwatermark(),
+ nc_dn_str=src_ou)
+
+ self.assertTrue(ctr6.linked_attributes_count == 1,
+ "DRS didn't return a link")
+ link = ctr6.linked_attributes[0]
+ rcvd_version = link.meta_data.version
+ self.assertTrue(rcvd_version == 1,
+ "Link version started from %u, not 1" % rcvd_version)
diff --git a/source4/torture/drs/python/linked_attributes_drs.py b/source4/torture/drs/python/linked_attributes_drs.py
new file mode 100644
index 0000000..93ad313
--- /dev/null
+++ b/source4/torture/drs/python/linked_attributes_drs.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Originally based on ./sam.py
+import sys
+
+sys.path.insert(0, "bin/python")
+import ldb
+
+from samba.dcerpc import drsuapi, misc
+from samba.ndr import ndr_unpack, ndr_pack
+
+import drs_base
+
+
+class LATestException(Exception):
+ pass
+
+
+class LATests(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(LATests, self).setUp()
+ # DrsBaseTestCase sets up self.ldb_dc1, self.ldb_dc2
+ # we're only using one
+ self.samdb = self.ldb_dc1
+
+ self.base_dn = self.samdb.domain_dn()
+ self.ou = "OU=la,%s" % self.base_dn
+ if True:
+ try:
+ self.samdb.delete(self.ou, ['tree_delete:1'])
+ except ldb.LdbError as e:
+ pass
+ self.samdb.add({'objectclass': 'organizationalUnit',
+ 'dn': self.ou})
+
+ self.dc_guid = self.samdb.get_invocation_id()
+ self.drs, self.drs_handle = self._ds_bind(self.dnsname_dc1)
+
+ def tearDown(self):
+ super(LATests, self).tearDown()
+ try:
+ self.samdb.delete(self.ou, ['tree_delete:1'])
+ except ldb.LdbError as e:
+ pass
+
+ def delete_user(self, user):
+ self.samdb.delete(user['dn'])
+ del self.users[self.users.index(user)]
+
+ def add_object(self, cn, objectclass):
+ dn = "CN=%s,%s" % (cn, self.ou)
+ self.samdb.add({'cn': cn,
+ 'objectclass': objectclass,
+ 'dn': dn})
+
+ return dn
+
+ def add_objects(self, n, objectclass, prefix=None):
+ if prefix is None:
+ prefix = objectclass
+ dns = []
+ for i in range(n):
+ dns.append(self.add_object("%s%d" % (prefix, i + 1),
+ objectclass))
+ return dns
+
+ def add_linked_attribute(self, src, dest, attr='member'):
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.samdb, src)
+ m[attr] = ldb.MessageElement(dest, ldb.FLAG_MOD_ADD, attr)
+ self.samdb.modify(m)
+
+ def remove_linked_attribute(self, src, dest, attr='member'):
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.samdb, src)
+ m[attr] = ldb.MessageElement(dest, ldb.FLAG_MOD_DELETE, attr)
+ self.samdb.modify(m)
+
+ def attr_search(self, obj, expected, attr, scope=ldb.SCOPE_BASE):
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=self.dc_guid,
+ nc_dn_str=obj,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ)
+
+ level, ctr = self.drs.DsGetNCChanges(self.drs_handle, 8, req8)
+ expected_attid = getattr(drsuapi, 'DRSUAPI_ATTID_' + attr)
+
+ links = []
+ for link in ctr.linked_attributes:
+ if link.attid == expected_attid:
+ unpacked = ndr_unpack(drsuapi.DsReplicaObjectIdentifier3,
+ link.value.blob)
+ active = link.flags & drsuapi.DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+ links.append((str(unpacked.dn), bool(active)))
+
+ return links
+
+ def assert_forward_links(self, obj, expected, attr='member'):
+ results = self.attr_search(obj, expected, attr)
+ self.assertEqual(len(results), len(expected))
+
+ for k, v in results:
+ self.assertTrue(k in expected)
+ self.assertEqual(expected[k], v, "%s active flag should be %d, not %d" %
+ (k, expected[k], v))
+
+ def get_object_guid(self, dn):
+ res = self.samdb.search(dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['objectGUID'])
+ return str(misc.GUID(res[0]['objectGUID'][0]))
+
+ def test_links_all_delete_group(self):
+ u1, u2 = self.add_objects(2, 'user', 'u_all_del_group')
+ g1, g2 = self.add_objects(2, 'group', 'g_all_del_group')
+ g2guid = self.get_object_guid(g2)
+
+ self.add_linked_attribute(g1, u1)
+ self.add_linked_attribute(g2, u1)
+ self.add_linked_attribute(g2, u2)
+
+ self.samdb.delete(g2)
+ self.assert_forward_links(g1, {u1: True})
+ res = self.samdb.search('<GUID=%s>' % g2guid,
+ scope=ldb.SCOPE_BASE,
+ controls=['show_deleted:1'])
+ new_dn = res[0].dn
+ self.assert_forward_links(new_dn, {})
+
+ def test_la_links_delete_link(self):
+ u1, u2 = self.add_objects(2, 'user', 'u_del_link')
+ g1, g2 = self.add_objects(2, 'group', 'g_del_link')
+
+ self.add_linked_attribute(g1, u1)
+ self.add_linked_attribute(g2, u1)
+ self.add_linked_attribute(g2, u2)
+
+ self.remove_linked_attribute(g2, u1)
+
+ self.assert_forward_links(g1, {u1: True})
+ self.assert_forward_links(g2, {u1: False, u2: True})
+
+ self.add_linked_attribute(g2, u1)
+ self.remove_linked_attribute(g2, u2)
+ self.assert_forward_links(g2, {u1: True, u2: False})
+ self.remove_linked_attribute(g2, u1)
+ self.assert_forward_links(g2, {u1: False, u2: False})
+
+ def test_la_links_delete_user(self):
+ u1, u2 = self.add_objects(2, 'user', 'u_del_user')
+ g1, g2 = self.add_objects(2, 'group', 'g_del_user')
+
+ self.add_linked_attribute(g1, u1)
+ self.add_linked_attribute(g2, u1)
+ self.add_linked_attribute(g2, u2)
+
+ self.samdb.delete(u1)
+
+ self.assert_forward_links(g1, {})
+ self.assert_forward_links(g2, {u2: True})
diff --git a/source4/torture/drs/python/repl_move.py b/source4/torture/drs/python/repl_move.py
new file mode 100644
index 0000000..c206ab8
--- /dev/null
+++ b/source4/torture/drs/python/repl_move.py
@@ -0,0 +1,2608 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN repl_move -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import time
+import samba.tests
+
+from samba.ndr import ndr_unpack
+from samba.dcerpc import drsblobs
+from samba.dcerpc import misc
+from samba.drs_utils import drs_DsBind
+
+from ldb import (
+ SCOPE_BASE,
+ SCOPE_SUBTREE,
+)
+
+import drs_base
+import ldb
+from samba.dcerpc.drsuapi import (
+ drsuapi,
+ DRSUAPI_ATTID_accountExpires,
+ DRSUAPI_ATTID_cn,
+ DRSUAPI_ATTID_codePage,
+ DRSUAPI_ATTID_countryCode,
+ DRSUAPI_ATTID_dBCSPwd,
+ DRSUAPI_ATTID_description,
+ DRSUAPI_ATTID_instanceType,
+ DRSUAPI_ATTID_isDeleted,
+ DRSUAPI_ATTID_isRecycled,
+ DRSUAPI_ATTID_lastKnownParent,
+ DRSUAPI_ATTID_lmPwdHistory,
+ DRSUAPI_ATTID_logonHours,
+ DRSUAPI_ATTID_name,
+ DRSUAPI_ATTID_ntPwdHistory,
+ DRSUAPI_ATTID_ntSecurityDescriptor,
+ DRSUAPI_ATTID_objectCategory,
+ DRSUAPI_ATTID_objectClass,
+ DRSUAPI_ATTID_objectSid,
+ DRSUAPI_ATTID_ou,
+ DRSUAPI_ATTID_primaryGroupID,
+ DRSUAPI_ATTID_pwdLastSet,
+ DRSUAPI_ATTID_sAMAccountName,
+ DRSUAPI_ATTID_sAMAccountType,
+ DRSUAPI_ATTID_unicodePwd,
+ DRSUAPI_ATTID_userAccountControl,
+ DRSUAPI_ATTID_userPrincipalName,
+ DRSUAPI_ATTID_whenCreated,
+ DRSUAPI_DRS_SYNC_FORCED,
+ DRSUAPI_EXOP_REPL_OBJ,
+ DsGetNCChangesRequest8,
+ DsReplicaHighWaterMark,
+ DsReplicaObjectIdentifier)
+
+
+class DrsMoveObjectTestCase(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(DrsMoveObjectTestCase, self).setUp()
+ # disable automatic replication temporary
+ self._disable_all_repl(self.dnsname_dc1)
+ self._disable_all_repl(self.dnsname_dc2)
+
+ # make sure DCs are synchronized before the test
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "replica_move")
+
+ self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
+ self.ou1_dn.add_base(self.top_ou)
+ ou1 = {}
+ ou1["dn"] = self.ou1_dn
+ ou1["objectclass"] = "organizationalUnit"
+ ou1["ou"] = self.ou1_dn.get_component_value(0)
+ self.ldb_dc1.add(ou1)
+
+ self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2")
+ self.ou2_dn.add_base(self.top_ou)
+ ou2 = {}
+ ou2["dn"] = self.ou2_dn
+ ou2["objectclass"] = "organizationalUnit"
+ ou2["ou"] = self.ou2_dn.get_component_value(0)
+ self.ldb_dc1.add(ou2)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self.dc1_guid = self.ldb_dc1.get_invocation_id()
+ self.dc2_guid = self.ldb_dc2.get_invocation_id()
+
+ self.drs_dc1 = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+ self.drs_dc2 = self._ds_bind(self.dnsname_dc2, ip=self.url_dc2)
+
+ def tearDown(self):
+ try:
+ self.ldb_dc1.delete(self.top_ou, ["tree_delete:1"])
+ except ldb.LdbError as e:
+ (enum, string) = e.args
+ if enum == ldb.ERR_NO_SUCH_OBJECT:
+ pass
+
+ self._enable_all_repl(self.dnsname_dc1)
+ self._enable_all_repl(self.dnsname_dc2)
+ super(DrsMoveObjectTestCase, self).tearDown()
+
+ def _make_username(self):
+ return "DrsMoveU_" + time.strftime("%s", time.gmtime())
+
+ def _check_metadata(self, user_dn, sam_ldb, drs, metadata, expected):
+ repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, metadata[0])
+
+ self.assertEqual(len(repl.ctr.array), len(expected))
+
+ i = 0
+ for o in repl.ctr.array:
+ e = expected[i]
+ (attid, orig_dsa, version) = e
+ self.assertEqual(attid, o.attid,
+ "(LDAP) Wrong attid "
+ "for expected value %d, wanted 0x%08x got 0x%08x"
+ % (i, attid, o.attid))
+ self.assertEqual(o.originating_invocation_id,
+ misc.GUID(orig_dsa),
+ "(LDAP) Wrong originating_invocation_id "
+ "for expected value %d, attid 0x%08x, wanted %s got %s"
+ % (i, o.attid,
+ misc.GUID(orig_dsa),
+ o.originating_invocation_id))
+ # Allow version to be skipped when it does not matter
+ if version is not None:
+ self.assertEqual(o.version, version,
+ "(LDAP) Wrong version for expected value %d, "
+ "attid 0x%08x, "
+ "wanted %d got %d"
+ % (i, o.attid,
+ version, o.version))
+ i = i + 1
+
+ if drs is None:
+ return
+
+ req8 = DsGetNCChangesRequest8()
+
+ req8.source_dsa_invocation_id = misc.GUID(sam_ldb.get_invocation_id())
+ req8.naming_context = DsReplicaObjectIdentifier()
+ req8.naming_context.dn = str(user_dn)
+ req8.highwatermark = DsReplicaHighWaterMark()
+ req8.highwatermark.tmp_highest_usn = 0
+ req8.highwatermark.reserved_usn = 0
+ req8.highwatermark.highest_usn = 0
+ req8.uptodateness_vector = None
+ req8.replica_flags = DRSUAPI_DRS_SYNC_FORCED
+ req8.max_object_count = 1
+ req8.max_ndr_size = 402116
+ req8.extended_op = DRSUAPI_EXOP_REPL_OBJ
+ req8.fsmo_info = 0
+ req8.partial_attribute_set = None
+ req8.partial_attribute_set_ex = None
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+
+ (drs_conn, drs_handle) = drs
+
+ (level, drs_ctr) = drs_conn.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(level, 6)
+ self.assertEqual(drs_ctr.object_count, 1)
+
+ self.assertEqual(len(drs_ctr.first_object.meta_data_ctr.meta_data), len(expected) - 1)
+ att_idx = 0
+ for o in drs_ctr.first_object.meta_data_ctr.meta_data:
+ i = 0
+ drs_attid = drs_ctr.first_object.object.attribute_ctr.attributes[att_idx]
+ e = expected[i]
+ (attid, orig_dsa, version) = e
+
+ # Skip the RDN from the expected set, it is not sent over DRS
+ if (user_dn.get_rdn_name().upper() == "CN"
+ and attid == DRSUAPI_ATTID_cn) \
+ or (user_dn.get_rdn_name().upper() == "OU"
+ and attid == DRSUAPI_ATTID_ou):
+ i = i + 1
+ e = expected[i]
+ (attid, orig_dsa, version) = e
+
+ self.assertEqual(attid, drs_attid.attid,
+ "(DRS) Wrong attid "
+ "for expected value %d, wanted 0x%08x got 0x%08x"
+ % (i, attid, drs_attid.attid))
+
+ self.assertEqual(o.originating_invocation_id,
+ misc.GUID(orig_dsa),
+ "(DRS) Wrong originating_invocation_id "
+ "for expected value %d, attid 0x%08x, wanted %s got %s"
+ % (i, attid,
+ misc.GUID(orig_dsa),
+ o.originating_invocation_id))
+ # Allow version to be skipped when it does not matter
+ if version is not None:
+ self.assertEqual(o.version, version,
+ "(DRS) Wrong version for expected value %d, "
+ "attid 0x%08x, "
+ "wanted %d got %d"
+ % (i, attid, version, o.version))
+ break
+ i = i + 1
+ att_idx = att_idx + 1
+
+ # now also used to check the group
+ def _check_obj(self, sam_ldb, obj_orig, is_deleted, expected_metadata=None, drs=None):
+ # search the user by guid as it may be deleted
+ guid_str = self._GUID_string(obj_orig["objectGUID"][0])
+ res = sam_ldb.search(base='<GUID=%s>' % guid_str,
+ controls=["show_deleted:1"],
+ attrs=["*", "parentGUID",
+ "replPropertyMetaData"])
+ self.assertEqual(len(res), 1)
+ user_cur = res[0]
+ rdn_orig = str(obj_orig[user_cur.dn.get_rdn_name()][0])
+ rdn_cur = str(user_cur[user_cur.dn.get_rdn_name()][0])
+ name_orig = str(obj_orig["name"][0])
+ name_cur = str(user_cur["name"][0])
+ dn_orig = obj_orig["dn"]
+ dn_cur = user_cur["dn"]
+ # now check properties of the user
+ if is_deleted:
+ self.assertTrue("isDeleted" in user_cur)
+ self.assertEqual(rdn_cur.split('\n')[0], rdn_orig)
+ self.assertEqual(name_cur.split('\n')[0], name_orig)
+ self.assertEqual(dn_cur.get_rdn_value().split('\n')[0],
+ dn_orig.get_rdn_value())
+ self.assertEqual(name_cur, rdn_cur)
+ else:
+ self.assertFalse("isDeleted" in user_cur)
+ self.assertEqual(rdn_cur, rdn_orig)
+ self.assertEqual(name_cur, name_orig)
+ self.assertEqual(dn_cur, dn_orig)
+ self.assertEqual(name_cur, rdn_cur)
+ parent_cur = user_cur["parentGUID"][0]
+ try:
+ parent_orig = obj_orig["parentGUID"][0]
+ self.assertEqual(parent_orig, parent_cur)
+ except KeyError:
+ pass
+ self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
+
+ if expected_metadata is not None:
+ self._check_metadata(dn_cur, sam_ldb, drs, user_cur["replPropertyMetaData"],
+ expected_metadata)
+
+ return user_cur
+
+ def test_ReplicateMoveObject1(self):
+ """Verifies how a moved container with a user inside is replicated between two DCs.
+ This test should verify that:
+ - the OU is replicated properly
+ - the OU is renamed
+ - We verify that after replication,
+ that the user has the correct DN (under OU2)
+ - the OU is deleted
+ - the OU is modified on DC2
+ - We verify that after replication,
+ that the user has the correct DN (deleted) and has not description
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ initial_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_orig, is_deleted=False,
+ expected_metadata=initial_metadata)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ moved_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC1 after rename - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=moved_metadata)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ moved_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=moved_metadata_dc2)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+ deleted_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True, expected_metadata=deleted_metadata)
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = new_dn
+ msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ modified_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_description, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=modified_metadata)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ deleted_modified_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
+ (DRSUAPI_ATTID_description, self.dc2_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_modified_metadata_dc2)
+ self.assertFalse("description" in user_cur)
+
+ # trigger replication from DC2 to DC1, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ deleted_modified_metadata_dc1 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_description, self.dc2_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC1 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_modified_metadata_dc1)
+ self.assertFalse("description" in user_cur)
+
+ def test_ReplicateMoveObject2(self):
+ """Verifies how a moved container with a user inside is not
+ replicated between two DCs as no replication is triggered
+ This test should verify that:
+ - the OU is not replicated
+ - the user is not replicated
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ initial_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_orig, is_deleted=False,
+ expected_metadata=initial_metadata)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_moved_orig = ldb_res[0]
+
+ moved_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC1 after rename - should be valid user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=moved_metadata)
+
+ # check user info on DC2 - should not be there, we have not done replication
+ ldb_res = self.ldb_dc2.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 0)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ deleted_metadata_dc1 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC1 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ deleted_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc2)
+
+ # trigger replication from DC2 to DC1, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ # check user info on DC1 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ def test_ReplicateMoveObject3(self):
+ """Verifies how a moved container with a user inside is replicated between two DCs.
+ This test should verify that:
+ - the OU is created on DC1
+ - the OU is renamed on DC1
+ - We verify that after replication,
+ that the user has the correct DN (under OU2).
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ initial_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_orig, is_deleted=False,
+ expected_metadata=initial_metadata)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ moved_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC1 after rename - should be valid user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=moved_metadata)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+ deleted_metadata_dc1 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC1 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ # check user info on DC1 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ deleted_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc2)
+
+ def test_ReplicateMoveObject3b(self):
+ """Verifies how a moved container with a user inside is replicated between two DCs.
+ This test should verify that:
+ - the OU is created on DC1
+ - the OU is renamed on DC1
+ - We verify that after replication,
+ that the user has the correct DN (under OU2).
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ initial_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_orig, is_deleted=False,
+ expected_metadata=initial_metadata)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # trigger replication from DC2 (Which has never seen the object) to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ moved_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC1 after rename - should be valid user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=moved_metadata)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+ deleted_metadata_dc1 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC1 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ # check user info on DC1 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ deleted_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should be deleted user
+ self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc2)
+
+ def test_ReplicateMoveObject4(self):
+ """Verifies how a moved container with a user inside is replicated between two DCs.
+ This test should verify that:
+ - the OU is replicated properly
+ - the user is modified on DC2
+ - the OU is renamed on DC1
+ - We verify that after replication DC1 -> DC2,
+ that the user has the correct DN (under OU2), and the description
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ initial_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_orig, is_deleted=False,
+ expected_metadata=initial_metadata)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ initial_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should still be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_orig, is_deleted=False,
+ expected_metadata=initial_metadata_dc2)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ moved_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC1 after rename - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=moved_metadata)
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = user_dn
+ msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ modified_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_description, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_orig,
+ is_deleted=False,
+ expected_metadata=modified_metadata)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ modified_renamed_metadata = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
+ (DRSUAPI_ATTID_description, self.dc2_guid, 1),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should still be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=modified_renamed_metadata)
+
+ self.assertTrue("description" in user_cur)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+ deleted_metadata_dc1 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC1 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC2 - should still be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=False,
+ expected_metadata=modified_renamed_metadata)
+
+ self.assertTrue("description" in user_cur)
+
+ deleted_metadata_dc1 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_description, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC1 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc1)
+
+ self.assertFalse("description" in user_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ deleted_metadata_dc2 = [
+ (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_cn, self.dc2_guid, 3),
+ (DRSUAPI_ATTID_description, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_name, self.dc1_guid, 3),
+ (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
+ (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
+ (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
+ (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
+
+ # check user info on DC2 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
+ obj_orig=user_moved_orig,
+ is_deleted=True,
+ expected_metadata=deleted_metadata_dc2)
+
+ self.assertFalse("description" in user_cur)
+
+ def test_ReplicateMoveObject5(self):
+ """Verifies how a moved container with a user inside is replicated between two DCs.
+ This test should verify that:
+ - the OU is replicated properly
+ - the user is modified on DC2
+ - the OU is renamed on DC1
+ - We verify that after replication DC2 -> DC1,
+ that the user has the correct DN (under OU2), and the description
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = user_dn
+ msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC1 - should still be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=False)
+ self.assertTrue("description" in user_cur)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+ self.assertTrue("description" in user_cur)
+
+ # delete user on DC2
+ self.ldb_dc2.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+ # trigger replication from DC2 to DC1 for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ # check user info on DC1 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
+ self.assertFalse("description" in user_cur)
+
+ def test_ReplicateMoveObject6(self):
+ """Verifies how a moved container is replicated between two DCs.
+ This test should verify that:
+ - the OU1 is replicated properly
+ - the OU1 is modified on DC2
+ - the OU1 is renamed on DC1
+ - We verify that after replication DC1 -> DC2,
+ that the OU1 has the correct DN (under OU2), and the description
+
+ """
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ ou_orig = ldb_res[0]
+ ou_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(ou_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=new_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ ou_moved_orig = ldb_res[0]
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = ou_dn
+ msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
+ self.assertTrue("description" in ou_cur)
+
+ # delete OU on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ def test_ReplicateMoveObject7(self):
+ """Verifies how a moved container is replicated between two DCs.
+ This test should verify that:
+ - the OU1 is replicated properly
+ - the OU1 is modified on DC2
+ - the OU1 is renamed on DC1 to be under OU2
+ - We verify that after replication DC2 -> DC1,
+ that the OU1 has the correct DN (under OU2), and the description
+
+ """
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ ou_orig = ldb_res[0]
+ ou_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(ou_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=new_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ ou_moved_orig = ldb_res[0]
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = ou_dn
+ msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC1 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
+ self.assertTrue("description" in ou_cur)
+
+ # delete OU on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ def test_ReplicateMoveObject8(self):
+ """Verifies how a moved container is replicated between two DCs.
+ This test should verify that:
+ - the OU1 is replicated properly
+ - the OU1 is modified on DC2
+ - the OU1 is renamed on DC1 to OU1-renamed
+ - We verify that after replication DC1 -> DC2,
+ that the OU1 has the correct DN (OU1-renamed), and the description
+
+ """
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ ou_orig = ldb_res[0]
+ ou_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
+ new_dn.add_base(self.ou1_dn.parent())
+ self.ldb_dc1.rename(ou_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=new_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ ou_moved_orig = ldb_res[0]
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = ou_dn
+ msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
+ self.assertTrue("description" in ou_cur)
+
+ # delete OU on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ def test_ReplicateMoveObject9(self):
+ """Verifies how a moved container is replicated between two DCs.
+ This test should verify that:
+ - the OU1 is replicated properly
+ - the OU1 is modified on DC2
+ - the OU1 is renamed on DC1 to be under OU2
+ - the OU1 is renamed on DC1 to OU1-renamed
+ - We verify that after replication DC1 -> DC2,
+ that the OU1 has the correct DN (OU1-renamed), and the description
+
+ """
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ ou_orig = ldb_res[0]
+ ou_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
+ new_dn.add_base(self.ou1_dn.parent())
+ self.ldb_dc1.rename(ou_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=new_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ ou_moved_orig = ldb_res[0]
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = ou_dn
+ msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC1 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
+ self.assertTrue("description" in ou_cur)
+
+ # delete OU on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check user info on DC2 - should be deleted user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ def test_ReplicateMoveObject10(self):
+ """Verifies how a moved container is replicated between two DCs.
+ This test should verify that:
+ - the OU1 is replicated properly
+ - the OU1 is modified on DC2
+ - the OU1 is deleted on DC1
+ - We verify that after replication DC1 -> DC2,
+ that the OU1 is deleted, and the description has gone away
+
+ """
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ ou_orig = ldb_res[0]
+ ou_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = ou_dn
+ msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # delete OU on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be deleted OU
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ # check user info on DC2 - should be deleted OU
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ def test_ReplicateMoveObject11(self):
+ """Verifies how a moved container is replicated between two DCs.
+ This test should verify that:
+ - the OU1 is replicated properly
+ - the OU1 is modified on DC2
+ - the OU1 is deleted on DC1
+ - We verify that after replication DC2 -> DC1,
+ that the OU1 is deleted, and the description has gone away
+
+ """
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_BASE,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ ou_orig = ldb_res[0]
+ ou_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should still be valid user
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
+
+ # Modify description on DC2. This triggers a replication, but
+ # not of 'name' and so a bug in Samba regarding the DN.
+ msg = ldb.Message()
+ msg.dn = ou_dn
+ msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # delete OU on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC2 - should be deleted OU
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # check user info on DC2 - should be deleted OU
+ ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
+ self.assertFalse("description" in ou_cur)
+
+
+class DrsMoveBetweenTreeOfObjectTestCase(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(DrsMoveBetweenTreeOfObjectTestCase, self).setUp()
+ # disable automatic replication temporary
+ self._disable_all_repl(self.dnsname_dc1)
+ self._disable_all_repl(self.dnsname_dc2)
+
+ self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "replica_move")
+
+ # make sure DCs are synchronized before the test
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
+ self.ou1_dn.add_base(self.top_ou)
+ self.ou1 = {}
+ self.ou1["dn"] = self.ou1_dn
+ self.ou1["objectclass"] = "organizationalUnit"
+ self.ou1["ou"] = self.ou1_dn.get_component_value(0)
+
+ self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2,OU=DrsOU1")
+ self.ou2_dn.add_base(self.top_ou)
+ self.ou2 = {}
+ self.ou2["dn"] = self.ou2_dn
+ self.ou2["objectclass"] = "organizationalUnit"
+ self.ou2["ou"] = self.ou2_dn.get_component_value(0)
+
+ self.ou2b_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2B,OU=DrsOU1")
+ self.ou2b_dn.add_base(self.top_ou)
+ self.ou2b = {}
+ self.ou2b["dn"] = self.ou2b_dn
+ self.ou2b["objectclass"] = "organizationalUnit"
+ self.ou2b["ou"] = self.ou2b_dn.get_component_value(0)
+
+ self.ou2c_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2C,OU=DrsOU1")
+ self.ou2c_dn.add_base(self.top_ou)
+
+ self.ou3_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
+ self.ou3_dn.add_base(self.top_ou)
+ self.ou3 = {}
+ self.ou3["dn"] = self.ou3_dn
+ self.ou3["objectclass"] = "organizationalUnit"
+ self.ou3["ou"] = self.ou3_dn.get_component_value(0)
+
+ self.ou4_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
+ self.ou4_dn.add_base(self.top_ou)
+ self.ou4 = {}
+ self.ou4["dn"] = self.ou4_dn
+ self.ou4["objectclass"] = "organizationalUnit"
+ self.ou4["ou"] = self.ou4_dn.get_component_value(0)
+
+ self.ou5_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
+ self.ou5_dn.add_base(self.top_ou)
+ self.ou5 = {}
+ self.ou5["dn"] = self.ou5_dn
+ self.ou5["objectclass"] = "organizationalUnit"
+ self.ou5["ou"] = self.ou5_dn.get_component_value(0)
+
+ self.ou6_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU6,OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
+ self.ou6_dn.add_base(self.top_ou)
+ self.ou6 = {}
+ self.ou6["dn"] = self.ou6_dn
+ self.ou6["objectclass"] = "organizationalUnit"
+ self.ou6["ou"] = self.ou6_dn.get_component_value(0)
+
+ def tearDown(self):
+ self.ldb_dc1.delete(self.top_ou, ["tree_delete:1"])
+ self._enable_all_repl(self.dnsname_dc1)
+ self._enable_all_repl(self.dnsname_dc2)
+ super(DrsMoveBetweenTreeOfObjectTestCase, self).tearDown()
+
+ def _make_username(self):
+ return "DrsTreeU_" + time.strftime("%s", time.gmtime())
+
+ # now also used to check the group
+ def _check_obj(self, sam_ldb, obj_orig, is_deleted):
+ # search the user by guid as it may be deleted
+ guid_str = self._GUID_string(obj_orig["objectGUID"][0])
+ res = sam_ldb.search(base='<GUID=%s>' % guid_str,
+ controls=["show_deleted:1"],
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(res), 1)
+ user_cur = res[0]
+ cn_orig = str(obj_orig["cn"][0])
+ cn_cur = str(user_cur["cn"][0])
+ name_orig = str(obj_orig["name"][0])
+ name_cur = str(user_cur["name"][0])
+ dn_orig = obj_orig["dn"]
+ dn_cur = user_cur["dn"]
+ # now check properties of the user
+ if is_deleted:
+ self.assertTrue("isDeleted" in user_cur)
+ self.assertEqual(cn_cur.split('\n')[0], cn_orig)
+ self.assertEqual(name_cur.split('\n')[0], name_orig)
+ self.assertEqual(dn_cur.get_rdn_value().split('\n')[0],
+ dn_orig.get_rdn_value())
+ self.assertEqual(name_cur, cn_cur)
+ else:
+ self.assertFalse("isDeleted" in user_cur)
+ self.assertEqual(cn_cur, cn_orig)
+ self.assertEqual(name_cur, name_orig)
+ self.assertEqual(dn_cur, dn_orig)
+ self.assertEqual(name_cur, cn_cur)
+ self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
+
+ return user_cur
+
+ def test_ReplicateMoveInTree1(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - a complex OU tree can be replicated correctly
+ - the user is in the correct spot (renamed into) within the tree
+ on both DCs
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ self.ldb_dc1.add(self.ou2)
+ self.ldb_dc1.add(self.ou3)
+ self.ldb_dc1.add(self.ou4)
+ self.ldb_dc1.add(self.ou5)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou5_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateMoveInTree2(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - a complex OU tree can be replicated correctly
+ - the user is in the correct spot (renamed into) within the tree
+ on both DCs
+ - that a rename back works correctly, and is replicated
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ self.ldb_dc1.add(self.ou2)
+ self.ldb_dc1.add(self.ou2b)
+ self.ldb_dc1.add(self.ou3)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou3_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
+ new_dn3.add_base(self.ou2b_dn)
+ self.ldb_dc1.rename(self.ou3_dn, new_dn3)
+
+ ldb_res = self.ldb_dc1.search(base=new_dn3,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+ user_moved_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+
+ # Rename on DC1
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou1_dn)
+ self.ldb_dc1.rename(user_moved_dn, new_dn)
+
+ # Modify description on DC2
+ msg = ldb.Message()
+ msg.dn = user_moved_dn
+ msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+ user_moved_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+ self.assertTrue("description" in user_cur)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # check user info on DC1 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
+ self.assertFalse("description" in user_cur)
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be deleted user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=True)
+ self.assertFalse("description" in user_cur)
+
+ def test_ReplicateMoveInTree3(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - a complex OU tree can be replicated correctly
+ - the user is in the correct spot (renamed into) within the tree
+ on both DCs
+ - that a rename back works correctly, and is replicated
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ self.ldb_dc1.add(self.ou2)
+ self.ldb_dc1.add(self.ou2b)
+ self.ldb_dc1.add(self.ou3)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou3_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
+ new_dn3.add_base(self.ou2b_dn)
+ self.ldb_dc1.rename(self.ou3_dn, new_dn3)
+
+ ldb_res = self.ldb_dc1.search(base=new_dn3,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+ user_moved_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_moved_dn, new_dn)
+
+ self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
+ self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
+ self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
+
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+ user_moved_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+
+ self.assertEqual(user_cur["parentGUID"], user_moved_orig["parentGUID"])
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateMoveInTree3b(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - a complex OU tree can be replicated correctly
+ - the user is in the correct spot (renamed into) within the tree
+ on both DCs
+ - that a rename back works correctly, and is replicated
+ - that a complex rename suffle, combined with unrelated changes to the object,
+ is replicated correctly. The aim here is the send the objects out-of-order
+ when sorted by usnChanged.
+ - confirm that the OU tree and (in particular the user DN) is identical between
+ the DCs once this has been replicated.
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ self.ldb_dc1.add(self.ou2)
+ self.ldb_dc1.add(self.ou2b)
+ self.ldb_dc1.add(self.ou3)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+
+ msg = ldb.Message()
+ msg.dn = new_dn
+ msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ # The sleep(1) calls here ensure that the name objects get a
+ # new 1-sec based timestamp, and so we select how the conflict
+ # resolution resolves.
+ self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
+ time.sleep(1)
+ self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
+ time.sleep(1)
+ self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]), new_dn)
+
+ msg = ldb.Message()
+ msg.dn = self.ou2_dn
+ msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ msg = ldb.Message()
+ msg.dn = self.ou2b_dn
+ msg["description"] = ldb.MessageElement("OU2b Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+ self.assertEqual(user_cur["parentGUID"][0], user_moved_orig["parentGUID"][0])
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateMoveInTree4(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - an OU and user can be replicated correctly, even after a rename
+ - The creation and rename of the OU has been combined with unrelated changes to the object,
+ The aim here is the send the objects out-of-order when sorted by usnChanged.
+ - That is, the OU will be sorted by usnChanged after the user that is within that OU.
+ - That will cause the client to need to get the OU first, by use of the GET_ANC flag
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # check user info on DC1
+ print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
+
+ self.ldb_dc1.add(self.ou2)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ msg = ldb.Message()
+ msg.dn = self.ou2_dn
+ msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username)
+ self.assertEqual(len(ldb_res), 1)
+
+ user_moved_orig = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateAddInOU(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - an OU and user can be replicated correctly
+ - The creation of the OU has been combined with unrelated changes to the object,
+ The aim here is the send the objects out-of-order when sorted by usnChanged.
+ - That is, the OU will be sorted by usnChanged after the user that is within that OU.
+ - That will cause the client to need to get the OU first, by use of the GET_ANC flag
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+
+ msg = ldb.Message()
+ msg.dn = self.ou1_dn
+ msg["description"] = ldb.MessageElement("OU1 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
+
+ self.assertEqual(user_cur["parentGUID"], user_orig["parentGUID"])
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateAddInMovedOU(self):
+ """Verifies how an object is replicated between two DCs.
+ This test should verify that:
+ - an OU and user can be replicated correctly
+ - The creation of the OU has been combined with unrelated changes to the object,
+ The aim here is the send the objects out-of-order when sorted by usnChanged.
+ - That is, the OU will be sorted by usnChanged after the user that is within that OU.
+ - That will cause the client to need to get the OU first, by use of the GET_ANC flag
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+ self.ldb_dc1.add(self.ou2)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ self.ldb_dc1.rename(self.ou2_dn, self.ou2b_dn)
+
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_moved = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be valid user
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
+
+ self.assertEqual(user_cur["parentGUID"], user_moved["parentGUID"])
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateAddInConflictOU_time(self):
+ """Verifies how an object is replicated between two DCs, when created in an ambiguous location
+ This test should verify that:
+ - Without replication, two conflicting objects can be created
+ - force the conflict resolution algorithm so we know which copy will win
+ (by sleeping while creating the objects, therefore increasing that timestamp on 'name')
+ - confirm that the user object, created on DC1, ends up in the right place on DC2
+ - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
+
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # Now create two, conflicting objects. This gives the user
+ # object something to be under on both DCs.
+
+ # We sleep between the two adds so that DC1 adds second, and
+ # so wins the conflict resolution due to a later creation time
+ # (modification timestamp on the name attribute).
+ self.ldb_dc2.add(self.ou2)
+ time.sleep(1)
+ self.ldb_dc1.add(self.ou2)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ # Now that we have renamed the user (and so bumped the
+ # usnChanged), bump the value on the OUs.
+ msg = ldb.Message()
+ msg.dn = self.ou2_dn
+ msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ msg = ldb.Message()
+ msg.dn = self.ou2_dn
+ msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_moved = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be under the OU2 from DC1
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
+
+ self.assertEqual(user_cur["parentGUID"], user_moved["parentGUID"])
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ def test_ReplicateAddInConflictOU2(self):
+ """Verifies how an object is replicated between two DCs, when created in an ambiguous location
+ This test should verify that:
+ - Without replication, two conflicting objects can be created
+ - force the conflict resolution algorithm so we know which copy will win
+ (by changing the description twice, therefore increasing that version count)
+ - confirm that the user object, created on DC1, ends up in the right place on DC2
+ - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
+ """
+ # work-out unique username to test with
+ username = self._make_username()
+
+ self.ldb_dc1.add(self.ou1)
+
+ # create user on DC1
+ self.ldb_dc1.newuser(username=username,
+ userou="ou=%s,ou=%s"
+ % (self.ou1_dn.get_component_value(0),
+ self.top_ou.get_component_value(0)),
+ password=None, setpassword=False)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_orig = ldb_res[0]
+ user_dn = ldb_res[0]["dn"]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # Now create two, conflicting objects. This gives the user
+ # object something to be under on both DCs. We create it on
+ # DC1 1sec later so that it will win the conflict resolution.
+
+ self.ldb_dc2.add(self.ou2)
+ time.sleep(1)
+ self.ldb_dc1.add(self.ou2)
+
+ new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
+ new_dn.add_base(self.ou2_dn)
+ self.ldb_dc1.rename(user_dn, new_dn)
+
+ # Now that we have renamed the user (and so bumped the
+ # usnChanged), bump the value on the OUs.
+ msg = ldb.Message()
+ msg.dn = self.ou2_dn
+ msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc1.modify(msg)
+
+ msg = ldb.Message()
+ msg.dn = self.ou2_dn
+ msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
+ self.ldb_dc2.modify(msg)
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
+ scope=SCOPE_SUBTREE,
+ expression="(samAccountName=%s)" % username,
+ attrs=["*", "parentGUID"])
+ self.assertEqual(len(ldb_res), 1)
+ user_moved = ldb_res[0]
+
+ # trigger replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ # check user info on DC2 - should be under the OU2 from DC1
+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
+
+ self.assertEqual(user_cur["parentGUID"], user_moved["parentGUID"])
+
+ # delete user on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
+
+ # trigger replication from DC1 to DC2, for cleanup
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
diff --git a/source4/torture/drs/python/repl_rodc.py b/source4/torture/drs/python/repl_rodc.py
new file mode 100644
index 0000000..ab3d6fa
--- /dev/null
+++ b/source4/torture/drs/python/repl_rodc.py
@@ -0,0 +1,735 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Test replication scenarios involving an RODC
+#
+# Copyright (C) Catalyst.Net Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc1_dns_name [this is unused for the test, but it'll still try to connect]
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN repl_rodc -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+import ldb
+
+from samba import WERRORError
+from samba.join import DCJoinContext
+from samba.dcerpc import drsuapi, misc, drsblobs, security
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.samdb import dsdb_Dn
+from samba.credentials import Credentials
+
+import random
+import time
+
+
+def drs_get_rodc_partial_attribute_set(samdb, samdb1, exceptions=None):
+ '''get a list of attributes for RODC replication'''
+ if exceptions is None:
+ exceptions = []
+
+ partial_attribute_set = drsuapi.DsPartialAttributeSet()
+ partial_attribute_set.version = 1
+
+ attids = []
+
+ # the exact list of attids we send is quite critical. Note that
+ # we do ask for the secret attributes, but set SPECIAL_SECRET_PROCESSING
+ # to zero them out
+ schema_dn = samdb.get_schema_basedn()
+ res = samdb.search(base=schema_dn, scope=ldb.SCOPE_SUBTREE,
+ expression="objectClass=attributeSchema",
+ attrs=["lDAPDisplayName", "systemFlags",
+ "searchFlags"])
+
+ for r in res:
+ ldap_display_name = str(r["lDAPDisplayName"][0])
+ if "systemFlags" in r:
+ system_flags = str(r["systemFlags"][0])
+ if (int(system_flags) & (samba.dsdb.DS_FLAG_ATTR_NOT_REPLICATED |
+ samba.dsdb.DS_FLAG_ATTR_IS_CONSTRUCTED)):
+ continue
+ if "searchFlags" in r:
+ search_flags = str(r["searchFlags"][0])
+ if (int(search_flags) & samba.dsdb.SEARCH_FLAG_RODC_ATTRIBUTE):
+ continue
+ try:
+ attid = samdb1.get_attid_from_lDAPDisplayName(ldap_display_name)
+ if attid not in exceptions:
+ attids.append(int(attid))
+ except:
+ pass
+
+ # the attids do need to be sorted, or windows doesn't return
+ # all the attributes we need
+ attids.sort()
+ partial_attribute_set.attids = attids
+ partial_attribute_set.num_attids = len(attids)
+ return partial_attribute_set
+
+
+class DrsRodcTestCase(drs_base.DrsBaseTestCase):
+ """Intended as a semi-black box test case for replication involving
+ an RODC."""
+
+ def setUp(self):
+ super(DrsRodcTestCase, self).setUp()
+ self.base_dn = self.ldb_dc1.get_default_basedn()
+
+ self.ou = samba.tests.create_test_ou(self.ldb_dc1, "test_drs_rodc")
+ self.allowed_group = "CN=Allowed RODC Password Replication Group,CN=Users,%s" % self.base_dn
+
+ self.site = self.ldb_dc1.server_site_name()
+ self.rodc_name = "TESTRODCDRS%s" % random.randint(1, 10000000)
+ self.rodc_pass = "password12#"
+ self.computer_dn = "CN=%s,OU=Domain Controllers,%s" % (self.rodc_name, self.base_dn)
+
+ self.rodc_ctx = DCJoinContext(server=self.ldb_dc1.host_dns_name(),
+ creds=self.get_credentials(),
+ lp=self.get_loadparm(), site=self.site,
+ netbios_name=self.rodc_name,
+ targetdir=None, domain=None,
+ machinepass=self.rodc_pass)
+ self._create_rodc(self.rodc_ctx)
+ self.rodc_ctx.create_tmp_samdb()
+ self.tmp_samdb = self.rodc_ctx.tmp_samdb
+
+ rodc_creds = Credentials()
+ rodc_creds.guess(self.rodc_ctx.lp)
+ rodc_creds.set_username(self.rodc_name + '$')
+ rodc_creds.set_password(self.rodc_pass)
+ self.rodc_creds = rodc_creds
+
+ (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
+ (self.rodc_drs, self.rodc_drs_handle) = self._ds_bind(self.dnsname_dc1, rodc_creds)
+
+ def tearDown(self):
+ self.rodc_ctx.cleanup_old_join()
+ super(DrsRodcTestCase, self).tearDown()
+
+ def test_admin_repl_secrets(self):
+ """
+ When a secret attribute is set to be replicated to an RODC with the
+ admin credentials, it should always replicate regardless of whether
+ or not it's in the Allowed RODC Password Replication Group.
+ """
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ user_name = "test_rodcA_%s" % rand
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, 'penguin12#', False, user_name)
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+
+ # Check that the user has been added to msDSRevealedUsers
+ self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ def test_admin_repl_secrets_DummyDN_GUID(self):
+ """
+ When a secret attribute is set to be replicated to an RODC with the
+ admin credentials, it should always replicate regardless of whether
+ or not it's in the Allowed RODC Password Replication Group.
+ """
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ user_name = "test_rodcA_%s" % rand
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ res = self.ldb_dc1.search(base=user_dn, scope=ldb.SCOPE_BASE,
+ attrs=["objectGUID"])
+
+ user_guid = misc.GUID(res[0]["objectGUID"][0])
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, 'penguin12#', False, user_name)
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str="DummyDN",
+ nc_guid=user_guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+ try:
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.fail(f"DsGetNCChanges failed with {estr}")
+
+ # Check that the user has been added to msDSRevealedUsers
+ self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ def test_rodc_repl_secrets(self):
+ """
+ When a secret attribute is set to be replicated to an RODC with
+ the RODC account credentials, it should not replicate if it's in
+ the Allowed RODC Password Replication Group. Once it is added to
+ the group, it should replicate.
+ """
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ user_name = "test_rodcB_%s" % rand
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, 'penguin12#', False, user_name)
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+
+ try:
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except WERRORError as e:
+ (enum, estr) = e.args
+ self.assertEqual(enum, 8630) # ERROR_DS_DRA_SECRETS_DENIED
+
+ # send the same request again and we should get the same response
+ try:
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except WERRORError as e1:
+ (enum, estr) = e1.args
+ self.assertEqual(enum, 8630) # ERROR_DS_DRA_SECRETS_DENIED
+
+ # Retry with Administrator credentials, ignores password replication groups
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+
+ # Check that the user has been added to msDSRevealedUsers
+ self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ def test_rodc_repl_secrets_follow_on_req(self):
+ """
+ Checks that an RODC can't subvert an existing (valid) GetNCChanges
+ request to reveal secrets it shouldn't have access to.
+ """
+
+ # send an acceptable request that will match as many GUIDs as possible.
+ # Here we set the SPECIAL_SECRET_PROCESSING flag so that the request gets accepted.
+ # (On the server, this builds up the getnc_state->guids array)
+ req8 = self._exop_req8(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=self.ldb_dc1.domain_dn(),
+ exop=drsuapi.DRSUAPI_EXOP_NONE,
+ max_objects=1,
+ replica_flags=drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING)
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 8, req8)
+
+ # Get the next replication chunk, but set REPL_SECRET this time. This
+ # is following on the the previous accepted request, but we've changed
+ # exop to now request secrets. This request should fail
+ try:
+ req8 = self._exop_req8(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=self.ldb_dc1.domain_dn(),
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET)
+ req8.highwatermark = ctr.new_highwatermark
+
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 8, req8)
+
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except RuntimeError as e2:
+ (enum, estr) = e2.args
+ pass
+
+ def test_msDSRevealedUsers_admin(self):
+ """
+ When a secret attribute is to be replicated to an RODC, the contents
+ of the attribute should be added to the msDSRevealedUsers attribute
+ of the computer object corresponding to the RODC.
+ """
+
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ # Add a user on DC1, add it to allowed password replication
+ # group, and replicate to RODC with EXOP_REPL_SECRETS
+ user_name = "test_rodcC_%s" % rand
+ password = "password12#"
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, password, False, user_name)
+
+ self.ldb_dc1.add_remove_group_members("Allowed RODC Password Replication Group",
+ [user_name],
+ add_members_operation=True)
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+
+ # Check that the user has been added to msDSRevealedUsers
+ (packed_attrs_1, unpacked_attrs_1) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ # Change the user's password on DC1
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, password + "1", False, user_name)
+
+ (packed_attrs_2, unpacked_attrs_2) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+ self._assert_attrlist_equals(unpacked_attrs_1, unpacked_attrs_2)
+
+ # Replicate to RODC again with EXOP_REPL_SECRETS
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+
+ # This is important for Windows, because the entry won't have been
+ # updated in time if we don't have it. Even with this sleep, it only
+ # passes some of the time...
+ time.sleep(5)
+
+ # Check that the entry in msDSRevealedUsers has been updated
+ (packed_attrs_3, unpacked_attrs_3) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+ self._assert_attrlist_changed(unpacked_attrs_2, unpacked_attrs_3, expected_user_attributes)
+
+ # We should be able to delete the user
+ self.ldb_dc1.deleteuser(user_name)
+
+ res = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=self.computer_dn,
+ attrs=["msDS-RevealedUsers"])
+ self.assertFalse("msDS-RevealedUsers" in res[0])
+
+ def test_msDSRevealedUsers(self):
+ """
+ When a secret attribute is to be replicated to an RODC, the contents
+ of the attribute should be added to the msDSRevealedUsers attribute
+ of the computer object corresponding to the RODC.
+ """
+
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ # Add a user on DC1, add it to allowed password replication
+ # group, and replicate to RODC with EXOP_REPL_SECRETS
+ user_name = "test_rodcD_%s" % rand
+ password = "password12#"
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, password, False, user_name)
+
+ self.ldb_dc1.add_remove_group_members("Allowed RODC Password Replication Group",
+ [user_name],
+ add_members_operation=True)
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+
+ # Check that the user has been added to msDSRevealedUsers
+ (packed_attrs_1, unpacked_attrs_1) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ # Change the user's password on DC1
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, password + "1", False, user_name)
+
+ (packed_attrs_2, unpacked_attrs_2) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+ self._assert_attrlist_equals(unpacked_attrs_1, unpacked_attrs_2)
+
+ # Replicate to RODC again with EXOP_REPL_SECRETS
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+
+ # This is important for Windows, because the entry won't have been
+ # updated in time if we don't have it. Even with this sleep, it only
+ # passes some of the time...
+ time.sleep(5)
+
+ # Check that the entry in msDSRevealedUsers has been updated
+ (packed_attrs_3, unpacked_attrs_3) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+ self._assert_attrlist_changed(unpacked_attrs_2, unpacked_attrs_3, expected_user_attributes)
+
+ # We should be able to delete the user
+ self.ldb_dc1.deleteuser(user_name)
+
+ res = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=self.computer_dn,
+ attrs=["msDS-RevealedUsers"])
+ self.assertFalse("msDS-RevealedUsers" in res[0])
+
+ def test_msDSRevealedUsers_pas(self):
+ """
+ If we provide a Partial Attribute Set when replicating to an RODC,
+ we should ignore it and replicate all of the secret attributes anyway
+ msDSRevealedUsers attribute.
+ """
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+ pas_exceptions = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ # Add a user on DC1, add it to allowed password replication
+ # group, and replicate to RODC with EXOP_REPL_SECRETS
+ user_name = "test_rodcE_%s" % rand
+ password = "password12#"
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, password, False, user_name)
+
+ self.ldb_dc1.add_remove_group_members("Allowed RODC Password Replication Group",
+ [user_name],
+ add_members_operation=True)
+
+ pas = drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb, exceptions=pas_exceptions)
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=pas,
+ max_objects=133,
+ replica_flags=0)
+ (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, 10, req10)
+
+ # Make sure that we still replicate the secrets
+ for attribute in ctr.first_object.object.attribute_ctr.attributes:
+ if attribute.attid in pas_exceptions:
+ pas_exceptions.remove(attribute.attid)
+ for attribute in pas_exceptions:
+ self.fail("%d was not replicated even though the partial attribute set should be ignored."
+ % attribute)
+
+ # Check that the user has been added to msDSRevealedUsers
+ (packed_attrs_1, unpacked_attrs_1) = self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ def test_msDSRevealedUsers_using_other_RODC(self):
+ """
+ Ensure that the machine account is tied to the destination DSA.
+ """
+ # Create a new identical RODC with just the first letter missing
+ other_rodc_name = self.rodc_name[1:]
+ other_rodc_ctx = DCJoinContext(server=self.ldb_dc1.host_dns_name(),
+ creds=self.get_credentials(),
+ lp=self.get_loadparm(), site=self.site,
+ netbios_name=other_rodc_name,
+ targetdir=None, domain=None,
+ machinepass=self.rodc_pass)
+ self._create_rodc(other_rodc_ctx)
+
+ other_rodc_creds = Credentials()
+ other_rodc_creds.guess(other_rodc_ctx.lp)
+ other_rodc_creds.set_username(other_rodc_name + '$')
+ other_rodc_creds.set_password(self.rodc_pass)
+
+ (other_rodc_drs, other_rodc_drs_handle) = self._ds_bind(self.dnsname_dc1, other_rodc_creds)
+
+ rand = random.randint(1, 10000000)
+
+ user_name = "test_rodcF_%s" % rand
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, 'penguin12#', False, user_name)
+ self.ldb_dc1.add_remove_group_members("Allowed RODC Password Replication Group",
+ [user_name],
+ add_members_operation=True)
+
+ req10 = self._getnc_req10(dest_dsa=str(other_rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+
+ try:
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except WERRORError as e3:
+ (enum, estr) = e3.args
+ self.assertEqual(enum, 8630) # ERROR_DS_DRA_SECRETS_DENIED
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+
+ try:
+ (level, ctr) = other_rodc_drs.DsGetNCChanges(other_rodc_drs_handle, 10, req10)
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except WERRORError as e4:
+ (enum, estr) = e4.args
+ self.assertEqual(enum, 8630) # ERROR_DS_DRA_SECRETS_DENIED
+
+ def test_msDSRevealedUsers_local_deny_allow(self):
+ """
+ Ensure that the deny trumps allow, and we can modify these
+ attributes directly instead of the global groups.
+
+ This may fail on Windows due to tokenGroup calculation caching.
+ """
+ rand = random.randint(1, 10000000)
+ expected_user_attributes = [drsuapi.DRSUAPI_ATTID_lmPwdHistory,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_ntPwdHistory,
+ drsuapi.DRSUAPI_ATTID_unicodePwd,
+ drsuapi.DRSUAPI_ATTID_dBCSPwd]
+
+ # Add a user on DC1, add it to allowed password replication
+ # group, and replicate to RODC with EXOP_REPL_SECRETS
+ user_name = "test_rodcF_%s" % rand
+ password = "password12#"
+ user_dn = "CN=%s,%s" % (user_name, self.ou)
+ self.ldb_dc1.add({
+ "dn": user_dn,
+ "objectclass": "user",
+ "sAMAccountName": user_name
+ })
+
+ # Store some secret on this user
+ self.ldb_dc1.setpassword("(sAMAccountName=%s)" % user_name, password, False, user_name)
+
+ req10 = self._getnc_req10(dest_dsa=str(self.rodc_ctx.ntds_guid),
+ invocation_id=self.ldb_dc1.get_invocation_id(),
+ nc_dn_str=user_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ partial_attribute_set=drs_get_rodc_partial_attribute_set(self.ldb_dc1, self.tmp_samdb),
+ max_objects=133,
+ replica_flags=0)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, self.computer_dn)
+
+ m["msDS-RevealOnDemandGroup"] = \
+ ldb.MessageElement(user_dn, ldb.FLAG_MOD_ADD,
+ "msDS-RevealOnDemandGroup")
+ self.ldb_dc1.modify(m)
+
+ # In local allow, should be success
+ try:
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+ except:
+ self.fail("Should have succeeded when in local allow group")
+
+ self._assert_in_revealed_users(user_dn, expected_user_attributes)
+
+ (self.rodc_drs, self.rodc_drs_handle) = self._ds_bind(self.dnsname_dc1, self.rodc_creds)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, self.computer_dn)
+
+ m["msDS-NeverRevealGroup"] = \
+ ldb.MessageElement(user_dn, ldb.FLAG_MOD_ADD,
+ "msDS-NeverRevealGroup")
+ self.ldb_dc1.modify(m)
+
+ # In local allow and deny, should be failure
+ try:
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except WERRORError as e5:
+ (enum, estr) = e5.args
+ self.assertEqual(enum, 8630) # ERROR_DS_DRA_SECRETS_DENIED
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, self.computer_dn)
+
+ m["msDS-RevealOnDemandGroup"] = \
+ ldb.MessageElement(user_dn, ldb.FLAG_MOD_DELETE,
+ "msDS-RevealOnDemandGroup")
+ self.ldb_dc1.modify(m)
+
+ # In local deny, should be failure
+ (self.rodc_drs, self.rodc_drs_handle) = self._ds_bind(self.dnsname_dc1, self.rodc_creds)
+ try:
+ (level, ctr) = self.rodc_drs.DsGetNCChanges(self.rodc_drs_handle, 10, req10)
+ self.fail("Successfully replicated secrets to an RODC that shouldn't have been replicated.")
+ except WERRORError as e6:
+ (enum, estr) = e6.args
+ self.assertEqual(enum, 8630) # ERROR_DS_DRA_SECRETS_DENIED
+
+ def _assert_in_revealed_users(self, user_dn, attrlist):
+ res = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=self.computer_dn,
+ attrs=["msDS-RevealedUsers"])
+ revealed_users = res[0]["msDS-RevealedUsers"]
+ actual_attrids = []
+ packed_attrs = []
+ unpacked_attrs = []
+ for attribute in revealed_users:
+ attribute = attribute.decode('utf8')
+ dsdb_dn = dsdb_Dn(self.ldb_dc1, attribute)
+ metadata = ndr_unpack(drsblobs.replPropertyMetaData1, dsdb_dn.get_bytes())
+ if user_dn in attribute:
+ unpacked_attrs.append(metadata)
+ packed_attrs.append(dsdb_dn.get_bytes())
+ actual_attrids.append(metadata.attid)
+
+ self.assertEqual(sorted(actual_attrids), sorted(attrlist))
+
+ return (packed_attrs, unpacked_attrs)
+
+ def _assert_attrlist_equals(self, list_1, list_2):
+ return self._assert_attrlist_changed(list_1, list_2, [], num_changes=0, expected_new_usn=False)
+
+ def _assert_attrlist_changed(self, list_1, list_2, changed_attributes, num_changes=1, expected_new_usn=True):
+ for i in range(len(list_2)):
+ self.assertEqual(list_1[i].attid, list_2[i].attid)
+ self.assertEqual(list_1[i].originating_invocation_id, list_2[i].originating_invocation_id)
+ self.assertEqual(list_1[i].version + num_changes, list_2[i].version)
+
+ if expected_new_usn:
+ self.assertTrue(list_1[i].originating_usn < list_2[i].originating_usn)
+ self.assertTrue(list_1[i].local_usn < list_2[i].local_usn)
+ else:
+ self.assertEqual(list_1[i].originating_usn, list_2[i].originating_usn)
+ self.assertEqual(list_1[i].local_usn, list_2[i].local_usn)
+
+ if list_1[i].attid in changed_attributes:
+ # We do the changes too quickly, so unless we put sleeps
+ # in between calls, these remain the same. Checking the USNs
+ # is enough.
+ pass
+ #self.assertTrue(list_1[i].originating_change_time < list_2[i].originating_change_time)
+ else:
+ self.assertEqual(list_1[i].originating_change_time, list_2[i].originating_change_time)
+
+ def _create_rodc(self, ctx):
+ ctx.nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn]
+ ctx.full_nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn]
+ ctx.krbtgt_dn = "CN=krbtgt_%s,CN=Users,%s" % (ctx.myname, ctx.base_dn)
+
+ ctx.never_reveal_sid = ["<SID=%s-%s>" % (ctx.domsid, security.DOMAIN_RID_RODC_DENY),
+ "<SID=%s>" % security.SID_BUILTIN_ADMINISTRATORS,
+ "<SID=%s>" % security.SID_BUILTIN_SERVER_OPERATORS,
+ "<SID=%s>" % security.SID_BUILTIN_BACKUP_OPERATORS,
+ "<SID=%s>" % security.SID_BUILTIN_ACCOUNT_OPERATORS]
+ ctx.reveal_sid = "<SID=%s-%s>" % (ctx.domsid, security.DOMAIN_RID_RODC_ALLOW)
+
+ mysid = ctx.get_mysid()
+ admin_dn = "<SID=%s>" % mysid
+ ctx.managedby = admin_dn
+
+ ctx.userAccountControl = (samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT |
+ samba.dsdb.UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
+ samba.dsdb.UF_PARTIAL_SECRETS_ACCOUNT)
+
+ ctx.connection_dn = "CN=RODC Connection (FRS),%s" % ctx.ntds_dn
+ ctx.secure_channel_type = misc.SEC_CHAN_RODC
+ ctx.RODC = True
+ ctx.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC |
+ drsuapi.DRSUAPI_DRS_PER_SYNC |
+ drsuapi.DRSUAPI_DRS_GET_ANC |
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED |
+ drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING)
+
+ ctx.join_add_objects()
diff --git a/source4/torture/drs/python/repl_schema.py b/source4/torture/drs/python/repl_schema.py
new file mode 100644
index 0000000..9c039a5
--- /dev/null
+++ b/source4/torture/drs/python/repl_schema.py
@@ -0,0 +1,444 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests various schema replication scenarios
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN repl_schema -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import time
+import random
+import ldb
+import drs_base
+
+from ldb import (
+ ERR_NO_SUCH_OBJECT,
+ LdbError,
+ SCOPE_BASE,
+ Message,
+ FLAG_MOD_ADD,
+ FLAG_MOD_REPLACE
+)
+from samba.dcerpc import drsuapi, misc
+from samba.drs_utils import drs_DsBind
+from samba import dsdb
+
+
+class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
+
+ # prefix for all objects created
+ obj_prefix = None
+ # current Class or Attribute object id
+ obj_id = 0
+
+ def _exop_req8(self, dest_dsa, invocation_id, nc_dn_str, exop,
+ replica_flags=0, max_objects=0):
+ req8 = drsuapi.DsGetNCChangesRequest8()
+
+ req8.destination_dsa_guid = misc.GUID(dest_dsa) if dest_dsa else misc.GUID()
+ req8.source_dsa_invocation_id = misc.GUID(invocation_id)
+ req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
+ req8.naming_context.dn = str(nc_dn_str)
+ req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
+ req8.highwatermark.tmp_highest_usn = 0
+ req8.highwatermark.reserved_usn = 0
+ req8.highwatermark.highest_usn = 0
+ req8.uptodateness_vector = None
+ req8.replica_flags = replica_flags
+ req8.max_object_count = max_objects
+ req8.max_ndr_size = 402116
+ req8.extended_op = exop
+ req8.fsmo_info = 0
+ req8.partial_attribute_set = None
+ req8.partial_attribute_set_ex = None
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+
+ return req8
+
+ def setUp(self):
+ super(DrsReplSchemaTestCase, self).setUp()
+
+ # disable automatic replication temporary
+ self._disable_all_repl(self.dnsname_dc1)
+ self._disable_all_repl(self.dnsname_dc2)
+
+ # make sure DCs are synchronized before the test
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ # initialize objects prefix if not done yet
+ if self.obj_prefix is None:
+ t = time.strftime("%s", time.gmtime())
+ DrsReplSchemaTestCase.obj_prefix = "DrsReplSchema-%s" % t
+
+ def tearDown(self):
+ self._enable_all_repl(self.dnsname_dc1)
+ self._enable_all_repl(self.dnsname_dc2)
+ super(DrsReplSchemaTestCase, self).tearDown()
+
+ def _make_obj_names(self, base_name):
+ '''Try to create a unique name for an object
+ that is to be added to schema'''
+ self.obj_id += 1
+ obj_name = "%s-%d-%s" % (self.obj_prefix, self.obj_id, base_name)
+ obj_ldn = obj_name.replace("-", "")
+ obj_dn = ldb.Dn(self.ldb_dc1, "CN=X")
+ obj_dn.add_base(ldb.Dn(self.ldb_dc1, self.schema_dn))
+ obj_dn.set_component(0, "CN", obj_name)
+ return (obj_dn, obj_name, obj_ldn)
+
+ def _schema_new_class(self, ldb_ctx, base_name, base_int, oc_cat=1, attrs=None):
+ (class_dn, class_name, class_ldn) = self._make_obj_names(base_name)
+ rec = {"dn": class_dn,
+ "objectClass": ["top", "classSchema"],
+ "cn": class_name,
+ "lDAPDisplayName": class_ldn,
+ "governsId": "1.3.6.1.4.1.7165.4.6.2.5."
+ + str((100000 * base_int) + random.randint(1, 100000)) + ".1.5.13",
+ "instanceType": "4",
+ "objectClassCategory": "%d" % oc_cat,
+ "subClassOf": "top",
+ "systemOnly": "FALSE"}
+ # allow overriding/adding attributes
+ if attrs is not None:
+ rec.update(attrs)
+ # add it to the Schema
+ try:
+ ldb_ctx.add(rec)
+ except LdbError as e:
+ (enum, estr) = e.args
+ self.fail("Adding record failed with %d/%s" % (enum, estr))
+
+ self._ldap_schemaUpdateNow(ldb_ctx)
+ return (rec["lDAPDisplayName"], rec["dn"])
+
+ def _schema_new_attr(self, ldb_ctx, base_name, base_int, attrs=None):
+ (attr_dn, attr_name, attr_ldn) = self._make_obj_names(base_name)
+ rec = {"dn": attr_dn,
+ "objectClass": ["top", "attributeSchema"],
+ "cn": attr_name,
+ "lDAPDisplayName": attr_ldn,
+ "attributeId": "1.3.6.1.4.1.7165.4.6.1.5."
+ + str((100000 * base_int) + random.randint(1, 100000)) + ".1.5.13",
+ "attributeSyntax": "2.5.5.12",
+ "omSyntax": "64",
+ "instanceType": "4",
+ "isSingleValued": "TRUE",
+ "systemOnly": "FALSE"}
+ # allow overriding/adding attributes
+ if attrs is not None:
+ rec.update(attrs)
+ # add it to the Schema
+ ldb_ctx.add(rec)
+ self._ldap_schemaUpdateNow(ldb_ctx)
+ return (rec["lDAPDisplayName"], rec["dn"])
+
+ def _check_object(self, obj_dn):
+ '''Check if object obj_dn exists on both DCs'''
+ res_dc1 = self.ldb_dc1.search(base=obj_dn,
+ scope=SCOPE_BASE,
+ attrs=["*"])
+ self.assertEqual(len(res_dc1), 1,
+ "%s doesn't exists on %s" % (obj_dn, self.dnsname_dc1))
+ try:
+ res_dc2 = self.ldb_dc2.search(base=obj_dn,
+ scope=SCOPE_BASE,
+ attrs=["*"])
+ except LdbError as e1:
+ (enum, estr) = e1.args
+ if enum == ERR_NO_SUCH_OBJECT:
+ self.fail("%s doesn't exists on %s" % (obj_dn, self.dnsname_dc2))
+ raise
+ self.assertEqual(len(res_dc2), 1,
+ "%s doesn't exists on %s" % (obj_dn, self.dnsname_dc2))
+
+ def test_class(self):
+ """Simple test for classSchema replication"""
+ # add new classSchema object
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-S", 0)
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True)
+ # check object is replicated
+ self._check_object(c_dn)
+
+ def test_classInheritance(self):
+ """Test inheritance through subClassOf
+ I think 5 levels of inheritance is pretty decent for now."""
+ # add 5 levels deep hierarchy
+ c_dn_list = []
+ c_ldn_last = None
+ for i in range(1, 6):
+ base_name = "cls-I-%02d" % i
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, base_name, i)
+ c_dn_list.append(c_dn)
+ if c_ldn_last:
+ # inherit from last class added
+ m = Message.from_dict(self.ldb_dc1,
+ {"dn": c_dn,
+ "subClassOf": c_ldn_last},
+ FLAG_MOD_REPLACE)
+ self.ldb_dc1.modify(m)
+ # store last class ldapDisplayName
+ c_ldn_last = c_ldn
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True)
+ # check objects are replicated
+ for c_dn in c_dn_list:
+ self._check_object(c_dn)
+
+ def test_classWithCustomAttribute(self):
+ """Create new Attribute and a Class,
+ that has value for newly created attribute.
+ This should check code path that searches for
+ AttributeID_id in Schema cache"""
+ # add new attributeSchema object
+ (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-A", 7)
+ # add a base classSchema class so we can use our new
+ # attribute in class definition in a sibling class
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-A", 8,
+ 1,
+ {"systemMayContain": a_ldn,
+ "subClassOf": "classSchema"})
+ # add new classSchema object with value for a_ldb attribute
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-B", 9,
+ 1,
+ {"objectClass": ["top", "classSchema", c_ldn],
+ a_ldn: "test_classWithCustomAttribute"})
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True)
+ # check objects are replicated
+ self._check_object(c_dn)
+ self._check_object(a_dn)
+
+ def test_classWithCustomLinkAttribute(self):
+ """Create new Attribute and a Class,
+ that has value for newly created attribute.
+ This should check code path that searches for
+ AttributeID_id in Schema cache"""
+ # add new attributeSchema object
+ (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-Link-X", 10,
+ attrs={'linkID': "1.2.840.113556.1.2.50",
+ "attributeSyntax": "2.5.5.1",
+ "omSyntax": "127"})
+ # add a base classSchema class so we can use our new
+ # attribute in class definition in a sibling class
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-Link-Y", 11,
+ 1,
+ {"systemMayContain": a_ldn,
+ "subClassOf": "classSchema"})
+ # add new classSchema object with value for a_ldb attribute
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-Link-Z", 12,
+ 1,
+ {"objectClass": ["top", "classSchema", c_ldn],
+ a_ldn: self.schema_dn})
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True)
+ # check objects are replicated
+ self._check_object(c_dn)
+ self._check_object(a_dn)
+
+ res = self.ldb_dc1.search(base="",
+ scope=SCOPE_BASE,
+ attrs=["domainFunctionality"])
+
+ if int(res[0]["domainFunctionality"][0]) > dsdb.DS_DOMAIN_FUNCTION_2000:
+ res = self.ldb_dc1.search(base=a_dn,
+ scope=SCOPE_BASE,
+ attrs=["msDS-IntId"])
+ self.assertEqual(1, len(res))
+ self.assertTrue("msDS-IntId" in res[0])
+ int_id = int(res[0]["msDS-IntId"][0])
+ if int_id < 0:
+ int_id += (1 << 32)
+
+ dc_guid_1 = self.ldb_dc1.get_invocation_id()
+
+ drs, drs_handle = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
+
+ req8 = self._exop_req8(dest_dsa=None,
+ invocation_id=dc_guid_1,
+ nc_dn_str=c_dn,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ replica_flags=drsuapi.DRSUAPI_DRS_SYNC_FORCED)
+
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ for link in ctr.linked_attributes:
+ self.assertTrue(link.attid != int_id,
+ 'Got %d for both' % link.attid)
+
+ def test_attribute(self):
+ """Simple test for attributeSchema replication"""
+ # add new attributeSchema object
+ (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-S", 13)
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True)
+ # check object is replicated
+ self._check_object(a_dn)
+
+ def test_attribute_on_ou(self):
+ """Simple test having an OU with a custom attribute replicated correctly
+
+ This ensures that the server
+ """
+
+ # add new attributeSchema object
+ (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-OU-S", 14)
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-OU-A", 15,
+ 3,
+ {"mayContain": a_ldn})
+ ou_dn = ldb.Dn(self.ldb_dc1, "ou=X")
+ ou_dn.add_base(self.ldb_dc1.get_default_basedn())
+ ou_dn.set_component(0, "OU", a_dn.get_component_value(0))
+ rec = {"dn": ou_dn,
+ "objectClass": ["top", "organizationalUnit", c_ldn],
+ "ou": ou_dn.get_component_value(0),
+ a_ldn: "test OU"}
+ self.ldb_dc1.add(rec)
+
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.domain_dn, forced=True)
+ # check objects are replicated
+ self._check_object(c_dn)
+ self._check_object(a_dn)
+ self._check_object(ou_dn)
+ self.ldb_dc1.delete(ou_dn)
+
+ def test_all(self):
+ """Basic plan is to create bunch of classSchema
+ and attributeSchema objects, replicate Schema NC
+ and then check all objects are replicated correctly"""
+
+ # add new classSchema object
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-A", 16)
+ # add new attributeSchema object
+ (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-A", 17)
+
+ # add attribute to the class we have
+ m = Message.from_dict(self.ldb_dc1,
+ {"dn": c_dn,
+ "mayContain": a_ldn},
+ FLAG_MOD_ADD)
+ self.ldb_dc1.modify(m)
+
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True)
+
+ # check objects are replicated
+ self._check_object(c_dn)
+ self._check_object(a_dn)
+
+ def test_classWithCustomBinaryDNLinkAttribute(self):
+ # Add a new attribute to the schema, which has binary DN syntax (2.5.5.7)
+ (bin_ldn, bin_dn) = self._schema_new_attr(self.ldb_dc1, "attr-Link-Bin", 18,
+ attrs={"linkID": "1.2.840.113556.1.2.50",
+ "attributeSyntax": "2.5.5.7",
+ "omSyntax": "127"})
+
+ (bin_ldn_b, bin_dn_b) = self._schema_new_attr(self.ldb_dc1, "attr-Link-Bin-Back", 19,
+ attrs={"linkID": bin_ldn,
+ "attributeSyntax": "2.5.5.1",
+ "omSyntax": "127"})
+
+ # Add a new class to the schema which can have the binary DN attribute
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-Link-Bin", 20,
+ 3,
+ {"mayContain": bin_ldn})
+ (c_ldn_b, c_dn_b) = self._schema_new_class(self.ldb_dc1, "cls-Link-Bin-Back", 21,
+ 3,
+ {"mayContain": bin_ldn_b})
+
+ link_end_dn = ldb.Dn(self.ldb_dc1, "ou=X")
+ link_end_dn.add_base(self.ldb_dc1.get_default_basedn())
+ link_end_dn.set_component(0, "OU", bin_dn_b.get_component_value(0))
+
+ ou_dn = ldb.Dn(self.ldb_dc1, "ou=X")
+ ou_dn.add_base(self.ldb_dc1.get_default_basedn())
+ ou_dn.set_component(0, "OU", bin_dn.get_component_value(0))
+
+ # Add an instance of the class to be pointed at
+ rec = {"dn": link_end_dn,
+ "objectClass": ["top", "organizationalUnit", c_ldn_b],
+ "ou": link_end_dn.get_component_value(0)}
+ self.ldb_dc1.add(rec)
+
+ # .. and one that does, and points to the first one
+ rec = {"dn": ou_dn,
+ "objectClass": ["top", "organizationalUnit", c_ldn],
+ "ou": ou_dn.get_component_value(0)}
+ self.ldb_dc1.add(rec)
+
+ m = Message.from_dict(self.ldb_dc1,
+ {"dn": ou_dn,
+ bin_ldn: "B:8:1234ABCD:%s" % str(link_end_dn)},
+ FLAG_MOD_ADD)
+ self.ldb_dc1.modify(m)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn=self.schema_dn, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn=self.domain_dn, forced=True)
+
+ self._check_object(c_dn)
+ self._check_object(bin_dn)
+
+ # Make sure we can delete the backlink
+ self.ldb_dc1.delete(link_end_dn)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn=self.schema_dn, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn=self.domain_dn, forced=True)
+
+ def test_rename(self):
+ """Basic plan is to create a classSchema
+ and attributeSchema objects, replicate Schema NC
+ and then check all objects are replicated correctly"""
+
+ # add new classSchema object
+ (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-B", 20)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn=self.schema_dn, forced=True)
+
+ # check objects are replicated
+ self._check_object(c_dn)
+
+ # rename the Class CN
+ c_dn_new = ldb.Dn(self.ldb_dc1, str(c_dn))
+ c_dn_new.set_component(0,
+ "CN",
+ c_dn.get_component_value(0) + "-NEW")
+ try:
+ self.ldb_dc1.rename(c_dn, c_dn_new)
+ except LdbError as e2:
+ (num, _) = e2.args
+ self.fail("failed to change CN for %s: %s" % (c_dn, _))
+
+ # force replication from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn=self.schema_dn, forced=True)
+
+ # check objects are replicated
+ self._check_object(c_dn_new)
diff --git a/source4/torture/drs/python/repl_secdesc.py b/source4/torture/drs/python/repl_secdesc.py
new file mode 100644
index 0000000..38ae25a
--- /dev/null
+++ b/source4/torture/drs/python/repl_secdesc.py
@@ -0,0 +1,400 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Catalyst.Net Ltd. 2017
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2019
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+import drs_base
+import ldb
+import samba
+from samba import sd_utils
+from ldb import LdbError
+
+class ReplAclTestCase(drs_base.DrsBaseTestCase):
+
+ def setUp(self):
+ super(ReplAclTestCase, self).setUp()
+ self.mod = "(A;CIOI;GA;;;SY)"
+ self.mod_becomes = "(A;OICIIO;GA;;;SY)"
+ self.mod_inherits_as = "(A;OICIIOID;GA;;;SY)"
+
+ self.sd_utils_dc1 = sd_utils.SDUtils(self.ldb_dc1)
+ self.sd_utils_dc2 = sd_utils.SDUtils(self.ldb_dc2)
+
+ self.ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "test_acl_inherit")
+
+ # disable replication for the tests so we can control at what point
+ # the DCs try to replicate
+ self._disable_all_repl(self.dnsname_dc1)
+ self._disable_all_repl(self.dnsname_dc2)
+
+ # make sure DCs are synchronized before the test
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ def tearDown(self):
+ self.ldb_dc1.delete(self.ou, ["tree_delete:1"])
+
+ # re-enable replication
+ self._enable_all_repl(self.dnsname_dc1)
+ self._enable_all_repl(self.dnsname_dc2)
+
+ super(ReplAclTestCase, self).tearDown()
+
+ def test_acl_inheirt_new_object_1_pass(self):
+ # Set the inherited ACL on the parent OU
+ self.sd_utils_dc1.dacl_add_ace(self.ou, self.mod)
+
+ # Assert ACL set stuck as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(self.ou))
+
+ # Make a new object
+ dn = ldb.Dn(self.ldb_dc1, "OU=l2,%s" % self.ou)
+ self.ldb_dc1.add({"dn": dn, "objectclass": "organizationalUnit"})
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Assert ACL replicated as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc2.get_sd_as_sddl(self.ou))
+
+ # Confirm inherited ACLs are identical and were inherited
+
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(dn),
+ self.sd_utils_dc2.get_sd_as_sddl(dn))
+
+ def test_acl_inheirt_new_object(self):
+ # Set the inherited ACL on the parent OU
+ self.sd_utils_dc1.dacl_add_ace(self.ou, self.mod)
+
+ # Assert ACL set stuck as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(self.ou))
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Make a new object
+ dn = ldb.Dn(self.ldb_dc1, "OU=l2,%s" % self.ou)
+ self.ldb_dc1.add({"dn": dn, "objectclass": "organizationalUnit"})
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Assert ACL replicated as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc2.get_sd_as_sddl(self.ou))
+
+ # Confirm inherited ACLs are identical and were inherited
+
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(dn),
+ self.sd_utils_dc2.get_sd_as_sddl(dn))
+
+ def test_acl_inherit_existing_object(self):
+ # Make a new object
+ dn = ldb.Dn(self.ldb_dc1, "OU=l2,%s" % self.ou)
+ self.ldb_dc1.add({"dn": dn, "objectclass": "organizationalUnit"})
+
+ try:
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=dn,
+ attrs=[])
+ self.fail()
+ except LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Confirm it is now replicated
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=dn,
+ attrs=[])
+
+ # Set the inherited ACL on the parent OU
+ self.sd_utils_dc1.dacl_add_ace(self.ou, self.mod)
+
+ # Assert ACL set stuck as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(self.ou))
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Confirm inherited ACLs are identical and were inherited
+
+ # Assert ACL replicated as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc2.get_sd_as_sddl(self.ou))
+
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(dn),
+ self.sd_utils_dc2.get_sd_as_sddl(dn))
+
+ def test_acl_inheirt_existing_object_1_pass(self):
+ # Make a new object
+ dn = ldb.Dn(self.ldb_dc1, "OU=l2,%s" % self.ou)
+ self.ldb_dc1.add({"dn": dn, "objectclass": "organizationalUnit"})
+
+ try:
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=dn,
+ attrs=[])
+ self.fail()
+ except LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ # Set the inherited ACL on the parent OU
+ self.sd_utils_dc1.dacl_add_ace(self.ou, self.mod)
+
+ # Assert ACL set as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(self.ou))
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Assert ACL replicated as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc2.get_sd_as_sddl(self.ou))
+
+ # Confirm inherited ACLs are identical and were inherited
+
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(dn),
+ self.sd_utils_dc2.get_sd_as_sddl(dn))
+
+ def test_acl_inheirt_renamed_object(self):
+ # Make a new object
+ new_ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "acl_test_l2")
+
+ sub_ou_dn = ldb.Dn(self.ldb_dc1, "OU=l2,%s" % self.ou)
+
+ try:
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=new_ou,
+ attrs=[])
+ self.fail()
+ except LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Confirm it is now replicated
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=new_ou,
+ attrs=[])
+
+ # Set the inherited ACL on the parent OU on DC1
+ self.sd_utils_dc1.dacl_add_ace(self.ou, self.mod)
+
+ # Assert ACL set as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(self.ou))
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Assert ACL replicated as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc2.get_sd_as_sddl(self.ou))
+
+ # Rename to under self.ou
+
+ self.ldb_dc1.rename(new_ou, sub_ou_dn)
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Confirm inherited ACLs are identical and were inherited
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(sub_ou_dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(sub_ou_dn),
+ self.sd_utils_dc2.get_sd_as_sddl(sub_ou_dn))
+
+
+ def test_acl_inheirt_renamed_child_object(self):
+ # Make a new OU
+ new_ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "acl_test_l2")
+
+ # Here is where the new OU will end up at the end.
+ sub2_ou_dn_final = ldb.Dn(self.ldb_dc1, "OU=l2,%s" % self.ou)
+
+ sub3_ou_dn = ldb.Dn(self.ldb_dc1, "OU=l3,%s" % new_ou)
+ sub3_ou_dn_final = ldb.Dn(self.ldb_dc1, "OU=l3,%s" % sub2_ou_dn_final)
+
+ self.ldb_dc1.add({"dn": sub3_ou_dn,
+ "objectclass": "organizationalUnit"})
+
+ sub4_ou_dn = ldb.Dn(self.ldb_dc1, "OU=l4,%s" % sub3_ou_dn)
+ sub4_ou_dn_final = ldb.Dn(self.ldb_dc1, "OU=l4,%s" % sub3_ou_dn_final)
+
+ self.ldb_dc1.add({"dn": sub4_ou_dn,
+ "objectclass": "organizationalUnit"})
+
+ try:
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=new_ou,
+ attrs=[])
+ self.fail()
+ except LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Confirm it is now replicated
+ self.ldb_dc2.search(scope=ldb.SCOPE_BASE,
+ base=new_ou,
+ attrs=[])
+
+ #
+ # Given a tree new_ou -> l3 -> l4
+ #
+
+ # Set the inherited ACL on the grandchild OU (l3) on DC1
+ self.sd_utils_dc1.dacl_add_ace(sub3_ou_dn, self.mod)
+
+ # Assert ACL set stuck as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(sub3_ou_dn))
+
+ # Rename new_ou (l2) to under self.ou (this must happen second). If the
+ # inheritance between l3 and l4 is name-based, this could
+ # break.
+
+ # The tree is now self.ou -> l2 -> l3 -> l4
+
+ self.ldb_dc1.rename(new_ou, sub2_ou_dn_final)
+
+ # Assert ACL set remained as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(sub3_ou_dn_final))
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Confirm set ACLs (on l3 ) are identical and were inherited
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc2.get_sd_as_sddl(sub3_ou_dn_final))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(sub3_ou_dn_final),
+ self.sd_utils_dc2.get_sd_as_sddl(sub3_ou_dn_final))
+
+ # Confirm inherited ACLs (from l3 to l4) are identical
+ # and were inherited
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(sub4_ou_dn_final))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(sub4_ou_dn_final),
+ self.sd_utils_dc2.get_sd_as_sddl(sub4_ou_dn_final))
+
+
+ def test_acl_inheirt_renamed_object_in_conflict(self):
+ # Make a new object to be renamed under self.ou
+ new_ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "acl_test_l2")
+
+ # Make a new OU under self.ou (on DC2)
+ sub_ou_dn = ldb.Dn(self.ldb_dc2, "OU=l2,%s" % self.ou)
+ self.ldb_dc2.add({"dn": sub_ou_dn,
+ "objectclass": "organizationalUnit"})
+
+ # Set the inherited ACL on the parent OU
+ self.sd_utils_dc1.dacl_add_ace(self.ou, self.mod)
+
+ # Assert ACL set stuck as expected
+ self.assertIn(self.mod_becomes,
+ self.sd_utils_dc1.get_sd_as_sddl(self.ou))
+
+ # Replicate to DC2
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ # Rename to under self.ou
+ self.ldb_dc1.rename(new_ou, sub_ou_dn)
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(sub_ou_dn))
+
+ # Replicate to DC2 (will cause a conflict, DC1 to win, version
+ # is higher since named twice)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2,
+ fromDC=self.dnsname_dc1,
+ forced=True)
+
+ children = self.ldb_dc2.search(scope=ldb.SCOPE_ONELEVEL,
+ base=self.ou,
+ attrs=[])
+ for child in children:
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc2.get_sd_as_sddl(child.dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(sub_ou_dn),
+ self.sd_utils_dc2.get_sd_as_sddl(child.dn))
+
+ # Replicate back
+ self._net_drs_replicate(DC=self.dnsname_dc1,
+ fromDC=self.dnsname_dc2,
+ forced=True)
+
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(sub_ou_dn))
+
+ for child in children:
+ self.assertIn(self.mod_inherits_as,
+ self.sd_utils_dc1.get_sd_as_sddl(child.dn))
+ self.assertEqual(self.sd_utils_dc1.get_sd_as_sddl(child.dn),
+ self.sd_utils_dc2.get_sd_as_sddl(child.dn))
diff --git a/source4/torture/drs/python/replica_sync.py b/source4/torture/drs/python/replica_sync.py
new file mode 100644
index 0000000..f40b16d
--- /dev/null
+++ b/source4/torture/drs/python/replica_sync.py
@@ -0,0 +1,747 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests various schema replication scenarios
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN replica_sync -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+import time
+import ldb
+
+from ldb import (
+ SCOPE_BASE, LdbError, ERR_NO_SUCH_OBJECT)
+
+
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
+ """Intended as a black box test case for DsReplicaSync
+ implementation. It should test the behavior of this
+ case in cases when inbound replication is disabled"""
+
+ def setUp(self):
+ super(DrsReplicaSyncTestCase, self).setUp()
+
+ # This OU avoids this test conflicting with anything
+ # that may already be in the DB
+ self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
+ "replica_sync")
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+ self.ou1 = None
+ self.ou2 = None
+
+ def tearDown(self):
+ self._cleanup_object(self.ou1)
+ self._cleanup_object(self.ou2)
+ self._cleanup_dn(self.top_ou)
+
+ # re-enable replication
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self._enable_inbound_repl(self.dnsname_dc2)
+
+ super(DrsReplicaSyncTestCase, self).tearDown()
+
+ def _cleanup_dn(self, dn):
+ try:
+ self.ldb_dc2.delete(dn, ["tree_delete:1"])
+ except LdbError as e:
+ (num, _) = e.args
+ self.assertEqual(num, ERR_NO_SUCH_OBJECT)
+ try:
+ self.ldb_dc1.delete(dn, ["tree_delete:1"])
+ except LdbError as e1:
+ (num, _) = e1.args
+ self.assertEqual(num, ERR_NO_SUCH_OBJECT)
+
+ def _cleanup_object(self, guid):
+ """Cleans up a test object, if it still exists"""
+ if guid is not None:
+ self._cleanup_dn('<GUID=%s>' % guid)
+
+ def test_ReplEnabled(self):
+ """Tests we can replicate when replication is enabled"""
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=False)
+
+ def test_ReplDisabled(self):
+ """Tests we can't replicate when replication is disabled"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+
+ ccache_name = self.get_creds_ccache_name()
+
+ # Tunnel the command line credentials down to the
+ # subcommand to avoid a new kinit
+ cmdline_auth = "--use-krb5-ccache=%s" % ccache_name
+
+ # bin/samba-tool drs <drs_command> <cmdline_auth>
+ cmd_list = ["drs", "replicate", cmdline_auth]
+
+ nc_dn = self.domain_dn
+ # bin/samba-tool drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>
+ cmd_list += [self.dnsname_dc1, self.dnsname_dc2, nc_dn]
+
+ (result, out, err) = self.runsubcmd(*cmd_list)
+ self.assertCmdFail(result)
+ self.assertTrue('WERR_DS_DRA_SINK_DISABLED' in err)
+
+ def test_ReplDisabledForced(self):
+ """Tests we can force replicate when replication is disabled"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
+
+ def test_ReplLocal(self):
+ """Tests we can replicate direct to the local db"""
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=False, local=True, full_sync=True)
+
+ def _create_ou(self, samdb, name):
+ ldif = """
+dn: %s,%s
+objectClass: organizationalUnit
+""" % (name, self.top_ou)
+ samdb.add_ldif(ldif)
+ res = samdb.search(base="%s,%s" % (name, self.top_ou),
+ scope=SCOPE_BASE, attrs=["objectGUID"])
+ return self._GUID_string(res[0]["objectGUID"][0])
+
+ def _check_deleted(self, sam_ldb, guid):
+ # search the user by guid as it may be deleted
+ res = sam_ldb.search(base='<GUID=%s>' % guid,
+ controls=["show_deleted:1"],
+ attrs=["isDeleted", "objectCategory", "ou"])
+ self.assertEqual(len(res), 1)
+ ou_cur = res[0]
+ # Deleted Object base DN
+ dodn = self._deleted_objects_dn(sam_ldb)
+ # now check properties of the user
+ name_cur = ou_cur["ou"][0]
+ self.assertEqual(ou_cur["isDeleted"][0], b"TRUE")
+ self.assertTrue(not("objectCategory" in ou_cur))
+ self.assertTrue(dodn in str(ou_cur["dn"]),
+ "OU %s is deleted but it is not located under %s!" % (name_cur, dodn))
+
+ def test_ReplConflictsFullSync(self):
+ """Tests that objects created in conflict become conflict DNs (honour full sync override)"""
+
+ # First confirm local replication (so when we test against windows, this fails fast without creating objects)
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, local=True, forced=True, full_sync=True)
+
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Full Sync")
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Full Sync")
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, local=True, forced=True, full_sync=True)
+
+ # Check that DC2 got the DC1 object, and OU1 was make into conflict
+ res1 = self.ldb_dc2.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertFalse('CNF:%s' % self.ou2 in str(res2[0]["name"][0]))
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc2, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc2, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC2
+
+ self.ldb_dc2.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc2.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=True)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplConflictsRemoteWin(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Remote Conflict")
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Remote Conflict")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and OU1 was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplConflictsLocalWin(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC2 object created first
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Local Conflict")
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Local Conflict")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and OU2 was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou2 in str(res2[0]["name"][0]), "Got %s for %s" % (str(res2[0]["name"][0]), self.ou2))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplConflictsRemoteWin_with_child(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Parent Remote Conflict")
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Parent Remote Conflict")
+ # Create children on DC2
+ ou1_child = self._create_ou(self.ldb_dc1, "OU=Test Child,OU=Test Parent Remote Conflict")
+ ou2_child = self._create_ou(self.ldb_dc2, "OU=Test Child,OU=Test Parent Remote Conflict")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and SELF.OU1 was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1, ["tree_delete:1"])
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2, ["tree_delete:1"])
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ self._check_deleted(self.ldb_dc1, ou1_child)
+ self._check_deleted(self.ldb_dc1, ou2_child)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, ou1_child)
+ self._check_deleted(self.ldb_dc2, ou2_child)
+
+ def test_ReplConflictsRenamedVsNewRemoteWin(self):
+ """Tests resolving a DN conflict between a renamed object and a new object"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create an OU and rename it on DC1
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Remote Rename Conflict orig")
+ self.ldb_dc1.rename("<GUID=%s>" % self.ou1, "OU=Test Remote Rename Conflict,%s" % self.top_ou)
+
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+
+ # create a conflicting object with the same DN on DC2
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Remote Rename Conflict")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and SELF.OU1 was made into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplConflictsRenamedVsNewLocalWin(self):
+ """Tests resolving a DN conflict between a renamed object and a new object"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, where the DC2 object has been renamed
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Rename Local Conflict orig")
+ self.ldb_dc2.rename("<GUID=%s>" % self.ou2, "OU=Test Rename Local Conflict,%s" % self.top_ou)
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Rename Local Conflict")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and OU2 was made into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou2 in str(res2[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplConflictsRenameRemoteWin(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Remote Rename Conflict")
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Remote Rename Conflict 2")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ self.ldb_dc1.rename("<GUID=%s>" % self.ou1, "OU=Test Remote Rename Conflict 3,%s" % self.top_ou)
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ldb_dc2.rename("<GUID=%s>" % self.ou2, "OU=Test Remote Rename Conflict 3,%s" % self.top_ou)
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and SELF.OU1 was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplConflictsRenameRemoteWin_with_child(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Parent Remote Rename Conflict")
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Parent Remote Rename Conflict 2")
+ # Create children on DC2
+ ou1_child = self._create_ou(self.ldb_dc1, "OU=Test Child,OU=Test Parent Remote Rename Conflict")
+ ou2_child = self._create_ou(self.ldb_dc2, "OU=Test Child,OU=Test Parent Remote Rename Conflict 2")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ self.ldb_dc1.rename("<GUID=%s>" % self.ou1, "OU=Test Parent Remote Rename Conflict 3,%s" % self.top_ou)
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ldb_dc2.rename("<GUID=%s>" % self.ou2, "OU=Test Parent Remote Rename Conflict 3,%s" % self.top_ou)
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and SELF.OU1 was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1, ["tree_delete:1"])
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2, ["tree_delete:1"])
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ self._check_deleted(self.ldb_dc1, ou1_child)
+ self._check_deleted(self.ldb_dc1, ou2_child)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, ou1_child)
+ self._check_deleted(self.ldb_dc2, ou2_child)
+
+ def test_ReplConflictsRenameLocalWin(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ self.ou1 = self._create_ou(self.ldb_dc1, "OU=Test Rename Local Conflict")
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Test Rename Local Conflict 2")
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ self.ldb_dc2.rename("<GUID=%s>" % self.ou2, "OU=Test Rename Local Conflict 3,%s" % self.top_ou)
+ # We have to sleep to ensure that the two objects have different timestamps
+ time.sleep(1)
+ self.ldb_dc1.rename("<GUID=%s>" % self.ou1, "OU=Test Rename Local Conflict 3,%s" % self.top_ou)
+
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC2 got the DC1 object, and OU2 was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou2 in str(res2[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) not in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+
+ def test_ReplLostAndFound(self):
+ """Tests that objects created under a OU deleted eleswhere end up in lostAndFound"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create two OUs on DC2
+ self.ou1 = self._create_ou(self.ldb_dc2, "OU=Deleted parent")
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Deleted parent 2")
+
+ # replicate them from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Delete both objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ # Create children on DC2
+ ou1_child = self._create_ou(self.ldb_dc2, "OU=Test Child,OU=Deleted parent")
+ ou2_child = self._create_ou(self.ldb_dc2, "OU=Test Child,OU=Deleted parent 2")
+
+ # Replicate from DC2
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check the sub-OUs are now in lostAndFound and the first one is a conflict DN
+
+ # Check that DC2 got the DC1 object, and one or other object was make into conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % ou1_child in str(res1[0]["name"][0]) or 'CNF:%s' % ou2_child in str(res2[0]["name"][0]))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) in str(res1[0].dn))
+ self.assertTrue(self._lost_and_found_dn(self.ldb_dc1, self.domain_dn) in str(res2[0].dn))
+ self.assertEqual(str(res1[0]["name"][0]), res1[0].dn.get_rdn_value())
+ self.assertEqual(str(res2[0]["name"][0]), res2[0].dn.get_rdn_value())
+
+ # Delete all objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % ou1_child)
+ self.ldb_dc1.delete('<GUID=%s>' % ou2_child)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ # Check all deleted on DC1
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ self._check_deleted(self.ldb_dc1, ou1_child)
+ self._check_deleted(self.ldb_dc1, ou2_child)
+ # Check all deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+ self._check_deleted(self.ldb_dc2, ou1_child)
+ self._check_deleted(self.ldb_dc2, ou2_child)
+
+ def test_ReplRenames(self):
+ """Tests that objects created under a OU deleted eleswhere end up in lostAndFound"""
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # Create two OUs on DC2
+ self.ou1 = self._create_ou(self.ldb_dc2, "OU=Original parent")
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Original parent 2")
+
+ # replicate them from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Create children on DC1
+ ou1_child = self._create_ou(self.ldb_dc1, "OU=Test Child,OU=Original parent")
+ ou2_child = self._create_ou(self.ldb_dc1, "OU=Test Child 2,OU=Original parent")
+ ou3_child = self._create_ou(self.ldb_dc1, "OU=Test Case Child,OU=Original parent")
+
+ # replicate them from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self.ldb_dc1.rename("<GUID=%s>" % ou2_child, "OU=Test Child 3,OU=Original parent 2,%s" % self.top_ou)
+ self.ldb_dc1.rename("<GUID=%s>" % ou1_child, "OU=Test Child 2,OU=Original parent 2,%s" % self.top_ou)
+ self.ldb_dc1.rename("<GUID=%s>" % ou2_child, "OU=Test Child,OU=Original parent 2,%s" % self.top_ou)
+ self.ldb_dc1.rename("<GUID=%s>" % ou3_child, "OU=Test CASE Child,OU=Original parent,%s" % self.top_ou)
+ self.ldb_dc2.rename("<GUID=%s>" % self.ou2, "OU=Original parent 3,%s" % self.top_ou)
+ self.ldb_dc2.rename("<GUID=%s>" % self.ou1, "OU=Original parent 2,%s" % self.top_ou)
+
+ # replicate them from DC1 to DC2
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ # Check the sub-OUs are now under Original Parent 3 (original
+ # parent 2 for Test CASE Child), and both have the right names
+
+ # Check that DC2 got the DC1 object, and the renames are all correct
+ res1 = self.ldb_dc2.search(base="<GUID=%s>" % ou1_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc2.search(base="<GUID=%s>" % ou2_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ res3 = self.ldb_dc2.search(base="<GUID=%s>" % ou3_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0].dn)
+ print(res2[0].dn)
+ print(res3[0].dn)
+ self.assertEqual('Test Child 2', str(res1[0]["name"][0]))
+ self.assertEqual('Test Child', str(res2[0]["name"][0]))
+ self.assertEqual('Test CASE Child', str(res3[0]["name"][0]))
+ self.assertEqual(str(res1[0].dn), "OU=Test Child 2,OU=Original parent 3,%s" % self.top_ou)
+ self.assertEqual(str(res2[0].dn), "OU=Test Child,OU=Original parent 3,%s" % self.top_ou)
+ self.assertEqual(str(res3[0].dn), "OU=Test CASE Child,OU=Original parent 2,%s" % self.top_ou)
+
+ # replicate them from DC2 to DC1
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check that DC1 got the DC2 object, and the renames are all correct
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % ou1_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % ou2_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ res3 = self.ldb_dc1.search(base="<GUID=%s>" % ou3_child,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0].dn)
+ print(res2[0].dn)
+ print(res3[0].dn)
+ self.assertEqual('Test Child 2', str(res1[0]["name"][0]))
+ self.assertEqual('Test Child', str(res2[0]["name"][0]))
+ self.assertEqual('Test CASE Child', str(res3[0]["name"][0]))
+ self.assertEqual(str(res1[0].dn), "OU=Test Child 2,OU=Original parent 3,%s" % self.top_ou)
+ self.assertEqual(str(res2[0].dn), "OU=Test Child,OU=Original parent 3,%s" % self.top_ou)
+ self.assertEqual(str(res3[0].dn), "OU=Test CASE Child,OU=Original parent 2,%s" % self.top_ou)
+
+ # Delete all objects by GUID on DC1
+
+ self.ldb_dc1.delete('<GUID=%s>' % ou1_child)
+ self.ldb_dc1.delete('<GUID=%s>' % ou2_child)
+ self.ldb_dc1.delete('<GUID=%s>' % ou3_child)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ # Check all deleted on DC1
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ self._check_deleted(self.ldb_dc1, ou1_child)
+ self._check_deleted(self.ldb_dc1, ou2_child)
+ self._check_deleted(self.ldb_dc1, ou3_child)
+ # Check all deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
+ self._check_deleted(self.ldb_dc2, ou1_child)
+ self._check_deleted(self.ldb_dc2, ou2_child)
+ self._check_deleted(self.ldb_dc2, ou3_child)
+
+ def reanimate_object(self, samdb, guid, new_dn):
+ """Re-animates a deleted object"""
+ res = samdb.search(base="<GUID=%s>" % guid, attrs=["isDeleted"],
+ controls=['show_deleted:1'], scope=SCOPE_BASE)
+ if len(res) != 1:
+ return
+
+ msg = ldb.Message()
+ msg.dn = res[0].dn
+ msg["isDeleted"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "isDeleted")
+ msg["distinguishedName"] = ldb.MessageElement([new_dn], ldb.FLAG_MOD_REPLACE, "distinguishedName")
+ samdb.modify(msg, ["show_deleted:1"])
+
+ def test_ReplReanimationConflict(self):
+ """
+ Checks that if a reanimated object conflicts with a new object, then
+ the conflict is resolved correctly.
+ """
+
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ # create an object, "accidentally" delete it, and replicate the changes to both DCs
+ self.ou1 = self._create_ou(self.ldb_dc2, "OU=Conflict object")
+ self.ldb_dc2.delete('<GUID=%s>' % self.ou1)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Now pretend that the admin for one DC resolves the problem by
+ # re-animating the object...
+ self.reanimate_object(self.ldb_dc1, self.ou1, "OU=Conflict object,%s" % self.top_ou)
+
+ # ...whereas another admin just creates a user with the same name
+ # again on a different DC
+ time.sleep(1)
+ self.ou2 = self._create_ou(self.ldb_dc2, "OU=Conflict object")
+
+ # Now sync the DCs to resolve the conflict
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True, full_sync=False)
+
+ # Check the latest change won and SELF.OU1 was made into a conflict
+ res1 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou1,
+ scope=SCOPE_BASE, attrs=["name"])
+ res2 = self.ldb_dc1.search(base="<GUID=%s>" % self.ou2,
+ scope=SCOPE_BASE, attrs=["name"])
+ print(res1[0]["name"][0])
+ print(res2[0]["name"][0])
+ self.assertTrue('CNF:%s' % self.ou1 in str(res1[0]["name"][0]))
+ self.assertFalse('CNF:%s' % self.ou2 in str(res2[0]["name"][0]))
+
+ # Delete both objects by GUID on DC1
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True, full_sync=False)
+
+ self._check_deleted(self.ldb_dc1, self.ou1)
+ self._check_deleted(self.ldb_dc1, self.ou2)
+ # Check deleted on DC2
+ self._check_deleted(self.ldb_dc2, self.ou1)
+ self._check_deleted(self.ldb_dc2, self.ou2)
diff --git a/source4/torture/drs/python/replica_sync_rodc.py b/source4/torture/drs/python/replica_sync_rodc.py
new file mode 100644
index 0000000..cbdcc12
--- /dev/null
+++ b/source4/torture/drs/python/replica_sync_rodc.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Test conflict scenarios on the RODC
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Catalyst.NET Ltd 2018
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name (RODC)
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN replica_sync_rodc -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+import samba.tests
+import time
+import ldb
+from samba.common import get_string
+
+from ldb import (
+ SCOPE_BASE, LdbError, ERR_NO_SUCH_OBJECT)
+
+
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
+ """Intended as a black box test case for DsReplicaSync
+ implementation. It should test the behavior of this
+ case in cases when inbound replication is disabled"""
+
+ def setUp(self):
+ super(DrsReplicaSyncTestCase, self).setUp()
+ self._disable_all_repl(self.dnsname_dc1)
+ self.ou1 = None
+ self.ou2 = None
+
+ def tearDown(self):
+ # re-enable replication
+ self._enable_all_repl(self.dnsname_dc1)
+
+ super(DrsReplicaSyncTestCase, self).tearDown()
+
+ def _create_ou(self, samdb, name):
+ ldif = """
+dn: %s,%s
+objectClass: organizationalUnit
+""" % (name, self.domain_dn)
+ samdb.add_ldif(ldif)
+ res = samdb.search(base="%s,%s" % (name, self.domain_dn),
+ scope=SCOPE_BASE, attrs=["objectGUID"])
+ return get_string(self._GUID_string(res[0]["objectGUID"][0]))
+
+ def _check_deleted(self, sam_ldb, guid):
+ # search the user by guid as it may be deleted
+ res = sam_ldb.search(base='<GUID=%s>' % guid,
+ controls=["show_deleted:1"],
+ attrs=["isDeleted", "objectCategory", "ou"])
+ self.assertEqual(len(res), 1)
+ ou_cur = res[0]
+ # Deleted Object base DN
+ dodn = self._deleted_objects_dn(sam_ldb)
+ # now check properties of the user
+ name_cur = ou_cur["ou"][0]
+ self.assertEqual(ou_cur["isDeleted"][0], "TRUE")
+ self.assertTrue(not("objectCategory" in ou_cur))
+ self.assertTrue(dodn in str(ou_cur["dn"]),
+ "OU %s is deleted but it is not located under %s!" % (name_cur, dodn))
+
+ def test_ReplConflictsRODC(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ # Replicate all objects to RODC beforehand
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ name = "OU=Test RODC Conflict"
+ self.ou1 = self._create_ou(self.ldb_dc1, name)
+
+ # Replicate single object
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn="%s,%s" % (name, self.domain_dn),
+ local=True, single=True, forced=True)
+
+ # Delete the object, so another can be added
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+
+ # Create a conflicting DN as it would appear to the RODC
+ self.ou2 = self._create_ou(self.ldb_dc1, name)
+
+ try:
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn="%s,%s" % (name, self.domain_dn),
+ local=True, single=True, forced=True)
+ except:
+ # Cleanup the object
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+ return
+
+ # Replicate cannot succeed, HWM would be updated incorrectly.
+ self.fail("DRS replicate should have failed.")
+
+ def test_ReplConflictsRODCRename(self):
+ """Tests that objects created in conflict become conflict DNs"""
+ # Replicate all objects to RODC beforehand
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
+
+ # Create conflicting objects on DC1 and DC2, with DC1 object created first
+ name = "OU=Test RODC Rename Conflict"
+ self.ou1 = self._create_ou(self.ldb_dc1, name)
+
+ # Replicate single object
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn="%s,%s" % (name, self.domain_dn),
+ local=True, single=True, forced=True)
+
+ # Create a non-conflicting DN to rename as conflicting
+ free_name = "OU=Test RODC Rename No Conflict"
+ self.ou2 = self._create_ou(self.ldb_dc1, free_name)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn="%s,%s" % (free_name, self.domain_dn),
+ local=True, single=True, forced=True)
+
+ # Delete the object, so we can rename freely
+ # DO NOT REPLICATE TO THE RODC
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou1)
+
+ # Collide the name from the RODC perspective
+ self.ldb_dc1.rename("<GUID=%s>" % self.ou2, "%s,%s" % (name, self.domain_dn))
+
+ try:
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+ nc_dn="%s,%s" % (name, self.domain_dn),
+ local=True, single=True, forced=True)
+ except:
+ # Cleanup the object
+ self.ldb_dc1.delete('<GUID=%s>' % self.ou2)
+ return
+
+ # Replicate cannot succeed, HWM would be updated incorrectly.
+ self.fail("DRS replicate should have failed.")
diff --git a/source4/torture/drs/python/ridalloc_exop.py b/source4/torture/drs/python/ridalloc_exop.py
new file mode 100644
index 0000000..ecd5cec
--- /dev/null
+++ b/source4/torture/drs/python/ridalloc_exop.py
@@ -0,0 +1,802 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Tests various RID allocation scenarios
+#
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
+# Copyright (C) Catalyst IT Ltd. 2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export DC1=dc1_dns_name
+# export DC2=dc2_dns_name
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN ridalloc_exop -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
+#
+
+import drs_base
+
+import ldb
+from ldb import SCOPE_BASE
+
+from samba.dcerpc import drsuapi, misc
+from samba.samdb import SamDB
+
+import shutil
+import os
+from samba.auth import system_session, admin_session
+from samba.dbchecker import dbcheck
+from samba.ndr import ndr_pack
+from samba.dcerpc import security
+from samba import drs_utils, dsdb
+
+
+class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
+ """Intended as a semi-black box test case for DsGetNCChanges
+ implementation for extended operations. It should be testing
+ how DsGetNCChanges handles different input params (mostly invalid).
+ Final goal is to make DsGetNCChanges as binary compatible to
+ Windows implementation as possible"""
+
+ def setUp(self):
+ super(DrsReplicaSyncTestCase, self).setUp()
+
+ def tearDown(self):
+ super(DrsReplicaSyncTestCase, self).tearDown()
+
+ def _determine_fSMORoleOwner(self, fsmo_obj_dn):
+ """Returns (owner, not_owner) pair where:
+ owner: dns name for FSMO owner
+ not_owner: dns name for DC not owning the FSMO"""
+ # collect info to return later
+ fsmo_info_1 = {"dns_name": self.dnsname_dc1,
+ "invocation_id": self.ldb_dc1.get_invocation_id(),
+ "ntds_guid": self.ldb_dc1.get_ntds_GUID(),
+ "server_dn": self.ldb_dc1.get_serverName()}
+ fsmo_info_2 = {"dns_name": self.dnsname_dc2,
+ "invocation_id": self.ldb_dc2.get_invocation_id(),
+ "ntds_guid": self.ldb_dc2.get_ntds_GUID(),
+ "server_dn": self.ldb_dc2.get_serverName()}
+
+ msgs = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=fsmo_info_1["server_dn"], attrs=["serverReference"])
+ fsmo_info_1["server_acct_dn"] = ldb.Dn(self.ldb_dc1, msgs[0]["serverReference"][0].decode('utf8'))
+ fsmo_info_1["rid_set_dn"] = ldb.Dn(self.ldb_dc1, "CN=RID Set") + fsmo_info_1["server_acct_dn"]
+
+ msgs = self.ldb_dc2.search(scope=ldb.SCOPE_BASE, base=fsmo_info_2["server_dn"], attrs=["serverReference"])
+ fsmo_info_2["server_acct_dn"] = ldb.Dn(self.ldb_dc2, msgs[0]["serverReference"][0].decode('utf8'))
+ fsmo_info_2["rid_set_dn"] = ldb.Dn(self.ldb_dc2, "CN=RID Set") + fsmo_info_2["server_acct_dn"]
+
+ # determine the owner dc
+ res = self.ldb_dc1.search(fsmo_obj_dn,
+ scope=SCOPE_BASE, attrs=["fSMORoleOwner"])
+ assert len(res) == 1, "Only one fSMORoleOwner value expected for %s!" % fsmo_obj_dn
+ fsmo_owner = res[0]["fSMORoleOwner"][0]
+ if fsmo_owner == self.info_dc1["dsServiceName"][0]:
+ return (fsmo_info_1, fsmo_info_2)
+ return (fsmo_info_2, fsmo_info_1)
+
+ def _check_exop_failed(self, ctr6, expected_failure):
+ self.assertEqual(ctr6.extended_ret, expected_failure)
+ #self.assertEqual(ctr6.object_count, 0)
+ #self.assertEqual(ctr6.first_object, None)
+ self.assertEqual(ctr6.more_data, False)
+ self.assertEqual(ctr6.nc_object_count, 0)
+ self.assertEqual(ctr6.nc_linked_attributes_count, 0)
+ self.assertEqual(ctr6.linked_attributes_count, 0)
+ self.assertEqual(ctr6.linked_attributes, [])
+ self.assertEqual(ctr6.drs_error[0], 0)
+
+ def test_InvalidDestDSA_ridalloc(self):
+ """Test RID allocation with invalid destination DSA guid"""
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa="9c637462-5b8c-4467-aef2-bdb1f57bc4ef",
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str=fsmo_dn,
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_RID_ALLOC)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_owner["dns_name"])
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self._check_exop_failed(ctr, drsuapi.DRSUAPI_EXOP_ERR_UNKNOWN_CALLER)
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_owner["invocation_id"]))
+
+ def test_do_ridalloc(self):
+ """Test doing a RID allocation with a valid destination DSA guid"""
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa=fsmo_not_owner["ntds_guid"],
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str=fsmo_dn,
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_RID_ALLOC)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_owner["dns_name"])
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_owner["invocation_id"]))
+ ctr6 = ctr
+ self.assertEqual(ctr6.extended_ret, drsuapi.DRSUAPI_EXOP_ERR_SUCCESS)
+ self.assertEqual(ctr6.object_count, 3)
+ self.assertNotEqual(ctr6.first_object, None)
+ self.assertEqual(ldb.Dn(self.ldb_dc1, ctr6.first_object.object.identifier.dn), fsmo_dn)
+ self.assertNotEqual(ctr6.first_object.next_object, None)
+ self.assertNotEqual(ctr6.first_object.next_object.next_object, None)
+ second_object = ctr6.first_object.next_object.object
+ self.assertEqual(ldb.Dn(self.ldb_dc1, second_object.identifier.dn), fsmo_not_owner["rid_set_dn"])
+ third_object = ctr6.first_object.next_object.next_object.object
+ self.assertEqual(ldb.Dn(self.ldb_dc1, third_object.identifier.dn), fsmo_not_owner["server_acct_dn"])
+
+ self.assertEqual(ctr6.more_data, False)
+ self.assertEqual(ctr6.nc_object_count, 0)
+ self.assertEqual(ctr6.nc_linked_attributes_count, 0)
+ self.assertEqual(ctr6.drs_error[0], 0)
+ # We don't check the linked_attributes_count as if the domain
+ # has an RODC, it can gain links on the server account object
+
+ def test_do_ridalloc_get_anc(self):
+ """Test doing a RID allocation with a valid destination DSA guid and GET_ANC flag"""
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ req8 = self._exop_req8(dest_dsa=fsmo_not_owner["ntds_guid"],
+ invocation_id=fsmo_owner["invocation_id"],
+ nc_dn_str=fsmo_dn,
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_RID_ALLOC,
+ replica_flags=drsuapi.DRSUAPI_DRS_GET_ANC)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_owner["dns_name"])
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_owner["invocation_id"]))
+ ctr6 = ctr
+ self.assertEqual(ctr6.extended_ret, drsuapi.DRSUAPI_EXOP_ERR_SUCCESS)
+ self.assertEqual(ctr6.object_count, 3)
+ self.assertNotEqual(ctr6.first_object, None)
+ self.assertEqual(ldb.Dn(self.ldb_dc1, ctr6.first_object.object.identifier.dn), fsmo_dn)
+ self.assertNotEqual(ctr6.first_object.next_object, None)
+ self.assertNotEqual(ctr6.first_object.next_object.next_object, None)
+ second_object = ctr6.first_object.next_object.object
+ self.assertEqual(ldb.Dn(self.ldb_dc1, second_object.identifier.dn), fsmo_not_owner["rid_set_dn"])
+ third_object = ctr6.first_object.next_object.next_object.object
+ self.assertEqual(ldb.Dn(self.ldb_dc1, third_object.identifier.dn), fsmo_not_owner["server_acct_dn"])
+ self.assertEqual(ctr6.more_data, False)
+ self.assertEqual(ctr6.nc_object_count, 0)
+ self.assertEqual(ctr6.nc_linked_attributes_count, 0)
+ self.assertEqual(ctr6.drs_error[0], 0)
+ # We don't check the linked_attributes_count as if the domain
+ # has an RODC, it can gain links on the server account object
+
+ def test_edit_rid_master(self):
+ """Test doing a RID allocation after changing the RID master from the original one.
+ This should set rIDNextRID to 0 on the new RID master."""
+ # 1. a. Transfer role to non-RID master
+ # b. Check that it succeeds correctly
+ #
+ # 2. a. Call the RID alloc against the former master.
+ # b. Check that it succeeds.
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ # 1. Swap RID master role
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb_dc1, "")
+ m["becomeRidMaster"] = ldb.MessageElement("1", ldb.FLAG_MOD_REPLACE,
+ "becomeRidMaster")
+
+ # Make sure that ldb_dc1 == RID Master
+
+ server_dn = str(ldb.Dn(self.ldb_dc1, self.ldb_dc1.get_dsServiceName()).parent())
+
+ # self.ldb_dc1 == LOCALDC
+ if server_dn == fsmo_owner['server_dn']:
+ # ldb_dc1 == VAMPIREDC
+ ldb_dc1, ldb_dc2 = self.ldb_dc2, self.ldb_dc1
+ else:
+ # Otherwise switch the two
+ ldb_dc1, ldb_dc2 = self.ldb_dc1, self.ldb_dc2
+
+ try:
+ # ldb_dc1 is now RID MASTER (as VAMPIREDC)
+ ldb_dc1.modify(m)
+ except ldb.LdbError as e1:
+ (num, msg) = e1.args
+ self.fail("Failed to reassign RID Master " + msg)
+
+ try:
+ # 2. Perform a RID alloc
+ req8 = self._exop_req8(dest_dsa=fsmo_owner["ntds_guid"],
+ invocation_id=fsmo_not_owner["invocation_id"],
+ nc_dn_str=fsmo_dn,
+ exop=drsuapi.DRSUAPI_EXOP_FSMO_RID_ALLOC)
+
+ (drs, drs_handle) = self._ds_bind(fsmo_not_owner["dns_name"])
+ # 3. Make sure the allocation succeeds
+ try:
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+ except RuntimeError as e:
+ self.fail("RID allocation failed: " + str(e))
+
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+
+ self.assertEqual(level, 6, "Expected level 6 response!")
+ self.assertEqual(ctr.source_dsa_guid, misc.GUID(fsmo_not_owner["ntds_guid"]))
+ self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(fsmo_not_owner["invocation_id"]))
+ ctr6 = ctr
+ self.assertEqual(ctr6.extended_ret, drsuapi.DRSUAPI_EXOP_ERR_SUCCESS)
+ self.assertEqual(ctr6.object_count, 3)
+ self.assertNotEqual(ctr6.first_object, None)
+ self.assertEqual(ldb.Dn(ldb_dc2, ctr6.first_object.object.identifier.dn), fsmo_dn)
+ self.assertNotEqual(ctr6.first_object.next_object, None)
+ self.assertNotEqual(ctr6.first_object.next_object.next_object, None)
+ second_object = ctr6.first_object.next_object.object
+ self.assertEqual(ldb.Dn(self.ldb_dc1, second_object.identifier.dn), fsmo_owner["rid_set_dn"])
+ third_object = ctr6.first_object.next_object.next_object.object
+ self.assertEqual(ldb.Dn(self.ldb_dc1, third_object.identifier.dn), fsmo_owner["server_acct_dn"])
+ finally:
+ # Swap the RID master back for other tests
+ m = ldb.Message()
+ m.dn = ldb.Dn(ldb_dc2, "")
+ m["becomeRidMaster"] = ldb.MessageElement("1", ldb.FLAG_MOD_REPLACE, "becomeRidMaster")
+ try:
+ ldb_dc2.modify(m)
+ except ldb.LdbError as e:
+ (num, msg) = e.args
+ self.fail("Failed to restore RID Master " + msg)
+
+ def test_offline_samba_tool_seized_ridalloc(self):
+ """Perform a join against the non-RID manager and then seize the RID Manager role"""
+
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST1")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ smbconf = os.path.join(targetdir, "etc/smb.conf")
+
+ lp = self.get_loadparm()
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=system_session(lp), lp=lp)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # Assert that no RID Set has been set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertFalse("rIDSetReferences" in res[0])
+
+ (result, out, err) = self.runsubcmd("fsmo", "seize", "--role", "rid", "-H", ldb_url, "--configfile=%s" % (smbconf), "--force")
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+ finally:
+ shutil.rmtree(targetdir, ignore_errors=True)
+ self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST1")
+
+ def _test_join(self, server, netbios_name):
+ tmpdir = os.path.join(self.tempdir, "targetdir")
+ creds = self.get_credentials()
+ (result, out, err) = self.runsubcmd("domain", "join",
+ creds.get_realm(),
+ "dc", "-U%s%%%s" % (creds.get_username(),
+ creds.get_password()),
+ '--targetdir=%s' % tmpdir,
+ '--server=%s' % server,
+ "--option=netbios name = %s" % netbios_name)
+ self.assertCmdSuccess(result, out, err)
+ return tmpdir
+
+ def _test_force_demote(self, server, netbios_name):
+ creds = self.get_credentials()
+ (result, out, err) = self.runsubcmd("domain", "demote",
+ "-U%s%%%s" % (creds.get_username(),
+ creds.get_password()),
+ '--server=%s' % server,
+ "--remove-other-dead-server=%s" % netbios_name)
+ self.assertCmdSuccess(result, out, err)
+
+ def test_offline_manual_seized_ridalloc_with_dbcheck(self):
+ """Perform the same actions as test_offline_samba_tool_seized_ridalloc,
+ but do not create the RID set. Confirm that dbcheck correctly creates
+ the RID Set.
+
+ Also check
+ """
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST2")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ lp = self.get_loadparm()
+
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=system_session(lp), lp=lp)
+
+ serviceName = new_ldb.get_dsServiceName()
+ m = ldb.Message()
+ m.dn = fsmo_dn
+ m["fSMORoleOwner"] = ldb.MessageElement(serviceName,
+ ldb.FLAG_MOD_REPLACE,
+ "fSMORoleOwner")
+ new_ldb.modify(m)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # Assert that no RID Set has been set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertFalse("rIDSetReferences" in res[0])
+
+ chk = dbcheck(new_ldb, verbose=False, fix=True, yes=True, quiet=True)
+
+ self.assertEqual(chk.check_database(DN=server_ref_dn, scope=ldb.SCOPE_BASE), 1, "Should have fixed one error (missing RID Set)")
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+ finally:
+ self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST2")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_offline_manual_seized_ridalloc_add_user(self):
+ """Perform the same actions as test_offline_samba_tool_seized_ridalloc,
+ but do not create the RID set. Confirm that user-add correctly creates
+ the RID Set."""
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST3")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ lp = self.get_loadparm()
+
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=system_session(lp), lp=lp)
+
+ serviceName = new_ldb.get_dsServiceName()
+ m = ldb.Message()
+ m.dn = fsmo_dn
+ m["fSMORoleOwner"] = ldb.MessageElement(serviceName,
+ ldb.FLAG_MOD_REPLACE,
+ "fSMORoleOwner")
+ new_ldb.modify(m)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # Assert that no RID Set has been set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertFalse("rIDSetReferences" in res[0])
+
+ new_ldb.newuser("ridalloctestuser", "P@ssword!")
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+
+ finally:
+ self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST3")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_offline_manual_seized_ridalloc_add_user_as_admin(self):
+ """Perform the same actions as test_offline_samba_tool_seized_ridalloc,
+ but do not create the RID set. Confirm that user-add correctly creates
+ the RID Set."""
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST4")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ lp = self.get_loadparm()
+
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=admin_session(lp, self.ldb_dc1.get_domain_sid()), lp=lp)
+
+ serviceName = new_ldb.get_dsServiceName()
+ m = ldb.Message()
+ m.dn = fsmo_dn
+ m["fSMORoleOwner"] = ldb.MessageElement(serviceName,
+ ldb.FLAG_MOD_REPLACE,
+ "fSMORoleOwner")
+ new_ldb.modify(m)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # Assert that no RID Set has been set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertFalse("rIDSetReferences" in res[0])
+
+ # Create a user to allocate a RID Set for itself (the RID master)
+ new_ldb.newuser("ridalloctestuser", "P@ssword!")
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+
+ finally:
+ self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST4")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_join_time_ridalloc(self):
+ """Perform a join against the RID manager and assert we have a RID Set"""
+
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_owner['dns_name'], "RIDALLOCTEST5")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+
+ lp = self.get_loadparm()
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=system_session(lp), lp=lp)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+ finally:
+ self._test_force_demote(fsmo_owner['dns_name'], "RIDALLOCTEST5")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_rid_set_dbcheck(self):
+ """Perform a join against the RID manager and assert we have a RID Set.
+ Using dbcheck, we assert that we can detect out of range users."""
+
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_owner['dns_name'], "RIDALLOCTEST6")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+
+ lp = self.get_loadparm()
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=system_session(lp), lp=lp)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+ rid_set_dn = ldb.Dn(new_ldb, res[0]["rIDSetReferences"][0].decode('utf8'))
+
+ # 4. Add a new user (triggers RID set work)
+ new_ldb.newuser("ridalloctestuser", "P@ssword!")
+
+ # 5. Now fetch the RID SET
+ rid_set_res = new_ldb.search(base=rid_set_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDNextRid',
+ 'rIDAllocationPool'])
+ next_pool = int(rid_set_res[0]["rIDAllocationPool"][0])
+ last_rid = (0xFFFFFFFF00000000 & next_pool) >> 32
+
+ # 6. Add user above the ridNextRid and at mid-range.
+ #
+ # We can do this with safety because this is an offline DB that will be
+ # destroyed.
+ m = ldb.Message()
+ m.dn = ldb.Dn(new_ldb, "CN=ridsettestuser1,CN=Users")
+ m.dn.add_base(new_ldb.get_default_basedn())
+ m['objectClass'] = ldb.MessageElement('user', ldb.FLAG_MOD_ADD, 'objectClass')
+ m['objectSid'] = ldb.MessageElement(ndr_pack(security.dom_sid(str(new_ldb.get_domain_sid()) + "-%d" % (last_rid - 10))),
+ ldb.FLAG_MOD_ADD,
+ 'objectSid')
+ new_ldb.add(m, controls=["relax:0"])
+
+ # 7. Check the RID Set
+ chk = dbcheck(new_ldb, verbose=False, fix=True, yes=True, quiet=True)
+
+ # Should have one error (wrong rIDNextRID)
+ self.assertEqual(chk.check_database(DN=rid_set_dn, scope=ldb.SCOPE_BASE), 1)
+
+ # 8. Assert we get didn't show any other errors
+ chk = dbcheck(new_ldb, verbose=False, fix=False, quiet=True)
+
+ rid_set_res = new_ldb.search(base=rid_set_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDNextRid',
+ 'rIDAllocationPool'])
+ last_allocated_rid = int(rid_set_res[0]["rIDNextRid"][0])
+ self.assertEqual(last_allocated_rid, last_rid - 10)
+
+ # 9. Assert that the range wasn't thrown away
+
+ next_pool = int(rid_set_res[0]["rIDAllocationPool"][0])
+ self.assertEqual(last_rid, (0xFFFFFFFF00000000 & next_pool) >> 32, "rid pool should have changed")
+ finally:
+ self._test_force_demote(fsmo_owner['dns_name'], "RIDALLOCTEST6")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_rid_set_dbcheck_after_seize(self):
+ """Perform a join against the RID manager and assert we have a RID Set.
+ We seize the RID master role, then using dbcheck, we assert that we can
+ detect out of range users (and then bump the RID set as required)."""
+
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ targetdir = self._test_join(fsmo_owner['dns_name'], "RIDALLOCTEST7")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ smbconf = os.path.join(targetdir, "etc/smb.conf")
+
+ lp = self.get_loadparm()
+ new_ldb = SamDB(ldb_url, credentials=self.get_credentials(),
+ session_info=system_session(lp), lp=lp)
+
+ # 1. Get server name
+ res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()),
+ scope=ldb.SCOPE_BASE, attrs=["serverReference"])
+ # 2. Get server reference
+ server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8'))
+
+ # 3. Assert we get the RID Set
+ res = new_ldb.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences'])
+
+ self.assertTrue("rIDSetReferences" in res[0])
+ rid_set_dn = ldb.Dn(new_ldb, res[0]["rIDSetReferences"][0].decode('utf8'))
+ # 4. Seize the RID Manager role
+ (result, out, err) = self.runsubcmd("fsmo", "seize", "--role", "rid", "-H", ldb_url, "--configfile=%s" % (smbconf), "--force")
+ self.assertCmdSuccess(result, out, err)
+ self.assertEqual(err, "", "Shouldn't be any error messages")
+
+ # 5. Add a new user (triggers RID set work)
+ new_ldb.newuser("ridalloctestuser", "P@ssword!")
+
+ # 6. Now fetch the RID SET
+ rid_set_res = new_ldb.search(base=rid_set_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDNextRid',
+ 'rIDAllocationPool'])
+ next_pool = int(rid_set_res[0]["rIDAllocationPool"][0])
+ last_rid = (0xFFFFFFFF00000000 & next_pool) >> 32
+
+ # 7. Add user above the ridNextRid and at almost the end of the range.
+ #
+ m = ldb.Message()
+ m.dn = ldb.Dn(new_ldb, "CN=ridsettestuser2,CN=Users")
+ m.dn.add_base(new_ldb.get_default_basedn())
+ m['objectClass'] = ldb.MessageElement('user', ldb.FLAG_MOD_ADD, 'objectClass')
+ m['objectSid'] = ldb.MessageElement(ndr_pack(security.dom_sid(str(new_ldb.get_domain_sid()) + "-%d" % (last_rid - 3))),
+ ldb.FLAG_MOD_ADD,
+ 'objectSid')
+ new_ldb.add(m, controls=["relax:0"])
+
+ # 8. Add user above the ridNextRid and at the end of the range
+ m = ldb.Message()
+ m.dn = ldb.Dn(new_ldb, "CN=ridsettestuser3,CN=Users")
+ m.dn.add_base(new_ldb.get_default_basedn())
+ m['objectClass'] = ldb.MessageElement('user', ldb.FLAG_MOD_ADD, 'objectClass')
+ m['objectSid'] = ldb.MessageElement(ndr_pack(security.dom_sid(str(new_ldb.get_domain_sid()) + "-%d" % last_rid)),
+ ldb.FLAG_MOD_ADD,
+ 'objectSid')
+ new_ldb.add(m, controls=["relax:0"])
+
+ chk = dbcheck(new_ldb, verbose=False, fix=True, yes=True, quiet=True)
+
+ # Should have fixed two errors (wrong ridNextRid)
+ self.assertEqual(chk.check_database(DN=rid_set_dn, scope=ldb.SCOPE_BASE), 2)
+
+ # 9. Assert we get didn't show any other errors
+ chk = dbcheck(new_ldb, verbose=False, fix=False, quiet=True)
+
+ # 10. Add another user (checks RID rollover)
+ # We have seized the role, so we can do that.
+ new_ldb.newuser("ridalloctestuser3", "P@ssword!")
+
+ rid_set_res = new_ldb.search(base=rid_set_dn,
+ scope=ldb.SCOPE_BASE, attrs=['rIDNextRid',
+ 'rIDAllocationPool'])
+ next_pool = int(rid_set_res[0]["rIDAllocationPool"][0])
+ self.assertNotEqual(last_rid, (0xFFFFFFFF00000000 & next_pool) >> 32, "rid pool should have changed")
+ finally:
+ self._test_force_demote(fsmo_owner['dns_name'], "RIDALLOCTEST7")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_replicate_against_deleted_objects_transaction(self):
+ """Not related to RID allocation, but uses the infrastructure here.
+ Do a join, create a link between two objects remotely, but
+ remove the target locally. Show that we need to set a magic
+ opaque if there is an outer transaction.
+
+ """
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ test_user4 = "ridalloctestuser4"
+ test_group = "ridalloctestgroup1"
+
+ self.ldb_dc1.newuser(test_user4, "P@ssword!")
+
+ self.addCleanup(self.ldb_dc1.deleteuser, test_user4)
+
+ self.ldb_dc1.newgroup(test_group)
+ self.addCleanup(self.ldb_dc1.deletegroup, test_group)
+
+ targetdir = self._test_join(self.dnsname_dc1, "RIDALLOCTEST8")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ lp = self.get_loadparm()
+
+ new_ldb = SamDB(ldb_url,
+ session_info=system_session(lp), lp=lp)
+
+ destination_dsa_guid = misc.GUID(new_ldb.get_ntds_GUID())
+
+ repl = drs_utils.drs_Replicate(f'ncacn_ip_tcp:{self.dnsname_dc1}[seal]',
+ lp,
+ self.get_credentials(),
+ new_ldb,
+ destination_dsa_guid)
+
+ source_dsa_invocation_id = misc.GUID(self.ldb_dc1.invocation_id)
+
+ # Add the link on the remote DC
+ self.ldb_dc1.add_remove_group_members(test_group, [test_user4])
+
+ # Starting a transaction overrides, currently the logic
+ # inside repl.replicatate to retry with GET_TGT which in
+ # turn tells the repl_meta_data module that the most up to
+ # date info is already available
+ new_ldb.transaction_start()
+ repl.replicate(self.ldb_dc1.domain_dn(),
+ source_dsa_invocation_id,
+ destination_dsa_guid)
+
+ # Delete the user locally, before applying the links.
+ # This simulates getting the delete in the replciation
+ # stream.
+ new_ldb.deleteuser(test_user4)
+
+ # This fails as the user has been deleted locally but a remote link is sent
+ self.assertRaises(ldb.LdbError, new_ldb.transaction_commit)
+
+ new_ldb.transaction_start()
+ repl.replicate(self.ldb_dc1.domain_dn(),
+ source_dsa_invocation_id,
+ destination_dsa_guid)
+
+ # Delete the user locally (the previous transaction
+ # doesn't apply), before applying the links. This
+ # simulates getting the delete in the replciation stream.
+ new_ldb.deleteuser(test_user4)
+
+ new_ldb.set_opaque_integer(dsdb.DSDB_FULL_JOIN_REPLICATION_COMPLETED_OPAQUE_NAME,
+ 1)
+
+ # This should now work
+ try:
+ new_ldb.transaction_commit()
+ except ldb.LdbError as e:
+ self.fail(f"Failed to replicate despite setting opaque with {e.args[1]}")
+
+ finally:
+ self._test_force_demote(self.dnsname_dc1, "RIDALLOCTEST8")
+ shutil.rmtree(targetdir, ignore_errors=True)
+
+ def test_replicate_against_deleted_objects_normal(self):
+ """Not related to RID allocation, but uses the infrastructure here.
+ Do a join, create a link between two objects remotely, but
+ remove the target locally. .
+
+ """
+ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn())
+ (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn)
+
+ test_user5 = "ridalloctestuser5"
+ test_group2 = "ridalloctestgroup2"
+
+ self.ldb_dc1.newuser(test_user5, "P@ssword!")
+ self.addCleanup(self.ldb_dc1.deleteuser, test_user5)
+
+ self.ldb_dc1.newgroup(test_group2)
+ self.addCleanup(self.ldb_dc1.deletegroup, test_group2)
+
+ targetdir = self._test_join(self.dnsname_dc1, "RIDALLOCTEST9")
+ try:
+ # Connect to the database
+ ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb")
+ lp = self.get_loadparm()
+
+ new_ldb = SamDB(ldb_url,
+ session_info=system_session(lp), lp=lp)
+
+ destination_dsa_guid = misc.GUID(new_ldb.get_ntds_GUID())
+
+ repl = drs_utils.drs_Replicate(f'ncacn_ip_tcp:{self.dnsname_dc1}[seal]',
+ lp,
+ self.get_credentials(),
+ new_ldb,
+ destination_dsa_guid)
+
+ source_dsa_invocation_id = misc.GUID(self.ldb_dc1.invocation_id)
+
+ # Add the link on the remote DC
+ self.ldb_dc1.add_remove_group_members(test_group2, [test_user5])
+
+ # Delete the user locally
+ new_ldb.deleteuser(test_user5)
+
+ # Confirm replication copes with a link to a locally deleted user
+ repl.replicate(self.ldb_dc1.domain_dn(),
+ source_dsa_invocation_id,
+ destination_dsa_guid)
+
+ finally:
+ self._test_force_demote(self.dnsname_dc1, "RIDALLOCTEST9")
+ shutil.rmtree(targetdir, ignore_errors=True)
diff --git a/source4/torture/drs/python/samba_tool_drs.py b/source4/torture/drs/python/samba_tool_drs.py
new file mode 100644
index 0000000..e622fe4
--- /dev/null
+++ b/source4/torture/drs/python/samba_tool_drs.py
@@ -0,0 +1,410 @@
+# Blackbox tests for "samba-tool drs" command
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Blackbox tests for samba-tool drs."""
+
+import samba.tests
+import os
+import ldb
+import drs_base
+
+
+class SambaToolDrsTests(drs_base.DrsBaseTestCase):
+ """Blackbox test case for samba-tool drs."""
+
+ def setUp(self):
+ super(SambaToolDrsTests, self).setUp()
+
+ self.dc1 = samba.tests.env_get_var_value("DC1")
+ self.dc2 = samba.tests.env_get_var_value("DC2")
+
+ creds = self.get_credentials()
+ self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(),
+ creds.get_username(), creds.get_password())
+
+ def tearDown(self):
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self._enable_inbound_repl(self.dnsname_dc2)
+
+ self.rm_files('names.tdb', allow_missing=True)
+ self.rm_dirs('etc', 'msg.lock', 'private', 'state', 'bind-dns',
+ allow_missing=True)
+
+ super(SambaToolDrsTests, self).tearDown()
+
+ def _get_rootDSE(self, dc, ldap_only=True):
+ samdb = samba.tests.connect_samdb(dc, lp=self.get_loadparm(),
+ credentials=self.get_credentials(),
+ ldap_only=ldap_only)
+ return samdb.search(base="", scope=samba.tests.ldb.SCOPE_BASE)[0]
+
+ def test_samba_tool_bind(self):
+ """Tests 'samba-tool drs bind' command."""
+
+ # Output should be like:
+ # Extensions supported:
+ # <list-of-supported-extensions>
+ # Site GUID: <GUID>
+ # Repl epoch: 0
+ out = self.check_output("samba-tool drs bind %s %s" % (self.dc1,
+ self.cmdline_creds))
+ self.assertTrue("Site GUID:" in out.decode('utf8'))
+ self.assertTrue("Repl epoch:" in out.decode('utf8'))
+
+ def test_samba_tool_kcc(self):
+ """Tests 'samba-tool drs kcc' command."""
+
+ # Output should be like 'Consistency check on <DC> successful.'
+ out = self.check_output("samba-tool drs kcc %s %s" % (self.dc1,
+ self.cmdline_creds))
+ self.assertTrue(b"Consistency check on" in out)
+ self.assertTrue(b"successful" in out)
+
+ def test_samba_tool_options(self):
+ """Tests 'samba-tool drs options' command
+ """
+ # Output should be like 'Current DSA options: IS_GC <OTHER_FLAGS>'
+ out = self.check_output("samba-tool drs options %s %s" % (self.dc1,
+ self.cmdline_creds))
+ self.assertTrue(b"Current DSA options:" in out)
+
+ def test_samba_tool_replicate(self):
+ """Tests 'samba-tool drs replicate' command."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate %s %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name,
+ self.cmdline_creds))
+ self.assertTrue(b"Replicate from" in out)
+ self.assertTrue(b"was successful" in out)
+
+ def test_samba_tool_replicate_async(self):
+ """Tests 'samba-tool drs replicate --async-op' command."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was started.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate --async-op %s %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name,
+ self.cmdline_creds))
+ self.assertTrue(b"Replicate from" in out)
+ self.assertTrue(b"was started" in out)
+
+ def test_samba_tool_replicate_local_online(self):
+ """Tests 'samba-tool drs replicate --local-online' command."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate --local-online %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name))
+ self.assertTrue(b"Replicate from" in out)
+ self.assertTrue(b"was successful" in out)
+
+ def test_samba_tool_replicate_local_online_async(self):
+ """Tests 'samba-tool drs replicate --local-online --async-op' command."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was started.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate --local-online --async-op %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name))
+ self.assertTrue(b"Replicate from" in out)
+ self.assertTrue(b"was started" in out)
+
+ def test_samba_tool_replicate_local_machine_creds(self):
+ """Tests 'samba-tool drs replicate --local -P' command (uses machine creds)."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate -P --local %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name))
+ self.assertTrue(b"Incremental" in out)
+ self.assertTrue(b"was successful" in out)
+
+ def test_samba_tool_replicate_local(self):
+ """Tests 'samba-tool drs replicate --local' command (uses machine creds)."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+
+ def get_num_obj_links(output):
+ num_objs = None
+ num_links = None
+ for word in output.decode('utf8').split(" "):
+ try:
+ int(word)
+ if num_objs is None:
+ num_objs = int(word)
+ elif num_links is None:
+ num_links = int(word)
+ except ValueError:
+ pass
+
+ return (num_objs, num_links)
+
+ out = self.check_output("samba-tool drs replicate --local --full-sync %s %s %s %s"
+ % (self.dc1, self.dc2, nc_name, self.cmdline_creds))
+ self.assertTrue(b"was successful" in out)
+ self.assertTrue(b"Full" in out)
+
+ (first_obj, _) = get_num_obj_links(out)
+
+ out = self.check_output("samba-tool drs replicate --local %s %s %s %s"
+ % (self.dc1, self.dc2, nc_name, self.cmdline_creds))
+ self.assertTrue(b"was successful" in out)
+ self.assertTrue(b"Incremental" in out)
+
+ (second_obj, _) = get_num_obj_links(out)
+
+ self.assertTrue(first_obj > second_obj)
+
+ server_rootdse = self._get_rootDSE(self.dc1)
+ server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ server_realm = server_ldap_service_name.split(":")[0]
+
+ # We have to give it a different netbiosname every time
+ # it runs, otherwise the collision causes strange issues
+ # to happen. This should be different on different environments.
+ netbiosname = "test" + self.dc2
+ if len(netbiosname) > 15:
+ netbiosname = netbiosname[:15]
+
+ out = self.check_output("samba-tool domain join %s dc --server=%s %s --targetdir=%s --option=netbiosname=%s"
+ % (server_realm, self.dc1, self.cmdline_creds, self.tempdir, netbiosname))
+
+ new_dc_config_file = "%s/etc/smb.conf" % self.tempdir
+
+ self.check_output("samba-tool drs replicate --local %s %s %s %s --configfile=%s"
+ % ("invalid", self.dc1, nc_name,
+ self.cmdline_creds, new_dc_config_file))
+
+ self._disable_inbound_repl(self.dnsname_dc1)
+ self._disable_inbound_repl(self.dnsname_dc2)
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2)
+
+ # add an object with link on dc1
+ group_name = "group-repl-local-%s" % self.dc2
+ user_name = "user-repl-local-%s" % self.dc2
+
+ self.check_output("samba-tool group add %s %s -H ldap://%s"
+ % (group_name, self.cmdline_creds, self.dc1))
+ self.check_output("samba-tool user add %s %s --random-password -H ldap://%s"
+ % (user_name, self.cmdline_creds, self.dc1))
+ self.check_output("samba-tool group addmembers %s %s %s -H ldap://%s"
+ % (group_name, user_name, self.cmdline_creds, self.dc1))
+
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1)
+
+ # pull that change with --local into local db from dc1: should send link and some objects
+ out = self.check_output("samba-tool drs replicate --local %s %s %s %s --configfile=%s"
+ % ("invalid", self.dc1, nc_name,
+ self.cmdline_creds, new_dc_config_file))
+
+ (obj_1, link_1) = get_num_obj_links(out)
+
+ self.assertGreaterEqual(obj_1, 2)
+ self.assertEqual(link_1, 1)
+
+ # pull that change with --local into local db from dc2: shouldn't send link or object
+ # as we sent an up-to-dateness vector showing that we had already synced with DC1
+ out = self.check_output("samba-tool drs replicate --local %s %s %s %s --configfile=%s"
+ % ("invalid", self.dc2, nc_name,
+ self.cmdline_creds, new_dc_config_file))
+
+ (obj_2, link_2) = get_num_obj_links(out)
+
+ self.assertEqual(obj_2, 0)
+ self.assertEqual(link_2, 0)
+
+ self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H ldap://%s %s --configfile=%s"
+ % (netbiosname, self.dc1, self.cmdline_creds, new_dc_config_file))
+
+ def test_samba_tool_replicate_machine_creds_P(self):
+ """Tests 'samba-tool drs replicate -P' command with machine creds."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate -P %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name))
+ self.assertTrue(b"Replicate from" in out)
+ self.assertTrue(b"was successful" in out)
+
+ def test_samba_tool_replicate_machine_creds(self):
+ """Tests 'samba-tool drs replicate' command with implicit machine creds."""
+
+ # Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'
+ nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
+ out = self.check_output("samba-tool drs replicate %s %s %s" % (self.dc1,
+ self.dc2,
+ nc_name))
+ self.assertTrue(b"Replicate from" in out)
+ self.assertTrue(b"was successful" in out)
+
+ def test_samba_tool_drs_clone_dc(self):
+ """Tests 'samba-tool drs clone-dc-database' command."""
+ server_rootdse = self._get_rootDSE(self.dc1)
+ server_nc_name = server_rootdse["defaultNamingContext"]
+ server_ds_name = server_rootdse["dsServiceName"]
+ server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ server_realm = server_ldap_service_name.split(":")[0]
+ self.check_output("samba-tool drs clone-dc-database %s --server=%s %s --targetdir=%s"
+ % (server_realm,
+ self.dc1,
+ self.cmdline_creds,
+ self.tempdir))
+ ldb_rootdse = self._get_rootDSE("ldb://" + os.path.join(self.tempdir, "private", "sam.ldb"), ldap_only=False)
+ nc_name = ldb_rootdse["defaultNamingContext"]
+ ds_name = ldb_rootdse["dsServiceName"]
+ ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ self.assertEqual(nc_name, server_nc_name)
+ # The clone should pretend to be the source server
+ self.assertEqual(ds_name, server_ds_name)
+ self.assertEqual(ldap_service_name, server_ldap_service_name)
+
+ samdb = samba.tests.connect_samdb("ldb://" + os.path.join(self.tempdir, "private", "sam.ldb"),
+ ldap_only=False, lp=self.get_loadparm())
+
+ def get_krbtgt_pw():
+ samdb.searchone("unicodePwd", "cn=krbtgt,CN=users,%s" % nc_name)
+ self.assertRaises(KeyError, get_krbtgt_pw)
+
+ server_dn = samdb.searchone("serverReferenceBL", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name)).decode('utf8')
+ ntds_guid = samdb.searchone("objectGUID", "cn=ntds settings,%s" % server_dn).decode('utf8')
+
+ res = samdb.search(base=str(server_nc_name),
+ expression="(&(objectclass=user)(cn=dns-%s))" % (self.dc2),
+ attrs=[], scope=ldb.SCOPE_SUBTREE)
+ if len(res) == 1:
+ dns_obj = res[0]
+ else:
+ dns_obj = None
+
+ # While we have this cloned, try demoting the other server on the clone, by GUID
+ self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H %s/private/sam.ldb"
+ % (ntds_guid,
+ self.tempdir))
+
+ # Check some of the objects that should have been removed
+ def check_machine_obj():
+ samdb.searchone("CN", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+ self.assertRaises(ldb.LdbError, check_machine_obj)
+
+ def check_server_obj():
+ samdb.searchone("CN", server_dn)
+ self.assertRaises(ldb.LdbError, check_server_obj)
+
+ def check_ntds_guid():
+ samdb.searchone("CN", "<GUID=%s>" % ntds_guid)
+ self.assertRaises(ldb.LdbError, check_ntds_guid)
+
+ if dns_obj is not None:
+ # Check some of the objects that should have been removed
+ def check_dns_account_obj():
+ samdb.search(base=dns_obj.dn, scope=ldb.SCOPE_BASE,
+ attrs=[])
+ self.assertRaises(ldb.LdbError, check_dns_account_obj)
+
+ def test_samba_tool_drs_clone_dc_secrets(self):
+ """Tests 'samba-tool drs clone-dc-database --include-secrets' command ."""
+ server_rootdse = self._get_rootDSE(self.dc1)
+ server_nc_name = server_rootdse["defaultNamingContext"]
+ server_ds_name = server_rootdse["dsServiceName"]
+ server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ server_realm = server_ldap_service_name.split(":")[0]
+ self.check_output("samba-tool drs clone-dc-database %s --server=%s %s --targetdir=%s --include-secrets"
+ % (server_realm,
+ self.dc1,
+ self.cmdline_creds,
+ self.tempdir))
+ ldb_rootdse = self._get_rootDSE("ldb://" + os.path.join(self.tempdir, "private", "sam.ldb"), ldap_only=False)
+ nc_name = ldb_rootdse["defaultNamingContext"]
+ ds_name = ldb_rootdse["dsServiceName"]
+ ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+
+ samdb = samba.tests.connect_samdb("ldb://" + os.path.join(self.tempdir, "private", "sam.ldb"),
+ ldap_only=False, lp=self.get_loadparm())
+ krbtgt_pw = samdb.searchone("unicodePwd", "cn=krbtgt,CN=users,%s" % nc_name)
+ self.assertIsNotNone(krbtgt_pw)
+
+ self.assertEqual(nc_name, server_nc_name)
+ # The clone should pretend to be the source server
+ self.assertEqual(ds_name, server_ds_name)
+ self.assertEqual(ldap_service_name, server_ldap_service_name)
+
+ server_dn = samdb.searchone("serverReferenceBL", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name)).decode('utf8')
+ ntds_guid = samdb.searchone("objectGUID", "cn=ntds settings,%s" % server_dn).decode('utf8')
+
+ res = samdb.search(base=str(server_nc_name),
+ expression="(&(objectclass=user)(cn=dns-%s))" % (self.dc2),
+ attrs=[], scope=ldb.SCOPE_SUBTREE)
+ if len(res) == 1:
+ dns_obj = res[0]
+ else:
+ dns_obj = None
+
+ def demote_self():
+ # While we have this cloned, try demoting the other server on the clone
+ self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H %s/private/sam.ldb"
+ % (self.dc1,
+ self.tempdir))
+ self.assertRaises(samba.tests.BlackboxProcessError, demote_self)
+
+ # While we have this cloned, try demoting the other server on the clone
+ self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H ldb://%s/private/sam.ldb"
+ % (self.dc2,
+ self.tempdir))
+
+ # Check some of the objects that should have been removed
+ def check_machine_obj():
+ samdb.searchone("CN", "cn=%s,ou=domain controllers,%s" % (self.dc2, server_nc_name))
+ self.assertRaises(ldb.LdbError, check_machine_obj)
+
+ def check_server_obj():
+ samdb.searchone("CN", server_dn)
+ self.assertRaises(ldb.LdbError, check_server_obj)
+
+ def check_ntds_guid():
+ samdb.searchone("CN", "<GUID=%s>" % ntds_guid)
+ self.assertRaises(ldb.LdbError, check_ntds_guid)
+
+ if dns_obj is not None:
+ # Check some of the objects that should have been removed
+ def check_dns_account_obj():
+ samdb.search(base=dns_obj.dn, scope=ldb.SCOPE_BASE,
+ attrs=[])
+ self.assertRaises(ldb.LdbError, check_dns_account_obj)
+
+ def test_samba_tool_drs_clone_dc_secrets_without_targetdir(self):
+ """Tests 'samba-tool drs clone-dc-database' command without --targetdir."""
+ server_rootdse = self._get_rootDSE(self.dc1)
+ server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ server_realm = server_ldap_service_name.split(":")[0]
+
+ def attempt_clone():
+ self.check_output("samba-tool drs clone-dc-database %s --server=%s %s"
+ % (server_realm,
+ self.dc1,
+ self.cmdline_creds))
+ self.assertRaises(samba.tests.BlackboxProcessError, attempt_clone)
diff --git a/source4/torture/drs/python/samba_tool_drs_critical.py b/source4/torture/drs/python/samba_tool_drs_critical.py
new file mode 100644
index 0000000..5260e15
--- /dev/null
+++ b/source4/torture/drs/python/samba_tool_drs_critical.py
@@ -0,0 +1,98 @@
+# Blackbox tests for "samba-tool drs" command
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Blackbox tests for samba-tool drs."""
+
+import samba.tests
+import os
+import ldb
+import drs_base
+import random
+
+class SambaToolDrsTests(drs_base.DrsBaseTestCase):
+ """Blackbox test case for samba-tool drs."""
+
+ def setUp(self):
+ super(SambaToolDrsTests, self).setUp()
+
+ self.dc1 = samba.tests.env_get_var_value("DC1")
+ self.dc2 = samba.tests.env_get_var_value("DC2")
+
+ creds = self.get_credentials()
+ self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(),
+ creds.get_username(), creds.get_password())
+
+ def tearDown(self):
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self._enable_inbound_repl(self.dnsname_dc2)
+
+ self.rm_files('names.tdb', allow_missing=True)
+ self.rm_dirs('etc', 'msg.lock', 'private', 'state', 'bind-dns',
+ allow_missing=True)
+
+ super(SambaToolDrsTests, self).tearDown()
+
+ # This test is for the Samba 4.5 emulation servers (but runs
+ # against a normal server as well) that fail to correctly
+ # implement DRSUAPI_DRS_GET_ANC when DRSUAPI_DRS_CRITICAL_ONLY is
+ # set.
+ def test_samba_tool_drs_clone_dc_critical_object_chain(self):
+ """Tests 'samba-tool drs clone-dc-database' command with a Critical/non-critical/critical object chain."""
+
+ samdb = samba.tests.connect_samdb(self.dc1, lp=self.get_loadparm(),
+ credentials=self.get_credentials(),
+ ldap_only=True)
+ server_rootdse = samdb.search(base="",
+ scope=samba.tests.ldb.SCOPE_BASE)[0]
+ nc_name = server_rootdse["defaultNamingContext"][0]
+ server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ server_realm = server_ldap_service_name.split(":")[0]
+
+ not_critical_dn = f"OU=not-critical{random.randint(1, 10000000)},{nc_name}"
+ samdb.create_ou(not_critical_dn)
+ self.addCleanup(samdb.delete,
+ not_critical_dn)
+ domain_sid = samdb.get_domain_sid()
+ admin_sid = f"{domain_sid}-500"
+ samdb.rename(f"<SID={admin_sid}>",
+ f"cn=administrator,{not_critical_dn}")
+ self.addCleanup(samdb.rename,
+ f"<SID={admin_sid}>",
+ f"cn=administrator,cn=users,{nc_name}")
+
+ try:
+ self.check_output("samba-tool drs clone-dc-database %s --server=%s %s --targetdir=%s"
+ % (server_realm,
+ self.dc1,
+ self.cmdline_creds,
+ self.tempdir))
+ except samba.tests.BlackboxProcessError as e:
+ self.fail("Error calling samba-tool: %s" % e)
+
+ local_samdb = samba.tests.connect_samdb("ldb://" + os.path.join(self.tempdir, "private", "sam.ldb"),
+ ldap_only=False, lp=self.get_loadparm())
+
+ # Check administrator was replicated and is in the right place
+ res = local_samdb.search(base=str(nc_name),
+ expression="(&(objectclass=user)(cn=administrator))",
+ attrs=[], scope=ldb.SCOPE_SUBTREE)
+ self.assertEqual(len(res), 1)
+
+ admin_obj = res[0]
+
+ self.assertEqual(admin_obj.dn, ldb.Dn(samdb, f"cn=administrator,{not_critical_dn}"))
diff --git a/source4/torture/drs/python/samba_tool_drs_no_dns.py b/source4/torture/drs/python/samba_tool_drs_no_dns.py
new file mode 100644
index 0000000..aad5966
--- /dev/null
+++ b/source4/torture/drs/python/samba_tool_drs_no_dns.py
@@ -0,0 +1,174 @@
+# Blackbox tests for "samba-tool drs" command
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+# Copyright (C) Catalyst.Net Ltd 2019
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+Blackbox tests for samba-tool drs with no DNS partitions
+
+Adapted from samba_tool_drs.py
+"""
+
+import samba.tests
+import os
+import ldb
+import drs_base
+
+from samba.tests import BlackboxProcessError
+from samba.common import get_string
+
+
+class SambaToolDrsNoDnsTests(drs_base.DrsBaseTestCase):
+ """Blackbox test case for samba-tool drs."""
+
+ def setUp(self):
+ super(SambaToolDrsNoDnsTests, self).setUp()
+
+ self.dc1 = samba.tests.env_get_var_value("DC1")
+
+ creds = self.get_credentials()
+ self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(),
+ creds.get_username(), creds.get_password())
+
+ def tearDown(self):
+ self._enable_inbound_repl(self.dnsname_dc1)
+ self.rm_files('names.tdb', allow_missing=True)
+ self.rm_dirs('etc', 'msg.lock', 'private', 'state', 'bind-dns',
+ allow_missing=True)
+
+ super(SambaToolDrsNoDnsTests, self).tearDown()
+
+ def _get_rootDSE(self, dc, ldap_only=True):
+ samdb = samba.tests.connect_samdb(dc, lp=self.get_loadparm(),
+ credentials=self.get_credentials(),
+ ldap_only=ldap_only)
+ return samdb.search(base="", scope=samba.tests.ldb.SCOPE_BASE)[0], samdb
+
+ def test_samba_tool_replicate_local_no_dns_tdb(self):
+ self.backend = 'tdb'
+ self._test_samba_tool_replicate_local_no_dns()
+
+ def test_samba_tool_replicate_local_no_dns_mdb(self):
+ self.backend = 'mdb'
+ self._test_samba_tool_replicate_local_no_dns()
+
+ def _test_samba_tool_replicate_local_no_dns(self):
+ """Check we can provision a database without DNS partitions
+ (and then add them afterwards)."""
+
+ server_rootdse, _ = self._get_rootDSE(self.dc1)
+ nc_name = server_rootdse["defaultNamingContext"]
+ server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
+ server_realm = server_ldap_service_name.split(":")[0]
+
+ # We have to give it a different netbiosname every time
+ # it runs, otherwise the collision causes strange issues
+ # to happen. This should be different on different environments.
+ netbiosname = "dns" + self.backend + self.dc1
+ if len(netbiosname) > 15:
+ netbiosname = netbiosname[:15]
+
+ self.check_output("samba-tool domain join %s dc --server=%s %s --targetdir=%s --option=netbiosname=%s %s --backend-store=%s"
+ % (server_realm, self.dc1, self.cmdline_creds,
+ self.tempdir, netbiosname,
+ "--dns-backend=NONE",
+ self.backend))
+
+ new_dc_config_file = os.path.join(self.tempdir, "etc", "smb.conf")
+ new_dc_sam = os.path.join(self.tempdir, "private", "sam.ldb")
+
+ forestdns_dn = ldb.binary_encode('DC=ForestDNSZones,' + str(nc_name))
+ domaindns_dn = ldb.binary_encode('DC=DomainDNSZones,' + str(nc_name))
+
+ self.check_output("samba-tool drs replicate --local %s %s %s %s --configfile=%s --full-sync"
+ % ("invalid", self.dc1, forestdns_dn,
+ self.cmdline_creds, new_dc_config_file))
+
+ self.check_output("samba-tool drs replicate --local %s %s %s %s --configfile=%s --full-sync"
+ % ("invalid", self.dc1, domaindns_dn,
+ self.cmdline_creds, new_dc_config_file))
+
+ server_rootdse, samdb = self._get_rootDSE("ldb://" + new_dc_sam, ldap_only=False)
+ server_ds_name = ldb.binary_encode(server_rootdse["dsServiceName"][0].decode('utf-8'))
+
+ # Show that Has-Master-NCs is fixed by samba_upgradedns
+ res = samdb.search(base=server_ds_name,
+ expression="(msds-hasmasterncs=%s)" % forestdns_dn)
+ self.assertEqual(len(res), 0)
+ res = samdb.search(base=server_ds_name,
+ expression="(msds-hasmasterncs=%s)" % domaindns_dn)
+ self.assertEqual(len(res), 0)
+
+ self.check_output("samba_upgradedns --configfile=%s" % (new_dc_config_file))
+
+ res = samdb.search(base=server_ds_name,
+ expression="(msds-hasmasterncs=%s)" % forestdns_dn)
+ self.assertEqual(len(res), 1)
+ res = samdb.search(base=server_ds_name,
+ expression="(msds-hasmasterncs=%s)" % domaindns_dn)
+ self.assertEqual(len(res), 1)
+
+ # Show that replica locations is fixed by dbcheck
+ res = samdb.search(controls=["search_options:1:2"],
+ expression="(&(msds-nc-replica-locations=%s)(ncname=%s))"
+ % (server_ds_name, forestdns_dn))
+ self.assertEqual(len(res), 0)
+ res = samdb.search(controls=["search_options:1:2"],
+ expression="(&(msds-nc-replica-locations=%s)(ncname=%s))"
+ % (server_ds_name, domaindns_dn))
+ self.assertEqual(len(res), 0)
+
+ try:
+ # This fixes any forward-link-backward-link issues with the tools
+ self.check_output("samba-tool dbcheck --configfile=%s --cross-ncs --fix --yes" % (new_dc_config_file))
+ except BlackboxProcessError as e:
+ self.assertTrue("Checked " in get_string(e.stdout))
+
+ self.check_output("samba-tool dbcheck --configfile=%s --cross-ncs" % (new_dc_config_file))
+
+ # Compare the two directories
+ self.check_output("samba-tool ldapcmp ldap://%s ldb://%s %s --filter=%s" %
+ (self.dc1, new_dc_sam, self.cmdline_creds,
+ "msDs-masteredBy,msDS-NC-Replica-Locations,msDS-hasMasterNCs"))
+
+ # Check all ForestDNS connections and backlinks
+ res = samdb.search(base=server_ds_name,
+ expression="(msds-hasmasterncs=%s)" % forestdns_dn)
+ self.assertEqual(len(res), 1)
+ res = samdb.search(base=forestdns_dn,
+ expression="(msds-masteredby=%s)" % server_ds_name)
+ self.assertEqual(len(res), 1)
+ res = samdb.search(controls=["search_options:1:2"],
+ expression="(&(msds-nc-replica-locations=%s)(ncname=%s))"
+ % (server_ds_name, forestdns_dn))
+ self.assertEqual(len(res), 1)
+
+ # Check all DomainDNS connections and backlinks
+ res = samdb.search(base=server_ds_name,
+ expression="(msds-hasmasterncs=%s)" % domaindns_dn)
+ self.assertEqual(len(res), 1)
+ res = samdb.search(base=domaindns_dn,
+ expression="(msds-masteredby=%s)" % server_ds_name)
+ self.assertEqual(len(res), 1)
+ res = samdb.search(controls=["search_options:1:2"],
+ expression="(&(msds-nc-replica-locations=%s)(ncname=%s))"
+ % (server_ds_name, domaindns_dn))
+ self.assertEqual(len(res), 1)
+
+ # Demote the DC we created in the test
+ self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H ldap://%s %s --configfile=%s"
+ % (netbiosname, self.dc1, self.cmdline_creds, new_dc_config_file))
diff --git a/source4/torture/drs/python/samba_tool_drs_showrepl.py b/source4/torture/drs/python/samba_tool_drs_showrepl.py
new file mode 100644
index 0000000..0f0ed86
--- /dev/null
+++ b/source4/torture/drs/python/samba_tool_drs_showrepl.py
@@ -0,0 +1,377 @@
+# Blackbox tests for "samba-tool drs" command
+# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""Blackbox tests for samba-tool drs showrepl."""
+import samba.tests
+import drs_base
+from samba.dcerpc import drsuapi
+from samba import drs_utils
+import os
+import json
+import ldb
+import random
+from samba.common import get_string
+
+GUID_RE = r'[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}'
+HEX8_RE = r'0x[\da-f]{8}'
+DN_RE = r'(?:(?:CN|DC)=[\\:\w -]+,)+DC=com'
+
+
+class SambaToolDrsShowReplTests(drs_base.DrsBaseTestCase):
+ """Blackbox test case for samba-tool drs."""
+
+ def setUp(self):
+ super(SambaToolDrsShowReplTests, self).setUp()
+
+ self.dc1 = samba.tests.env_get_var_value("DC1")
+ self.dc2 = samba.tests.env_get_var_value("DC2")
+
+ creds = self.get_credentials()
+ self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(),
+ creds.get_username(),
+ creds.get_password())
+
+ def test_samba_tool_showrepl(self):
+ """Tests 'samba-tool drs showrepl' command.
+ """
+ nc_list = [self.config_dn, self.domain_dn, self.schema_dn]
+ dns_name = self.ldb_dc1.domain_dns_name()
+
+ # Manually run kcc to create a "Connection" object, so we can find
+ # this for the expected output below.
+ kcc_out = self.check_output("samba-tool drs kcc %s %s" % (self.dc1,
+ self.cmdline_creds))
+ self.assertIn(b"successful", kcc_out)
+
+ # Run replicate to ensure there are incoming and outgoing partners
+ # exist, so we can expect these in the output below.
+ for nc in nc_list:
+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=nc, forced=True)
+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, nc_dn=nc, forced=True)
+
+ # Output should be like:
+ # <site-name>/<domain-name>
+ # DSA Options: <hex-options>
+ # DSA object GUID: <DSA-object-GUID>
+ # DSA invocationId: <DSA-invocationId>
+ # <Inbound-connections-list>
+ # <Outbound-connections-list>
+ # <KCC-objects>
+ # ...
+ # TODO: Perhaps we should check at least for
+ # DSA's objectGUDI and invocationId
+ out = self.check_output("samba-tool drs showrepl "
+ "%s %s" % (self.dc1, self.cmdline_creds))
+
+ out = get_string(out)
+ # We want to assert that we are getting the same results, but
+ # dates and GUIDs change randomly.
+ #
+ # There are sections with headers like ==== THIS ===="
+ (header,
+ _inbound, inbound,
+ _outbound, outbound,
+ _conn, conn) = out.split("====")
+
+ self.assertEqual(_inbound, ' INBOUND NEIGHBORS ')
+ self.assertEqual(_outbound, ' OUTBOUND NEIGHBORS ')
+ self.assertEqual(_conn, ' KCC CONNECTION OBJECTS ')
+
+ self.assertRegex(header,
+ r'^Default-First-Site-Name\\%s\s+'
+ r"DSA Options: %s\s+"
+ r"DSA object GUID: %s\s+"
+ r"DSA invocationId: %s" %
+ (self.dc1.upper(), HEX8_RE, GUID_RE, GUID_RE))
+
+ # We don't assert the DomainDnsZones and ForestDnsZones are
+ # there because we don't know that they have been set up yet.
+
+ for p in nc_list:
+ self.assertRegex(
+ inbound,
+ r'%s\n'
+ r'\tDefault-First-Site-Name\\[A-Z0-9]+ via RPC\n'
+ r'\t\tDSA object GUID: %s\n'
+ r'\t\tLast attempt @ [^\n]+\n'
+ r'\t\t\d+ consecutive failure\(s\).\n'
+ r'\t\tLast success @ [^\n]+\n'
+ r'\n' % (p, GUID_RE),
+ msg="%s inbound missing" % p)
+
+ self.assertRegex(
+ outbound,
+ r'%s\n'
+ r'\tDefault-First-Site-Name\\[A-Z0-9]+ via RPC\n'
+ r'\t\tDSA object GUID: %s\n'
+ r'\t\tLast attempt @ [^\n]+\n'
+ r'\t\t\d+ consecutive failure\(s\).\n'
+ r'\t\tLast success @ [^\n]+\n'
+ r'\n' % (p, GUID_RE),
+ msg="%s outbound missing" % p)
+
+ self.assertRegex(conn,
+ r'Connection --\n'
+ r'\tConnection name: %s\n'
+ r'\tEnabled : TRUE\n'
+ r'\tServer DNS name : \w+.%s\n'
+ r'\tServer DN name : %s'
+ r'\n' % (GUID_RE, dns_name, DN_RE))
+
+ def test_samba_tool_showrepl_json(self):
+ """Tests 'samba-tool drs showrepl --json' command.
+ """
+ dns_name = self.ldb_dc1.domain_dns_name()
+ out = self.check_output("samba-tool drs showrepl %s %s --json" %
+ (self.dc1, self.cmdline_creds))
+ d = json.loads(get_string(out))
+ self.assertEqual(set(d), set(['repsFrom',
+ 'repsTo',
+ "NTDSConnections",
+ "dsa"]))
+
+ # dsa
+ for k in ["objectGUID", "invocationId"]:
+ self.assertRegex(d['dsa'][k], '^%s$' % GUID_RE)
+ self.assertTrue(isinstance(d['dsa']["options"], int))
+
+ # repsfrom and repsto
+ for reps in (d['repsFrom'], d['repsTo']):
+ for r in reps:
+ for k in ('NC dn', "NTDS DN"):
+ self.assertRegex(r[k], '^%s$' % DN_RE)
+ for k in ("last attempt time",
+ "last attempt message",
+ "last success"):
+ self.assertTrue(isinstance(r[k], str))
+ self.assertRegex(r["DSA objectGUID"], '^%s$' % GUID_RE)
+ self.assertTrue(isinstance(r["consecutive failures"], int))
+
+ # ntdsconnection
+ for n in d["NTDSConnections"]:
+ self.assertTrue(n["dns name"].endswith(dns_name))
+ self.assertRegex(n["name"], "^%s$" % GUID_RE)
+ self.assertTrue(isinstance(n['enabled'], bool))
+ self.assertTrue(isinstance(n['options'], int))
+ self.assertTrue(isinstance(n['replicates NC'], list))
+ self.assertRegex(n["remote DN"], "^%s$" % DN_RE)
+
+ def _force_all_reps(self, samdb, dc, direction):
+ if direction == 'inbound':
+ info_type = drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
+ elif direction == 'outbound':
+ info_type = drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO
+ else:
+ raise ValueError("expected 'inbound' or 'outbound'")
+
+ self._enable_all_repl(dc)
+ lp = self.get_loadparm()
+ creds = self.get_credentials()
+ drsuapi_conn, drsuapi_handle, _ = drs_utils.drsuapi_connect(dc, lp, creds)
+ req1 = drsuapi.DsReplicaGetInfoRequest1()
+ req1.info_type = info_type
+ _, info = drsuapi_conn.DsReplicaGetInfo(drsuapi_handle, 1, req1)
+ for x in info.array:
+ # you might think x.source_dsa_address was the thing, but no.
+ # and we need to filter out RODCs and deleted DCs
+
+ res = []
+ try:
+ res = samdb.search(base=x.source_dsa_obj_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-isRODC', 'isDeleted'],
+ controls=['show_deleted:0'])
+ except ldb.LdbError as e:
+ if e.args[0] != ldb.ERR_NO_SUCH_OBJECT:
+ raise
+
+ if (len(res) == 0 or
+ len(res[0].get('msDS-isRODC', '')) > 0 or
+ res[0]['isDeleted'] == 'TRUE'):
+ continue
+
+ dsa_dn = str(ldb.Dn(samdb, x.source_dsa_obj_dn).parent())
+ try:
+ res = samdb.search(base=dsa_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['dNSHostName'])
+ except ldb.LdbError as e:
+ if e.args[0] != ldb.ERR_NO_SUCH_OBJECT:
+ raise
+ continue
+
+ if len(res) == 0:
+ print("server %s has no dNSHostName" % dsa_dn)
+ continue
+
+ remote = res[0].get('dNSHostName', [''])[0]
+ if remote:
+ self._enable_all_repl(remote)
+
+ if direction == 'inbound':
+ src, dest = remote, dc
+ else:
+ src, dest = dc, remote
+ self._net_drs_replicate(dest, src, forced=True)
+
+ def test_samba_tool_showrepl_pull_summary_all_good(self):
+ """Tests 'samba-tool drs showrepl --pull-summary' command."""
+ # To be sure that all is good we need to force replication
+ # with everyone (because others might have it turned off), and
+ # turn replication on for them in case they suddenly decide to
+ # try again.
+ #
+ # We don't restore them to the non-auto-replication state.
+ samdb1 = self.getSamDB("-H", "ldap://%s" % self.dc1,
+ self.cmdline_creds)
+ self._enable_all_repl(self.dc1)
+ self._force_all_reps(samdb1, self.dc1, 'inbound')
+ self._force_all_reps(samdb1, self.dc1, 'outbound')
+ old_no_color = os.environ.get('NO_COLOR')
+ all_good_green = "\033[1;32m[ALL GOOD]\033[0m\n"
+ all_good = "[ALL GOOD]\n"
+
+ try:
+ out = self.check_output(
+ "samba-tool drs showrepl --pull-summary %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good)
+ out = get_string(out)
+
+ out = self.check_output("samba-tool drs showrepl --pull-summary "
+ "--color=yes %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good_green)
+
+ # --verbose output is still quiet when all is good.
+ out = self.check_output(
+ "samba-tool drs showrepl --pull-summary -v %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good)
+
+ out = self.check_output("samba-tool drs showrepl --pull-summary -v "
+ "--color=always %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good_green)
+
+ out = self.check_output("samba-tool drs showrepl --pull-summary -v "
+ "--color=never %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good)
+
+ os.environ['NO_COLOR'] = 'bean'
+
+ out = self.check_output("samba-tool drs showrepl --pull-summary -v "
+ "--color=auto %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good)
+
+ os.environ['NO_COLOR'] = ''
+
+ out = self.check_output("samba-tool drs showrepl --pull-summary -v "
+ "--color=auto %s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual(out, all_good_green)
+
+ except samba.tests.BlackboxProcessError as e:
+ self.fail(str(e))
+ finally:
+ if old_no_color is None:
+ os.environ.pop('NO_COLOR', None)
+ else:
+ os.environ['NO_COLOR'] = old_no_color
+
+ def test_samba_tool_showrepl_summary_forced_failure(self):
+ """Tests 'samba-tool drs showrepl --summary' command when we break the
+ network on purpose.
+ """
+ self.addCleanup(self._enable_all_repl, self.dc1)
+ self._disable_all_repl(self.dc1)
+
+ samdb1 = self.getSamDB("-H", "ldap://%s" % self.dc1,
+ self.cmdline_creds)
+ samdb2 = self.getSamDB("-H", "ldap://%s" % self.dc2,
+ self.cmdline_creds)
+ domain_dn = samdb1.domain_dn()
+
+ # Add some things to NOT replicate
+ ou1 = "OU=dc1.%x,%s" % (random.randrange(1 << 64), domain_dn)
+ ou2 = "OU=dc2.%x,%s" % (random.randrange(1 << 64), domain_dn)
+ samdb1.add({
+ "dn": ou1,
+ "objectclass": "organizationalUnit"
+ })
+ self.addCleanup(samdb1.delete, ou1, ['tree_delete:1'])
+ samdb2.add({
+ "dn": ou2,
+ "objectclass": "organizationalUnit"
+ })
+ self.addCleanup(samdb2.delete, ou2, ['tree_delete:1'])
+
+ dn1 = 'cn=u1.%%d,%s' % (ou1)
+ dn2 = 'cn=u2.%%d,%s' % (ou2)
+
+ try:
+ for i in range(100):
+ samdb1.add({
+ "dn": dn1 % i,
+ "objectclass": "user"
+ })
+ samdb2.add({
+ "dn": dn2 % i,
+ "objectclass": "user"
+ })
+ out = self.check_output("samba-tool drs showrepl --summary -v "
+ "%s %s" %
+ (self.dc1, self.cmdline_creds))
+ out = get_string(out)
+ self.assertStringsEqual('[ALL GOOD]', out, strip=True)
+ out = self.check_output("samba-tool drs showrepl --summary -v "
+ "--color=yes %s %s" %
+ (self.dc2, self.cmdline_creds))
+ out = get_string(out)
+ self.assertIn('[ALL GOOD]', out)
+
+ except samba.tests.BlackboxProcessError as e:
+ e_stdout = get_string(e.stdout)
+ e_stderr = get_string(e.stderr)
+ print("Good, failed as expected after %d rounds: %r" % (i, e.cmd))
+ self.assertIn('There are failing connections', e_stdout,
+ msg=('stdout: %r\nstderr: %r\nretcode: %s'
+ '\nmessage: %r\ncmd: %r') % (e_stdout,
+ e_stderr,
+ e.returncode,
+ e.msg,
+ e.cmd))
+ self.assertRegex(
+ e_stdout,
+ r'result 845[67] '
+ r'\(WERR_DS_DRA_(SINK|SOURCE)_DISABLED\)',
+ msg=("The process should have failed "
+ "because replication was forced off, "
+ "but it failed for some other reason."))
+ self.assertIn('consecutive failure(s).', e_stdout)
+ else:
+ self.fail("No DRS failure noticed after 100 rounds of trying")
diff --git a/source4/torture/drs/rpc/dssync.c b/source4/torture/drs/rpc/dssync.c
new file mode 100644
index 0000000..64d0498
--- /dev/null
+++ b/source4/torture/drs/rpc/dssync.c
@@ -0,0 +1,1072 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DsGetNCChanges replication test
+
+ Copyright (C) Stefan (metze) Metzmacher 2005
+ Copyright (C) Brad Henry 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "libcli/cldap/cldap.h"
+#include "torture/torture.h"
+#include "../libcli/drsuapi/drsuapi.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/drs/proto.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/util/util_paths.h"
+
+#undef strcasecmp
+
+struct DsSyncBindInfo {
+ struct dcerpc_pipe *drs_pipe;
+ struct dcerpc_binding_handle *drs_handle;
+ struct drsuapi_DsBind req;
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfoCtr our_bind_info_ctr;
+ struct drsuapi_DsBindInfo28 our_bind_info28;
+ struct drsuapi_DsBindInfo28 peer_bind_info28;
+ struct policy_handle bind_handle;
+};
+
+struct DsSyncLDAPInfo {
+ struct ldb_context *ldb;
+};
+
+struct DsSyncTest {
+ struct dcerpc_binding *drsuapi_binding;
+
+ const char *ldap_url;
+ const char *dest_address;
+ const char *domain_dn;
+ const char *config_dn;
+ const char *schema_dn;
+
+ /* what we need to do as 'Administrator' */
+ struct {
+ struct cli_credentials *credentials;
+ struct DsSyncBindInfo drsuapi;
+ struct DsSyncLDAPInfo ldap;
+ } admin;
+
+ /* what we need to do as the new dc machine account */
+ struct {
+ struct cli_credentials *credentials;
+ struct DsSyncBindInfo drsuapi;
+ struct drsuapi_DsGetDCInfo2 dc_info2;
+ struct GUID invocation_id;
+ struct GUID object_guid;
+ } new_dc;
+
+ /* info about the old dc */
+ struct {
+ struct drsuapi_DsGetDomainControllerInfo dc_info;
+ } old_dc;
+};
+
+static struct DsSyncTest *test_create_context(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct DsSyncTest *ctx;
+ struct drsuapi_DsBindInfo28 *our_bind_info28;
+ struct drsuapi_DsBindInfoCtr *our_bind_info_ctr;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ const char *host;
+ struct nbt_name name;
+
+ ctx = talloc_zero(tctx, struct DsSyncTest);
+ if (!ctx) return NULL;
+
+ status = dcerpc_parse_binding(ctx, binding, &ctx->drsuapi_binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Bad binding string %s\n", binding);
+ return NULL;
+ }
+ status = dcerpc_binding_set_flags(ctx->drsuapi_binding,
+ DCERPC_SIGN | DCERPC_SEAL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("dcerpc_binding_set_flags - %s\n", nt_errstr(status));
+ return NULL;
+ }
+
+ host = dcerpc_binding_get_string_option(ctx->drsuapi_binding, "host");
+
+ ctx->ldap_url = talloc_asprintf(ctx, "ldap://%s", host);
+
+ make_nbt_name_server(&name, host);
+
+ /* do an initial name resolution to find its IP */
+ status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0, &name, tctx,
+ &ctx->dest_address, tctx->ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to resolve %s - %s\n",
+ name.name, nt_errstr(status));
+ return NULL;
+ }
+
+ /* ctx->admin ...*/
+ ctx->admin.credentials = samba_cmdline_get_creds();
+
+ our_bind_info28 = &ctx->admin.drsuapi.our_bind_info28;
+ our_bind_info28->supported_extensions = 0xFFFFFFFF;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ our_bind_info28->site_guid = GUID_zero();
+ our_bind_info28->pid = 0;
+ our_bind_info28->repl_epoch = 1;
+
+ our_bind_info_ctr = &ctx->admin.drsuapi.our_bind_info_ctr;
+ our_bind_info_ctr->length = 28;
+ our_bind_info_ctr->info.info28 = *our_bind_info28;
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &ctx->admin.drsuapi.bind_guid);
+
+ ctx->admin.drsuapi.req.in.bind_guid = &ctx->admin.drsuapi.bind_guid;
+ ctx->admin.drsuapi.req.in.bind_info = our_bind_info_ctr;
+ ctx->admin.drsuapi.req.out.bind_handle = &ctx->admin.drsuapi.bind_handle;
+
+ /* ctx->new_dc ...*/
+ ctx->new_dc.credentials = samba_cmdline_get_creds();
+
+ our_bind_info28 = &ctx->new_dc.drsuapi.our_bind_info28;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "xpress", false)) {
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS;
+ }
+ our_bind_info28->site_guid = GUID_zero();
+ our_bind_info28->pid = 0;
+ our_bind_info28->repl_epoch = 0;
+
+ our_bind_info_ctr = &ctx->new_dc.drsuapi.our_bind_info_ctr;
+ our_bind_info_ctr->length = 28;
+ our_bind_info_ctr->info.info28 = *our_bind_info28;
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &ctx->new_dc.drsuapi.bind_guid);
+
+ ctx->new_dc.drsuapi.req.in.bind_guid = &ctx->new_dc.drsuapi.bind_guid;
+ ctx->new_dc.drsuapi.req.in.bind_info = our_bind_info_ctr;
+ ctx->new_dc.drsuapi.req.out.bind_handle = &ctx->new_dc.drsuapi.bind_handle;
+
+ ctx->new_dc.invocation_id = ctx->new_dc.drsuapi.bind_guid;
+
+ /* ctx->old_dc ...*/
+
+ return ctx;
+}
+
+static bool _test_DsBind(struct torture_context *tctx,
+ struct DsSyncTest *ctx, struct cli_credentials *credentials, struct DsSyncBindInfo *b)
+{
+ NTSTATUS status;
+ bool ret = true;
+
+ status = dcerpc_pipe_connect_b(ctx,
+ &b->drs_pipe, ctx->drsuapi_binding,
+ &ndr_table_drsuapi,
+ credentials, tctx->ev, tctx->lp_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status));
+ return false;
+ }
+ b->drs_handle = b->drs_pipe->binding_handle;
+
+ status = dcerpc_drsuapi_DsBind_r(b->drs_handle, ctx, &b->req);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr);
+ ret = false;
+ } else if (!W_ERROR_IS_OK(b->req.out.result)) {
+ printf("DsBind failed - %s\n", win_errstr(b->req.out.result));
+ ret = false;
+ }
+
+ ZERO_STRUCT(b->peer_bind_info28);
+ if (b->req.out.bind_info) {
+ switch (b->req.out.bind_info->length) {
+ case 24: {
+ struct drsuapi_DsBindInfo24 *info24;
+ info24 = &b->req.out.bind_info->info.info24;
+ b->peer_bind_info28.supported_extensions= info24->supported_extensions;
+ b->peer_bind_info28.site_guid = info24->site_guid;
+ b->peer_bind_info28.pid = info24->pid;
+ b->peer_bind_info28.repl_epoch = 0;
+ break;
+ }
+ case 28: {
+ b->peer_bind_info28 = b->req.out.bind_info->info.info28;
+ break;
+ }
+ case 32: {
+ struct drsuapi_DsBindInfo32 *info32;
+ info32 = &b->req.out.bind_info->info.info32;
+ b->peer_bind_info28.supported_extensions= info32->supported_extensions;
+ b->peer_bind_info28.site_guid = info32->site_guid;
+ b->peer_bind_info28.pid = info32->pid;
+ b->peer_bind_info28.repl_epoch = info32->repl_epoch;
+ break;
+ }
+ case 48: {
+ struct drsuapi_DsBindInfo48 *info48;
+ info48 = &b->req.out.bind_info->info.info48;
+ b->peer_bind_info28.supported_extensions= info48->supported_extensions;
+ b->peer_bind_info28.site_guid = info48->site_guid;
+ b->peer_bind_info28.pid = info48->pid;
+ b->peer_bind_info28.repl_epoch = info48->repl_epoch;
+ break;
+ }
+ case 52: {
+ struct drsuapi_DsBindInfo52 *info52;
+ info52 = &b->req.out.bind_info->info.info52;
+ b->peer_bind_info28.supported_extensions= info52->supported_extensions;
+ b->peer_bind_info28.site_guid = info52->site_guid;
+ b->peer_bind_info28.pid = info52->pid;
+ b->peer_bind_info28.repl_epoch = info52->repl_epoch;
+ break;
+ }
+ default:
+ printf("DsBind - warning: unknown BindInfo length: %u\n",
+ b->req.out.bind_info->length);
+ }
+ }
+
+ return ret;
+}
+
+static bool test_LDAPBind(struct torture_context *tctx, struct DsSyncTest *ctx,
+ struct cli_credentials *credentials, struct DsSyncLDAPInfo *l)
+{
+ bool ret = true;
+
+ struct ldb_context *ldb;
+
+ const char *modules_option[] = { "modules:paged_searches", NULL };
+ ctx->admin.ldap.ldb = ldb = ldb_init(ctx, tctx->ev);
+ if (ldb == NULL) {
+ return false;
+ }
+
+ /* Despite us loading the schema from the AD server, we need
+ * the samba handlers to get the extended DN syntax stuff */
+ ret = ldb_register_samba_handlers(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ldb_set_modules_dir(ldb, modules_path(ldb, "ldb"));
+
+ if (ldb_set_opaque(ldb, "credentials", credentials)) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ if (ldb_set_opaque(ldb, "loadparm", tctx->lp_ctx)) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ret = ldb_connect(ldb, ctx->ldap_url, 0, modules_option);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ torture_assert_int_equal(tctx, ret, LDB_SUCCESS, "Failed to make LDB connection to target");
+ }
+
+ printf("connected to LDAP: %s\n", ctx->ldap_url);
+
+ return true;
+}
+
+static bool test_GetInfo(struct torture_context *tctx, struct DsSyncTest *ctx)
+{
+ struct ldb_context *ldb = ctx->admin.ldap.ldb;
+
+ /* We must have LDB connection ready by this time */
+ SMB_ASSERT(ldb != NULL);
+
+ ctx->domain_dn = ldb_dn_get_linearized(ldb_get_default_basedn(ldb));
+ torture_assert(tctx, ctx->domain_dn != NULL, "Failed to get Domain DN");
+
+ ctx->config_dn = ldb_dn_get_linearized(ldb_get_config_basedn(ldb));
+ torture_assert(tctx, ctx->config_dn != NULL, "Failed to get Domain DN");
+
+ ctx->schema_dn = ldb_dn_get_linearized(ldb_get_schema_basedn(ldb));
+ torture_assert(tctx, ctx->schema_dn != NULL, "Failed to get Domain DN");
+
+ return true;
+}
+
+static bool test_analyse_objects(struct torture_context *tctx,
+ struct DsSyncTest *ctx,
+ const char *partition,
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
+ uint32_t object_count,
+ const struct drsuapi_DsReplicaObjectListItemEx *first_object,
+ const DATA_BLOB *gensec_skey)
+{
+ static uint32_t object_id;
+ const char *save_values_dir;
+ const struct drsuapi_DsReplicaObjectListItemEx *cur;
+ struct ldb_context *ldb = ctx->admin.ldap.ldb;
+ struct ldb_dn *deleted_dn;
+ WERROR status;
+ int i, j, ret;
+ struct dsdb_extended_replicated_objects *objs;
+ struct ldb_extended_dn_control *extended_dn_ctrl;
+ struct dsdb_schema *ldap_schema;
+ struct ldb_dn *partition_dn = ldb_dn_new(tctx, ldb, partition);
+
+ torture_assert_not_null(tctx, partition_dn, "Failed to parse partition DN as as DN");
+
+ /* load dsdb_schema using remote prefixMap */
+ torture_assert(tctx,
+ drs_util_dsdb_schema_load_ldb(tctx, ldb, mapping_ctr, false),
+ "drs_util_dsdb_schema_load_ldb() failed");
+ ldap_schema = dsdb_get_schema(ldb, NULL);
+
+ status = dsdb_replicated_objects_convert(ldb,
+ ldap_schema,
+ partition_dn,
+ mapping_ctr,
+ object_count,
+ first_object,
+ 0, NULL,
+ NULL, NULL,
+ gensec_skey,
+ 0,
+ ctx, &objs);
+ torture_assert_werr_ok(tctx, status, "dsdb_extended_replicated_objects_convert() failed!");
+
+ extended_dn_ctrl = talloc(objs, struct ldb_extended_dn_control);
+ extended_dn_ctrl->type = 1;
+
+ deleted_dn = ldb_dn_new(objs, ldb, partition);
+ ldb_dn_add_child_fmt(deleted_dn, "CN=Deleted Objects");
+
+ for (i=0; i < objs->num_objects; i++) {
+ struct ldb_request *search_req;
+ struct ldb_result *res;
+ struct ldb_message *new_msg, *drs_msg, *ldap_msg;
+ size_t num_attrs = objs->objects[i].msg->num_elements+1;
+ const char **attrs = talloc_array(objs, const char *, num_attrs);
+ for (j=0; j < objs->objects[i].msg->num_elements; j++) {
+ attrs[j] = objs->objects[i].msg->elements[j].name;
+ }
+ attrs[j] = NULL;
+ res = talloc_zero(objs, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_build_search_req(&search_req, ldb, objs,
+ objs->objects[i].msg->dn,
+ LDB_SCOPE_BASE,
+ NULL,
+ attrs,
+ NULL,
+ res,
+ ldb_search_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ return false;
+ }
+ talloc_steal(search_req, res);
+ ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
+ if (ret != LDB_SUCCESS) {
+ return false;
+ }
+
+ ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_dn_ctrl);
+ if (ret != LDB_SUCCESS) {
+ return false;
+ }
+
+ ret = ldb_request(ldb, search_req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
+ }
+
+ torture_assert_int_equal(tctx, ret, LDB_SUCCESS,
+ talloc_asprintf(tctx,
+ "Could not re-fetch object just delivered over DRS: %s",
+ ldb_errstring(ldb)));
+ torture_assert_int_equal(tctx, res->count, 1, "Could not re-fetch object just delivered over DRS");
+ ldap_msg = res->msgs[0];
+ for (j=0; j < ldap_msg->num_elements; j++) {
+ ldap_msg->elements[j].flags = LDB_FLAG_MOD_ADD;
+ /* For unknown reasons, there is no nTSecurityDescriptor on cn=deleted objects over LDAP, but there is over DRS! Skip it on both transports for now here so */
+ if ((ldb_attr_cmp(ldap_msg->elements[j].name, "nTSecurityDescriptor") == 0) &&
+ (ldb_dn_compare(ldap_msg->dn, deleted_dn) == 0)) {
+ ldb_msg_remove_element(ldap_msg, &ldap_msg->elements[j]);
+ /* Don't skip one */
+ j--;
+ }
+ }
+
+ ret = ldb_msg_normalize(ldb, search_req,
+ objs->objects[i].msg, &drs_msg);
+ torture_assert(tctx, ret == LDB_SUCCESS,
+ "ldb_msg_normalize() has failed");
+
+ for (j=0; j < drs_msg->num_elements; j++) {
+ if (drs_msg->elements[j].num_values == 0) {
+ ldb_msg_remove_element(drs_msg, &drs_msg->elements[j]);
+ /* Don't skip one */
+ j--;
+
+ /* For unknown reasons, there is no nTSecurityDescriptor on cn=deleted objects over LDAP, but there is over DRS! */
+ } else if ((ldb_attr_cmp(drs_msg->elements[j].name, "nTSecurityDescriptor") == 0) &&
+ (ldb_dn_compare(drs_msg->dn, deleted_dn) == 0)) {
+ ldb_msg_remove_element(drs_msg, &drs_msg->elements[j]);
+ /* Don't skip one */
+ j--;
+ } else if (ldb_attr_cmp(drs_msg->elements[j].name, "unicodePwd") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "dBCSPwd") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "userPassword") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "ntPwdHistory") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "lmPwdHistory") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "supplementalCredentials") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "priorValue") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "currentValue") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "trustAuthOutgoing") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "trustAuthIncoming") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "initialAuthOutgoing") == 0 ||
+ ldb_attr_cmp(drs_msg->elements[j].name, "initialAuthIncoming") == 0) {
+
+ /* These are not shown over LDAP, so we need to skip them for the comparison */
+ ldb_msg_remove_element(drs_msg, &drs_msg->elements[j]);
+ /* Don't skip one */
+ j--;
+ } else {
+ drs_msg->elements[j].flags = LDB_FLAG_MOD_ADD;
+ }
+ }
+
+
+ ret = ldb_msg_difference(ldb, search_req,
+ drs_msg, ldap_msg, &new_msg);
+ torture_assert(tctx, ret == LDB_SUCCESS, "ldb_msg_difference() has failed");
+ if (new_msg->num_elements != 0) {
+ char *s;
+ bool is_warning = true;
+ unsigned int idx;
+ struct ldb_message_element *el;
+ const struct dsdb_attribute * a;
+ struct ldb_ldif ldif;
+ ldif.changetype = LDB_CHANGETYPE_MODIFY;
+ ldif.msg = new_msg;
+ s = ldb_ldif_write_string(ldb, new_msg, &ldif);
+ s = talloc_asprintf(tctx, "\n# Difference in between DRS and LDAP objects: \n%s", s);
+
+ ret = ldb_msg_difference(ldb, search_req,
+ ldap_msg, drs_msg, &ldif.msg);
+ torture_assert(tctx, ret == LDB_SUCCESS, "ldb_msg_difference() has failed");
+ s = talloc_asprintf_append(s,
+ "\n# Difference in between LDAP and DRS objects: \n%s",
+ ldb_ldif_write_string(ldb, new_msg, &ldif));
+
+ s = talloc_asprintf_append(s,
+ "# Should have no objects in 'difference' message. Diff elements: %d",
+ new_msg->num_elements);
+
+ /*
+ * In case differences in messages are:
+ * 1. Attributes with different values, i.e. 'replace'
+ * 2. Those attributes are forward-link attributes
+ * then we just warn about those differences.
+ * It turns out windows doesn't send all of those values
+ * in replicated_object but in linked_attributes.
+ */
+ for (idx = 0; idx < new_msg->num_elements && is_warning; idx++) {
+ el = &new_msg->elements[idx];
+ a = dsdb_attribute_by_lDAPDisplayName(ldap_schema,
+ el->name);
+ if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
+ LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
+ {
+ /* DRS only value */
+ is_warning = false;
+ } else if (a->linkID & 1) {
+ is_warning = false;
+ }
+ }
+ if (is_warning) {
+ torture_warning(tctx, "%s", s);
+ } else {
+ torture_fail(tctx, s);
+ }
+ }
+
+ /* search_req is used as a tmp talloc context in the above */
+ talloc_free(search_req);
+ }
+
+ if (!lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "print_pwd_blobs", false)) {
+ talloc_free(objs);
+ return true;
+ }
+
+ save_values_dir = lpcfg_parm_string(tctx->lp_ctx, NULL, "dssync", "save_pwd_blobs_dir");
+
+ for (cur = first_object; cur; cur = cur->next_object) {
+ const char *dn;
+ bool dn_printed = false;
+
+ if (!cur->object.identifier) continue;
+
+ dn = cur->object.identifier->dn;
+
+ for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
+ const char *name = NULL;
+ DATA_BLOB plain_data;
+ struct drsuapi_DsReplicaAttribute *attr;
+ ndr_pull_flags_fn_t pull_fn = NULL;
+ ndr_print_fn_t print_fn = NULL;
+ void *ptr = NULL;
+ attr = &cur->object.attribute_ctr.attributes[i];
+
+ switch (attr->attid) {
+ case DRSUAPI_ATTID_dBCSPwd:
+ name = "dBCSPwd";
+ break;
+ case DRSUAPI_ATTID_unicodePwd:
+ name = "unicodePwd";
+ break;
+ case DRSUAPI_ATTID_ntPwdHistory:
+ name = "ntPwdHistory";
+ break;
+ case DRSUAPI_ATTID_lmPwdHistory:
+ name = "lmPwdHistory";
+ break;
+ case DRSUAPI_ATTID_supplementalCredentials:
+ name = "supplementalCredentials";
+ pull_fn = (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob;
+ print_fn = (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob;
+ ptr = talloc(ctx, struct supplementalCredentialsBlob);
+ break;
+ case DRSUAPI_ATTID_priorValue:
+ name = "priorValue";
+ break;
+ case DRSUAPI_ATTID_currentValue:
+ name = "currentValue";
+ break;
+ case DRSUAPI_ATTID_trustAuthOutgoing:
+ name = "trustAuthOutgoing";
+ pull_fn = (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob;
+ print_fn = (ndr_print_fn_t)ndr_print_trustAuthInOutBlob;
+ ptr = talloc(ctx, struct trustAuthInOutBlob);
+ break;
+ case DRSUAPI_ATTID_trustAuthIncoming:
+ name = "trustAuthIncoming";
+ pull_fn = (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob;
+ print_fn = (ndr_print_fn_t)ndr_print_trustAuthInOutBlob;
+ ptr = talloc(ctx, struct trustAuthInOutBlob);
+ break;
+ case DRSUAPI_ATTID_initialAuthOutgoing:
+ name = "initialAuthOutgoing";
+ break;
+ case DRSUAPI_ATTID_initialAuthIncoming:
+ name = "initialAuthIncoming";
+ break;
+ default:
+ continue;
+ }
+
+ if (attr->value_ctr.num_values != 1) continue;
+
+ if (!attr->value_ctr.values[0].blob) continue;
+
+ plain_data = *attr->value_ctr.values[0].blob;
+
+ if (!dn_printed) {
+ object_id++;
+ DEBUG(0,("DN[%u] %s\n", object_id, dn));
+ dn_printed = true;
+ }
+ DEBUGADD(0,("ATTR: %s plain.length=%lu\n",
+ name, (long)plain_data.length));
+ if (plain_data.length) {
+ enum ndr_err_code ndr_err;
+ dump_data(0, plain_data.data, plain_data.length);
+ if (save_values_dir) {
+ char *fname;
+ fname = talloc_asprintf(ctx, "%s/%s%02d",
+ save_values_dir,
+ name, object_id);
+ if (fname) {
+ bool ok;
+ ok = file_save(fname, plain_data.data, plain_data.length);
+ if (!ok) {
+ DEBUGADD(0,("Failed to save '%s'\n", fname));
+ }
+ }
+ talloc_free(fname);
+ }
+
+ if (pull_fn) {
+ /* Can't use '_all' because of PIDL bugs with relative pointers */
+ ndr_err = ndr_pull_struct_blob(&plain_data, ptr,
+ ptr, pull_fn);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ (void)ndr_print_debug(1, print_fn, name, ptr, __location__, __func__);
+ } else {
+ DEBUG(0, ("Failed to decode %s\n", name));
+ }
+ }
+ }
+ talloc_free(ptr);
+ }
+ }
+ talloc_free(objs);
+ return true;
+}
+
+static bool test_GetNCChanges(struct torture_context *tctx,
+ struct DsSyncTest *ctx,
+ const char *nc_dn_str)
+{
+ NTSTATUS status;
+ bool ret = true;
+ int i, y = 0;
+ uint64_t highest_usn = 0;
+ struct drsuapi_DsGetNCChanges r;
+ union drsuapi_DsGetNCChangesRequest req;
+ struct drsuapi_DsReplicaObjectIdentifier nc;
+ struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
+ uint32_t out_level = 0;
+ struct dom_sid null_sid;
+ DATA_BLOB gensec_skey;
+ struct {
+ uint32_t level;
+ } array[] = {
+/* {
+ 5
+ },
+*/ {
+ 8
+ }
+ };
+
+ ZERO_STRUCT(null_sid);
+
+ highest_usn = lpcfg_parm_int(tctx->lp_ctx, NULL, "dssync", "highest_usn", 0);
+
+ array[0].level = lpcfg_parm_int(tctx->lp_ctx, NULL, "dssync", "get_nc_changes_level", array[0].level);
+
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "print_pwd_blobs", false)) {
+ const struct samr_Password *nthash;
+ nthash = cli_credentials_get_nt_hash(ctx->new_dc.credentials, ctx);
+ if (nthash) {
+ dump_data_pw("CREDENTIALS nthash:", nthash->hash, sizeof(nthash->hash));
+ }
+ }
+ status = gensec_session_key(ctx->new_dc.drsuapi.drs_pipe->conn->security_state.generic_state,
+ ctx, &gensec_skey);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("failed to get gensec session key: %s\n", nt_errstr(status));
+ return false;
+ }
+
+ for (i=0; i < ARRAY_SIZE(array); i++) {
+ printf("Testing DsGetNCChanges level %d\n",
+ array[i].level);
+
+ r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle;
+ r.in.level = array[i].level;
+
+ switch (r.in.level) {
+ case 5:
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+ nc.dn = nc_dn_str;
+
+ r.in.req = &req;
+ r.in.req->req5.destination_dsa_guid = ctx->new_dc.invocation_id;
+ r.in.req->req5.source_dsa_invocation_id = GUID_zero();
+ r.in.req->req5.naming_context = &nc;
+ r.in.req->req5.highwatermark.tmp_highest_usn = highest_usn;
+ r.in.req->req5.highwatermark.reserved_usn = 0;
+ r.in.req->req5.highwatermark.highest_usn = highest_usn;
+ r.in.req->req5.uptodateness_vector = NULL;
+ r.in.req->req5.replica_flags = 0;
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "compression", false)) {
+ r.in.req->req5.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
+ }
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "neighbour_writeable", true)) {
+ r.in.req->req5.replica_flags |= DRSUAPI_DRS_WRIT_REP;
+ }
+ r.in.req->req5.replica_flags |= DRSUAPI_DRS_INIT_SYNC
+ | DRSUAPI_DRS_PER_SYNC
+ | DRSUAPI_DRS_GET_ANC
+ | DRSUAPI_DRS_NEVER_SYNCED
+ ;
+ r.in.req->req5.max_object_count = 133;
+ r.in.req->req5.max_ndr_size = 1336770;
+ r.in.req->req5.extended_op = DRSUAPI_EXOP_NONE;
+ r.in.req->req5.fsmo_info = 0;
+
+ break;
+ case 8:
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+ nc.dn = nc_dn_str;
+ /* nc.dn can be set to any other ad partition */
+
+ r.in.req = &req;
+ r.in.req->req8.destination_dsa_guid = ctx->new_dc.invocation_id;
+ r.in.req->req8.source_dsa_invocation_id = GUID_zero();
+ r.in.req->req8.naming_context = &nc;
+ r.in.req->req8.highwatermark.tmp_highest_usn = highest_usn;
+ r.in.req->req8.highwatermark.reserved_usn = 0;
+ r.in.req->req8.highwatermark.highest_usn = highest_usn;
+ r.in.req->req8.uptodateness_vector = NULL;
+ r.in.req->req8.replica_flags = 0;
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "compression", false)) {
+ r.in.req->req8.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
+ }
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "dssync", "neighbour_writeable", true)) {
+ r.in.req->req8.replica_flags |= DRSUAPI_DRS_WRIT_REP;
+ }
+ r.in.req->req8.replica_flags |= DRSUAPI_DRS_INIT_SYNC
+ | DRSUAPI_DRS_PER_SYNC
+ | DRSUAPI_DRS_GET_ANC
+ | DRSUAPI_DRS_NEVER_SYNCED
+ ;
+ r.in.req->req8.max_object_count = 402;
+ r.in.req->req8.max_ndr_size = 402116;
+
+ r.in.req->req8.extended_op = DRSUAPI_EXOP_NONE;
+ r.in.req->req8.fsmo_info = 0;
+ r.in.req->req8.partial_attribute_set = NULL;
+ r.in.req->req8.partial_attribute_set_ex = NULL;
+ r.in.req->req8.mapping_ctr.num_mappings = 0;
+ r.in.req->req8.mapping_ctr.mappings = NULL;
+
+ break;
+ }
+
+ for (y=0; ;y++) {
+ uint32_t _level = 0;
+ union drsuapi_DsGetNCChangesCtr ctr;
+
+ ZERO_STRUCT(r.out);
+
+ r.out.level_out = &_level;
+ r.out.ctr = &ctr;
+
+ if (r.in.level == 5) {
+ torture_comment(tctx,
+ "start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",
+ y,
+ (unsigned long long) r.in.req->req5.highwatermark.tmp_highest_usn,
+ (unsigned long long) r.in.req->req5.highwatermark.highest_usn);
+ }
+
+ if (r.in.level == 8) {
+ torture_comment(tctx,
+ "start[%d] tmp_higest_usn: %llu , highest_usn: %llu\n",
+ y,
+ (unsigned long long) r.in.req->req8.highwatermark.tmp_highest_usn,
+ (unsigned long long) r.in.req->req8.highwatermark.highest_usn);
+ }
+
+ status = dcerpc_drsuapi_DsGetNCChanges_r(ctx->new_dc.drsuapi.drs_handle, ctx, &r);
+ torture_drsuapi_assert_call(tctx, ctx->new_dc.drsuapi.drs_pipe, status,
+ &r, "dcerpc_drsuapi_DsGetNCChanges");
+
+ if (ret == true && *r.out.level_out == 1) {
+ out_level = 1;
+ ctr1 = &r.out.ctr->ctr1;
+ } else if (ret == true && *r.out.level_out == 2 &&
+ r.out.ctr->ctr2.mszip1.ts) {
+ out_level = 1;
+ ctr1 = &r.out.ctr->ctr2.mszip1.ts->ctr1;
+ }
+
+ if (out_level == 1) {
+ torture_comment(tctx,
+ "end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",
+ y,
+ (unsigned long long) ctr1->new_highwatermark.tmp_highest_usn,
+ (unsigned long long) ctr1->new_highwatermark.highest_usn);
+
+ if (!test_analyse_objects(tctx, ctx, nc_dn_str, &ctr1->mapping_ctr, ctr1->object_count,
+ ctr1->first_object, &gensec_skey)) {
+ return false;
+ }
+
+ if (ctr1->more_data) {
+ r.in.req->req5.highwatermark = ctr1->new_highwatermark;
+ continue;
+ }
+ }
+
+ if (ret == true && *r.out.level_out == 6) {
+ out_level = 6;
+ ctr6 = &r.out.ctr->ctr6;
+ } else if (ret == true && *r.out.level_out == 7
+ && r.out.ctr->ctr7.level == 6
+ && r.out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP
+ && r.out.ctr->ctr7.ctr.mszip6.ts) {
+ out_level = 6;
+ ctr6 = &r.out.ctr->ctr7.ctr.mszip6.ts->ctr6;
+ } else if (ret == true && *r.out.level_out == 7
+ && r.out.ctr->ctr7.level == 6
+ && r.out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2
+ && r.out.ctr->ctr7.ctr.xpress6.ts) {
+ out_level = 6;
+ ctr6 = &r.out.ctr->ctr7.ctr.xpress6.ts->ctr6;
+ }
+
+ if (out_level == 6) {
+ torture_comment(tctx,
+ "end[%d] tmp_highest_usn: %llu , highest_usn: %llu\n",
+ y,
+ (unsigned long long) ctr6->new_highwatermark.tmp_highest_usn,
+ (unsigned long long) ctr6->new_highwatermark.highest_usn);
+
+ if (!test_analyse_objects(tctx, ctx, nc_dn_str, &ctr6->mapping_ctr, ctr6->object_count,
+ ctr6->first_object, &gensec_skey)) {
+ return false;
+ }
+
+ if (ctr6->more_data) {
+ r.in.req->req8.highwatermark = ctr6->new_highwatermark;
+ continue;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Test DsGetNCChanges() DRSUAPI call against one
+ * or more Naming Contexts.
+ * Specific NC to test with may be supplied
+ * in lp_ctx configuration. If no NC is specified,
+ * it will test DsGetNCChanges() on all NCs on remote DC
+ */
+static bool test_FetchData(struct torture_context *tctx, struct DsSyncTest *ctx)
+{
+ bool ret = true;
+ size_t i, count;
+ const char *nc_dn_str;
+ const char **nc_list;
+
+ nc_list = const_str_list(str_list_make_empty(ctx));
+ torture_assert(tctx, nc_list, "Not enough memory!");
+
+ /* make a list of partitions to test with */
+ nc_dn_str = lpcfg_parm_string(tctx->lp_ctx, NULL, "dssync", "partition");
+ if (nc_dn_str == NULL) {
+ nc_list = str_list_add_const(nc_list, ctx->domain_dn);
+ nc_list = str_list_add_const(nc_list, ctx->config_dn);
+ nc_list = str_list_add_const(nc_list, ctx->schema_dn);
+ } else {
+ nc_list = str_list_add_const(nc_list, nc_dn_str);
+ }
+
+ count = str_list_length(nc_list);
+ for (i = 0; i < count && ret; i++) {
+ torture_comment(tctx, "\nNaming Context: %s\n", nc_list[i]);
+ ret = test_GetNCChanges(tctx, ctx, nc_list[i]);
+ }
+
+ talloc_free(nc_list);
+ return ret;
+}
+
+
+static bool test_FetchNT4Data(struct torture_context *tctx,
+ struct DsSyncTest *ctx)
+{
+ NTSTATUS status;
+ struct drsuapi_DsGetNT4ChangeLog r;
+ union drsuapi_DsGetNT4ChangeLogRequest req;
+ union drsuapi_DsGetNT4ChangeLogInfo info;
+ uint32_t level_out = 0;
+ DATA_BLOB cookie;
+
+ ZERO_STRUCT(cookie);
+
+ ZERO_STRUCT(r);
+ r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle;
+ r.in.level = 1;
+ r.out.info = &info;
+ r.out.level_out = &level_out;
+
+ req.req1.flags = lpcfg_parm_int(tctx->lp_ctx, NULL,
+ "dssync", "nt4changelog_flags",
+ DRSUAPI_NT4_CHANGELOG_GET_CHANGELOG |
+ DRSUAPI_NT4_CHANGELOG_GET_SERIAL_NUMBERS);
+ req.req1.preferred_maximum_length = lpcfg_parm_int(tctx->lp_ctx, NULL,
+ "dssync", "nt4changelog_preferred_len",
+ 0x00004000);
+
+ while (1) {
+ req.req1.restart_length = cookie.length;
+ req.req1.restart_data = cookie.data;
+
+ r.in.req = &req;
+
+ status = dcerpc_drsuapi_DsGetNT4ChangeLog_r(ctx->new_dc.drsuapi.drs_handle, ctx, &r);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ torture_skip(tctx,
+ "DsGetNT4ChangeLog not supported: NT_STATUS_NOT_IMPLEMENTED");
+ } else if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ torture_skip(tctx,
+ "DsGetNT4ChangeLog not supported: NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE");
+ }
+ torture_fail(tctx,
+ talloc_asprintf(tctx, "dcerpc_drsuapi_DsGetNT4ChangeLog failed - %s\n",
+ errstr));
+ } else if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_DOMAIN_ROLE)) {
+ torture_skip(tctx,
+ "DsGetNT4ChangeLog not supported: WERR_INVALID_DOMAIN_ROLE");
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx, "DsGetNT4ChangeLog failed - %s\n",
+ win_errstr(r.out.result)));
+ } else if (*r.out.level_out != 1) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx, "DsGetNT4ChangeLog unknown level - %u\n",
+ *r.out.level_out));
+ } else if (NT_STATUS_IS_OK(r.out.info->info1.status)) {
+ } else if (NT_STATUS_EQUAL(r.out.info->info1.status, STATUS_MORE_ENTRIES)) {
+ cookie.length = r.out.info->info1.restart_length;
+ cookie.data = r.out.info->info1.restart_data;
+ continue;
+ } else {
+ torture_fail(tctx,
+ talloc_asprintf(tctx, "DsGetNT4ChangeLog failed - %s\n",
+ nt_errstr(r.out.info->info1.status)));
+ }
+
+ break;
+ }
+
+ return true;
+}
+
+/**
+ * DSSYNC test case setup
+ */
+static bool torture_dssync_tcase_setup(struct torture_context *tctx, void **data)
+{
+ bool bret;
+ struct DsSyncTest *ctx;
+
+ *data = ctx = test_create_context(tctx);
+ torture_assert(tctx, ctx, "test_create_context() failed");
+
+ bret = _test_DsBind(tctx, ctx, ctx->admin.credentials, &ctx->admin.drsuapi);
+ torture_assert(tctx, bret, "_test_DsBind() failed");
+
+ bret = test_LDAPBind(tctx, ctx, ctx->admin.credentials, &ctx->admin.ldap);
+ torture_assert(tctx, bret, "test_LDAPBind() failed");
+
+ bret = test_GetInfo(tctx, ctx);
+ torture_assert(tctx, bret, "test_GetInfo() failed");
+
+ bret = _test_DsBind(tctx, ctx, ctx->new_dc.credentials, &ctx->new_dc.drsuapi);
+ torture_assert(tctx, bret, "_test_DsBind() failed");
+
+ return true;
+}
+
+/**
+ * DSSYNC test case cleanup
+ */
+static bool torture_dssync_tcase_teardown(struct torture_context *tctx, void *data)
+{
+ struct DsSyncTest *ctx;
+ struct drsuapi_DsUnbind r;
+ struct policy_handle bind_handle;
+
+ ctx = talloc_get_type(data, struct DsSyncTest);
+
+ ZERO_STRUCT(r);
+ r.out.bind_handle = &bind_handle;
+
+ /* Unbing admin handle */
+ r.in.bind_handle = &ctx->admin.drsuapi.bind_handle;
+ dcerpc_drsuapi_DsUnbind_r(ctx->admin.drsuapi.drs_handle, ctx, &r);
+
+ /* Unbing new_dc handle */
+ r.in.bind_handle = &ctx->new_dc.drsuapi.bind_handle;
+ dcerpc_drsuapi_DsUnbind_r(ctx->new_dc.drsuapi.drs_handle, ctx, &r);
+
+ talloc_free(ctx);
+
+ return true;
+}
+
+/**
+ * DSSYNC test case implementation
+ */
+void torture_drs_rpc_dssync_tcase(struct torture_suite *suite)
+{
+ typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "dssync");
+
+ torture_tcase_set_fixture(tcase,
+ torture_dssync_tcase_setup,
+ torture_dssync_tcase_teardown);
+
+ torture_tcase_add_simple_test(tcase, "DC_FetchData", (run_func)test_FetchData);
+ torture_tcase_add_simple_test(tcase, "FetchNT4Data", (run_func)test_FetchNT4Data);
+}
+
diff --git a/source4/torture/drs/rpc/msds_intid.c b/source4/torture/drs/rpc/msds_intid.c
new file mode 100644
index 0000000..1bc5c32
--- /dev/null
+++ b/source4/torture/drs/rpc/msds_intid.c
@@ -0,0 +1,792 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ msDS-IntId attribute replication test.
+
+ Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "libcli/cldap/cldap.h"
+#include "torture/torture.h"
+#include "../libcli/drsuapi/drsuapi.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/drs/proto.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/util/util_paths.h"
+
+struct DsSyncBindInfo {
+ struct dcerpc_pipe *drs_pipe;
+ struct dcerpc_binding_handle *drs_handle;
+ struct drsuapi_DsBind req;
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfoCtr our_bind_info_ctr;
+ struct drsuapi_DsBindInfo28 our_bind_info28;
+ struct drsuapi_DsBindInfo28 peer_bind_info28;
+ struct policy_handle bind_handle;
+};
+
+struct DsaBindInfo {
+ struct dcerpc_binding *server_binding;
+
+ struct dcerpc_pipe *drs_pipe;
+ struct dcerpc_binding_handle *drs_handle;
+
+ DATA_BLOB gensec_skey;
+ struct drsuapi_DsBindInfo48 srv_info48;
+ struct policy_handle rpc_handle;
+};
+
+struct DsIntIdTestCtx {
+ const char *ldap_url;
+ const char *domain_dn;
+ const char *config_dn;
+ const char *schema_dn;
+
+ /* what we need to do as 'Administrator' */
+ struct cli_credentials *creds;
+ struct DsaBindInfo dsa_bind;
+ struct ldb_context *ldb;
+
+};
+
+/* Format string to create provision LDIF with */
+#define PROVISION_LDIF_FMT \
+ "###########################################################\n" \
+ "# Format string with positional params:\n" \
+ "# 1 - (int) Unique ID between 1 and 2^16\n" \
+ "# 2 - (string) Domain DN\n" \
+ "###########################################################\n" \
+ "\n" \
+ "###########################################################\n" \
+ "# Update schema\n" \
+ "###########################################################\n" \
+ "dn: CN=msds-intid-%1$d,CN=Schema,CN=Configuration,%2$s\n" \
+ "changetype: add\n" \
+ "objectClass: top\n" \
+ "objectClass: attributeSchema\n" \
+ "cn: msds-intid-%1$d\n" \
+ "attributeID: 1.3.6.1.4.1.7165.4.6.1.%1$d.1.5.9940\n" \
+ "attributeSyntax: 2.5.5.10\n" \
+ "omSyntax: 4\n" \
+ "instanceType: 4\n" \
+ "isSingleValued: TRUE\n" \
+ "systemOnly: FALSE\n" \
+ "\n" \
+ "# schemaUpdateNow\n" \
+ "DN:\n" \
+ "changeType: modify\n" \
+ "add: schemaUpdateNow\n" \
+ "schemaUpdateNow: 1\n" \
+ "-\n" \
+ "\n" \
+ "###########################################################\n" \
+ "# Update schema (with linked attribute)\n" \
+ "###########################################################\n" \
+ "dn: CN=msds-intid-link-%1$d,CN=Schema,CN=Configuration,%2$s\n" \
+ "changetype: add\n" \
+ "objectClass: top\n" \
+ "objectClass: attributeSchema\n" \
+ "cn: msds-intid-link-%1$d\n" \
+ "attributeID: 1.3.6.1.4.1.7165.4.6.1.%1$d.1.5.9941\n" \
+ "attributeSyntax: 2.5.5.1\n" \
+ "omSyntax: 127\n" \
+ "instanceType: 4\n" \
+ "isSingleValued: TRUE\n" \
+ "systemOnly: FALSE\n" \
+ "linkID: 1.2.840.113556.1.2.50\n" \
+ "\n" \
+ "# schemaUpdateNow\n" \
+ "DN:\n" \
+ "changeType: modify\n" \
+ "add: schemaUpdateNow\n" \
+ "schemaUpdateNow: 1\n" \
+ "-\n" \
+ "\n" \
+ "###########################################################\n" \
+ "# Update User class\n" \
+ "###########################################################\n" \
+ "dn: CN=User,CN=Schema,CN=Configuration,%2$s\n" \
+ "changetype: modify\n" \
+ "add: mayContain\n" \
+ "mayContain: msdsIntid%1$d\n" \
+ "mayContain: msdsIntidLink%1$d\n" \
+ "-\n" \
+ "\n" \
+ "# schemaUpdateNow\n" \
+ "DN:\n" \
+ "changeType: modify\n" \
+ "add: schemaUpdateNow\n" \
+ "schemaUpdateNow: 1\n" \
+ "-\n" \
+ "\n" \
+ "###########################################################\n" \
+ "# create user to test with\n" \
+ "###########################################################\n" \
+ "dn: CN=dsIntId_usr_%1$d,CN=Users,%2$s\n" \
+ "changetype: add\n" \
+ "objectClass: user\n" \
+ "cn: dsIntId_usr_%1$d\n" \
+ "name: dsIntId_usr_%1$d\n" \
+ "displayName: dsIntId_usr_%1$d\n" \
+ "sAMAccountName: dsIntId_usr_%1$d\n" \
+ "msdsIntid%1$d: msDS-IntId-%1$d attribute value\n" \
+ "msdsIntidLink%1$d: %2$s\n" \
+ "\n"
+
+
+static struct DsIntIdTestCtx *_dsintid_create_context(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct DsIntIdTestCtx *ctx;
+ struct dcerpc_binding *server_binding;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+
+ /* Create test suite context */
+ ctx = talloc_zero(tctx, struct DsIntIdTestCtx);
+ if (!ctx) {
+ torture_result(tctx, TORTURE_FAIL, "Not enough memory!");
+ return NULL;
+ }
+
+ /* parse binding object */
+ status = dcerpc_parse_binding(ctx, binding, &server_binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Bad binding string '%s': %s", binding, nt_errstr(status));
+ return NULL;
+ }
+
+ status = dcerpc_binding_set_flags(server_binding,
+ DCERPC_SIGN | DCERPC_SEAL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "dcerpc_binding_set_flags: %s", nt_errstr(status));
+ return NULL;
+ }
+
+ /* populate test suite context */
+ ctx->creds = samba_cmdline_get_creds();
+ ctx->dsa_bind.server_binding = server_binding;
+
+ ctx->ldap_url = talloc_asprintf(ctx, "ldap://%s",
+ dcerpc_binding_get_string_option(server_binding, "host"));
+
+ return ctx;
+}
+
+static bool _test_DsaBind(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials *credentials,
+ uint32_t req_extensions,
+ struct DsaBindInfo *bi)
+{
+ NTSTATUS status;
+ struct GUID bind_guid;
+ struct drsuapi_DsBind r;
+ struct drsuapi_DsBindInfoCtr bind_info_ctr;
+ uint32_t supported_extensions;
+
+ /* make DCE RPC connection */
+ status = dcerpc_pipe_connect_b(mem_ctx,
+ &bi->drs_pipe,
+ bi->server_binding,
+ &ndr_table_drsuapi,
+ credentials, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to connect to server");
+
+ bi->drs_handle = bi->drs_pipe->binding_handle;
+
+ status = gensec_session_key(bi->drs_pipe->conn->security_state.generic_state,
+ mem_ctx, &bi->gensec_skey);
+ torture_assert_ntstatus_ok(tctx, status, "failed to get gensec session key");
+
+ /* Bind to DRSUAPI interface */
+ GUID_from_string(DRSUAPI_DS_BIND_GUID_W2K3, &bind_guid);
+
+ /*
+ * Add flags that should be 1, according to MS docs.
+ * It turns out DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
+ * is actually required in order for GetNCChanges() to
+ * return schemaInfo entry in the prefixMap returned.
+ * Use DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION so
+ * we are able to fetch sensitive data.
+ */
+ supported_extensions = req_extensions
+ | DRSUAPI_SUPPORTED_EXTENSION_BASE
+ | DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
+ | DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
+ | DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
+ | DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+
+ ZERO_STRUCT(bind_info_ctr);
+ bind_info_ctr.length = 28;
+ bind_info_ctr.info.info28.supported_extensions = supported_extensions;
+
+ r.in.bind_guid = &bind_guid;
+ r.in.bind_info = &bind_info_ctr;
+ r.out.bind_handle = &bi->rpc_handle;
+
+ status = dcerpc_drsuapi_DsBind_r(bi->drs_handle, mem_ctx, &r);
+ torture_drsuapi_assert_call(tctx, bi->drs_pipe, status,
+ &r, "dcerpc_drsuapi_DsBind_r");
+
+
+ switch (r.out.bind_info->length) {
+ case 24: {
+ struct drsuapi_DsBindInfo24 *info24;
+ info24 = &r.out.bind_info->info.info24;
+ bi->srv_info48.supported_extensions = info24->supported_extensions;
+ bi->srv_info48.site_guid = info24->site_guid;
+ bi->srv_info48.pid = info24->pid;
+ break;
+ }
+ case 28: {
+ struct drsuapi_DsBindInfo28 *info28;
+ info28 = &r.out.bind_info->info.info28;
+ bi->srv_info48.supported_extensions = info28->supported_extensions;
+ bi->srv_info48.site_guid = info28->site_guid;
+ bi->srv_info48.pid = info28->pid;
+ bi->srv_info48.repl_epoch = info28->repl_epoch;
+ break;
+ }
+ case 32: {
+ struct drsuapi_DsBindInfo32 *info32;
+ info32 = &r.out.bind_info->info.info32;
+ bi->srv_info48.supported_extensions = info32->supported_extensions;
+ bi->srv_info48.site_guid = info32->site_guid;
+ bi->srv_info48.pid = info32->pid;
+ bi->srv_info48.repl_epoch = info32->repl_epoch;
+ break;
+ }
+ case 48: {
+ bi->srv_info48 = r.out.bind_info->info.info48;
+ break;
+ }
+ case 52: {
+ struct drsuapi_DsBindInfo52 *info52;
+ info52 = &r.out.bind_info->info.info52;
+ bi->srv_info48.supported_extensions = info52->supported_extensions;
+ bi->srv_info48.site_guid = info52->site_guid;
+ bi->srv_info48.pid = info52->pid;
+ bi->srv_info48.repl_epoch = info52->repl_epoch;
+ break;
+ }
+ default:
+ torture_result(tctx, TORTURE_FAIL,
+ "DsBind: unknown BindInfo length: %u",
+ r.out.bind_info->length);
+ return false;
+ }
+
+ /* check if server supports extensions we've requested */
+ if ((bi->srv_info48.supported_extensions & req_extensions) != req_extensions) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Server does not support requested extensions. "
+ "Requested: 0x%08X, Supported: 0x%08X",
+ req_extensions, bi->srv_info48.supported_extensions);
+ return false;
+ }
+
+ return true;
+}
+
+static bool _test_LDAPBind(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials *credentials,
+ const char *ldap_url,
+ struct ldb_context **_ldb)
+{
+ bool ret = true;
+
+ struct ldb_context *ldb;
+
+ const char *modules_option[] = { "modules:paged_searches", NULL };
+ ldb = ldb_init(mem_ctx, tctx->ev);
+ if (ldb == NULL) {
+ return false;
+ }
+
+ /* Despite us loading the schema from the AD server, we need
+ * the samba handlers to get the extended DN syntax stuff */
+ ret = ldb_register_samba_handlers(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ldb_set_modules_dir(ldb, modules_path(ldb, "ldb"));
+
+ if (ldb_set_opaque(ldb, "credentials", credentials) != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ if (ldb_set_opaque(ldb, "loadparm", tctx->lp_ctx) != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ret = ldb_connect(ldb, ldap_url, 0, modules_option);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ torture_assert_int_equal(tctx, ret, LDB_SUCCESS, "Failed to make LDB connection to target");
+ }
+
+ *_ldb = ldb;
+
+ return true;
+}
+
+static bool _test_provision(struct torture_context *tctx, struct DsIntIdTestCtx *ctx)
+{
+ int ret;
+ char *ldif_str;
+ const char *pstr;
+ struct ldb_ldif *ldif;
+ uint32_t attr_id;
+ struct ldb_context *ldb = ctx->ldb;
+
+ /* We must have LDB connection ready by this time */
+ SMB_ASSERT(ldb != NULL);
+
+ ctx->domain_dn = ldb_dn_get_linearized(ldb_get_default_basedn(ldb));
+ torture_assert(tctx, ctx->domain_dn != NULL, "Failed to get Domain DN");
+
+ ctx->config_dn = ldb_dn_get_linearized(ldb_get_config_basedn(ldb));
+ torture_assert(tctx, ctx->config_dn != NULL, "Failed to get Domain DN");
+
+ ctx->schema_dn = ldb_dn_get_linearized(ldb_get_schema_basedn(ldb));
+ torture_assert(tctx, ctx->schema_dn != NULL, "Failed to get Domain DN");
+
+ /* prepare LDIF to provision with */
+ attr_id = generate_random() % 0xFFFF;
+ pstr = ldif_str = talloc_asprintf(ctx, PROVISION_LDIF_FMT,
+ attr_id, ctx->domain_dn);
+
+ /* Provision test data */
+ while ((ldif = ldb_ldif_read_string(ldb, &pstr)) != NULL) {
+ switch (ldif->changetype) {
+ case LDB_CHANGETYPE_DELETE:
+ ret = ldb_delete(ldb, ldif->msg->dn);
+ break;
+ case LDB_CHANGETYPE_MODIFY:
+ ret = ldb_modify(ldb, ldif->msg);
+ break;
+ case LDB_CHANGETYPE_ADD:
+ default:
+ ret = ldb_add(ldb, ldif->msg);
+ break;
+ }
+ if (ret != LDB_SUCCESS) {
+ char *msg = talloc_asprintf(ctx,
+ "Failed to apply ldif - %s (%s): \n%s",
+ ldb_errstring(ldb),
+ ldb_strerror(ret),
+ ldb_ldif_write_string(ldb, ctx, ldif));
+ torture_fail(tctx, msg);
+
+ }
+ ldb_ldif_read_free(ldb, ldif);
+ }
+
+ return true;
+}
+
+
+static bool _test_GetNCChanges(struct torture_context *tctx,
+ struct DsaBindInfo *bi,
+ const char *nc_dn_str,
+ TALLOC_CTX *mem_ctx,
+ struct drsuapi_DsGetNCChangesCtr6 **_ctr6)
+{
+ NTSTATUS status;
+ struct drsuapi_DsGetNCChanges r;
+ union drsuapi_DsGetNCChangesRequest req;
+ struct drsuapi_DsReplicaObjectIdentifier nc;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6_chunk = NULL;
+ struct drsuapi_DsGetNCChangesCtr6 ctr6;
+ uint32_t _level = 0;
+ union drsuapi_DsGetNCChangesCtr ctr;
+
+ struct dom_sid null_sid;
+
+ ZERO_STRUCT(null_sid);
+
+ /* fill-in Naming Context */
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+ nc.dn = nc_dn_str;
+
+ /* fill-in request fields */
+ req.req8.destination_dsa_guid = GUID_random();
+ req.req8.source_dsa_invocation_id = GUID_zero();
+ req.req8.naming_context = &nc;
+ req.req8.highwatermark.tmp_highest_usn = 0;
+ req.req8.highwatermark.reserved_usn = 0;
+ req.req8.highwatermark.highest_usn = 0;
+ req.req8.uptodateness_vector = NULL;
+ req.req8.replica_flags = DRSUAPI_DRS_WRIT_REP
+ | DRSUAPI_DRS_INIT_SYNC
+ | DRSUAPI_DRS_PER_SYNC
+ | DRSUAPI_DRS_GET_ANC
+ | DRSUAPI_DRS_NEVER_SYNCED
+ ;
+ req.req8.max_object_count = 402;
+ req.req8.max_ndr_size = 402116;
+
+ req.req8.extended_op = DRSUAPI_EXOP_NONE;
+ req.req8.fsmo_info = 0;
+ req.req8.partial_attribute_set = NULL;
+ req.req8.partial_attribute_set_ex = NULL;
+ req.req8.mapping_ctr.num_mappings = 0;
+ req.req8.mapping_ctr.mappings = NULL;
+
+ r.in.bind_handle = &bi->rpc_handle;
+ r.in.level = 8;
+ r.in.req = &req;
+
+ ZERO_STRUCT(r.out);
+ r.out.level_out = &_level;
+ r.out.ctr = &ctr;
+
+ ZERO_STRUCT(ctr6);
+ do {
+ ZERO_STRUCT(ctr);
+
+ status = dcerpc_drsuapi_DsGetNCChanges_r(bi->drs_handle, mem_ctx, &r);
+ torture_drsuapi_assert_call(tctx, bi->drs_pipe, status,
+ &r, "dcerpc_drsuapi_DsGetNCChanges_r");
+
+ /* we expect to get level 6 reply */
+ torture_assert_int_equal(tctx, _level, 6, "Expected level 6 reply");
+
+ /* store this chunk for later use */
+ ctr6_chunk = &r.out.ctr->ctr6;
+
+ if (!ctr6.first_object) {
+ ctr6 = *ctr6_chunk;
+ } else {
+ struct drsuapi_DsReplicaObjectListItemEx *cur;
+
+ ctr6.object_count += ctr6_chunk->object_count;
+ for (cur = ctr6.first_object; cur->next_object; cur = cur->next_object) {}
+ cur->next_object = ctr6_chunk->first_object;
+
+ if (ctr6_chunk->linked_attributes_count != 0) {
+ uint32_t i;
+ ctr6.linked_attributes = talloc_realloc(mem_ctx, ctr6.linked_attributes,
+ struct drsuapi_DsReplicaLinkedAttribute,
+ ctr6.linked_attributes_count + ctr6_chunk->linked_attributes_count);
+ for (i = 0; i < ctr6_chunk->linked_attributes_count; i++) {
+ ctr6.linked_attributes[ctr6.linked_attributes_count++] = ctr6_chunk->linked_attributes[i];
+ }
+ }
+ }
+
+ /* prepare for next request */
+ r.in.req->req8.highwatermark = ctr6_chunk->new_highwatermark;
+
+ } while (ctr6_chunk->more_data);
+
+ *_ctr6 = talloc(mem_ctx, struct drsuapi_DsGetNCChangesCtr6);
+ torture_assert(mem_ctx, *_ctr6, "Not enough memory");
+ **_ctr6 = ctr6;
+
+ return true;
+}
+
+static char * _make_error_message(TALLOC_CTX *mem_ctx,
+ enum drsuapi_DsAttributeId drs_attid,
+ const struct dsdb_attribute *dsdb_attr,
+ const struct drsuapi_DsReplicaObjectIdentifier *identifier)
+{
+ return talloc_asprintf(mem_ctx, "\nInvalid ATTID for %1$s (%2$s)\n"
+ " drs_attid: %3$11d (0x%3$08X)\n"
+ " msDS_IntId: %4$11d (0x%4$08X)\n"
+ " attributeId_id: %5$11d (0x%5$08X)",
+ dsdb_attr->lDAPDisplayName,
+ identifier->dn,
+ drs_attid,
+ dsdb_attr->msDS_IntId,
+ dsdb_attr->attributeID_id);
+}
+
+/**
+ * Fetch Schema NC and check ATTID values returned.
+ * When Schema partition is replicated, ATTID
+ * should always be made using prefixMap
+ */
+static bool test_dsintid_schema(struct torture_context *tctx, struct DsIntIdTestCtx *ctx)
+{
+ uint32_t i;
+ const struct dsdb_schema *ldap_schema;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
+ const struct dsdb_attribute *dsdb_attr;
+ const struct drsuapi_DsReplicaAttribute *drs_attr;
+ const struct drsuapi_DsReplicaAttributeCtr *attr_ctr;
+ const struct drsuapi_DsReplicaObjectListItemEx *cur;
+ const struct drsuapi_DsReplicaLinkedAttribute *la;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(ctx);
+ torture_assert(tctx, mem_ctx, "Not enough memory");
+
+ /* fetch whole Schema partition */
+ torture_comment(tctx, "Fetch partition: %s\n", ctx->schema_dn);
+ if (!_test_GetNCChanges(tctx, &ctx->dsa_bind, ctx->schema_dn, mem_ctx, &ctr6)) {
+ torture_fail(tctx, "_test_GetNCChanges() failed");
+ }
+
+ /* load schema if not loaded yet */
+ torture_comment(tctx, "Loading schema...\n");
+ if (!drs_util_dsdb_schema_load_ldb(tctx, ctx->ldb, &ctr6->mapping_ctr, false)) {
+ torture_fail(tctx, "drs_util_dsdb_schema_load_ldb() failed");
+ }
+ ldap_schema = dsdb_get_schema(ctx->ldb, NULL);
+
+ /* verify ATTIDs fetched */
+ torture_comment(tctx, "Verify ATTIDs fetched\n");
+ for (cur = ctr6->first_object; cur; cur = cur->next_object) {
+ attr_ctr = &cur->object.attribute_ctr;
+ for (i = 0; i < attr_ctr->num_attributes; i++) {
+ drs_attr = &attr_ctr->attributes[i];
+ dsdb_attr = dsdb_attribute_by_attributeID_id(ldap_schema,
+ drs_attr->attid);
+
+ torture_assert(tctx,
+ drs_attr->attid == dsdb_attr->attributeID_id,
+ _make_error_message(ctx, drs_attr->attid,
+ dsdb_attr,
+ cur->object.identifier));
+ if (dsdb_attr->msDS_IntId) {
+ torture_assert(tctx,
+ drs_attr->attid != dsdb_attr->msDS_IntId,
+ _make_error_message(ctx, drs_attr->attid,
+ dsdb_attr,
+ cur->object.identifier));
+ }
+ }
+ }
+
+ /* verify ATTIDs for Linked Attributes */
+ torture_comment(tctx, "Verify ATTIDs for Linked Attributes (%u)\n",
+ ctr6->linked_attributes_count);
+ for (i = 0; i < ctr6->linked_attributes_count; i++) {
+ la = &ctr6->linked_attributes[i];
+ dsdb_attr = dsdb_attribute_by_attributeID_id(ldap_schema, la->attid);
+
+ torture_assert(tctx,
+ la->attid == dsdb_attr->attributeID_id,
+ _make_error_message(ctx, la->attid,
+ dsdb_attr,
+ la->identifier));
+ if (dsdb_attr->msDS_IntId) {
+ torture_assert(tctx,
+ la->attid != dsdb_attr->msDS_IntId,
+ _make_error_message(ctx, la->attid,
+ dsdb_attr,
+ la->identifier));
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/**
+ * Fetch non-Schema NC and check ATTID values returned.
+ * When non-Schema partition is replicated, ATTID
+ * should be msDS-IntId value for the attribute
+ * if this value exists
+ */
+static bool _test_dsintid(struct torture_context *tctx,
+ struct DsIntIdTestCtx *ctx,
+ const char *nc_dn_str)
+{
+ uint32_t i;
+ const struct dsdb_schema *ldap_schema;
+ struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
+ const struct dsdb_attribute *dsdb_attr;
+ const struct drsuapi_DsReplicaAttribute *drs_attr;
+ const struct drsuapi_DsReplicaAttributeCtr *attr_ctr;
+ const struct drsuapi_DsReplicaObjectListItemEx *cur;
+ const struct drsuapi_DsReplicaLinkedAttribute *la;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(ctx);
+ torture_assert(tctx, mem_ctx, "Not enough memory");
+
+ /* fetch whole Schema partition */
+ torture_comment(tctx, "Fetch partition: %s\n", nc_dn_str);
+ if (!_test_GetNCChanges(tctx, &ctx->dsa_bind, nc_dn_str, mem_ctx, &ctr6)) {
+ torture_fail(tctx, "_test_GetNCChanges() failed");
+ }
+
+ /* load schema if not loaded yet */
+ torture_comment(tctx, "Loading schema...\n");
+ if (!drs_util_dsdb_schema_load_ldb(tctx, ctx->ldb, &ctr6->mapping_ctr, false)) {
+ torture_fail(tctx, "drs_util_dsdb_schema_load_ldb() failed");
+ }
+ ldap_schema = dsdb_get_schema(ctx->ldb, NULL);
+
+ /* verify ATTIDs fetched */
+ torture_comment(tctx, "Verify ATTIDs fetched\n");
+ for (cur = ctr6->first_object; cur; cur = cur->next_object) {
+ attr_ctr = &cur->object.attribute_ctr;
+ for (i = 0; i < attr_ctr->num_attributes; i++) {
+ drs_attr = &attr_ctr->attributes[i];
+ dsdb_attr = dsdb_attribute_by_attributeID_id(ldap_schema,
+ drs_attr->attid);
+ if (dsdb_attr->msDS_IntId) {
+ torture_assert(tctx,
+ drs_attr->attid == dsdb_attr->msDS_IntId,
+ _make_error_message(ctx, drs_attr->attid,
+ dsdb_attr,
+ cur->object.identifier));
+ } else {
+ torture_assert(tctx,
+ drs_attr->attid == dsdb_attr->attributeID_id,
+ _make_error_message(ctx, drs_attr->attid,
+ dsdb_attr,
+ cur->object.identifier));
+ }
+ }
+ }
+
+ /* verify ATTIDs for Linked Attributes */
+ torture_comment(tctx, "Verify ATTIDs for Linked Attributes (%u)\n",
+ ctr6->linked_attributes_count);
+ for (i = 0; i < ctr6->linked_attributes_count; i++) {
+ la = &ctr6->linked_attributes[i];
+ dsdb_attr = dsdb_attribute_by_attributeID_id(ldap_schema, la->attid);
+
+ if (dsdb_attr->msDS_IntId) {
+ torture_assert(tctx,
+ la->attid == dsdb_attr->msDS_IntId,
+ _make_error_message(ctx, la->attid,
+ dsdb_attr,
+ la->identifier));
+ } else {
+ torture_assert(tctx,
+ la->attid == dsdb_attr->attributeID_id,
+ _make_error_message(ctx, la->attid,
+ dsdb_attr,
+ la->identifier));
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/**
+ * Fetch Domain NC and check ATTID values returned.
+ * When Domain partition is replicated, ATTID
+ * should be msDS-IntId value for the attribute
+ * if this value exists
+ */
+static bool test_dsintid_configuration(struct torture_context *tctx, struct DsIntIdTestCtx *ctx)
+{
+ return _test_dsintid(tctx, ctx, ctx->config_dn);
+}
+
+/**
+ * Fetch Configuration NC and check ATTID values returned.
+ * When Configuration partition is replicated, ATTID
+ * should be msDS-IntId value for the attribute
+ * if this value exists
+ */
+static bool test_dsintid_domain(struct torture_context *tctx, struct DsIntIdTestCtx *ctx)
+{
+ return _test_dsintid(tctx, ctx, ctx->domain_dn);
+}
+
+
+/**
+ * DSSYNC test case setup
+ */
+static bool torture_dsintid_tcase_setup(struct torture_context *tctx, void **data)
+{
+ bool bret;
+ struct DsIntIdTestCtx *ctx;
+
+ *data = ctx = _dsintid_create_context(tctx);
+ torture_assert(tctx, ctx, "test_create_context() failed");
+
+ bret = _test_DsaBind(tctx, ctx, ctx->creds,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8 |
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6,
+ &ctx->dsa_bind);
+ torture_assert(tctx, bret, "_test_DsaBind() failed");
+
+ bret = _test_LDAPBind(tctx, ctx, ctx->creds, ctx->ldap_url, &ctx->ldb);
+ torture_assert(tctx, bret, "_test_LDAPBind() failed");
+
+ bret = _test_provision(tctx, ctx);
+ torture_assert(tctx, bret, "_test_provision() failed");
+
+ return true;
+}
+
+/**
+ * DSSYNC test case cleanup
+ */
+static bool torture_dsintid_tcase_teardown(struct torture_context *tctx, void *data)
+{
+ struct DsIntIdTestCtx *ctx;
+ struct drsuapi_DsUnbind r;
+ struct policy_handle bind_handle;
+
+ ctx = talloc_get_type(data, struct DsIntIdTestCtx);
+
+ ZERO_STRUCT(r);
+ r.out.bind_handle = &bind_handle;
+
+ /* Release DRSUAPI handle */
+ r.in.bind_handle = &ctx->dsa_bind.rpc_handle;
+ dcerpc_drsuapi_DsUnbind_r(ctx->dsa_bind.drs_handle, ctx, &r);
+
+ talloc_free(ctx);
+
+ return true;
+}
+
+/**
+ * DSSYNC test case implementation
+ */
+void torture_drs_rpc_dsintid_tcase(struct torture_suite *suite)
+{
+ typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "msDSIntId");
+
+ torture_tcase_set_fixture(tcase,
+ torture_dsintid_tcase_setup,
+ torture_dsintid_tcase_teardown);
+
+ torture_tcase_add_simple_test(tcase, "Schema", (run_func)test_dsintid_schema);
+ torture_tcase_add_simple_test(tcase, "Configuration", (run_func)test_dsintid_configuration);
+ torture_tcase_add_simple_test(tcase, "Domain", (run_func)test_dsintid_domain);
+}
diff --git a/source4/torture/drs/unit/prefixmap_tests.c b/source4/torture/drs/unit/prefixmap_tests.c
new file mode 100644
index 0000000..35764cd
--- /dev/null
+++ b/source4/torture/drs/unit/prefixmap_tests.c
@@ -0,0 +1,900 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUAPI prefixMap unit tests
+
+ Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2009-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "torture/smbtorture.h"
+#include "dsdb/samdb/samdb.h"
+#include "torture/rpc/drsuapi.h"
+#include "torture/drs/proto.h"
+#include "param/param.h"
+#include "librpc/ndr/libndr.h"
+
+/**
+ * Private data to be shared among all test in Test case
+ */
+struct drsut_prefixmap_data {
+ struct dsdb_schema_prefixmap *pfm_new;
+ struct dsdb_schema_prefixmap *pfm_full;
+
+ /* default schemaInfo value to test with */
+ struct dsdb_schema_info *schi_default;
+
+ struct ldb_context *ldb_ctx;
+};
+
+/**
+ * Test-oid data structure
+ */
+struct drsut_pfm_oid_data {
+ uint32_t id;
+ const char *bin_oid;
+ const char *oid_prefix;
+};
+
+/**
+ * Default prefixMap initialization data.
+ * This prefixMap is what dsdb_schema_pfm_new() should return.
+ * Based on: MS-DRSR, 5.16.4 ATTRTYP-to-OID Conversion
+ * procedure NewPrefixTable( )
+ */
+static const struct drsut_pfm_oid_data _prefixmap_test_new_data[] = {
+ {.id=0x00000000, .bin_oid="5504", .oid_prefix="2.5.4"},
+ {.id=0x00000001, .bin_oid="5506", .oid_prefix="2.5.6"},
+ {.id=0x00000002, .bin_oid="2A864886F7140102", .oid_prefix="1.2.840.113556.1.2"},
+ {.id=0x00000003, .bin_oid="2A864886F7140103", .oid_prefix="1.2.840.113556.1.3"},
+ {.id=0x00000004, .bin_oid="6086480165020201", .oid_prefix="2.16.840.1.101.2.2.1"},
+ {.id=0x00000005, .bin_oid="6086480165020203", .oid_prefix="2.16.840.1.101.2.2.3"},
+ {.id=0x00000006, .bin_oid="6086480165020105", .oid_prefix="2.16.840.1.101.2.1.5"},
+ {.id=0x00000007, .bin_oid="6086480165020104", .oid_prefix="2.16.840.1.101.2.1.4"},
+ {.id=0x00000008, .bin_oid="5505", .oid_prefix="2.5.5"},
+ {.id=0x00000009, .bin_oid="2A864886F7140104", .oid_prefix="1.2.840.113556.1.4"},
+ {.id=0x0000000A, .bin_oid="2A864886F7140105", .oid_prefix="1.2.840.113556.1.5"},
+ {.id=0x00000013, .bin_oid="0992268993F22C64", .oid_prefix="0.9.2342.19200300.100"},
+ {.id=0x00000014, .bin_oid="6086480186F84203", .oid_prefix="2.16.840.1.113730.3"},
+ {.id=0x00000015, .bin_oid="0992268993F22C6401", .oid_prefix="0.9.2342.19200300.100.1"},
+ {.id=0x00000016, .bin_oid="6086480186F8420301", .oid_prefix="2.16.840.1.113730.3.1"},
+ {.id=0x00000017, .bin_oid="2A864886F7140105B658", .oid_prefix="1.2.840.113556.1.5.7000"},
+ {.id=0x00000018, .bin_oid="5515", .oid_prefix="2.5.21"},
+ {.id=0x00000019, .bin_oid="5512", .oid_prefix="2.5.18"},
+ {.id=0x0000001A, .bin_oid="5514", .oid_prefix="2.5.20"},
+};
+
+/**
+ * Data to be used for creating full prefix map for testing.
+ * 'full-prefixMap' is based on what w2k8 returns as a prefixMap
+ * on clean installation - i.e. prefixMap for clean Schema
+ */
+static const struct drsut_pfm_oid_data _prefixmap_full_map_data[] = {
+ {.id=0x00000000, .bin_oid="0x5504", .oid_prefix="2.5.4"},
+ {.id=0x00000001, .bin_oid="0x5506", .oid_prefix="2.5.6"},
+ {.id=0x00000002, .bin_oid="0x2A864886F7140102", .oid_prefix="1.2.840.113556.1.2"},
+ {.id=0x00000003, .bin_oid="0x2A864886F7140103", .oid_prefix="1.2.840.113556.1.3"},
+ {.id=0x00000004, .bin_oid="0x6086480165020201", .oid_prefix="2.16.840.1.101.2.2.1"},
+ {.id=0x00000005, .bin_oid="0x6086480165020203", .oid_prefix="2.16.840.1.101.2.2.3"},
+ {.id=0x00000006, .bin_oid="0x6086480165020105", .oid_prefix="2.16.840.1.101.2.1.5"},
+ {.id=0x00000007, .bin_oid="0x6086480165020104", .oid_prefix="2.16.840.1.101.2.1.4"},
+ {.id=0x00000008, .bin_oid="0x5505", .oid_prefix="2.5.5"},
+ {.id=0x00000009, .bin_oid="0x2A864886F7140104", .oid_prefix="1.2.840.113556.1.4"},
+ {.id=0x0000000a, .bin_oid="0x2A864886F7140105", .oid_prefix="1.2.840.113556.1.5"},
+ {.id=0x00000013, .bin_oid="0x0992268993F22C64", .oid_prefix="0.9.2342.19200300.100"},
+ {.id=0x00000014, .bin_oid="0x6086480186F84203", .oid_prefix="2.16.840.1.113730.3"},
+ {.id=0x00000015, .bin_oid="0x0992268993F22C6401", .oid_prefix="0.9.2342.19200300.100.1"},
+ {.id=0x00000016, .bin_oid="0x6086480186F8420301", .oid_prefix="2.16.840.1.113730.3.1"},
+ {.id=0x00000017, .bin_oid="0x2A864886F7140105B658", .oid_prefix="1.2.840.113556.1.5.7000"},
+ {.id=0x00000018, .bin_oid="0x5515", .oid_prefix="2.5.21"},
+ {.id=0x00000019, .bin_oid="0x5512", .oid_prefix="2.5.18"},
+ {.id=0x0000001a, .bin_oid="0x5514", .oid_prefix="2.5.20"},
+ {.id=0x0000000b, .bin_oid="0x2A864886F71401048204", .oid_prefix="1.2.840.113556.1.4.260"},
+ {.id=0x0000000c, .bin_oid="0x2A864886F714010538", .oid_prefix="1.2.840.113556.1.5.56"},
+ {.id=0x0000000d, .bin_oid="0x2A864886F71401048206", .oid_prefix="1.2.840.113556.1.4.262"},
+ {.id=0x0000000e, .bin_oid="0x2A864886F714010539", .oid_prefix="1.2.840.113556.1.5.57"},
+ {.id=0x0000000f, .bin_oid="0x2A864886F71401048207", .oid_prefix="1.2.840.113556.1.4.263"},
+ {.id=0x00000010, .bin_oid="0x2A864886F71401053A", .oid_prefix="1.2.840.113556.1.5.58"},
+ {.id=0x00000011, .bin_oid="0x2A864886F714010549", .oid_prefix="1.2.840.113556.1.5.73"},
+ {.id=0x00000012, .bin_oid="0x2A864886F71401048231", .oid_prefix="1.2.840.113556.1.4.305"},
+ {.id=0x0000001b, .bin_oid="0x2B060104018B3A6577", .oid_prefix="1.3.6.1.4.1.1466.101.119"},
+ {.id=0x0000001c, .bin_oid="0x6086480186F8420302", .oid_prefix="2.16.840.1.113730.3.2"},
+ {.id=0x0000001d, .bin_oid="0x2B06010401817A01", .oid_prefix="1.3.6.1.4.1.250.1"},
+ {.id=0x0000001e, .bin_oid="0x2A864886F70D0109", .oid_prefix="1.2.840.113549.1.9"},
+ {.id=0x0000001f, .bin_oid="0x0992268993F22C6404", .oid_prefix="0.9.2342.19200300.100.4"},
+ {.id=0x00000020, .bin_oid="0x2A864886F714010617", .oid_prefix="1.2.840.113556.1.6.23"},
+ {.id=0x00000021, .bin_oid="0x2A864886F71401061201", .oid_prefix="1.2.840.113556.1.6.18.1"},
+ {.id=0x00000022, .bin_oid="0x2A864886F71401061202", .oid_prefix="1.2.840.113556.1.6.18.2"},
+ {.id=0x00000023, .bin_oid="0x2A864886F71401060D03", .oid_prefix="1.2.840.113556.1.6.13.3"},
+ {.id=0x00000024, .bin_oid="0x2A864886F71401060D04", .oid_prefix="1.2.840.113556.1.6.13.4"},
+ {.id=0x00000025, .bin_oid="0x2B0601010101", .oid_prefix="1.3.6.1.1.1.1"},
+ {.id=0x00000026, .bin_oid="0x2B0601010102", .oid_prefix="1.3.6.1.1.1.2"},
+ {.id=0x000003ed, .bin_oid="0x2A864886F7140104B65866", .oid_prefix="1.2.840.113556.1.4.7000.102"},
+ {.id=0x00000428, .bin_oid="0x2A864886F7140105B6583E", .oid_prefix="1.2.840.113556.1.5.7000.62"},
+ {.id=0x0000044c, .bin_oid="0x2A864886F7140104B6586683", .oid_prefix="1.2.840.113556.1.4.7000.102:0x83"},
+ {.id=0x0000044f, .bin_oid="0x2A864886F7140104B6586681", .oid_prefix="1.2.840.113556.1.4.7000.102:0x81"},
+ {.id=0x0000047d, .bin_oid="0x2A864886F7140105B6583E81", .oid_prefix="1.2.840.113556.1.5.7000.62:0x81"},
+ {.id=0x00000561, .bin_oid="0x2A864886F7140105B6583E83", .oid_prefix="1.2.840.113556.1.5.7000.62:0x83"},
+ {.id=0x000007d1, .bin_oid="0x2A864886F71401061401", .oid_prefix="1.2.840.113556.1.6.20.1"},
+ {.id=0x000007e1, .bin_oid="0x2A864886F71401061402", .oid_prefix="1.2.840.113556.1.6.20.2"},
+ {.id=0x00001b86, .bin_oid="0x2A817A", .oid_prefix="1.2.250"},
+ {.id=0x00001c78, .bin_oid="0x2A817A81", .oid_prefix="1.2.250:0x81"},
+ {.id=0x00001c7b, .bin_oid="0x2A817A8180", .oid_prefix="1.2.250:0x8180"},
+};
+
+
+/**
+ * OID-to-ATTID mappings to be used for testing.
+ * An entry is marked as 'exists=true' if it exists in
+ * base prefixMap (_prefixmap_test_new_data)
+ */
+static const struct {
+ const char *oid;
+ uint32_t id;
+ uint32_t attid;
+ bool exists;
+} _prefixmap_test_data[] = {
+ {.oid="2.5.4.0", .id=0x00000000, .attid=0x000000, .exists=true},
+ {.oid="2.5.4.42", .id=0x00000000, .attid=0x00002a, .exists=true},
+ {.oid="1.2.840.113556.1.2.1", .id=0x00000002, .attid=0x020001, .exists=true},
+ {.oid="1.2.840.113556.1.2.13", .id=0x00000002, .attid=0x02000d, .exists=true},
+ {.oid="1.2.840.113556.1.2.281", .id=0x00000002, .attid=0x020119, .exists=true},
+ {.oid="1.2.840.113556.1.4.125", .id=0x00000009, .attid=0x09007d, .exists=true},
+ {.oid="1.2.840.113556.1.4.146", .id=0x00000009, .attid=0x090092, .exists=true},
+ {.oid="1.2.250.1", .id=0x00001b86, .attid=0x1b860001, .exists=false},
+ {.oid="1.2.250.16386", .id=0x00001c78, .attid=0x1c788002, .exists=false},
+ {.oid="1.2.250.2097154", .id=0x00001c7b, .attid=0x1c7b8002, .exists=false},
+};
+
+
+/**
+ * Creates dsdb_schema_prefixmap based on predefined data
+ */
+static WERROR _drsut_prefixmap_new(const struct drsut_pfm_oid_data *_pfm_init_data, uint32_t count,
+ TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap **_pfm)
+{
+ uint32_t i;
+ struct dsdb_schema_prefixmap *pfm;
+
+ pfm = talloc(mem_ctx, struct dsdb_schema_prefixmap);
+ W_ERROR_HAVE_NO_MEMORY(pfm);
+
+ pfm->length = count;
+ pfm->prefixes = talloc_array(pfm, struct dsdb_schema_prefixmap_oid, pfm->length);
+ if (!pfm->prefixes) {
+ talloc_free(pfm);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ for (i = 0; i < pfm->length; i++) {
+ pfm->prefixes[i].id = _pfm_init_data[i].id;
+ pfm->prefixes[i].bin_oid = strhex_to_data_blob(pfm, _pfm_init_data[i].bin_oid);
+ if (!pfm->prefixes[i].bin_oid.data) {
+ talloc_free(pfm);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ *_pfm = pfm;
+
+ return WERR_OK;
+}
+
+/**
+ * Compares two prefixMaps for being equal - same items on same indexes
+ */
+static bool _torture_drs_pfm_compare_same(struct torture_context *tctx,
+ const struct dsdb_schema_prefixmap *pfm_left,
+ const struct dsdb_schema_prefixmap *pfm_right,
+ bool quiet)
+{
+ uint32_t i;
+ char *err_msg = NULL;
+
+ if (pfm_left->length != pfm_right->length) {
+ err_msg = talloc_asprintf(tctx, "prefixMaps differ in size; left = %d, right = %d",
+ pfm_left->length, pfm_right->length);
+ goto failed;
+ }
+
+ for (i = 0; i < pfm_left->length; i++) {
+ struct dsdb_schema_prefixmap_oid *entry_left = &pfm_left->prefixes[i];
+ struct dsdb_schema_prefixmap_oid *entry_right = &pfm_right->prefixes[i];
+
+ if (entry_left->id != entry_right->id) {
+ err_msg = talloc_asprintf(tctx, "Different IDs for index=%d", i);
+ goto failed;
+ }
+ if (data_blob_cmp(&entry_left->bin_oid, &entry_right->bin_oid)) {
+ err_msg = talloc_asprintf(tctx, "Different bin_oid for index=%d", i);
+ goto failed;
+ }
+ }
+
+ return true;
+
+failed:
+ if (!quiet) {
+ torture_comment(tctx, "_torture_drs_pfm_compare_same: %s", err_msg);
+ }
+ talloc_free(err_msg);
+
+ return false;
+}
+
+/*
+ * Tests dsdb_schema_pfm_new()
+ */
+static bool torture_drs_unit_pfm_new(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ bool bret;
+ TALLOC_CTX *mem_ctx;
+ struct dsdb_schema_prefixmap *pfm = NULL;
+
+ mem_ctx = talloc_new(priv);
+
+ /* create new prefix map */
+ werr = dsdb_schema_pfm_new(mem_ctx, &pfm);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_new() failed!");
+ torture_assert(tctx, pfm != NULL, "NULL prefixMap created!");
+ torture_assert(tctx, pfm->length > 0, "Empty prefixMap created!");
+ torture_assert(tctx, pfm->prefixes != NULL, "No prefixes for newly created prefixMap!");
+
+ /* compare newly created prefixMap with template one */
+ bret = _torture_drs_pfm_compare_same(tctx, priv->pfm_new, pfm, false);
+
+ talloc_free(mem_ctx);
+
+ return bret;
+}
+
+/**
+ * Tests dsdb_schema_pfm_make_attid() using full prefixMap.
+ * In this test we know exactly which ATTID and prefixMap->ID
+ * should be returned, i.e. no prefixMap entries should be added.
+ */
+static bool torture_drs_unit_pfm_make_attid_full_map(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ uint32_t i, count;
+ uint32_t attid;
+ char *err_msg;
+
+ count = ARRAY_SIZE(_prefixmap_test_data);
+ for (i = 0; i < count; i++) {
+ werr = dsdb_schema_pfm_make_attid(priv->pfm_full, _prefixmap_test_data[i].oid, &attid);
+ /* prepare error message */
+ err_msg = talloc_asprintf(priv, "dsdb_schema_pfm_make_attid() failed with %s",
+ _prefixmap_test_data[i].oid);
+ torture_assert(tctx, err_msg, "Unexpected: Have no memory!");
+ /* verify result and returned ATTID */
+ torture_assert_werr_ok(tctx, werr, err_msg);
+ torture_assert_int_equal(tctx, attid, _prefixmap_test_data[i].attid, err_msg);
+ /* reclaim memory for prepared error message */
+ talloc_free(err_msg);
+ }
+
+ return true;
+}
+
+/**
+ * Tests dsdb_schema_pfm_make_attid() using initially small prefixMap.
+ * In this test we don't know exactly which ATTID and prefixMap->ID
+ * should be returned, but we can verify lo-word of ATTID.
+ * This test verifies implementation branch when a new
+ * prefix should be added into prefixMap.
+ */
+static bool torture_drs_unit_pfm_make_attid_small_map(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ uint32_t i, j;
+ uint32_t idx;
+ uint32_t attid, attid_2;
+ char *err_msg;
+ struct dsdb_schema_prefixmap *pfm = NULL;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(priv);
+
+ /* create new prefix map */
+ werr = dsdb_schema_pfm_new(mem_ctx, &pfm);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_new() failed!");
+
+ /* make some ATTIDs and check result */
+ for (i = 0; i < ARRAY_SIZE(_prefixmap_test_data); i++) {
+ werr = dsdb_schema_pfm_make_attid(pfm, _prefixmap_test_data[i].oid, &attid);
+
+ /* prepare error message */
+ err_msg = talloc_asprintf(mem_ctx, "dsdb_schema_pfm_make_attid() failed with %s",
+ _prefixmap_test_data[i].oid);
+ torture_assert(tctx, err_msg, "Unexpected: Have no memory!");
+
+ /* verify result and returned ATTID */
+ torture_assert_werr_ok(tctx, werr, err_msg);
+ /* verify ATTID lo-word */
+ torture_assert_int_equal(tctx, attid & 0xFFFF, _prefixmap_test_data[i].attid & 0xFFFF, err_msg);
+
+ /* try again, this time verify for whole ATTID */
+ werr = dsdb_schema_pfm_make_attid(pfm, _prefixmap_test_data[i].oid, &attid_2);
+ torture_assert_werr_ok(tctx, werr, err_msg);
+ torture_assert_int_equal(tctx, attid_2, attid, err_msg);
+
+ /* reclaim memory for prepared error message */
+ talloc_free(err_msg);
+
+ /* check there is such an index in modified prefixMap */
+ idx = (attid >> 16);
+ for (j = 0; j < pfm->length; j++) {
+ if (pfm->prefixes[j].id == idx)
+ break;
+ }
+ if (j >= pfm->length) {
+ torture_result(tctx, TORTURE_FAIL, __location__": No prefix for ATTID=0x%08X", attid);
+ return false;
+ }
+
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/**
+ * Tests dsdb_schema_pfm_attid_from_oid() using full prefixMap.
+ * In this test we know exactly which ATTID and prefixMap->ID
+ * should be returned- dsdb_schema_pfm_attid_from_oid() should succeed.
+ */
+static bool torture_drs_unit_pfm_attid_from_oid_full_map(struct torture_context *tctx,
+ struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ uint32_t i, count;
+ uint32_t attid;
+ char *err_msg;
+
+ count = ARRAY_SIZE(_prefixmap_test_data);
+ for (i = 0; i < count; i++) {
+ werr = dsdb_schema_pfm_attid_from_oid(priv->pfm_full,
+ _prefixmap_test_data[i].oid,
+ &attid);
+ /* prepare error message */
+ err_msg = talloc_asprintf(priv, "dsdb_schema_pfm_attid_from_oid() failed with %s",
+ _prefixmap_test_data[i].oid);
+ torture_assert(tctx, err_msg, "Unexpected: Have no memory!");
+ /* verify result and returned ATTID */
+ torture_assert_werr_ok(tctx, werr, err_msg);
+ torture_assert_int_equal(tctx, attid, _prefixmap_test_data[i].attid, err_msg);
+ /* reclaim memory for prepared error message */
+ talloc_free(err_msg);
+ }
+
+ return true;
+}
+
+/**
+ * Tests dsdb_schema_pfm_attid_from_oid() using base (initial) prefixMap.
+ * dsdb_schema_pfm_attid_from_oid() should fail when testing with OID
+ * that are not already in the prefixMap.
+ */
+static bool torture_drs_unit_pfm_attid_from_oid_base_map(struct torture_context *tctx,
+ struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ uint32_t i;
+ uint32_t attid;
+ char *err_msg;
+ struct dsdb_schema_prefixmap *pfm = NULL;
+ struct dsdb_schema_prefixmap pfm_prev;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(priv);
+ torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!");
+
+ /* create new prefix map */
+ werr = dsdb_schema_pfm_new(mem_ctx, &pfm);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_new() failed!");
+
+ /* keep initial pfm around for testing */
+ pfm_prev = *pfm;
+ pfm_prev.prefixes = talloc_reference(mem_ctx, pfm->prefixes);
+
+ /* get some ATTIDs and check result */
+ for (i = 0; i < ARRAY_SIZE(_prefixmap_test_data); i++) {
+ werr = dsdb_schema_pfm_attid_from_oid(pfm, _prefixmap_test_data[i].oid, &attid);
+
+ /* prepare error message */
+ err_msg = talloc_asprintf(mem_ctx,
+ "dsdb_schema_pfm_attid_from_oid() failed for %s",
+ _prefixmap_test_data[i].oid);
+ torture_assert(tctx, err_msg, "Unexpected: Have no memory!");
+
+
+ /* verify pfm hasn't been altered */
+ if (_prefixmap_test_data[i].exists) {
+ /* should succeed and return valid ATTID */
+ torture_assert_werr_ok(tctx, werr, err_msg);
+ /* verify ATTID */
+ torture_assert_int_equal(tctx,
+ attid, _prefixmap_test_data[i].attid,
+ err_msg);
+ } else {
+ /* should fail */
+ torture_assert_werr_equal(tctx, werr, WERR_NOT_FOUND, err_msg);
+ }
+
+ /* prefixMap should never be changed */
+ if (!_torture_drs_pfm_compare_same(tctx, &pfm_prev, pfm, true)) {
+ torture_fail(tctx, "schema->prefixmap has changed");
+ }
+
+ /* reclaim memory for prepared error message */
+ talloc_free(err_msg);
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/**
+ * Tests dsdb_schema_pfm_oid_from_attid() using full prefixMap.
+ */
+static bool torture_drs_unit_pfm_oid_from_attid(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ uint32_t i, count;
+ char *err_msg;
+ const char *oid;
+
+ count = ARRAY_SIZE(_prefixmap_test_data);
+ for (i = 0; i < count; i++) {
+ oid = NULL;
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, _prefixmap_test_data[i].attid,
+ priv, &oid);
+ /* prepare error message */
+ err_msg = talloc_asprintf(priv, "dsdb_schema_pfm_oid_from_attid() failed with 0x%08X",
+ _prefixmap_test_data[i].attid);
+ torture_assert(tctx, err_msg, "Unexpected: Have no memory!");
+ /* verify result and returned ATTID */
+ torture_assert_werr_ok(tctx, werr, err_msg);
+ torture_assert(tctx, oid, "dsdb_schema_pfm_oid_from_attid() returned NULL OID!!!");
+ torture_assert_str_equal(tctx, oid, _prefixmap_test_data[i].oid, err_msg);
+ /* reclaim memory for prepared error message */
+ talloc_free(err_msg);
+ /* free memory for OID */
+ talloc_free(discard_const(oid));
+ }
+
+ return true;
+}
+
+/**
+ * Tests dsdb_schema_pfm_oid_from_attid() for handling
+ * correctly different type of attid values.
+ * See: MS-ADTS, 3.1.1.2.6 ATTRTYP
+ */
+static bool torture_drs_unit_pfm_oid_from_attid_check_attid(struct torture_context *tctx,
+ struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ const char *oid;
+
+ /* Test with valid prefixMap attid */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x00010001, tctx, &oid);
+ torture_assert_werr_ok(tctx, werr, "Testing prefixMap type attid = 0x00010001");
+
+ /* Test with valid attid but invalid index */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x01110001, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE,
+ "Testing invalid-index attid = 0x01110001");
+
+ /* Test with attid in msDS-IntId range */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0x80000000, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing msDS-IntId type attid = 0x80000000");
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xBFFFFFFF, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing msDS-IntId type attid = 0xBFFFFFFF");
+
+ /* Test with attid in RESERVED range */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xC0000000, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing RESERVED type attid = 0xC0000000");
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFEFFFF, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing RESERVED type attid = 0xFFFEFFFF");
+
+ /* Test with attid in INTERNAL range */
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFF0000, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing INTERNAL type attid = 0xFFFF0000");
+ werr = dsdb_schema_pfm_oid_from_attid(priv->pfm_full, 0xFFFFFFFF, tctx, &oid);
+ torture_assert_werr_equal(tctx, werr, WERR_INVALID_PARAMETER,
+ "Testing INTERNAL type attid = 0xFFFFFFFF");
+
+ return true;
+}
+
+/**
+ * Test Schema prefixMap conversions to/from drsuapi prefixMap
+ * representation.
+ */
+static bool torture_drs_unit_pfm_to_from_drsuapi(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ struct dsdb_schema_info *schema_info;
+ DATA_BLOB schema_info_blob;
+ struct dsdb_schema_prefixmap *pfm;
+ struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!");
+
+ /* convert Schema_prefixMap to drsuapi_prefixMap */
+ werr = dsdb_drsuapi_pfm_from_schema_pfm(priv->pfm_full, priv->schi_default, mem_ctx, &ctr);
+ torture_assert_werr_ok(tctx, werr, "dsdb_drsuapi_pfm_from_schema_pfm() failed");
+ torture_assert(tctx, ctr && ctr->mappings, "drsuapi_prefixMap not constructed correctly");
+ torture_assert_int_equal(tctx, ctr->num_mappings, priv->pfm_full->length + 1,
+ "drs_mappings count does not match");
+ /* look for schema_info entry - it should be the last one */
+ schema_info_blob = data_blob_const(ctr->mappings[ctr->num_mappings - 1].oid.binary_oid,
+ ctr->mappings[ctr->num_mappings - 1].oid.length);
+ werr = dsdb_schema_info_from_blob(&schema_info_blob, tctx, &schema_info);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob failed");
+ torture_assert_int_equal(tctx, schema_info->revision, priv->schi_default->revision,
+ "schema_info (revision) not stored correctly or not last entry");
+ torture_assert(tctx, GUID_equal(&schema_info->invocation_id, &priv->schi_default->invocation_id),
+ "schema_info (invocation_id) not stored correctly or not last entry");
+
+ /* compare schema_prefixMap and drsuapi_prefixMap */
+ werr = dsdb_schema_pfm_contains_drsuapi_pfm(priv->pfm_full, ctr);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_contains_drsuapi_pfm() failed");
+
+ /* convert back drsuapi_prefixMap to schema_prefixMap */
+ werr = dsdb_schema_pfm_from_drsuapi_pfm(ctr, true, mem_ctx, &pfm, &schema_info);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_from_drsuapi_pfm() failed");
+ torture_assert_int_equal(tctx, schema_info->revision, priv->schi_default->revision,
+ "Fetched schema_info is different (revision)");
+ torture_assert(tctx, GUID_equal(&schema_info->invocation_id, &priv->schi_default->invocation_id),
+ "Fetched schema_info is different (invocation_id)");
+
+ /* compare against the original */
+ if (!_torture_drs_pfm_compare_same(tctx, priv->pfm_full, pfm, true)) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ /* test conversion with partial drsuapi_prefixMap */
+ ctr->num_mappings--;
+ werr = dsdb_schema_pfm_from_drsuapi_pfm(ctr, false, mem_ctx, &pfm, NULL);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_from_drsuapi_pfm() failed");
+ /* compare against the original */
+ if (!_torture_drs_pfm_compare_same(tctx, priv->pfm_full, pfm, false)) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+
+/**
+ * Test Schema prefixMap conversions to/from ldb_val
+ * blob representation.
+ */
+static bool torture_drs_unit_pfm_to_from_ldb_val(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ struct dsdb_schema *schema;
+ struct ldb_val pfm_ldb_val;
+ struct ldb_val schema_info_ldb_val;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!");
+
+ schema = dsdb_new_schema(mem_ctx);
+ torture_assert(tctx, schema, "Unexpected: failed to allocate schema object");
+
+ /* set priv->pfm_full as prefixMap for new schema object */
+ schema->prefixmap = priv->pfm_full;
+ schema->schema_info = priv->schi_default;
+
+ /* convert schema_prefixMap to ldb_val blob */
+ werr = dsdb_get_oid_mappings_ldb(schema, mem_ctx, &pfm_ldb_val, &schema_info_ldb_val);
+ torture_assert_werr_ok(tctx, werr, "dsdb_get_oid_mappings_ldb() failed");
+ torture_assert(tctx, pfm_ldb_val.data && pfm_ldb_val.length,
+ "pfm_ldb_val not constructed correctly");
+ torture_assert(tctx, schema_info_ldb_val.data && schema_info_ldb_val.length,
+ "schema_info_ldb_val not constructed correctly");
+
+ /* convert pfm_ldb_val back to schema_prefixMap */
+ schema->prefixmap = NULL;
+ schema->schema_info = NULL;
+ werr = dsdb_load_oid_mappings_ldb(schema, &pfm_ldb_val, &schema_info_ldb_val);
+ torture_assert_werr_ok(tctx, werr, "dsdb_load_oid_mappings_ldb() failed");
+ /* compare against the original */
+ if (!_torture_drs_pfm_compare_same(tctx, schema->prefixmap, priv->pfm_full, false)) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+ torture_assert_int_equal(tctx, schema->schema_info->revision, priv->schi_default->revision,
+ "Fetched schema_info is different (revision)");
+ torture_assert(tctx, GUID_equal(&schema->schema_info->invocation_id, &priv->schi_default->invocation_id),
+ "Fetched schema_info is different (invocation_id)");
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+/**
+ * Test read/write in ldb implementation
+ */
+static bool torture_drs_unit_pfm_read_write_ldb(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ struct dsdb_schema *schema;
+ struct dsdb_schema_prefixmap *pfm;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!");
+
+ /* makeup a dsdb_schema to test with */
+ schema = dsdb_new_schema(mem_ctx);
+ torture_assert(tctx, schema, "Unexpected: failed to allocate schema object");
+ /* set priv->pfm_full as prefixMap for new schema object */
+ schema->prefixmap = priv->pfm_full;
+ schema->schema_info = priv->schi_default;
+
+ /* write prfixMap to ldb */
+ werr = dsdb_write_prefixes_from_schema_to_ldb(mem_ctx, priv->ldb_ctx, schema);
+ torture_assert_werr_ok(tctx, werr, "dsdb_write_prefixes_from_schema_to_ldb() failed");
+
+ /* read from ldb what we have written */
+ werr = dsdb_read_prefixes_from_ldb(priv->ldb_ctx, mem_ctx, &pfm);
+ torture_assert_werr_ok(tctx, werr, "dsdb_read_prefixes_from_ldb() failed");
+
+ /* compare data written/read */
+ if (!_torture_drs_pfm_compare_same(tctx, schema->prefixmap, priv->pfm_full, false)) {
+ torture_fail(tctx, "prefixMap read/write in LDB is not consistent");
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/**
+ * Test dsdb_create_prefix_mapping
+ */
+static bool torture_drs_unit_dsdb_create_prefix_mapping(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ WERROR werr;
+ uint32_t i;
+ struct dsdb_schema *schema;
+ TALLOC_CTX *mem_ctx;
+ struct dsdb_schema_prefixmap *pfm_ldb = NULL;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert(tctx, mem_ctx, "Unexpected: Have no memory!");
+
+ /* makeup a dsdb_schema to test with */
+ schema = dsdb_new_schema(mem_ctx);
+ torture_assert(tctx, schema, "Unexpected: failed to allocate schema object");
+ /* set priv->pfm_full as prefixMap for new schema object */
+ schema->schema_info = priv->schi_default;
+ werr = _drsut_prefixmap_new(_prefixmap_test_new_data, ARRAY_SIZE(_prefixmap_test_new_data),
+ schema, &schema->prefixmap);
+ torture_assert_werr_ok(tctx, werr, "_drsut_prefixmap_new() failed");
+ /* write prfixMap to ldb */
+ werr = dsdb_write_prefixes_from_schema_to_ldb(mem_ctx, priv->ldb_ctx, schema);
+ torture_assert_werr_ok(tctx, werr, "dsdb_write_prefixes_from_schema_to_ldb() failed");
+
+ /* read from ldb what we have written */
+ werr = dsdb_read_prefixes_from_ldb(priv->ldb_ctx, mem_ctx, &pfm_ldb);
+ torture_assert_werr_ok(tctx, werr, "dsdb_read_prefixes_from_ldb() failed");
+ /* compare data written/read */
+ if (!_torture_drs_pfm_compare_same(tctx, schema->prefixmap, pfm_ldb, true)) {
+ torture_fail(tctx, "pfm in LDB is different");
+ }
+ TALLOC_FREE(pfm_ldb);
+
+ for (i = 0; i < ARRAY_SIZE(_prefixmap_test_data); i++) {
+ struct dsdb_schema_prefixmap *pfm_prev;
+ struct dsdb_schema_prefixmap *pfm_new;
+
+ pfm_prev = schema->prefixmap;
+
+ pfm_new = dsdb_schema_pfm_copy_shallow(schema, pfm_prev);
+ torture_assert(tctx, pfm_new != NULL, "dsdb_schema_pfm_copy_shallow() failed");
+
+ if (!_prefixmap_test_data[i].exists) {
+ uint32_t attid;
+
+ werr = dsdb_schema_pfm_make_attid(pfm_new,
+ _prefixmap_test_data[i].oid,
+ &attid);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_pfm_make_attid() failed");
+ }
+
+ /* call dsdb_create_prefix_mapping() and check result accordingly */
+ werr = dsdb_create_prefix_mapping(priv->ldb_ctx, schema, _prefixmap_test_data[i].oid);
+ torture_assert_werr_ok(tctx, werr, "dsdb_create_prefix_mapping() failed");
+
+ /*
+ * The prefix should not change, only on reload
+ */
+ torture_assert(tctx, pfm_prev == schema->prefixmap,
+ "schema->prefixmap has been reallocated!");
+ if (!_torture_drs_pfm_compare_same(tctx, pfm_prev, schema->prefixmap, true)) {
+ torture_fail(tctx, "schema->prefixmap has changed");
+ }
+
+ /* read from ldb what we have written */
+ werr = dsdb_read_prefixes_from_ldb(priv->ldb_ctx, mem_ctx, &pfm_ldb);
+ torture_assert_werr_ok(tctx, werr, "dsdb_read_prefixes_from_ldb() failed");
+ /* compare data written/read */
+ if (!_torture_drs_pfm_compare_same(tctx, pfm_new, pfm_ldb, true)) {
+ torture_fail(tctx, talloc_asprintf(tctx, "%u: pfm in LDB is different", i));
+ }
+ /* free mem for pfm read from LDB */
+ TALLOC_FREE(pfm_ldb);
+
+ /* prepare for the next round */
+ schema->prefixmap = pfm_new;
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/**
+ * Prepare temporary LDB and opens it
+ */
+static bool torture_drs_unit_ldb_setup(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ int ldb_err;
+ char *ldb_url;
+ bool bret = true;
+ TALLOC_CTX* mem_ctx;
+ char *tempdir;
+ NTSTATUS status;
+
+ mem_ctx = talloc_new(priv);
+
+ status = torture_temp_dir(tctx, "drs_", &tempdir);
+ torture_assert_ntstatus_ok(tctx, status, "creating temp dir");
+
+ ldb_url = talloc_asprintf(priv, "%s/drs_test.ldb", tempdir);
+
+ /* create LDB */
+ priv->ldb_ctx = ldb_init(priv, tctx->ev);
+ ldb_err = ldb_connect(priv->ldb_ctx, ldb_url, 0, NULL);
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, "ldb_connect() failed");
+
+ /* set some schemaNamingContext */
+ ldb_err = ldb_set_opaque(priv->ldb_ctx,
+ "schemaNamingContext",
+ ldb_dn_new(priv->ldb_ctx, priv->ldb_ctx, "CN=Schema,CN=Config"));
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, "ldb_set_opaque() failed");
+
+ /* add prefixMap attribute so tested layer could work properly */
+ {
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ msg->dn = ldb_get_schema_basedn(priv->ldb_ctx);
+ ldb_err = ldb_msg_add_string(msg, "prefixMap", "prefixMap");
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
+ "ldb_msg_add_string() failed");
+
+ ldb_err = ldb_add(priv->ldb_ctx, msg);
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE, "ldb_add() failed");
+ }
+
+DONE:
+ talloc_free(mem_ctx);
+ return bret;
+}
+
+/*
+ * Setup/Teardown for test case
+ */
+static bool torture_drs_unit_prefixmap_setup(struct torture_context *tctx, struct drsut_prefixmap_data **_priv)
+{
+ WERROR werr;
+ DATA_BLOB blob;
+ struct drsut_prefixmap_data *priv;
+
+ priv = *_priv = talloc_zero(tctx, struct drsut_prefixmap_data);
+ torture_assert(tctx, priv != NULL, "Not enough memory");
+
+ werr = _drsut_prefixmap_new(_prefixmap_test_new_data, ARRAY_SIZE(_prefixmap_test_new_data),
+ tctx, &priv->pfm_new);
+ torture_assert_werr_ok(tctx, werr, "failed to create pfm_new");
+
+ werr = _drsut_prefixmap_new(_prefixmap_full_map_data, ARRAY_SIZE(_prefixmap_full_map_data),
+ tctx, &priv->pfm_full);
+ torture_assert_werr_ok(tctx, werr, "failed to create pfm_test");
+
+ torture_assert(tctx, drsut_schemainfo_new(tctx, &priv->schi_default),
+ "drsut_schemainfo_new() failed");
+
+ werr = dsdb_blob_from_schema_info(priv->schi_default, priv, &blob);
+ torture_assert_werr_ok(tctx, werr, "dsdb_blob_from_schema_info() failed");
+
+ /* create temporary LDB and populate with data */
+ if (!torture_drs_unit_ldb_setup(tctx, priv)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool torture_drs_unit_prefixmap_teardown(struct torture_context *tctx, struct drsut_prefixmap_data *priv)
+{
+ talloc_free(priv);
+
+ return true;
+}
+
+/**
+ * Test case initialization for
+ * drs.unit.prefixMap
+ */
+struct torture_tcase * torture_drs_unit_prefixmap(struct torture_suite *suite)
+{
+ typedef bool (*pfn_setup)(struct torture_context *, void **);
+ typedef bool (*pfn_teardown)(struct torture_context *, void *);
+ typedef bool (*pfn_run)(struct torture_context *, void *);
+
+ struct torture_tcase * tc = torture_suite_add_tcase(suite, "prefixMap");
+
+ torture_tcase_set_fixture(tc,
+ (pfn_setup)torture_drs_unit_prefixmap_setup,
+ (pfn_teardown)torture_drs_unit_prefixmap_teardown);
+
+ tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::prefixMap implementation");
+
+ torture_tcase_add_simple_test(tc, "new", (pfn_run)torture_drs_unit_pfm_new);
+
+ torture_tcase_add_simple_test(tc, "make_attid_full_map", (pfn_run)torture_drs_unit_pfm_make_attid_full_map);
+ torture_tcase_add_simple_test(tc, "make_attid_small_map", (pfn_run)torture_drs_unit_pfm_make_attid_small_map);
+
+ torture_tcase_add_simple_test(tc, "attid_from_oid_full_map",
+ (pfn_run)torture_drs_unit_pfm_attid_from_oid_full_map);
+ torture_tcase_add_simple_test(tc, "attid_from_oid_empty_map",
+ (pfn_run)torture_drs_unit_pfm_attid_from_oid_base_map);
+
+ torture_tcase_add_simple_test(tc, "oid_from_attid_full_map", (pfn_run)torture_drs_unit_pfm_oid_from_attid);
+ torture_tcase_add_simple_test(tc, "oid_from_attid_check_attid",
+ (pfn_run)torture_drs_unit_pfm_oid_from_attid_check_attid);
+
+ torture_tcase_add_simple_test(tc, "pfm_to_from_drsuapi", (pfn_run)torture_drs_unit_pfm_to_from_drsuapi);
+
+ torture_tcase_add_simple_test(tc, "pfm_to_from_ldb_val", (pfn_run)torture_drs_unit_pfm_to_from_ldb_val);
+
+ torture_tcase_add_simple_test(tc, "pfm_read_write_ldb", (pfn_run)torture_drs_unit_pfm_read_write_ldb);
+
+ torture_tcase_add_simple_test(tc, "dsdb_create_prefix_mapping", (pfn_run)torture_drs_unit_dsdb_create_prefix_mapping);
+
+ return tc;
+}
diff --git a/source4/torture/drs/unit/schemainfo_tests.c b/source4/torture/drs/unit/schemainfo_tests.c
new file mode 100644
index 0000000..4b4cca6
--- /dev/null
+++ b/source4/torture/drs/unit/schemainfo_tests.c
@@ -0,0 +1,740 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUAPI schemaInfo unit tests
+
+ Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "torture/smbtorture.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/samdb/ldb_modules/util.h"
+#include "ldb_wrap.h"
+#include <ldb_module.h>
+#include "torture/rpc/drsuapi.h"
+#include "librpc/ndr/libndr.h"
+#include "param/param.h"
+#include "torture/drs/proto.h"
+#include "torture/drs/proto.h"
+
+
+/**
+ * schemaInfo to init ldb context with
+ * Rev: 0
+ * GUID: 00000000-0000-0000-0000-000000000000
+ */
+#define SCHEMA_INFO_INIT_STR "FF0000000000000000000000000000000000000000"
+
+/**
+ * Default schema_info string to be used for testing
+ * Rev: 01
+ * GUID: 071c82fd-45c7-4351-a3db-51f75a630a7f
+ */
+#define SCHEMA_INFO_DEFAULT_STR "FF00000001FD821C07C7455143A3DB51F75A630A7F"
+
+/**
+ * Schema info data to test with
+ */
+struct schemainfo_data {
+ DATA_BLOB ndr_blob;
+ struct dsdb_schema_info schi;
+ WERROR werr_expected;
+ bool test_both_ways;
+};
+
+/**
+ * Schema info test data in human-readable format (... kind of)
+ */
+static const struct {
+ const char *schema_info_str;
+ uint32_t revision;
+ const char *guid_str;
+ WERROR werr_expected;
+ bool test_both_ways;
+} _schemainfo_test_data[] = {
+ {
+ .schema_info_str = "FF0000000000000000000000000000000000000000",
+ .revision = 0,
+ .guid_str = "00000000-0000-0000-0000-000000000000",
+ .werr_expected = WERR_OK,
+ .test_both_ways = true
+ },
+ {
+ .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F",
+ .revision = 1,
+ .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
+ .werr_expected = WERR_OK,
+ .test_both_ways = true
+ },
+ {
+ .schema_info_str = "FFFFFFFFFFFD821C07C7455143A3DB51F75A630A7F",
+ .revision = 0xFFFFFFFF,
+ .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
+ .werr_expected = WERR_OK,
+ .test_both_ways = true
+ },
+ { /* len == 21 */
+ .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F00",
+ .revision = 1,
+ .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
+ .werr_expected = WERR_INVALID_PARAMETER,
+ .test_both_ways = false
+ },
+ { /* marker == FF */
+ .schema_info_str = "AA00000001FD821C07C7455143A3DB51F75A630A7F",
+ .revision = 1,
+ .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
+ .werr_expected = WERR_INVALID_PARAMETER,
+ .test_both_ways = false
+ }
+};
+
+/**
+ * Private data to be shared among all test in Test case
+ */
+struct drsut_schemainfo_data {
+ struct ldb_context *ldb;
+ struct ldb_module *ldb_module;
+ struct dsdb_schema *schema;
+
+ /* Initial schemaInfo set in ldb to test with */
+ struct dsdb_schema_info *schema_info;
+
+ uint32_t test_data_count;
+ struct schemainfo_data *test_data;
+};
+
+/**
+ * torture macro to assert for equal dsdb_schema_info's
+ */
+#define torture_assert_schema_info_equal(torture_ctx,got,expected,cmt)\
+ do { const struct dsdb_schema_info *__got = (got), *__expected = (expected); \
+ if (__got->revision != __expected->revision) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got".revision %d did not match "#expected".revision %d: %s", \
+ (int)__got->revision, (int)__expected->revision, cmt); \
+ return false; \
+ } \
+ if (!GUID_equal(&__got->invocation_id, &__expected->invocation_id)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, \
+ __location__": "#got".invocation_id did not match "#expected".invocation_id: %s", cmt); \
+ return false; \
+ } \
+ } while(0)
+
+/*
+ * forward declaration for internal functions
+ */
+static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
+ struct ldb_context *ldb,
+ const char *schema_info_str,
+ bool in_setup);
+
+
+/**
+ * Creates dsdb_schema_info object based on NDR data
+ * passed as hex string
+ */
+static bool _drsut_schemainfo_new(struct torture_context *tctx,
+ const char *schema_info_str, struct dsdb_schema_info **_si)
+{
+ WERROR werr;
+ DATA_BLOB blob;
+
+ blob = strhex_to_data_blob(tctx, schema_info_str);
+ if (!blob.data) {
+ torture_comment(tctx, "Not enough memory!\n");
+ return false;
+ }
+
+ werr = dsdb_schema_info_from_blob(&blob, tctx, _si);
+ if (!W_ERROR_IS_OK(werr)) {
+ torture_comment(tctx,
+ "Failed to create dsdb_schema_info object for %s: %s",
+ schema_info_str,
+ win_errstr(werr));
+ return false;
+ }
+
+ data_blob_free(&blob);
+
+ return true;
+}
+
+/**
+ * Creates dsdb_schema_info object based on predefined data
+ * Function is public as it is intended to be used by other
+ * tests (e.g. prefixMap tests)
+ */
+bool drsut_schemainfo_new(struct torture_context *tctx, struct dsdb_schema_info **_si)
+{
+ return _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, _si);
+}
+
+
+/*
+ * Tests dsdb_schema_info_new() and dsdb_schema_info_blob_new()
+ */
+static bool test_dsdb_schema_info_new(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ WERROR werr;
+ DATA_BLOB ndr_blob;
+ DATA_BLOB ndr_blob_expected;
+ struct dsdb_schema_info *schi;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(priv);
+ torture_assert(tctx, mem_ctx, "Not enough memory!");
+ ndr_blob_expected = strhex_to_data_blob(mem_ctx, SCHEMA_INFO_INIT_STR);
+ torture_assert(tctx, ndr_blob_expected.data, "Not enough memory!");
+
+ werr = dsdb_schema_info_new(mem_ctx, &schi);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_new() failed");
+ torture_assert_int_equal(tctx, schi->revision, 0,
+ "dsdb_schema_info_new() creates schemaInfo with invalid revision");
+ torture_assert(tctx, GUID_all_zero(&schi->invocation_id),
+ "dsdb_schema_info_new() creates schemaInfo with not ZERO GUID");
+
+ werr = dsdb_schema_info_blob_new(mem_ctx, &ndr_blob);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_blob_new() failed");
+ torture_assert_data_blob_equal(tctx, ndr_blob, ndr_blob_expected,
+ "dsdb_schema_info_blob_new() returned invalid blob");
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+/*
+ * Tests dsdb_schema_info_from_blob()
+ */
+static bool test_dsdb_schema_info_from_blob(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ uint32_t i;
+ WERROR werr;
+ char *msg;
+ struct dsdb_schema_info *schema_info;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(priv);
+ torture_assert(tctx, mem_ctx, "Not enough memory!");
+
+ for (i = 0; i < priv->test_data_count; i++) {
+ struct schemainfo_data *data = &priv->test_data[i];
+
+ msg = talloc_asprintf(tctx, "dsdb_schema_info_from_blob() [%d]-[%s]",
+ i, _schemainfo_test_data[i].schema_info_str);
+
+ werr = dsdb_schema_info_from_blob(&data->ndr_blob, mem_ctx, &schema_info);
+ torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
+
+ /* test returned data */
+ if (W_ERROR_IS_OK(werr)) {
+ torture_assert_schema_info_equal(tctx,
+ schema_info, &data->schi,
+ "after dsdb_schema_info_from_blob() call");
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+/*
+ * Tests dsdb_blob_from_schema_info()
+ */
+static bool test_dsdb_blob_from_schema_info(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ uint32_t i;
+ WERROR werr;
+ char *msg;
+ DATA_BLOB ndr_blob;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(priv);
+ torture_assert(tctx, mem_ctx, "Not enough memory!");
+
+ for (i = 0; i < priv->test_data_count; i++) {
+ struct schemainfo_data *data = &priv->test_data[i];
+
+ /* not all test are valid reverse type of conversion */
+ if (!data->test_both_ways) {
+ continue;
+ }
+
+ msg = talloc_asprintf(tctx, "dsdb_blob_from_schema_info() [%d]-[%s]",
+ i, _schemainfo_test_data[i].schema_info_str);
+
+ werr = dsdb_blob_from_schema_info(&data->schi, mem_ctx, &ndr_blob);
+ torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
+
+ /* test returned data */
+ if (W_ERROR_IS_OK(werr)) {
+ torture_assert_data_blob_equal(tctx,
+ ndr_blob, data->ndr_blob,
+ "dsdb_blob_from_schema_info()");
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+static bool test_dsdb_schema_info_cmp(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ DATA_BLOB blob;
+ struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;
+ struct dsdb_schema_info schema_info;
+
+ ctr = talloc_zero(priv, struct drsuapi_DsReplicaOIDMapping_Ctr);
+ torture_assert(tctx, ctr, "Not enough memory!");
+
+ /* not enough elements */
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_INVALID_PARAMETER,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* an empty element for schemaInfo */
+ ctr->num_mappings = 1;
+ ctr->mappings = talloc_zero_array(ctr, struct drsuapi_DsReplicaOIDMapping, 1);
+ torture_assert(tctx, ctr->mappings, "Not enough memory!");
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_INVALID_PARAMETER,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with invalid schemaInfo - length != 21 */
+ blob = strhex_to_data_blob(ctr, "FF00000001FD821C07C7455143A3DB51F75A630A7F00");
+ torture_assert(tctx, blob.data, "Not enough memory!");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_INVALID_PARAMETER,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with invalid schemaInfo - marker != 0xFF */
+ blob = strhex_to_data_blob(ctr, "AA00000001FD821C07C7455143A3DB51F75A630A7F");
+ torture_assert(tctx, blob.data, "Not enough memory!");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_INVALID_PARAMETER,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo, but older one should be ok */
+ blob = strhex_to_data_blob(ctr, "FF0000000000000000000000000000000000000000");
+ torture_assert(tctx, blob.data, "Not enough memory!");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_OK,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with correct schemaInfo, but invalid ATTID */
+ schema_info = *priv->schema->schema_info;
+ torture_assert_werr_ok(tctx,
+ dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
+ "dsdb_blob_from_schema_info() failed");
+ ctr->mappings[0].id_prefix = 1;
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_INVALID_PARAMETER,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo */
+ ctr->mappings[0].id_prefix = 0;
+ torture_assert_werr_ok(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo, but older revision */
+ schema_info = *priv->schema->schema_info;
+ schema_info.revision -= 1;
+ torture_assert_werr_ok(tctx,
+ dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
+ "dsdb_blob_from_schema_info() failed");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_OK,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo, but newer revision */
+ schema_info = *priv->schema->schema_info;
+ schema_info.revision += 1;
+ torture_assert_werr_ok(tctx,
+ dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
+ "dsdb_blob_from_schema_info() failed");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_DS_DRA_SCHEMA_MISMATCH,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo, but newer revision and other invocationId */
+ schema_info = *priv->schema->schema_info;
+ schema_info.revision += 1;
+ schema_info.invocation_id.time_mid += 1;
+ torture_assert_werr_ok(tctx,
+ dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
+ "dsdb_blob_from_schema_info() failed");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_DS_DRA_SCHEMA_MISMATCH,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo, but older revision and other invocationId */
+ schema_info = *priv->schema->schema_info;
+ schema_info.revision -= 1;
+ schema_info.invocation_id.time_mid += 1;
+ torture_assert_werr_ok(tctx,
+ dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
+ "dsdb_blob_from_schema_info() failed");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_OK,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ /* test with valid schemaInfo, but same revision and other invocationId */
+ schema_info = *priv->schema->schema_info;
+ schema_info.invocation_id.time_mid += 1;
+ torture_assert_werr_ok(tctx,
+ dsdb_blob_from_schema_info(&schema_info, tctx, &blob),
+ "dsdb_blob_from_schema_info() failed");
+ ctr->mappings[0].oid.length = blob.length;
+ ctr->mappings[0].oid.binary_oid = blob.data;
+ torture_assert_werr_equal(tctx,
+ dsdb_schema_info_cmp(priv->schema, ctr),
+ WERR_DS_DRA_SCHEMA_CONFLICT,
+ "dsdb_schema_info_cmp(): unexpected result");
+
+ talloc_free(ctr);
+ return true;
+}
+
+/*
+ * Tests dsdb_module_schema_info_blob_read()
+ * and dsdb_module_schema_info_blob_write()
+ */
+static bool test_dsdb_module_schema_info_blob_rw(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ int ldb_err;
+ DATA_BLOB blob_write;
+ DATA_BLOB blob_read;
+
+ /* reset schmeInfo to know value */
+ torture_assert(tctx,
+ _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
+ "_drsut_ldb_schema_info_reset() failed");
+
+ /* write tests' default schemaInfo */
+ blob_write = strhex_to_data_blob(priv, SCHEMA_INFO_DEFAULT_STR);
+ torture_assert(tctx, blob_write.data, "Not enough memory!");
+
+ ldb_err = dsdb_module_schema_info_blob_write(priv->ldb_module,
+ DSDB_FLAG_TOP_MODULE,
+ &blob_write, NULL);
+ torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_write() failed");
+
+ ldb_err = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
+ priv, &blob_read, NULL);
+ torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_read() failed");
+
+ /* check if we get what we wrote */
+ torture_assert_data_blob_equal(tctx, blob_read, blob_write,
+ "Write/Read of schemeInfo blob failed");
+
+ return true;
+}
+
+/*
+ * Tests dsdb_schema_update_schema_info()
+ */
+static bool test_dsdb_module_schema_info_update(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ int ldb_err;
+ WERROR werr;
+ DATA_BLOB blob;
+ struct dsdb_schema_info *schema_info;
+
+ /* reset schmeInfo to know value */
+ torture_assert(tctx,
+ _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
+ "_drsut_ldb_schema_info_reset() failed");
+
+ ldb_err = dsdb_module_schema_info_update(priv->ldb_module,
+ priv->schema,
+ DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM, NULL);
+ torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_update() failed");
+
+ /* get updated schemaInfo */
+ ldb_err = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
+ priv, &blob, NULL);
+ torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "dsdb_module_schema_info_blob_read() failed");
+
+ werr = dsdb_schema_info_from_blob(&blob, priv, &schema_info);
+ torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob() failed");
+
+ /* check against default schema_info */
+ torture_assert_schema_info_equal(tctx, schema_info, priv->schema_info,
+ "schemaInfo attribute no updated correctly");
+
+ return true;
+}
+
+
+/**
+ * Reset schemaInfo record to know value
+ */
+static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
+ struct ldb_context *ldb,
+ const char *schema_info_str,
+ bool in_setup)
+{
+ bool bret = true;
+ int ldb_err;
+ DATA_BLOB blob;
+ struct ldb_message *msg;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+
+ blob = strhex_to_data_blob(mem_ctx, schema_info_str);
+ torture_assert_goto(tctx, blob.data, bret, DONE, "Not enough memory!");
+
+ msg = ldb_msg_new(mem_ctx);
+ torture_assert_goto(tctx, msg, bret, DONE, "Not enough memory!");
+
+ msg->dn = ldb_get_schema_basedn(ldb);
+ ldb_err = ldb_msg_add_value(msg, "schemaInfo", &blob, NULL);
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
+ "ldb_msg_add_value() failed");
+
+ if (in_setup) {
+ ldb_err = ldb_add(ldb, msg);
+ } else {
+ ldb_err = dsdb_replace(ldb, msg, DSDB_MODIFY_PERMISSIVE);
+ }
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
+ "dsdb_replace() failed");
+
+DONE:
+ talloc_free(mem_ctx);
+ return bret;
+}
+
+/**
+ * Prepare temporary LDB and opens it
+ */
+static bool _drsut_ldb_setup(struct torture_context *tctx, struct drsut_schemainfo_data *priv)
+{
+ int ldb_err;
+ char *ldb_url;
+ bool bret = true;
+ char *tempdir = NULL;
+ NTSTATUS status;
+ TALLOC_CTX* mem_ctx;
+
+ mem_ctx = talloc_new(priv);
+ torture_assert(tctx, mem_ctx, "Not enough memory!");
+
+ status = torture_temp_dir(tctx, "drs_", &tempdir);
+ torture_assert_ntstatus_ok_goto(tctx, status, bret, DONE, "creating temp dir");
+
+ ldb_url = talloc_asprintf(priv, "%s/drs_schemainfo.ldb", tempdir);
+ torture_assert_goto(tctx, ldb_url, bret, DONE, "Not enough memory!");
+
+ /* create LDB */
+ priv->ldb = ldb_wrap_connect(priv, tctx->ev, tctx->lp_ctx,
+ ldb_url, NULL, NULL, 0);
+ torture_assert_goto(tctx, priv->ldb, bret, DONE, "ldb_wrap_connect() failed");
+
+ /* set some schemaNamingContext */
+ ldb_err = ldb_set_opaque(priv->ldb,
+ "schemaNamingContext",
+ ldb_dn_new(priv->ldb, priv->ldb, "CN=Schema,CN=Config"));
+ torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
+ "ldb_set_opaque() failed");
+
+ /* add schemaInfo attribute so tested layer could work properly */
+ torture_assert_goto(tctx,
+ _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, true),
+ bret, DONE,
+ "_drsut_ldb_schema_info_reset() failed");
+
+DONE:
+ talloc_free(tempdir);
+ talloc_free(mem_ctx);
+ return bret;
+}
+
+/*
+ * Setup/Teardown for test case
+ */
+static bool torture_drs_unit_schemainfo_setup(struct torture_context *tctx,
+ struct drsut_schemainfo_data **_priv)
+{
+ size_t i;
+ int ldb_err;
+ NTSTATUS status;
+ DATA_BLOB ndr_blob;
+ struct GUID guid;
+ struct drsut_schemainfo_data *priv;
+
+ priv = talloc_zero(tctx, struct drsut_schemainfo_data);
+ torture_assert(tctx, priv, "Not enough memory!");
+
+ /* returned allocated pointer here
+ * teardown() will be called even in case of failure,
+ * so we'll get a changes to clean up */
+ *_priv = priv;
+
+ /* create initial schemaInfo */
+ torture_assert(tctx,
+ _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema_info),
+ "Failed to create schema_info test object");
+
+ /* create data to test with */
+ priv->test_data_count = ARRAY_SIZE(_schemainfo_test_data);
+ priv->test_data = talloc_array(tctx, struct schemainfo_data, priv->test_data_count);
+
+ for (i = 0; i < ARRAY_SIZE(_schemainfo_test_data); i++) {
+ struct schemainfo_data *data = &priv->test_data[i];
+
+ ndr_blob = strhex_to_data_blob(priv,
+ _schemainfo_test_data[i].schema_info_str);
+ torture_assert(tctx, ndr_blob.data, "Not enough memory!");
+
+ status = GUID_from_string(_schemainfo_test_data[i].guid_str, &guid);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx,
+ "GUID_from_string() failed for %s",
+ _schemainfo_test_data[i].guid_str));
+
+ data->ndr_blob = ndr_blob;
+ data->schi.invocation_id = guid;
+ data->schi.revision = _schemainfo_test_data[i].revision;
+ data->werr_expected = _schemainfo_test_data[i].werr_expected;
+ data->test_both_ways = _schemainfo_test_data[i].test_both_ways;
+
+ }
+
+ /* create temporary LDB and populate with data */
+ if (!_drsut_ldb_setup(tctx, priv)) {
+ return false;
+ }
+
+ /* create ldb_module mockup object */
+ priv->ldb_module = ldb_module_new(priv, priv->ldb, "schemaInfo_test_module", NULL);
+ torture_assert(tctx, priv->ldb_module, "Not enough memory!");
+
+ /* create schema mockup object */
+ priv->schema = dsdb_new_schema(priv);
+
+ /* set schema_info in dsdb_schema for testing */
+ torture_assert(tctx,
+ _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema->schema_info),
+ "Failed to create schema_info test object");
+
+ /* pre-cache invocationId for samdb_ntds_invocation_id()
+ * to work with our mock ldb */
+ ldb_err = ldb_set_opaque(priv->ldb, "cache.invocation_id",
+ &priv->schema_info->invocation_id);
+ torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "ldb_set_opaque() failed");
+
+ /* Perform all tests in transactions so that
+ * underlying modify calls not to fail */
+ ldb_err = ldb_transaction_start(priv->ldb);
+ torture_assert_int_equal(tctx,
+ ldb_err,
+ LDB_SUCCESS,
+ "ldb_transaction_start() failed");
+
+ return true;
+}
+
+static bool torture_drs_unit_schemainfo_teardown(struct torture_context *tctx,
+ struct drsut_schemainfo_data *priv)
+{
+ int ldb_err;
+
+ /* commit pending transaction so we will
+ * be able to check what LDB state is */
+ ldb_err = ldb_transaction_commit(priv->ldb);
+ if (ldb_err != LDB_SUCCESS) {
+ torture_comment(tctx, "ldb_transaction_commit() - %s (%s)",
+ ldb_strerror(ldb_err),
+ ldb_errstring(priv->ldb));
+ }
+
+ talloc_free(priv);
+
+ return true;
+}
+
+/**
+ * Test case initialization for
+ * drs.unit.schemaInfo
+ */
+struct torture_tcase * torture_drs_unit_schemainfo(struct torture_suite *suite)
+{
+ typedef bool (*pfn_setup)(struct torture_context *, void **);
+ typedef bool (*pfn_teardown)(struct torture_context *, void *);
+ typedef bool (*pfn_run)(struct torture_context *, void *);
+
+ struct torture_tcase * tc = torture_suite_add_tcase(suite, "schemaInfo");
+
+ torture_tcase_set_fixture(tc,
+ (pfn_setup)torture_drs_unit_schemainfo_setup,
+ (pfn_teardown)torture_drs_unit_schemainfo_teardown);
+
+ tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::schemaInfo implementation");
+
+ torture_tcase_add_simple_test(tc, "dsdb_schema_info_new",
+ (pfn_run)test_dsdb_schema_info_new);
+ torture_tcase_add_simple_test(tc, "dsdb_schema_info_from_blob",
+ (pfn_run)test_dsdb_schema_info_from_blob);
+ torture_tcase_add_simple_test(tc, "dsdb_blob_from_schema_info",
+ (pfn_run)test_dsdb_blob_from_schema_info);
+ torture_tcase_add_simple_test(tc, "dsdb_schema_info_cmp",
+ (pfn_run)test_dsdb_schema_info_cmp);
+ torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_blob read|write",
+ (pfn_run)test_dsdb_module_schema_info_blob_rw);
+ torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_update",
+ (pfn_run)test_dsdb_module_schema_info_update);
+
+
+ return tc;
+}
diff --git a/source4/torture/drs/wscript_build b/source4/torture/drs/wscript_build
new file mode 100644
index 0000000..0dc26d6
--- /dev/null
+++ b/source4/torture/drs/wscript_build
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_DRS',
+ source='drs_init.c drs_util.c unit/prefixmap_tests.c unit/schemainfo_tests.c rpc/dssync.c rpc/msds_intid.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_drs_init',
+ deps='samba-util ldb samba-errors torture ldbsamba talloc dcerpc ndr NDR_DRSUAPI gensec samba-hostconfig RPC_NDR_DRSUAPI DSDB_MODULE_HELPERS asn1util samdb NDR_DRSBLOBS samba-credentials samdb-common LIBCLI_RESOLVE LP_RESOLVE torturemain',
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c
new file mode 100644
index 0000000..a832c59
--- /dev/null
+++ b/source4/torture/gentest.c
@@ -0,0 +1,3463 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ generic testing tool - version with both SMB and SMB2 support
+
+ Copyright (C) Andrew Tridgell 2003-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "lib/events/events.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/raw/request.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/resolve/resolve.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+#include "dynconfig/dynconfig.h"
+#include "libcli/security/security.h"
+#include "libcli/raw/raw_proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+#define NSERVERS 2
+#define NINSTANCES 2
+
+/* global options */
+static struct gentest_options {
+ int showall;
+ int analyze;
+ int analyze_always;
+ int analyze_continuous;
+ unsigned int max_open_handles;
+ unsigned int seed;
+ unsigned int numops;
+ int use_oplocks;
+ char **ignore_patterns;
+ const char *seeds_file;
+ int use_preset_seeds;
+ int fast_reconnect;
+ int mask_indexing;
+ int no_eas;
+ int no_acls;
+ int skip_cleanup;
+ int valid;
+ int smb2;
+} options;
+
+/* mapping between open handles on the server and local handles */
+static struct {
+ bool active;
+ unsigned int instance;
+ struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */
+ uint16_t smb_handle[NSERVERS]; /* SMB */
+ const char *name;
+} *open_handles;
+static unsigned int num_open_handles;
+
+/* state information for the servers. We open NINSTANCES connections to
+ each server */
+static struct {
+ struct smb2_tree *smb2_tree[NINSTANCES];
+ struct smbcli_tree *smb_tree[NINSTANCES];
+ char *server_name;
+ char *share_name;
+ struct cli_credentials *credentials;
+} servers[NSERVERS];
+
+/* the seeds and flags for each operation */
+static struct {
+ unsigned int seed;
+ bool disabled;
+} *op_parms;
+
+
+/* oplock break info */
+static struct {
+ bool got_break;
+ struct smb2_handle smb2_handle;
+ uint16_t smb_handle;
+ uint16_t handle;
+ uint8_t level;
+ bool do_close;
+} oplocks[NSERVERS][NINSTANCES];
+
+/* change notify reply info */
+static struct {
+ int notify_count;
+ NTSTATUS status;
+ union smb_notify notify;
+} notifies[NSERVERS][NINSTANCES];
+
+/* info relevant to the current operation */
+static struct {
+ const char *name;
+ unsigned int seed;
+ NTSTATUS status;
+ unsigned int opnum;
+ TALLOC_CTX *mem_ctx;
+ const char *mismatch;
+} current_op;
+
+static struct smb2_handle bad_smb2_handle;
+
+
+#define BAD_HANDLE 0xFFFE
+
+static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle,
+ uint8_t level, void *private_data);
+static void idle_func_smb2(struct smb2_transport *transport, void *private_data);
+static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private_data);
+static void idle_func_smb(struct smbcli_transport *transport, void *private_data);
+
+/*
+ check if a string should be ignored. This is used as the basis
+ for all error ignore settings
+*/
+static bool ignore_pattern(const char *str)
+{
+ int i;
+ if (!options.ignore_patterns) return false;
+
+ for (i=0;options.ignore_patterns[i];i++) {
+ if (strcmp(options.ignore_patterns[i], str) == 0 ||
+ gen_fnmatch(options.ignore_patterns[i], str) == 0) {
+ DEBUG(2,("Ignoring '%s'\n", str));
+ return true;
+ }
+ }
+ return false;
+}
+
+/*****************************************************
+connect to the servers
+*******************************************************/
+static bool connect_servers_fast(void)
+{
+ int h, i;
+
+ /* close all open files */
+ for (h=0;h<options.max_open_handles;h++) {
+ if (!open_handles[h].active) continue;
+ for (i=0;i<NSERVERS;i++) {
+ NTSTATUS status;
+ if (options.smb2) {
+ status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance],
+ open_handles[h].smb2_handle[i]);
+ } else {
+ status = smbcli_close(servers[i].smb_tree[open_handles[h].instance],
+ open_handles[h].smb_handle[i]);
+ }
+ if (NT_STATUS_IS_ERR(status)) {
+ return false;
+ }
+ open_handles[h].active = false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+/*****************************************************
+connect to the servers
+*******************************************************/
+static bool connect_servers(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx)
+{
+ int i, j;
+
+ if (options.fast_reconnect && servers[0].smb2_tree[0]) {
+ if (connect_servers_fast()) {
+ return true;
+ }
+ }
+
+ /* close any existing connections */
+ for (i=0;i<NSERVERS;i++) {
+ for (j=0;j<NINSTANCES;j++) {
+ if (servers[i].smb2_tree[j]) {
+ smb2_tdis(servers[i].smb2_tree[j]);
+ talloc_free(servers[i].smb2_tree[j]);
+ servers[i].smb2_tree[j] = NULL;
+ }
+ if (servers[i].smb_tree[j]) {
+ smb_tree_disconnect(servers[i].smb_tree[j]);
+ talloc_free(servers[i].smb_tree[j]);
+ servers[i].smb_tree[j] = NULL;
+ }
+ }
+ }
+
+ for (i=0;i<NSERVERS;i++) {
+ for (j=0;j<NINSTANCES;j++) {
+ NTSTATUS status;
+ struct smbcli_options smb_options;
+ struct smbcli_session_options smb_session_options;
+ lpcfg_smbcli_options(lp_ctx, &smb_options);
+ lpcfg_smbcli_session_options(lp_ctx, &smb_session_options);
+
+ printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
+ servers[i].server_name, servers[i].share_name,
+ cli_credentials_get_username(servers[i].credentials),
+ j);
+
+ cli_credentials_set_workstation(servers[i].credentials,
+ "gentest", CRED_SPECIFIED);
+
+ if (options.smb2) {
+ status = smb2_connect(NULL, servers[i].server_name,
+ lpcfg_smb_ports(lp_ctx),
+ servers[i].share_name,
+ lpcfg_resolve_context(lp_ctx),
+ servers[i].credentials,
+ &servers[i].smb2_tree[j],
+ ev, &smb_options,
+ lpcfg_socket_options(lp_ctx),
+ lpcfg_gensec_settings(lp_ctx, lp_ctx)
+ );
+ } else {
+ status = smbcli_tree_full_connection(NULL,
+ &servers[i].smb_tree[j],
+ servers[i].server_name,
+ lpcfg_smb_ports(lp_ctx),
+ servers[i].share_name, "A:",
+ lpcfg_socket_options(lp_ctx),
+ servers[i].credentials,
+ lpcfg_resolve_context(lp_ctx), ev,
+ &smb_options,
+ &smb_session_options,
+ lpcfg_gensec_settings(lp_ctx, lp_ctx));
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect to \\\\%s\\%s - %s\n",
+ servers[i].server_name, servers[i].share_name,
+ nt_errstr(status));
+ return false;
+ }
+
+ if (options.smb2) {
+ servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2;
+ servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j);
+ smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport,
+ idle_func_smb2, 50000, NULL);
+ } else {
+ smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb,
+ (void *)(uintptr_t)((i<<8)|j));
+ smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb,
+ 50000, (void *)(uintptr_t)((i<<8)|j));
+ }
+ }
+ }
+
+ return true;
+}
+
+/*
+ work out the time skew between the servers - be conservative
+*/
+static unsigned int time_skew(void)
+{
+ unsigned int ret;
+ NTTIME nt0, nt1;
+
+ if (options.smb2) {
+ struct smbXcli_conn *c0, *c1;
+
+ c0 = servers[0].smb2_tree[0]->session->transport->conn;
+ c1 = servers[1].smb2_tree[0]->session->transport->conn;
+
+ nt0 = smbXcli_conn_server_system_time(c0);
+ nt1 = smbXcli_conn_server_system_time(c1);
+ } else {
+ nt0 = servers[0].smb_tree[0]->session->transport->negotiate.server_time;
+ nt1 = servers[1].smb_tree[0]->session->transport->negotiate.server_time;
+ }
+ /* Samba's NTTIME is unsigned, abs() won't work! */
+ if (nt0 > nt1){
+ ret = nt0 - nt1;
+ } else {
+ ret = nt1 - nt0;
+ }
+ return ret + 300;
+}
+
+
+static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2)
+{
+ return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0;
+}
+
+/*
+ turn a server handle into a local handle
+*/
+static unsigned int fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle)
+{
+ unsigned int i;
+ for (i=0;i<options.max_open_handles;i++) {
+ if (!open_handles[i].active ||
+ instance != open_handles[i].instance) continue;
+ if (smb2_handle_equal(&open_handles[i].smb2_handle[server], &server_handle)) {
+ return i;
+ }
+ }
+ printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
+ server, instance);
+ return BAD_HANDLE;
+}
+
+/*
+ turn a server handle into a local handle
+*/
+static unsigned int fnum_to_handle_smb(int server, int instance, uint16_t server_handle)
+{
+ unsigned int i;
+ for (i=0;i<options.max_open_handles;i++) {
+ if (!open_handles[i].active ||
+ instance != open_handles[i].instance) continue;
+ if (open_handles[i].smb_handle[server] == server_handle) {
+ return i;
+ }
+ }
+ printf("Invalid server handle in fnum_to_handle on server %d instance %d\n",
+ server, instance);
+ return BAD_HANDLE;
+}
+
+/*
+ add some newly opened handles
+*/
+static void gen_add_handle_smb2(int instance, const char *name, struct smb2_handle handles[NSERVERS])
+{
+ int i, h;
+ for (h=0;h<options.max_open_handles;h++) {
+ if (!open_handles[h].active) break;
+ }
+ if (h == options.max_open_handles) {
+ /* we have to force close a random handle */
+ h = random() % options.max_open_handles;
+ for (i=0;i<NSERVERS;i++) {
+ NTSTATUS status;
+ status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance],
+ open_handles[h].smb2_handle[i]);
+ if (NT_STATUS_IS_ERR(status)) {
+ printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
+ nt_errstr(status));
+ }
+ }
+ printf("Recovered handle %d\n", h);
+ num_open_handles--;
+ }
+ for (i=0;i<NSERVERS;i++) {
+ open_handles[h].smb2_handle[i] = handles[i];
+ open_handles[h].instance = instance;
+ open_handles[h].active = true;
+ open_handles[h].name = name;
+ }
+ num_open_handles++;
+
+ printf("OPEN num_open_handles=%d h=%d (%s)\n",
+ num_open_handles, h, name);
+}
+
+/*
+ add some newly opened handles
+*/
+static void gen_add_handle_smb(int instance, const char *name, uint16_t handles[NSERVERS])
+{
+ int i, h;
+ for (h=0;h<options.max_open_handles;h++) {
+ if (!open_handles[h].active) break;
+ }
+ if (h == options.max_open_handles) {
+ /* we have to force close a random handle */
+ h = random() % options.max_open_handles;
+ for (i=0;i<NSERVERS;i++) {
+ NTSTATUS status;
+ status = smbcli_close(servers[i].smb_tree[open_handles[h].instance],
+ open_handles[h].smb_handle[i]);
+ if (NT_STATUS_IS_ERR(status)) {
+ printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
+ nt_errstr(status));
+ }
+ }
+ printf("Recovered handle %d\n", h);
+ num_open_handles--;
+ }
+ for (i=0;i<NSERVERS;i++) {
+ open_handles[h].smb_handle[i] = handles[i];
+ open_handles[h].instance = instance;
+ open_handles[h].active = true;
+ open_handles[h].name = name;
+ }
+ num_open_handles++;
+
+ printf("OPEN num_open_handles=%d h=%d (%s)\n",
+ num_open_handles, h, name);
+}
+
+
+/*
+ remove a closed handle
+*/
+static void gen_remove_handle_smb2(int instance, struct smb2_handle handles[NSERVERS])
+{
+ int h;
+ for (h=0;h<options.max_open_handles;h++) {
+ if (instance == open_handles[h].instance &&
+ smb2_handle_equal(&open_handles[h].smb2_handle[0], &handles[0])) {
+ open_handles[h].active = false;
+ num_open_handles--;
+ printf("CLOSE num_open_handles=%d h=%d (%s)\n",
+ num_open_handles, h,
+ open_handles[h].name);
+ return;
+ }
+ }
+ printf("Removing invalid handle!?\n");
+ exit(1);
+}
+
+/*
+ remove a closed handle
+*/
+static void gen_remove_handle_smb(int instance, uint16_t handles[NSERVERS])
+{
+ int h;
+ for (h=0;h<options.max_open_handles;h++) {
+ if (instance == open_handles[h].instance &&
+ open_handles[h].smb_handle[0] == handles[0]) {
+ open_handles[h].active = false;
+ num_open_handles--;
+ printf("CLOSE num_open_handles=%d h=%d (%s)\n",
+ num_open_handles, h,
+ open_handles[h].name);
+ return;
+ }
+ }
+ printf("Removing invalid handle!?\n");
+ exit(1);
+}
+
+/*
+ return true with 'chance' probability as a percentage
+*/
+static bool gen_chance(unsigned int chance)
+{
+ return ((random() % 100) <= chance);
+}
+
+/*
+ map an internal handle number to a server handle
+*/
+static struct smb2_handle gen_lookup_handle_smb2(int server, uint16_t handle)
+{
+ if (handle == BAD_HANDLE) return bad_smb2_handle;
+ return open_handles[handle].smb2_handle[server];
+}
+
+/*
+ map an internal handle number to a server handle
+*/
+static uint16_t gen_lookup_handle_smb(int server, uint16_t handle)
+{
+ if (handle == BAD_HANDLE) return BAD_HANDLE;
+ return open_handles[handle].smb_handle[server];
+}
+
+/*
+ return a file handle
+*/
+static uint16_t gen_fnum(int instance)
+{
+ uint16_t h;
+ int count = 0;
+
+ if (gen_chance(20)) return BAD_HANDLE;
+
+ while (num_open_handles > 0 && count++ < 10*options.max_open_handles) {
+ h = random() % options.max_open_handles;
+ if (open_handles[h].active &&
+ open_handles[h].instance == instance) {
+ return h;
+ }
+ }
+ return BAD_HANDLE;
+}
+
+/*
+ return a file handle, but skewed so we don't close the last
+ couple of handles too readily
+*/
+static uint16_t gen_fnum_close(int instance)
+{
+ if (num_open_handles < 5) {
+ if (gen_chance(90)) return BAD_HANDLE;
+ }
+
+ return gen_fnum(instance);
+}
+
+/*
+ generate an integer in a specified range
+*/
+static int gen_int_range(uint64_t min, uint64_t max)
+{
+ unsigned int r = random();
+ return min + (r % (1+max-min));
+}
+
+/*
+ return a fnum for use as a root fid
+ be careful to call GEN_SET_FNUM() when you use this!
+*/
+static uint16_t gen_root_fid(int instance)
+{
+ if (gen_chance(5)) return gen_fnum(instance);
+ return 0;
+}
+
+/*
+ generate a file offset
+*/
+static int gen_offset(void)
+{
+ if (gen_chance(20)) return 0;
+// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
+ return gen_int_range(0, 1024*1024);
+}
+
+/*
+ generate a io count
+*/
+static int gen_io_count(void)
+{
+ if (gen_chance(20)) return 0;
+// if (gen_chance(5)) return gen_int_range(0, 0xFFFFFFFF);
+ return gen_int_range(0, 4096);
+}
+
+/*
+ generate a filename
+*/
+static const char *gen_fname(void)
+{
+ const char *names[] = {"gentest\\gentest.dat",
+ "gentest\\foo",
+ "gentest\\foo2.sym",
+ "gentest\\foo3.dll",
+ "gentest\\foo4",
+ "gentest\\foo4:teststream1",
+ "gentest\\foo4:teststream2",
+ "gentest\\foo5.exe",
+ "gentest\\foo5.exe:teststream3",
+ "gentest\\foo5.exe:teststream4",
+ "gentest\\foo6.com",
+ "gentest\\blah",
+ "gentest\\blah\\blergh.txt",
+ "gentest\\blah\\blergh2",
+ "gentest\\blah\\blergh3.txt",
+ "gentest\\blah\\blergh4",
+ "gentest\\blah\\blergh5.txt",
+ "gentest\\blah\\blergh5",
+ "gentest\\blah\\.",
+ "gentest\\blah\\..",
+ "gentest\\a_very_long_name.bin",
+ "gentest\\x.y",
+ "gentest\\blah"};
+ int i;
+
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(names)-1);
+ } while (ignore_pattern(names[i]));
+
+ return names[i];
+}
+
+/*
+ generate a filename with a higher chance of choosing an already
+ open file
+*/
+static const char *gen_fname_open(int instance)
+{
+ uint16_t h;
+ h = gen_fnum(instance);
+ if (h == BAD_HANDLE) {
+ return gen_fname();
+ }
+ return open_handles[h].name;
+}
+
+/*
+ generate a wildcard pattern
+*/
+static const char *gen_pattern(void)
+{
+ int i;
+ const char *names[] = {"gentest\\*.dat",
+ "gentest\\*",
+ "gentest\\*.*",
+ "gentest\\blah\\*.*",
+ "gentest\\blah\\*",
+ "gentest\\?"};
+
+ if (gen_chance(50)) return gen_fname();
+
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(names)-1);
+ } while (ignore_pattern(names[i]));
+
+ return names[i];
+}
+
+static uint32_t gen_bits_levels(int nlevels, ...)
+{
+ va_list ap;
+ uint32_t pct;
+ uint32_t mask;
+ int i;
+ va_start(ap, nlevels);
+ for (i=0;i<nlevels;i++) {
+ pct = va_arg(ap, uint32_t);
+ mask = va_arg(ap, uint32_t);
+ if (pct == 100 || gen_chance(pct)) {
+ va_end(ap);
+ return mask & random();
+ }
+ }
+ va_end(ap);
+ return 0;
+}
+
+/*
+ generate a bitmask
+*/
+static uint32_t gen_bits_mask(unsigned int mask)
+{
+ unsigned int ret = random();
+ return ret & mask;
+}
+
+/*
+ generate a bitmask with high probability of the first mask
+ and low of the second
+*/
+static uint32_t gen_bits_mask2(uint32_t mask1, uint32_t mask2)
+{
+ if (!options.valid && gen_chance(10)) return gen_bits_mask(mask2);
+ return gen_bits_mask(mask1);
+}
+
+/*
+ generate reserved values
+ */
+static uint64_t gen_reserved8(void)
+{
+ if (options.valid) return 0;
+ return gen_bits_mask(0xFF);
+}
+
+static uint64_t gen_reserved16(void)
+{
+ if (options.valid) return 0;
+ return gen_bits_mask(0xFFFF);
+}
+
+static uint64_t gen_reserved32(void)
+{
+ if (options.valid) return 0;
+ return gen_bits_mask(0xFFFFFFFF);
+}
+
+static uint64_t gen_reserved64(void)
+{
+ if (options.valid) return 0;
+ return gen_bits_mask(0xFFFFFFFF) | (((uint64_t)gen_bits_mask(0xFFFFFFFF))<<32);
+}
+
+
+
+/*
+ generate a boolean
+*/
+static bool gen_bool(void)
+{
+ return gen_bits_mask2(0x1, 0xFF);
+}
+
+/*
+ generate ntrename flags
+*/
+static uint16_t gen_rename_flags(void)
+{
+ if (gen_chance(30)) return RENAME_FLAG_RENAME;
+ if (gen_chance(30)) return RENAME_FLAG_HARD_LINK;
+ if (gen_chance(30)) return RENAME_FLAG_COPY;
+ return gen_bits_mask(0xFFFF);
+}
+
+/*
+ generate a pid
+*/
+static uint16_t gen_pid(void)
+{
+ if (gen_chance(10)) return gen_bits_mask(0xFFFF);
+ return getpid();
+}
+
+/*
+ return a set of lock flags
+*/
+static uint16_t gen_lock_flags_smb2(void)
+{
+ if (!options.valid && gen_chance(5)) return gen_bits_mask(0xFFFF);
+ if (gen_chance(20)) return gen_bits_mask(0x1F);
+ if (gen_chance(50)) return SMB2_LOCK_FLAG_UNLOCK;
+ return gen_bits_mask(SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY);
+}
+
+/*
+ generate a lock count
+*/
+static off_t gen_lock_count(void)
+{
+ return gen_int_range(0, 3);
+}
+
+/*
+ generate a NT access mask
+*/
+static uint32_t gen_access_mask(void)
+{
+ uint32_t ret;
+ if (gen_chance(70)) return SEC_FLAG_MAXIMUM_ALLOWED;
+ if (gen_chance(70)) return SEC_FILE_ALL;
+ ret = gen_bits_mask(0xFFFFFFFF);
+ if (options.valid) ret &= ~SEC_MASK_INVALID;
+ return ret;
+}
+
+/*
+ return a lockingx lock mode
+*/
+static uint16_t gen_lock_mode(void)
+{
+ if (!options.valid && gen_chance(5)) return gen_bits_mask(0xFFFF);
+ if (gen_chance(20)) return gen_bits_mask(0x1F);
+ return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES);
+}
+
+/*
+ generate a ntcreatex flags field
+*/
+static uint32_t gen_ntcreatex_flags(void)
+{
+ if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED;
+ return gen_bits_mask2(0x1F, 0xFFFFFFFF);
+}
+
+/*
+ generate a ntcreatex create options bitfield
+*/
+static uint32_t gen_create_options(void)
+{
+ if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
+ if (gen_chance(50)) return 0;
+ return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE | NTCREATEX_OPTIONS_DIRECTORY);
+}
+
+/*
+ generate a ntcreatex open disposition
+*/
+static uint32_t gen_open_disp(void)
+{
+ if (gen_chance(50)) return NTCREATEX_DISP_OPEN_IF;
+ if (!options.valid && gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
+ return gen_int_range(0, 5);
+}
+
+/*
+ generate an openx open mode
+*/
+static uint16_t gen_openx_mode(void)
+{
+ if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
+ if (gen_chance(20)) return gen_bits_mask(0xFF);
+ return OPENX_MODE_DENY_NONE | gen_bits_mask(0x3);
+}
+
+/*
+ generate an openx flags field
+*/
+static uint16_t gen_openx_flags(void)
+{
+ if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
+ return gen_bits_mask(0x7);
+}
+
+/*
+ generate an openx open function
+*/
+static uint16_t gen_openx_func(void)
+{
+ if (!options.valid && gen_chance(20)) return gen_bits_mask(0xFFFF);
+ return gen_bits_mask(0x13);
+}
+
+/*
+ generate a file attrib combination
+*/
+static uint32_t gen_attrib(void)
+{
+ uint32_t ret;
+ if (gen_chance(20)) {
+ ret = gen_bits_mask(0xFFFFFFFF);
+ if (options.valid) ret &= FILE_ATTRIBUTE_ALL_MASK;
+ return ret;
+ }
+ return gen_bits_mask(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
+}
+
+/*
+ generate a unix timestamp
+*/
+static time_t gen_timet(void)
+{
+ if (gen_chance(30)) return 0;
+ return (time_t)random();
+}
+
+/*
+ generate a milliseconds protocol timeout
+*/
+static uint32_t gen_timeout(void)
+{
+ if (gen_chance(98)) return 0;
+ return random() % 50;
+}
+
+/*
+ generate a timestamp
+*/
+static NTTIME gen_nttime(void)
+{
+ NTTIME ret;
+ unix_to_nt_time(&ret, gen_timet());
+ return ret;
+}
+
+/*
+ generate a timewarp value
+*/
+static NTTIME gen_timewarp(void)
+{
+ NTTIME ret = gen_nttime();
+ if (gen_chance(98)) ret = 0;
+ return ret;
+}
+
+/*
+ generate a file allocation size
+*/
+static unsigned int gen_alloc_size(void)
+{
+ unsigned int ret;
+
+ if (gen_chance(30)) return 0;
+
+ ret = random() % 4*1024*1024;
+ /* give a high chance of a round number */
+ if (gen_chance(60)) {
+ ret &= ~(1024*1024 - 1);
+ }
+ return ret;
+}
+
+/*
+ generate an ea_struct
+*/
+static struct ea_struct gen_ea_struct(void)
+{
+ struct ea_struct ea;
+ const char *names[] = {"EAONE",
+ "",
+ "FOO!",
+ " WITH SPACES ",
+ ".",
+ "AVERYLONGATTRIBUTENAME"};
+ const char *values[] = {"VALUE1",
+ "",
+ "NOT MUCH FOO",
+ " LEADING SPACES ",
+ ":",
+ "ASOMEWHATLONGERATTRIBUTEVALUE"};
+ int i;
+
+ ZERO_STRUCT(ea);
+
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(names)-1);
+ } while (ignore_pattern(names[i]));
+
+ ea.name.s = names[i];
+
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(values)-1);
+ } while (ignore_pattern(values[i]));
+
+ ea.value = data_blob(values[i], strlen(values[i]));
+
+ if (gen_chance(10)) ea.flags = gen_bits_mask(0xFF);
+ ea.flags = 0;
+
+ return ea;
+}
+
+/*
+ generate an ea_struct
+*/
+static struct smb_ea_list gen_ea_list(void)
+{
+ struct smb_ea_list eas;
+ int i;
+ if (options.no_eas) {
+ ZERO_STRUCT(eas);
+ return eas;
+ }
+ eas.num_eas = gen_int_range(0, 3);
+ eas.eas = talloc_array(current_op.mem_ctx, struct ea_struct, eas.num_eas);
+ for (i=0;i<eas.num_eas;i++) {
+ eas.eas[i] = gen_ea_struct();
+ }
+ return eas;
+}
+
+/* generate a security descriptor */
+static struct security_descriptor *gen_sec_desc(void)
+{
+ struct security_descriptor *sd;
+ if (options.no_acls || gen_chance(90)) return NULL;
+
+ sd = security_descriptor_dacl_create(current_op.mem_ctx,
+ 0, NULL, NULL,
+ NULL,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ return sd;
+}
+
+
+static void oplock_handler_close_recv_smb(struct smbcli_request *req)
+{
+ NTSTATUS status;
+ status = smbcli_request_simple_recv(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("close failed in oplock_handler\n");
+ smb_panic("close failed in oplock_handler");
+ }
+}
+
+/*
+ the oplock handler will either ack the break or close the file
+*/
+static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private_data)
+{
+ union smb_close io;
+ int i, j;
+ bool do_close;
+ struct smbcli_tree *tree = NULL;
+ struct smbcli_request *req;
+
+ srandom(current_op.seed);
+ do_close = gen_chance(50);
+
+ for (i=0;i<NSERVERS;i++) {
+ for (j=0;j<NINSTANCES;j++) {
+ if (transport == servers[i].smb_tree[j]->session->transport &&
+ tid == servers[i].smb_tree[j]->tid) {
+ oplocks[i][j].got_break = true;
+ oplocks[i][j].smb_handle = fnum;
+ oplocks[i][j].handle = fnum_to_handle_smb(i, j, fnum);
+ oplocks[i][j].level = level;
+ oplocks[i][j].do_close = do_close;
+ tree = servers[i].smb_tree[j];
+ }
+ }
+ }
+
+ if (!tree) {
+ printf("Oplock break not for one of our trees!?\n");
+ return false;
+ }
+
+ if (!do_close) {
+ printf("oplock ack fnum=%d\n", fnum);
+ return smbcli_oplock_ack(tree, fnum, level);
+ }
+
+ printf("oplock close fnum=%d\n", fnum);
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.file.fnum = fnum;
+ io.close.in.write_time = 0;
+ req = smb_raw_close_send(tree, &io);
+
+ if (req == NULL) {
+ printf("WARNING: close failed in oplock_handler_close\n");
+ return false;
+ }
+
+ req->async.fn = oplock_handler_close_recv_smb;
+ req->async.private_data = NULL;
+
+ return true;
+}
+
+
+/*
+ the idle function tries to cope with getting an oplock break on a connection, and
+ an operation on another connection blocking until that break is acked
+ we check for operations on all transports in the idle function
+*/
+static void idle_func_smb(struct smbcli_transport *transport, void *private_data)
+{
+ int i, j;
+ for (i=0;i<NSERVERS;i++) {
+ for (j=0;j<NINSTANCES;j++) {
+ if (servers[i].smb_tree[j] &&
+ transport != servers[i].smb_tree[j]->session->transport) {
+ smbcli_transport_process(servers[i].smb_tree[j]->session->transport);
+ }
+ }
+ }
+
+}
+
+static void oplock_handler_close_recv_smb2(struct smb2_request *req)
+{
+ NTSTATUS status;
+ struct smb2_close io;
+ status = smb2_close_recv(req, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("close failed in oplock_handler\n");
+ smb_panic("close failed in oplock_handler");
+ }
+}
+
+static void oplock_handler_ack_callback_smb2(struct smb2_request *req)
+{
+ NTSTATUS status;
+ struct smb2_break br;
+
+ status = smb2_break_recv(req, &br);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("oplock break ack failed in oplock_handler\n");
+ smb_panic("oplock break ack failed in oplock_handler");
+ }
+}
+
+static bool send_oplock_ack_smb2(struct smb2_tree *tree, struct smb2_handle handle,
+ uint8_t level)
+{
+ struct smb2_break br;
+ struct smb2_request *req;
+
+ ZERO_STRUCT(br);
+ br.in.file.handle = handle;
+ br.in.oplock_level = level;
+ br.in.reserved = gen_reserved8();
+ br.in.reserved2 = gen_reserved32();
+
+ req = smb2_break_send(tree, &br);
+ if (req == NULL) return false;
+ req->async.fn = oplock_handler_ack_callback_smb2;
+ req->async.private_data = NULL;
+ return true;
+}
+
+/*
+ the oplock handler will either ack the break or close the file
+*/
+static bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle,
+ uint8_t level, void *private_data)
+{
+ struct smb2_close io;
+ unsigned i, j;
+ bool do_close;
+ struct smb2_tree *tree = NULL;
+ struct smb2_request *req;
+
+ srandom(current_op.seed);
+ do_close = gen_chance(50);
+
+ i = ((uintptr_t)private_data) >> 8;
+ j = ((uintptr_t)private_data) & 0xFF;
+
+ if (i >= NSERVERS || j >= NINSTANCES) {
+ printf("Bad private_data in oplock_handler\n");
+ return false;
+ }
+
+ oplocks[i][j].got_break = true;
+ oplocks[i][j].smb2_handle = *handle;
+ oplocks[i][j].handle = fnum_to_handle_smb2(i, j, *handle);
+ oplocks[i][j].level = level;
+ oplocks[i][j].do_close = do_close;
+ tree = talloc_get_type(servers[i].smb2_tree[j], struct smb2_tree);
+
+ if (!tree) {
+ printf("Oplock break not for one of our trees!?\n");
+ return false;
+ }
+
+ if (!do_close) {
+ printf("oplock ack handle=%d\n", oplocks[i][j].handle);
+ return send_oplock_ack_smb2(tree, *handle, level);
+ }
+
+ printf("oplock close fnum=%d\n", oplocks[i][j].handle);
+
+ ZERO_STRUCT(io);
+ io.in.file.handle = *handle;
+ io.in.flags = 0;
+ req = smb2_close_send(tree, &io);
+
+ if (req == NULL) {
+ printf("WARNING: close failed in oplock_handler_close\n");
+ return false;
+ }
+
+ req->async.fn = oplock_handler_close_recv_smb2;
+ req->async.private_data = NULL;
+
+ return true;
+}
+
+
+/*
+ the idle function tries to cope with getting an oplock break on a connection, and
+ an operation on another connection blocking until that break is acked
+ we check for operations on all transports in the idle function
+*/
+static void idle_func_smb2(struct smb2_transport *transport, void *private_data)
+{
+ int i, j;
+ for (i=0;i<NSERVERS;i++) {
+ for (j=0;j<NINSTANCES;j++) {
+ if (servers[i].smb2_tree[j] &&
+ transport != servers[i].smb2_tree[j]->session->transport) {
+ // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
+ }
+ }
+ }
+
+}
+
+
+/*
+ compare NTSTATUS, using checking ignored patterns
+*/
+static bool compare_status(NTSTATUS status1, NTSTATUS status2)
+{
+ char *s;
+
+ if (NT_STATUS_EQUAL(status1, status2)) return true;
+
+ /* one code being an error and the other OK is always an error */
+ if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) {
+ current_op.mismatch = nt_errstr(status1);
+ return false;
+ }
+
+ /* if we are ignoring one of the status codes then consider this a match */
+ if (ignore_pattern(nt_errstr(status1)) ||
+ ignore_pattern(nt_errstr(status2))) {
+ return true;
+ }
+
+ /* also support ignore patterns of the form NT_STATUS_XX:NT_STATUS_YY
+ meaning that the first server returns NT_STATUS_XX and the 2nd
+ returns NT_STATUS_YY */
+ s = talloc_asprintf(current_op.mem_ctx, "%s:%s",
+ nt_errstr(status1),
+ nt_errstr(status2));
+ if (ignore_pattern(s)) {
+ return true;
+ }
+
+ current_op.mismatch = nt_errstr(status1);
+ return false;
+}
+
+/*
+ check for pending packets on all connections
+*/
+static void check_pending(void)
+{
+ int i, j;
+
+ smb_msleep(20);
+
+ for (j=0;j<NINSTANCES;j++) {
+ for (i=0;i<NSERVERS;i++) {
+ // smb2_transport_process(servers[i].smb2_tree[j]->session->transport);
+ }
+ }
+}
+
+/*
+ check that the same oplock breaks have been received by all instances
+*/
+static bool check_oplocks(const char *call)
+{
+ int i, j;
+ int tries = 0;
+
+ if (!options.use_oplocks || options.smb2) {
+ /* no smb2 oplocks in gentest yet */
+ return true;
+ }
+
+again:
+ check_pending();
+
+ for (j=0;j<NINSTANCES;j++) {
+ for (i=1;i<NSERVERS;i++) {
+ if (oplocks[0][j].got_break != oplocks[i][j].got_break ||
+ oplocks[0][j].handle != oplocks[i][j].handle ||
+ oplocks[0][j].level != oplocks[i][j].level) {
+ if (tries++ < 10) goto again;
+ printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
+ oplocks[0][j].got_break,
+ oplocks[0][j].handle,
+ oplocks[0][j].level,
+ oplocks[i][j].got_break,
+ oplocks[i][j].handle,
+ oplocks[i][j].level);
+ current_op.mismatch = "oplock break";
+ return false;
+ }
+ }
+ }
+
+ /* if we got a break and closed then remove the handle */
+ for (j=0;j<NINSTANCES;j++) {
+ if (oplocks[0][j].got_break &&
+ oplocks[0][j].do_close) {
+ uint16_t fnums[NSERVERS];
+ for (i=0;i<NSERVERS;i++) {
+ fnums[i] = oplocks[i][j].smb_handle;
+ }
+ gen_remove_handle_smb(j, fnums);
+ break;
+ }
+ }
+ return true;
+}
+
+
+/*
+ check that the same change notify info has been received by all instances
+*/
+static bool check_notifies(const char *call)
+{
+ int i, j;
+ int tries = 0;
+
+ if (options.smb2) {
+ /* no smb2 notifies in gentest yet */
+ return true;
+ }
+
+again:
+ check_pending();
+
+ for (j=0;j<NINSTANCES;j++) {
+ for (i=1;i<NSERVERS;i++) {
+ int n;
+ union smb_notify not1, not2;
+
+ if (notifies[0][j].notify_count != notifies[i][j].notify_count) {
+ if (tries++ < 10) goto again;
+ printf("Notify count inconsistent %d %d\n",
+ notifies[0][j].notify_count,
+ notifies[i][j].notify_count);
+ current_op.mismatch = "notify count";
+ return false;
+ }
+
+ if (notifies[0][j].notify_count == 0) continue;
+
+ if (!NT_STATUS_EQUAL(notifies[0][j].status,
+ notifies[i][j].status)) {
+ printf("Notify status mismatch - %s - %s\n",
+ nt_errstr(notifies[0][j].status),
+ nt_errstr(notifies[i][j].status));
+ current_op.mismatch = "Notify status";
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(notifies[0][j].status)) {
+ continue;
+ }
+
+ not1 = notifies[0][j].notify;
+ not2 = notifies[i][j].notify;
+
+ for (n=0;n<not1.nttrans.out.num_changes;n++) {
+ if (not1.nttrans.out.changes[n].action !=
+ not2.nttrans.out.changes[n].action) {
+ printf("Notify action %d inconsistent %d %d\n", n,
+ not1.nttrans.out.changes[n].action,
+ not2.nttrans.out.changes[n].action);
+ current_op.mismatch = "notify action";
+ return false;
+ }
+ if (strcmp(not1.nttrans.out.changes[n].name.s,
+ not2.nttrans.out.changes[n].name.s)) {
+ printf("Notify name %d inconsistent %s %s\n", n,
+ not1.nttrans.out.changes[n].name.s,
+ not2.nttrans.out.changes[n].name.s);
+ current_op.mismatch = "notify name";
+ return false;
+ }
+ if (not1.nttrans.out.changes[n].name.private_length !=
+ not2.nttrans.out.changes[n].name.private_length) {
+ printf("Notify name length %d inconsistent %d %d\n", n,
+ not1.nttrans.out.changes[n].name.private_length,
+ not2.nttrans.out.changes[n].name.private_length);
+ current_op.mismatch = "notify name length";
+ return false;
+ }
+ }
+ }
+ }
+
+ ZERO_STRUCT(notifies);
+
+ return true;
+}
+
+#define GEN_COPY_PARM do { \
+ int i; \
+ for (i=1;i<NSERVERS;i++) { \
+ parm[i] = parm[0]; \
+ } \
+} while (0)
+
+#define GEN_CALL(call, treetype, treefield) do { \
+ int i; \
+ ZERO_STRUCT(oplocks); \
+ ZERO_STRUCT(notifies); \
+ for (i=0;i<NSERVERS;i++) { \
+ struct treetype *tree = servers[i].treefield[instance]; \
+ status[i] = call; \
+ } \
+ current_op.status = status[0]; \
+ for (i=1;i<NSERVERS;i++) { \
+ if (!compare_status(status[0], status[1])) { \
+ printf("status different in %s - %s %s\n", #call, \
+ nt_errstr(status[0]), nt_errstr(status[i])); \
+ current_op.mismatch = nt_errstr(status[0]); \
+ return false; \
+ } \
+ } \
+ if (!check_oplocks(#call)) return false; \
+ if (!check_notifies(#call)) return false; \
+ if (!NT_STATUS_IS_OK(status[0])) { \
+ return true; \
+ } \
+} while(0)
+
+#define GEN_CALL_SMB(call) GEN_CALL(call, smbcli_tree, smb_tree)
+#define GEN_CALL_SMB2(call) GEN_CALL(call, smb2_tree, smb2_tree)
+
+#define ADD_HANDLE_SMB2(name, field) do { \
+ struct smb2_handle handles[NSERVERS]; \
+ int i; \
+ for (i=0;i<NSERVERS;i++) { \
+ handles[i] = parm[i].field; \
+ } \
+ gen_add_handle_smb2(instance, name, handles); \
+} while(0)
+
+#define REMOVE_HANDLE_SMB2(field) do { \
+ struct smb2_handle handles[NSERVERS]; \
+ int i; \
+ for (i=0;i<NSERVERS;i++) { \
+ handles[i] = parm[i].field; \
+ } \
+ gen_remove_handle_smb2(instance, handles); \
+} while(0)
+
+#define ADD_HANDLE_SMB(name, field) do { \
+ uint16_t handles[NSERVERS]; \
+ int i; \
+ for (i=0;i<NSERVERS;i++) { \
+ handles[i] = parm[i].field; \
+ } \
+ gen_add_handle_smb(instance, name, handles); \
+} while(0)
+
+#define REMOVE_HANDLE_SMB(field) do { \
+ uint16_t handles[NSERVERS]; \
+ int i; \
+ for (i=0;i<NSERVERS;i++) { \
+ handles[i] = parm[i].field; \
+ } \
+ gen_remove_handle_smb(instance, handles); \
+} while(0)
+
+#define GEN_SET_FNUM_SMB2(field) do { \
+ int i; \
+ for (i=0;i<NSERVERS;i++) { \
+ parm[i].field = gen_lookup_handle_smb2(i, parm[i].field.data[0]); \
+ } \
+} while(0)
+
+#define GEN_SET_FNUM_SMB(field) do { \
+ int i; \
+ for (i=0;i<NSERVERS;i++) { \
+ parm[i].field = gen_lookup_handle_smb(i, parm[i].field); \
+ } \
+} while(0)
+
+#define CHECK_EQUAL(field) do { \
+ if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s - 0x%llx 0x%llx\n", #field, \
+ (unsigned long long)parm[0].field, (unsigned long long)parm[1].field); \
+ return false; \
+ } \
+} while(0)
+
+#define CHECK_SECDESC(field) do { \
+ if (!security_acl_equal(parm[0].field->dacl, parm[1].field->dacl) && !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s\n", #field); \
+ return false; \
+ } \
+} while(0)
+
+#define CHECK_ATTRIB(field) do { \
+ if (!options.mask_indexing) { \
+ CHECK_EQUAL(field); \
+ } else if ((~FILE_ATTRIBUTE_NONINDEXED & parm[0].field) != (~FILE_ATTRIBUTE_NONINDEXED & parm[1].field) && !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
+ (int)parm[0].field, (int)parm[1].field); \
+ return false; \
+ } \
+} while(0)
+
+#define CHECK_WSTR_EQUAL(field) do { \
+ if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
+ current_op.mismatch = #field; \
+ printf("%s is NULL!\n", #field); \
+ return false; \
+ } \
+ if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s - %s %s\n", #field, \
+ parm[0].field.s, parm[1].field.s); \
+ return false; \
+ } \
+ CHECK_EQUAL(field.private_length); \
+} while(0)
+
+#define CHECK_BLOB_EQUAL(field) do { \
+ if (((parm[0].field.data == NULL && parm[1].field.data != NULL) || \
+ (parm[1].field.data == NULL && parm[0].field.data != NULL) || \
+ (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0)) && !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s\n", #field); \
+ return false; \
+ } \
+ CHECK_EQUAL(field.length); \
+} while(0)
+
+#define CHECK_TIMES_EQUAL(field) do { \
+ if (labs(parm[0].field - parm[1].field) > time_skew() && \
+ !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
+ (int)parm[0].field, (int)parm[1].field); \
+ return false; \
+ } \
+} while(0)
+
+#define CHECK_NTTIMES_EQUAL(field) do { \
+ if (labs(nt_time_to_unix(parm[0].field) - \
+ nt_time_to_unix(parm[1].field)) > time_skew() && \
+ !ignore_pattern(#field)) { \
+ current_op.mismatch = #field; \
+ printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
+ (int)nt_time_to_unix(parm[0].field), \
+ (int)nt_time_to_unix(parm[1].field)); \
+ return false; \
+ } \
+} while(0)
+
+
+/*
+ compare returned fileinfo structures
+*/
+static bool cmp_fileinfo(int instance,
+ union smb_fileinfo parm[NSERVERS],
+ NTSTATUS status[NSERVERS])
+{
+ int i;
+ enum smb_fileinfo_level level = parm[0].generic.level;
+
+ if (level == RAW_FILEINFO_ALL_INFORMATION &&
+ options.smb2) {
+ level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ }
+
+ switch (level) {
+ case RAW_FILEINFO_GENERIC:
+ return false;
+
+ case RAW_FILEINFO_GETATTR:
+ CHECK_ATTRIB(getattr.out.attrib);
+ CHECK_EQUAL(getattr.out.size);
+ CHECK_TIMES_EQUAL(getattr.out.write_time);
+ break;
+
+ case RAW_FILEINFO_GETATTRE:
+ CHECK_TIMES_EQUAL(getattre.out.create_time);
+ CHECK_TIMES_EQUAL(getattre.out.access_time);
+ CHECK_TIMES_EQUAL(getattre.out.write_time);
+ CHECK_EQUAL(getattre.out.size);
+ CHECK_EQUAL(getattre.out.alloc_size);
+ CHECK_ATTRIB(getattre.out.attrib);
+ break;
+
+ case RAW_FILEINFO_STANDARD:
+ CHECK_TIMES_EQUAL(standard.out.create_time);
+ CHECK_TIMES_EQUAL(standard.out.access_time);
+ CHECK_TIMES_EQUAL(standard.out.write_time);
+ CHECK_EQUAL(standard.out.size);
+ CHECK_EQUAL(standard.out.alloc_size);
+ CHECK_ATTRIB(standard.out.attrib);
+ break;
+
+ case RAW_FILEINFO_EA_SIZE:
+ CHECK_TIMES_EQUAL(ea_size.out.create_time);
+ CHECK_TIMES_EQUAL(ea_size.out.access_time);
+ CHECK_TIMES_EQUAL(ea_size.out.write_time);
+ CHECK_EQUAL(ea_size.out.size);
+ CHECK_EQUAL(ea_size.out.alloc_size);
+ CHECK_ATTRIB(ea_size.out.attrib);
+ CHECK_EQUAL(ea_size.out.ea_size);
+ break;
+
+ case RAW_FILEINFO_ALL_EAS:
+ CHECK_EQUAL(all_eas.out.num_eas);
+ for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
+ CHECK_EQUAL(all_eas.out.eas[i].flags);
+ CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
+ CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
+ }
+ break;
+
+ case RAW_FILEINFO_IS_NAME_VALID:
+ break;
+
+ case RAW_FILEINFO_BASIC_INFO:
+ case RAW_FILEINFO_BASIC_INFORMATION:
+ CHECK_NTTIMES_EQUAL(basic_info.out.create_time);
+ CHECK_NTTIMES_EQUAL(basic_info.out.access_time);
+ CHECK_NTTIMES_EQUAL(basic_info.out.write_time);
+ CHECK_NTTIMES_EQUAL(basic_info.out.change_time);
+ CHECK_ATTRIB(basic_info.out.attrib);
+ break;
+
+ case RAW_FILEINFO_STANDARD_INFO:
+ case RAW_FILEINFO_STANDARD_INFORMATION:
+ CHECK_EQUAL(standard_info.out.alloc_size);
+ CHECK_EQUAL(standard_info.out.size);
+ CHECK_EQUAL(standard_info.out.nlink);
+ CHECK_EQUAL(standard_info.out.delete_pending);
+ CHECK_EQUAL(standard_info.out.directory);
+ break;
+
+ case RAW_FILEINFO_EA_INFO:
+ case RAW_FILEINFO_EA_INFORMATION:
+ CHECK_EQUAL(ea_info.out.ea_size);
+ break;
+
+ case RAW_FILEINFO_NAME_INFO:
+ case RAW_FILEINFO_NAME_INFORMATION:
+ CHECK_WSTR_EQUAL(name_info.out.fname);
+ break;
+
+ case RAW_FILEINFO_ALL_INFO:
+ case RAW_FILEINFO_ALL_INFORMATION:
+ CHECK_NTTIMES_EQUAL(all_info.out.create_time);
+ CHECK_NTTIMES_EQUAL(all_info.out.access_time);
+ CHECK_NTTIMES_EQUAL(all_info.out.write_time);
+ CHECK_NTTIMES_EQUAL(all_info.out.change_time);
+ CHECK_ATTRIB(all_info.out.attrib);
+ CHECK_EQUAL(all_info.out.alloc_size);
+ CHECK_EQUAL(all_info.out.size);
+ CHECK_EQUAL(all_info.out.nlink);
+ CHECK_EQUAL(all_info.out.delete_pending);
+ CHECK_EQUAL(all_info.out.directory);
+ CHECK_EQUAL(all_info.out.ea_size);
+ CHECK_WSTR_EQUAL(all_info.out.fname);
+ break;
+
+ case RAW_FILEINFO_ALT_NAME_INFO:
+ case RAW_FILEINFO_ALT_NAME_INFORMATION:
+ case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION:
+ CHECK_WSTR_EQUAL(alt_name_info.out.fname);
+ break;
+
+ case RAW_FILEINFO_STREAM_INFO:
+ case RAW_FILEINFO_STREAM_INFORMATION:
+ CHECK_EQUAL(stream_info.out.num_streams);
+ for (i=0;i<parm[0].stream_info.out.num_streams;i++) {
+ CHECK_EQUAL(stream_info.out.streams[i].size);
+ CHECK_EQUAL(stream_info.out.streams[i].alloc_size);
+ CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name);
+ }
+ break;
+
+ case RAW_FILEINFO_COMPRESSION_INFO:
+ case RAW_FILEINFO_COMPRESSION_INFORMATION:
+ CHECK_EQUAL(compression_info.out.compressed_size);
+ CHECK_EQUAL(compression_info.out.format);
+ CHECK_EQUAL(compression_info.out.unit_shift);
+ CHECK_EQUAL(compression_info.out.chunk_shift);
+ CHECK_EQUAL(compression_info.out.cluster_shift);
+ break;
+
+ case RAW_FILEINFO_INTERNAL_INFORMATION:
+ CHECK_EQUAL(internal_information.out.file_id);
+ break;
+
+ case RAW_FILEINFO_ACCESS_INFORMATION:
+ CHECK_EQUAL(access_information.out.access_flags);
+ break;
+
+ case RAW_FILEINFO_POSITION_INFORMATION:
+ CHECK_EQUAL(position_information.out.position);
+ break;
+
+ case RAW_FILEINFO_MODE_INFORMATION:
+ CHECK_EQUAL(mode_information.out.mode);
+ break;
+
+ case RAW_FILEINFO_ALIGNMENT_INFORMATION:
+ CHECK_EQUAL(alignment_information.out.alignment_requirement);
+ break;
+
+ case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
+ CHECK_NTTIMES_EQUAL(network_open_information.out.create_time);
+ CHECK_NTTIMES_EQUAL(network_open_information.out.access_time);
+ CHECK_NTTIMES_EQUAL(network_open_information.out.write_time);
+ CHECK_NTTIMES_EQUAL(network_open_information.out.change_time);
+ CHECK_EQUAL(network_open_information.out.alloc_size);
+ CHECK_EQUAL(network_open_information.out.size);
+ CHECK_ATTRIB(network_open_information.out.attrib);
+ break;
+
+ case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
+ CHECK_ATTRIB(attribute_tag_information.out.attrib);
+ CHECK_EQUAL(attribute_tag_information.out.reparse_tag);
+ break;
+
+ case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION:
+ CHECK_WSTR_EQUAL(normalized_name_info.out.fname);
+ break;
+
+ case RAW_FILEINFO_SMB2_ALL_INFORMATION:
+ CHECK_NTTIMES_EQUAL(all_info2.out.create_time);
+ CHECK_NTTIMES_EQUAL(all_info2.out.access_time);
+ CHECK_NTTIMES_EQUAL(all_info2.out.write_time);
+ CHECK_NTTIMES_EQUAL(all_info2.out.change_time);
+ CHECK_ATTRIB(all_info2.out.attrib);
+ CHECK_EQUAL(all_info2.out.unknown1);
+ CHECK_EQUAL(all_info2.out.alloc_size);
+ CHECK_EQUAL(all_info2.out.size);
+ CHECK_EQUAL(all_info2.out.nlink);
+ CHECK_EQUAL(all_info2.out.delete_pending);
+ CHECK_EQUAL(all_info2.out.directory);
+ CHECK_EQUAL(all_info2.out.file_id);
+ CHECK_EQUAL(all_info2.out.ea_size);
+ CHECK_EQUAL(all_info2.out.access_mask);
+ CHECK_EQUAL(all_info2.out.position);
+ CHECK_EQUAL(all_info2.out.mode);
+ CHECK_EQUAL(all_info2.out.alignment_requirement);
+ CHECK_WSTR_EQUAL(all_info2.out.fname);
+ break;
+
+ case RAW_FILEINFO_SMB2_ALL_EAS:
+ CHECK_EQUAL(all_eas.out.num_eas);
+ for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
+ CHECK_EQUAL(all_eas.out.eas[i].flags);
+ CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
+ CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
+ }
+ break;
+
+ case RAW_FILEINFO_SEC_DESC:
+ CHECK_SECDESC(query_secdesc.out.sd);
+ break;
+
+ /* Unhandled levels */
+ case RAW_FILEINFO_EA_LIST:
+ case RAW_FILEINFO_UNIX_BASIC:
+ case RAW_FILEINFO_UNIX_LINK:
+ case RAW_FILEINFO_UNIX_INFO2:
+ break;
+ }
+
+ return true;
+}
+
+
+
+/*
+ generate openx operations
+*/
+static bool handler_smb_openx(int instance)
+{
+ union smb_open parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].openx.level = RAW_OPEN_OPENX;
+ parm[0].openx.in.flags = gen_openx_flags();
+ parm[0].openx.in.open_mode = gen_openx_mode();
+ parm[0].openx.in.search_attrs = gen_attrib();
+ parm[0].openx.in.file_attrs = gen_attrib();
+ parm[0].openx.in.write_time = gen_timet();
+ parm[0].openx.in.open_func = gen_openx_func();
+ parm[0].openx.in.size = gen_io_count();
+ parm[0].openx.in.timeout = gen_timeout();
+ parm[0].openx.in.fname = gen_fname_open(instance);
+
+ if (!options.use_oplocks) {
+ /* mask out oplocks */
+ parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
+ OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
+ }
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
+
+ CHECK_ATTRIB(openx.out.attrib);
+ CHECK_EQUAL(openx.out.size);
+ CHECK_EQUAL(openx.out.access);
+ CHECK_EQUAL(openx.out.ftype);
+ CHECK_EQUAL(openx.out.devstate);
+ CHECK_EQUAL(openx.out.action);
+ CHECK_EQUAL(openx.out.access_mask);
+ CHECK_EQUAL(openx.out.unknown);
+ CHECK_TIMES_EQUAL(openx.out.write_time);
+
+ /* open creates a new file handle */
+ ADD_HANDLE_SMB(parm[0].openx.in.fname, openx.out.file.fnum);
+
+ return true;
+}
+
+
+/*
+ generate open operations
+*/
+static bool handler_smb_open(int instance)
+{
+ union smb_open parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].openold.level = RAW_OPEN_OPEN;
+ parm[0].openold.in.open_mode = gen_bits_mask2(0xF, 0xFFFF);
+ parm[0].openold.in.search_attrs = gen_attrib();
+ parm[0].openold.in.fname = gen_fname_open(instance);
+
+ if (!options.use_oplocks) {
+ /* mask out oplocks */
+ parm[0].openold.in.open_mode &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
+ OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
+ }
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
+
+ CHECK_ATTRIB(openold.out.attrib);
+ CHECK_TIMES_EQUAL(openold.out.write_time);
+ CHECK_EQUAL(openold.out.size);
+ CHECK_EQUAL(openold.out.rmode);
+
+ /* open creates a new file handle */
+ ADD_HANDLE_SMB(parm[0].openold.in.fname, openold.out.file.fnum);
+
+ return true;
+}
+
+
+/*
+ generate ntcreatex operations
+*/
+static bool handler_smb_ntcreatex(int instance)
+{
+ union smb_open parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].ntcreatex.level = RAW_OPEN_NTCREATEX;
+ parm[0].ntcreatex.in.flags = gen_ntcreatex_flags();
+ parm[0].ntcreatex.in.root_fid.fnum = gen_root_fid(instance);
+ parm[0].ntcreatex.in.access_mask = gen_access_mask();
+ parm[0].ntcreatex.in.alloc_size = gen_alloc_size();
+ parm[0].ntcreatex.in.file_attr = gen_attrib();
+ parm[0].ntcreatex.in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
+ parm[0].ntcreatex.in.open_disposition = gen_open_disp();
+ parm[0].ntcreatex.in.create_options = gen_create_options();
+ parm[0].ntcreatex.in.impersonation = gen_bits_mask2(0, 0xFFFFFFFF);
+ parm[0].ntcreatex.in.security_flags = gen_bits_mask2(0, 0xFF);
+ parm[0].ntcreatex.in.fname = gen_fname_open(instance);
+
+ if (!options.use_oplocks) {
+ /* mask out oplocks */
+ parm[0].ntcreatex.in.flags &= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK|
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK);
+ }
+
+ GEN_COPY_PARM;
+ if (parm[0].ntcreatex.in.root_fid.fnum != 0) {
+ GEN_SET_FNUM_SMB(ntcreatex.in.root_fid.fnum);
+ }
+ GEN_CALL_SMB(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
+
+ CHECK_EQUAL(ntcreatex.out.oplock_level);
+ CHECK_EQUAL(ntcreatex.out.create_action);
+ CHECK_NTTIMES_EQUAL(ntcreatex.out.create_time);
+ CHECK_NTTIMES_EQUAL(ntcreatex.out.access_time);
+ CHECK_NTTIMES_EQUAL(ntcreatex.out.write_time);
+ CHECK_NTTIMES_EQUAL(ntcreatex.out.change_time);
+ CHECK_ATTRIB(ntcreatex.out.attrib);
+ CHECK_EQUAL(ntcreatex.out.alloc_size);
+ CHECK_EQUAL(ntcreatex.out.size);
+ CHECK_EQUAL(ntcreatex.out.file_type);
+ CHECK_EQUAL(ntcreatex.out.ipc_state);
+ CHECK_EQUAL(ntcreatex.out.is_directory);
+
+ /* ntcreatex creates a new file handle */
+ ADD_HANDLE_SMB(parm[0].ntcreatex.in.fname, ntcreatex.out.file.fnum);
+
+ return true;
+}
+
+/*
+ generate close operations
+*/
+static bool handler_smb_close(int instance)
+{
+ union smb_close parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].close.level = RAW_CLOSE_CLOSE;
+ parm[0].close.in.file.fnum = gen_fnum_close(instance);
+ parm[0].close.in.write_time = gen_timet();
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(close.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_close(tree, &parm[i]));
+
+ REMOVE_HANDLE_SMB(close.in.file.fnum);
+
+ return true;
+}
+
+/*
+ generate unlink operations
+*/
+static bool handler_smb_unlink(int instance)
+{
+ union smb_unlink parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].unlink.in.pattern = gen_pattern();
+ parm[0].unlink.in.attrib = gen_attrib();
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_unlink(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ generate chkpath operations
+*/
+static bool handler_smb_chkpath(int instance)
+{
+ union smb_chkpath parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].chkpath.in.path = gen_fname_open(instance);
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_chkpath(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ generate mkdir operations
+*/
+static bool handler_smb_mkdir(int instance)
+{
+ union smb_mkdir parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].mkdir.level = RAW_MKDIR_MKDIR;
+ parm[0].mkdir.in.path = gen_fname_open(instance);
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_mkdir(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ generate rmdir operations
+*/
+static bool handler_smb_rmdir(int instance)
+{
+ struct smb_rmdir parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].in.path = gen_fname_open(instance);
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_rmdir(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ generate rename operations
+*/
+static bool handler_smb_rename(int instance)
+{
+ union smb_rename parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].generic.level = RAW_RENAME_RENAME;
+ parm[0].rename.in.pattern1 = gen_pattern();
+ parm[0].rename.in.pattern2 = gen_pattern();
+ parm[0].rename.in.attrib = gen_attrib();
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ generate ntrename operations
+*/
+static bool handler_smb_ntrename(int instance)
+{
+ union smb_rename parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].generic.level = RAW_RENAME_NTRENAME;
+ parm[0].ntrename.in.old_name = gen_fname();
+ parm[0].ntrename.in.new_name = gen_fname();
+ parm[0].ntrename.in.attrib = gen_attrib();
+ parm[0].ntrename.in.cluster_size = gen_bits_mask2(0, 0xFFFFFFF);
+ parm[0].ntrename.in.flags = gen_rename_flags();
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_rename(tree, &parm[i]));
+
+ return true;
+}
+
+
+/*
+ generate seek operations
+*/
+static bool handler_smb_seek(int instance)
+{
+ union smb_seek parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].lseek.in.file.fnum = gen_fnum(instance);
+ parm[0].lseek.in.mode = gen_bits_mask2(0x3, 0xFFFF);
+ parm[0].lseek.in.offset = gen_offset();
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(lseek.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_seek(tree, &parm[i]));
+
+ CHECK_EQUAL(lseek.out.offset);
+
+ return true;
+}
+
+
+/*
+ generate readx operations
+*/
+static bool handler_smb_readx(int instance)
+{
+ union smb_read parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].readx.level = RAW_READ_READX;
+ parm[0].readx.in.file.fnum = gen_fnum(instance);
+ parm[0].readx.in.offset = gen_offset();
+ parm[0].readx.in.mincnt = gen_io_count();
+ parm[0].readx.in.maxcnt = gen_io_count();
+ parm[0].readx.in.remaining = gen_io_count();
+ parm[0].readx.in.read_for_execute = gen_bool();
+ parm[0].readx.out.data = talloc_array(current_op.mem_ctx, uint8_t,
+ MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt));
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(readx.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_read(tree, &parm[i]));
+
+ CHECK_EQUAL(readx.out.remaining);
+ CHECK_EQUAL(readx.out.compaction_mode);
+ CHECK_EQUAL(readx.out.nread);
+
+ return true;
+}
+
+/*
+ generate writex operations
+*/
+static bool handler_smb_writex(int instance)
+{
+ union smb_write parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].writex.level = RAW_WRITE_WRITEX;
+ parm[0].writex.in.file.fnum = gen_fnum(instance);
+ parm[0].writex.in.offset = gen_offset();
+ parm[0].writex.in.wmode = gen_bits_mask(0xFFFF);
+ parm[0].writex.in.remaining = gen_io_count();
+ parm[0].writex.in.count = gen_io_count();
+ parm[0].writex.in.data = talloc_zero_array(current_op.mem_ctx, uint8_t, parm[0].writex.in.count);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(writex.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_write(tree, &parm[i]));
+
+ CHECK_EQUAL(writex.out.nwritten);
+ CHECK_EQUAL(writex.out.remaining);
+
+ return true;
+}
+
+/*
+ generate lockingx operations
+*/
+static bool handler_smb_lockingx(int instance)
+{
+ union smb_lock parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+ int n, nlocks;
+
+ parm[0].lockx.level = RAW_LOCK_LOCKX;
+ parm[0].lockx.in.file.fnum = gen_fnum(instance);
+ parm[0].lockx.in.mode = gen_lock_mode();
+ parm[0].lockx.in.timeout = gen_timeout();
+ do {
+ /* make sure we don't accidentally generate an oplock
+ break ack - otherwise the server can just block forever */
+ parm[0].lockx.in.ulock_cnt = gen_lock_count();
+ parm[0].lockx.in.lock_cnt = gen_lock_count();
+ nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt;
+ } while (nlocks == 0);
+
+ if (nlocks > 0) {
+ parm[0].lockx.in.locks = talloc_array(current_op.mem_ctx,
+ struct smb_lock_entry,
+ nlocks);
+ for (n=0;n<nlocks;n++) {
+ parm[0].lockx.in.locks[n].pid = gen_pid();
+ parm[0].lockx.in.locks[n].offset = gen_offset();
+ parm[0].lockx.in.locks[n].count = gen_io_count();
+ }
+ }
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(lockx.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_lock(tree, &parm[i]));
+
+ return true;
+}
+
+#if 0
+/*
+ generate a fileinfo query structure
+*/
+static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
+{
+ int i;
+ #undef LVL
+ #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
+ struct {
+ enum smb_setfileinfo_level level;
+ const char *name;
+ } levels[] = {
+#if 0
+ /* disabled until win2003 can handle them ... */
+ LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO),
+ LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO),
+#endif
+ LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
+ LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION),
+ LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
+ LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION),
+ LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
+ };
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(levels)-1);
+ } while (ignore_pattern(levels[i].name));
+
+ info->generic.level = levels[i].level;
+
+ switch (info->generic.level) {
+ case RAW_SFILEINFO_SETATTR:
+ info->setattr.in.attrib = gen_attrib();
+ info->setattr.in.write_time = gen_timet();
+ break;
+ case RAW_SFILEINFO_SETATTRE:
+ info->setattre.in.create_time = gen_timet();
+ info->setattre.in.access_time = gen_timet();
+ info->setattre.in.write_time = gen_timet();
+ break;
+ case RAW_SFILEINFO_STANDARD:
+ info->standard.in.create_time = gen_timet();
+ info->standard.in.access_time = gen_timet();
+ info->standard.in.write_time = gen_timet();
+ break;
+ case RAW_SFILEINFO_EA_SET: {
+ static struct ea_struct ea;
+ info->ea_set.in.num_eas = 1;
+ info->ea_set.in.eas = &ea;
+ info->ea_set.in.eas[0] = gen_ea_struct();
+ }
+ break;
+ case RAW_SFILEINFO_BASIC_INFO:
+ case RAW_SFILEINFO_BASIC_INFORMATION:
+ info->basic_info.in.create_time = gen_nttime();
+ info->basic_info.in.access_time = gen_nttime();
+ info->basic_info.in.write_time = gen_nttime();
+ info->basic_info.in.change_time = gen_nttime();
+ info->basic_info.in.attrib = gen_attrib();
+ break;
+ case RAW_SFILEINFO_DISPOSITION_INFO:
+ case RAW_SFILEINFO_DISPOSITION_INFORMATION:
+ info->disposition_info.in.delete_on_close = gen_bool();
+ break;
+ case RAW_SFILEINFO_ALLOCATION_INFO:
+ case RAW_SFILEINFO_ALLOCATION_INFORMATION:
+ info->allocation_info.in.alloc_size = gen_alloc_size();
+ break;
+ case RAW_SFILEINFO_END_OF_FILE_INFO:
+ case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
+ info->end_of_file_info.in.size = gen_offset();
+ break;
+ case RAW_SFILEINFO_RENAME_INFORMATION:
+ case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
+ info->rename_information.in.overwrite = gen_bool();
+ info->rename_information.in.root_fid = gen_root_fid(instance);
+ info->rename_information.in.new_name = gen_fname_open(instance);
+ break;
+ case RAW_SFILEINFO_POSITION_INFORMATION:
+ info->position_information.in.position = gen_offset();
+ break;
+ case RAW_SFILEINFO_MODE_INFORMATION:
+ info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
+ break;
+ case RAW_SFILEINFO_FULL_EA_INFORMATION:
+ info->full_ea_information.in.eas = gen_ea_list();
+ break;
+ case RAW_SFILEINFO_GENERIC:
+ case RAW_SFILEINFO_SEC_DESC:
+ case RAW_SFILEINFO_UNIX_BASIC:
+ case RAW_SFILEINFO_UNIX_LINK:
+ case RAW_SFILEINFO_UNIX_HLINK:
+ case RAW_SFILEINFO_1023:
+ case RAW_SFILEINFO_1025:
+ case RAW_SFILEINFO_1029:
+ case RAW_SFILEINFO_1032:
+ case RAW_SFILEINFO_1039:
+ case RAW_SFILEINFO_1040:
+ case RAW_SFILEINFO_UNIX_INFO2:
+ /* Untested */
+ break;
+ }
+}
+#endif
+
+/*
+ generate a fileinfo query structure
+*/
+static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
+{
+ int i;
+ #undef LVL
+ #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
+ struct levels {
+ enum smb_setfileinfo_level level;
+ const char *name;
+ };
+ struct levels smb_levels[] = {
+ LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO),
+ LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO),
+ LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
+ LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION),
+ LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION),
+ LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION),
+ LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION),
+ LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
+ LVL(1041), LVL(1042), LVL(1043), LVL(1044),
+ };
+ struct levels smb2_levels[] = {
+ LVL(BASIC_INFORMATION),
+ LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION),
+ LVL(POSITION_INFORMATION), LVL(FULL_EA_INFORMATION), LVL(MODE_INFORMATION),
+ LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION),
+ LVL(PIPE_INFORMATION), LVL(VALID_DATA_INFORMATION), LVL(SHORT_NAME_INFORMATION),
+ LVL(1025), LVL(1027), LVL(1029), LVL(1030), LVL(1031), LVL(1032), LVL(1036),
+ LVL(1041), LVL(1042), LVL(1043), LVL(1044),
+ };
+ struct levels *levels = options.smb2?smb2_levels:smb_levels;
+ uint32_t num_levels = options.smb2?ARRAY_SIZE(smb2_levels):ARRAY_SIZE(smb_levels);
+
+ do {
+ i = gen_int_range(0, num_levels-1);
+ } while (ignore_pattern(levels[i].name));
+
+ ZERO_STRUCTP(info);
+ info->generic.level = levels[i].level;
+
+ switch (info->generic.level) {
+ case RAW_SFILEINFO_SETATTR:
+ info->setattr.in.attrib = gen_attrib();
+ info->setattr.in.write_time = gen_timet();
+ break;
+ case RAW_SFILEINFO_SETATTRE:
+ info->setattre.in.create_time = gen_timet();
+ info->setattre.in.access_time = gen_timet();
+ info->setattre.in.write_time = gen_timet();
+ break;
+ case RAW_SFILEINFO_STANDARD:
+ info->standard.in.create_time = gen_timet();
+ info->standard.in.access_time = gen_timet();
+ info->standard.in.write_time = gen_timet();
+ break;
+ case RAW_SFILEINFO_EA_SET: {
+ static struct ea_struct ea;
+ info->ea_set.in.num_eas = 1;
+ info->ea_set.in.eas = &ea;
+ info->ea_set.in.eas[0] = gen_ea_struct();
+ break;
+ }
+ case RAW_SFILEINFO_BASIC_INFO:
+ case RAW_SFILEINFO_BASIC_INFORMATION:
+ info->basic_info.in.create_time = gen_nttime();
+ info->basic_info.in.access_time = gen_nttime();
+ info->basic_info.in.write_time = gen_nttime();
+ info->basic_info.in.change_time = gen_nttime();
+ info->basic_info.in.attrib = gen_attrib();
+ break;
+ case RAW_SFILEINFO_DISPOSITION_INFO:
+ case RAW_SFILEINFO_DISPOSITION_INFORMATION:
+ info->disposition_info.in.delete_on_close = gen_bool();
+ break;
+ case RAW_SFILEINFO_ALLOCATION_INFO:
+ case RAW_SFILEINFO_ALLOCATION_INFORMATION:
+ info->allocation_info.in.alloc_size = gen_alloc_size();
+ break;
+ case RAW_SFILEINFO_END_OF_FILE_INFO:
+ case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
+ info->end_of_file_info.in.size = gen_offset();
+ break;
+ case RAW_SFILEINFO_RENAME_INFORMATION:
+ case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
+ info->rename_information.in.overwrite = gen_bool();
+ info->rename_information.in.root_fid = gen_root_fid(instance);
+ info->rename_information.in.new_name = gen_fname_open(instance);
+ break;
+ case RAW_SFILEINFO_POSITION_INFORMATION:
+ info->position_information.in.position = gen_offset();
+ break;
+ case RAW_SFILEINFO_MODE_INFORMATION:
+ info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
+ break;
+ case RAW_SFILEINFO_FULL_EA_INFORMATION:
+ info->full_ea_information.in.eas = gen_ea_list();
+ break;
+
+ case RAW_SFILEINFO_GENERIC:
+ case RAW_SFILEINFO_SEC_DESC:
+ case RAW_SFILEINFO_1025:
+ case RAW_SFILEINFO_1029:
+ case RAW_SFILEINFO_1032:
+ case RAW_SFILEINFO_UNIX_BASIC:
+ case RAW_SFILEINFO_UNIX_INFO2:
+ case RAW_SFILEINFO_UNIX_LINK:
+ case RAW_SFILEINFO_UNIX_HLINK:
+ case RAW_SFILEINFO_LINK_INFORMATION:
+ case RAW_SFILEINFO_PIPE_INFORMATION:
+ case RAW_SFILEINFO_VALID_DATA_INFORMATION:
+ case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
+ case RAW_SFILEINFO_1027:
+ case RAW_SFILEINFO_1030:
+ case RAW_SFILEINFO_1031:
+ case RAW_SFILEINFO_1036:
+ case RAW_SFILEINFO_1041:
+ case RAW_SFILEINFO_1042:
+ case RAW_SFILEINFO_1043:
+ case RAW_SFILEINFO_1044:
+ /* Untested */
+ break;
+ }
+}
+
+
+
+/*
+ generate a fileinfo query structure
+*/
+static void gen_fileinfo_smb(int instance, union smb_fileinfo *info)
+{
+ int i;
+ #undef LVL
+ #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
+ struct {
+ enum smb_fileinfo_level level;
+ const char *name;
+ } levels[] = {
+ LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD),
+ LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID),
+ LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO),
+ LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO),
+ LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION),
+ LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
+ LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
+ LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION),
+ LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
+ LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION)
+ };
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(levels)-1);
+ } while (ignore_pattern(levels[i].name));
+
+ info->generic.level = levels[i].level;
+}
+
+/*
+ generate qpathinfo operations
+*/
+static bool handler_smb_qpathinfo(int instance)
+{
+ union smb_fileinfo parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].generic.in.file.path = gen_fname_open(instance);
+
+ gen_fileinfo_smb(instance, &parm[0]);
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i]));
+
+ return cmp_fileinfo(instance, parm, status);
+}
+
+/*
+ generate qfileinfo operations
+*/
+static bool handler_smb_qfileinfo(int instance)
+{
+ union smb_fileinfo parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].generic.in.file.fnum = gen_fnum(instance);
+
+ gen_fileinfo_smb(instance, &parm[0]);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(generic.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i]));
+
+ return cmp_fileinfo(instance, parm, status);
+}
+
+
+/*
+ generate setpathinfo operations
+*/
+static bool handler_smb_spathinfo(int instance)
+{
+ union smb_setfileinfo parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ gen_setfileinfo(instance, &parm[0]);
+ parm[0].generic.in.file.path = gen_fname_open(instance);
+
+ GEN_COPY_PARM;
+
+ /* a special case for the fid in a RENAME */
+ if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION &&
+ parm[0].rename_information.in.root_fid != 0) {
+ GEN_SET_FNUM_SMB(rename_information.in.root_fid);
+ }
+
+ GEN_CALL_SMB(smb_raw_setpathinfo(tree, &parm[i]));
+
+ return true;
+}
+
+
+/*
+ generate setfileinfo operations
+*/
+static bool handler_smb_sfileinfo(int instance)
+{
+ union smb_setfileinfo parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].generic.in.file.fnum = gen_fnum(instance);
+
+ gen_setfileinfo(instance, &parm[0]);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(generic.in.file.fnum);
+ GEN_CALL_SMB(smb_raw_setfileinfo(tree, &parm[i]));
+
+ return true;
+}
+
+
+/*
+ this is called when a change notify reply comes in
+*/
+static void async_notify_smb(struct smbcli_request *req)
+{
+ union smb_notify notify;
+ NTSTATUS status;
+ int i, j;
+ uint16_t tid = 0;
+ struct smbcli_transport *transport = req->transport;
+
+ if (req->tree) {
+ tid = req->tree->tid;
+ }
+
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ status = smb_raw_changenotify_recv(req, current_op.mem_ctx, &notify);
+ if (NT_STATUS_IS_OK(status) && notify.nttrans.out.num_changes > 0) {
+ printf("notify tid=%d num_changes=%d action=%d name=%s\n",
+ tid,
+ notify.nttrans.out.num_changes,
+ notify.nttrans.out.changes[0].action,
+ notify.nttrans.out.changes[0].name.s);
+ }
+
+ for (i=0;i<NSERVERS;i++) {
+ for (j=0;j<NINSTANCES;j++) {
+ if (transport == servers[i].smb_tree[j]->session->transport &&
+ tid == servers[i].smb_tree[j]->tid) {
+ notifies[i][j].notify_count++;
+ notifies[i][j].status = status;
+ notifies[i][j].notify = notify;
+ }
+ }
+ }
+}
+
+/*
+ generate change notify operations
+*/
+static bool handler_smb_notify(int instance)
+{
+ union smb_notify parm[NSERVERS];
+ int n;
+
+ ZERO_STRUCT(parm[0]);
+ parm[0].nttrans.level = RAW_NOTIFY_NTTRANS;
+ parm[0].nttrans.in.buffer_size = gen_io_count();
+ parm[0].nttrans.in.completion_filter = gen_bits_mask(0xFF);
+ parm[0].nttrans.in.file.fnum = gen_fnum(instance);
+ parm[0].nttrans.in.recursive = gen_bool();
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB(nttrans.in.file.fnum);
+
+ for (n=0;n<NSERVERS;n++) {
+ struct smbcli_request *req;
+ req = smb_raw_changenotify_send(servers[n].smb_tree[instance], &parm[n]);
+ req->async.fn = async_notify_smb;
+ }
+
+ return true;
+}
+
+
+/*
+ generate ntcreatex operations
+*/
+static bool handler_smb2_create(int instance)
+{
+ struct smb2_create parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ ZERO_STRUCT(parm[0]);
+ parm[0].in.security_flags = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFF);
+ parm[0].in.oplock_level = gen_bits_levels(3, 90, 0x0, 70, 0x9, 100, 0xFF);
+ parm[0].in.impersonation_level = gen_bits_levels(3, 90, 0x0, 70, 0x3, 100, 0xFFFFFFFF);
+ parm[0].in.create_flags = gen_reserved64();
+ parm[0].in.reserved = gen_reserved64();
+ parm[0].in.desired_access = gen_access_mask();
+ parm[0].in.file_attributes = gen_attrib();
+ parm[0].in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
+ parm[0].in.create_disposition = gen_open_disp();
+ parm[0].in.create_options = gen_create_options();
+ parm[0].in.fname = gen_fname_open(instance);
+ parm[0].in.eas = gen_ea_list();
+ parm[0].in.alloc_size = gen_alloc_size();
+ parm[0].in.durable_open = gen_bool();
+ parm[0].in.query_maximal_access = gen_bool();
+ parm[0].in.timewarp = gen_timewarp();
+ parm[0].in.query_on_disk_id = gen_bool();
+ parm[0].in.sec_desc = gen_sec_desc();
+
+ if (!options.use_oplocks) {
+ /* mask out oplocks */
+ parm[0].in.oplock_level = 0;
+ }
+
+ if (options.valid) {
+ parm[0].in.security_flags &= 3;
+ parm[0].in.oplock_level &= 9;
+ parm[0].in.impersonation_level &= 3;
+ }
+
+ GEN_COPY_PARM;
+ GEN_CALL_SMB2(smb2_create(tree, current_op.mem_ctx, &parm[i]));
+
+ CHECK_EQUAL(out.oplock_level);
+ CHECK_EQUAL(out.reserved);
+ CHECK_EQUAL(out.create_action);
+ CHECK_NTTIMES_EQUAL(out.create_time);
+ CHECK_NTTIMES_EQUAL(out.access_time);
+ CHECK_NTTIMES_EQUAL(out.write_time);
+ CHECK_NTTIMES_EQUAL(out.change_time);
+ CHECK_EQUAL(out.alloc_size);
+ CHECK_EQUAL(out.size);
+ CHECK_ATTRIB(out.file_attr);
+ CHECK_EQUAL(out.reserved2);
+ CHECK_EQUAL(out.maximal_access);
+
+ /* ntcreatex creates a new file handle */
+ ADD_HANDLE_SMB2(parm[0].in.fname, out.file.handle);
+
+ return true;
+}
+
+/*
+ generate close operations
+*/
+static bool handler_smb2_close(int instance)
+{
+ struct smb2_close parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ ZERO_STRUCT(parm[0]);
+ parm[0].in.file.handle.data[0] = gen_fnum_close(instance);
+ parm[0].in.flags = gen_bits_mask2(0x1, 0xFFFF);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(in.file.handle);
+ GEN_CALL_SMB2(smb2_close(tree, &parm[i]));
+
+ CHECK_EQUAL(out.flags);
+ CHECK_EQUAL(out._pad);
+ CHECK_NTTIMES_EQUAL(out.create_time);
+ CHECK_NTTIMES_EQUAL(out.access_time);
+ CHECK_NTTIMES_EQUAL(out.write_time);
+ CHECK_NTTIMES_EQUAL(out.change_time);
+ CHECK_EQUAL(out.alloc_size);
+ CHECK_EQUAL(out.size);
+ CHECK_ATTRIB(out.file_attr);
+
+ REMOVE_HANDLE_SMB2(in.file.handle);
+
+ return true;
+}
+
+/*
+ generate read operations
+*/
+static bool handler_smb2_read(int instance)
+{
+ struct smb2_read parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].in.file.handle.data[0] = gen_fnum(instance);
+ parm[0].in.reserved = gen_reserved8();
+ parm[0].in.length = gen_io_count();
+ parm[0].in.offset = gen_offset();
+ parm[0].in.min_count = gen_io_count();
+ parm[0].in.channel = gen_bits_mask2(0x0, 0xFFFFFFFF);
+ parm[0].in.remaining = gen_bits_mask2(0x0, 0xFFFFFFFF);
+ parm[0].in.channel_offset = gen_bits_mask2(0x0, 0xFFFF);
+ parm[0].in.channel_length = gen_bits_mask2(0x0, 0xFFFF);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(in.file.handle);
+ GEN_CALL_SMB2(smb2_read(tree, current_op.mem_ctx, &parm[i]));
+
+ CHECK_EQUAL(out.remaining);
+ CHECK_EQUAL(out.reserved);
+ CHECK_EQUAL(out.data.length);
+
+ return true;
+}
+
+/*
+ generate write operations
+*/
+static bool handler_smb2_write(int instance)
+{
+ struct smb2_write parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].in.file.handle.data[0] = gen_fnum(instance);
+ parm[0].in.offset = gen_offset();
+ parm[0].in.unknown1 = gen_bits_mask2(0, 0xFFFFFFFF);
+ parm[0].in.unknown2 = gen_bits_mask2(0, 0xFFFFFFFF);
+ parm[0].in.data = data_blob_talloc(current_op.mem_ctx, NULL,
+ gen_io_count());
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(in.file.handle);
+ GEN_CALL_SMB2(smb2_write(tree, &parm[i]));
+
+ CHECK_EQUAL(out._pad);
+ CHECK_EQUAL(out.nwritten);
+ CHECK_EQUAL(out.unknown1);
+
+ return true;
+}
+
+/*
+ generate lockingx operations
+*/
+static bool handler_smb2_lock(int instance)
+{
+ struct smb2_lock parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+ int n;
+
+ parm[0].level = RAW_LOCK_LOCKX;
+ parm[0].in.file.handle.data[0] = gen_fnum(instance);
+ parm[0].in.lock_count = gen_lock_count();
+ parm[0].in.lock_sequence = gen_reserved32();
+
+ parm[0].in.locks = talloc_array(current_op.mem_ctx,
+ struct smb2_lock_element,
+ parm[0].in.lock_count);
+ for (n=0;n<parm[0].in.lock_count;n++) {
+ parm[0].in.locks[n].offset = gen_offset();
+ parm[0].in.locks[n].length = gen_io_count();
+ /* don't yet cope with async replies */
+ parm[0].in.locks[n].flags = gen_lock_flags_smb2() |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ parm[0].in.locks[n].reserved = gen_bits_mask2(0x0, 0xFFFFFFFF);
+ }
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(in.file.handle);
+ GEN_CALL_SMB2(smb2_lock(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ generate flush operations
+*/
+static bool handler_smb2_flush(int instance)
+{
+ struct smb2_flush parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ ZERO_STRUCT(parm[0]);
+ parm[0].in.file.handle.data[0] = gen_fnum(instance);
+ parm[0].in.reserved1 = gen_reserved16();
+ parm[0].in.reserved2 = gen_reserved32();
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(in.file.handle);
+ GEN_CALL_SMB2(smb2_flush(tree, &parm[i]));
+
+ CHECK_EQUAL(out.reserved);
+
+ return true;
+}
+
+/*
+ generate echo operations
+*/
+static bool handler_smb2_echo(int instance)
+{
+ NTSTATUS status[NSERVERS];
+
+ GEN_CALL_SMB2(smb2_keepalive(tree->session->transport));
+
+ return true;
+}
+
+
+
+/*
+ generate a fileinfo query structure
+*/
+static void gen_fileinfo_smb2(int instance, union smb_fileinfo *info)
+{
+ int i;
+ #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
+ struct {
+ enum smb_fileinfo_level level;
+ const char *name;
+ } levels[] = {
+ LVL(BASIC_INFORMATION),
+ LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
+ LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
+ LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(SMB2_ALL_INFORMATION),
+ LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
+ LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION),
+ LVL(SMB2_ALL_EAS), LVL(SMB2_ALL_INFORMATION), LVL(SEC_DESC),
+ };
+ do {
+ i = gen_int_range(0, ARRAY_SIZE(levels)-1);
+ } while (ignore_pattern(levels[i].name));
+
+ info->generic.level = levels[i].level;
+}
+
+/*
+ generate qfileinfo operations
+*/
+static bool handler_smb2_qfileinfo(int instance)
+{
+ union smb_fileinfo parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ parm[0].generic.in.file.handle.data[0] = gen_fnum(instance);
+
+ gen_fileinfo_smb2(instance, &parm[0]);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(generic.in.file.handle);
+ GEN_CALL_SMB2(smb2_getinfo_file(tree, current_op.mem_ctx, &parm[i]));
+
+ return cmp_fileinfo(instance, parm, status);
+}
+
+
+/*
+ generate setfileinfo operations
+*/
+static bool handler_smb2_sfileinfo(int instance)
+{
+ union smb_setfileinfo parm[NSERVERS];
+ NTSTATUS status[NSERVERS];
+
+ gen_setfileinfo(instance, &parm[0]);
+ parm[0].generic.in.file.fnum = gen_fnum(instance);
+
+ GEN_COPY_PARM;
+ GEN_SET_FNUM_SMB2(generic.in.file.handle);
+ GEN_CALL_SMB2(smb2_setinfo_file(tree, &parm[i]));
+
+ return true;
+}
+
+/*
+ wipe any relevant files
+*/
+static void wipe_files(void)
+{
+ int i;
+ NTSTATUS status;
+
+ if (options.skip_cleanup) {
+ return;
+ }
+
+ for (i=0;i<NSERVERS;i++) {
+ int n;
+ if (options.smb2) {
+ n = smb2_deltree(servers[i].smb2_tree[0], "gentest");
+ } else {
+ n = smbcli_deltree(servers[i].smb_tree[0], "gentest");
+ }
+ if (n == -1) {
+ printf("Failed to wipe tree on server %d\n", i);
+ exit(1);
+ }
+ if (options.smb2) {
+ status = smb2_util_mkdir(servers[i].smb2_tree[0], "gentest");
+ } else {
+ status = smbcli_mkdir(servers[i].smb_tree[0], "gentest");
+ }
+ if (NT_STATUS_IS_ERR(status)) {
+ printf("Failed to create gentest on server %d - %s\n", i, nt_errstr(status));
+ exit(1);
+ }
+ if (n > 0) {
+ printf("Deleted %d files on server %d\n", n, i);
+ }
+ }
+}
+
+/*
+ dump the current seeds - useful for continuing a backtrack
+*/
+static void dump_seeds(void)
+{
+ int i;
+ FILE *f;
+
+ if (!options.seeds_file) {
+ return;
+ }
+ f = fopen("seeds.tmp", "w");
+ if (!f) return;
+
+ for (i=0;i<options.numops;i++) {
+ fprintf(f, "%u\n", op_parms[i].seed);
+ }
+ fclose(f);
+ rename("seeds.tmp", options.seeds_file);
+}
+
+
+
+/*
+ the list of top-level operations that we will generate
+*/
+static struct {
+ const char *name;
+ bool (*handler)(int instance);
+ bool smb2;
+ int count, success_count;
+} gen_ops[] = {
+ {
+ .name = "CREATE",
+ .handler = handler_smb2_create,
+ .smb2 = true,
+ },
+ {
+ .name = "CLOSE",
+ .handler = handler_smb2_close,
+ .smb2 = true,
+ },
+ {
+ .name = "READ",
+ .handler = handler_smb2_read,
+ .smb2 = true,
+ },
+ {
+ .name = "WRITE",
+ .handler = handler_smb2_write,
+ .smb2 = true,
+ },
+ {
+ .name = "LOCK",
+ .handler = handler_smb2_lock,
+ .smb2 = true,
+ },
+ {
+ .name = "FLUSH",
+ .handler = handler_smb2_flush,
+ .smb2 = true,
+ },
+ {
+ .name = "ECHO",
+ .handler = handler_smb2_echo,
+ .smb2 = true,
+ },
+ {
+ .name = "QFILEINFO",
+ .handler = handler_smb2_qfileinfo,
+ .smb2 = true,
+ },
+ {
+ .name = "SFILEINFO",
+ .handler = handler_smb2_sfileinfo,
+ .smb2 = true,
+ },
+
+ {
+ .name = "OPEN",
+ .handler = handler_smb_open,
+ .smb2 = false,
+ },
+ {
+ .name = "OPENX",
+ .handler = handler_smb_openx,
+ .smb2 = false,
+ },
+ {
+ .name = "NTCREATEX",
+ .handler = handler_smb_ntcreatex,
+ .smb2 = false,
+ },
+ {
+ .name = "CLOSE",
+ .handler = handler_smb_close,
+ .smb2 = false,
+ },
+ {
+ .name = "UNLINK",
+ .handler = handler_smb_unlink,
+ .smb2 = false,
+ },
+ {
+ .name = "MKDIR",
+ .handler = handler_smb_mkdir,
+ .smb2 = false,
+ },
+ {
+ .name = "RMDIR",
+ .handler = handler_smb_rmdir,
+ .smb2 = false,
+ },
+ {
+ .name = "RENAME",
+ .handler = handler_smb_rename,
+ .smb2 = false,
+ },
+ {
+ .name = "NTRENAME",
+ .handler = handler_smb_ntrename,
+ .smb2 = false,
+ },
+ {
+ .name = "READX",
+ .handler = handler_smb_readx,
+ .smb2 = false,
+ },
+ {
+ .name = "WRITEX",
+ .handler = handler_smb_writex,
+ .smb2 = false,
+ },
+ {
+ .name = "CHKPATH",
+ .handler = handler_smb_chkpath,
+ .smb2 = false,
+ },
+ {
+ .name = "SEEK",
+ .handler = handler_smb_seek,
+ .smb2 = false,
+ },
+ {
+ .name = "LOCKINGX",
+ .handler = handler_smb_lockingx,
+ .smb2 = false,
+ },
+ {
+ .name = "QPATHINFO",
+ .handler = handler_smb_qpathinfo,
+ .smb2 = false,
+ },
+ {
+ .name = "QFILEINFO",
+ .handler = handler_smb_qfileinfo,
+ .smb2 = false,
+ },
+ {
+ .name = "SPATHINFO",
+ .handler = handler_smb_spathinfo,
+ .smb2 = false,
+ },
+ {
+ .name = "SFILEINFO",
+ .handler = handler_smb_sfileinfo,
+ .smb2 = false,
+ },
+ {
+ .name = "NOTIFY",
+ .handler = handler_smb_notify,
+ .smb2 = false,
+ },
+};
+
+
+/*
+ run the test with the current set of op_parms parameters
+ return the number of operations that completed successfully
+*/
+static int run_test(struct tevent_context *ev, struct loadparm_context *lp_ctx)
+{
+ int op, i;
+
+ if (!connect_servers(ev, lp_ctx)) {
+ printf("Failed to connect to servers\n");
+ exit(1);
+ }
+
+ dump_seeds();
+
+ /* wipe any leftover files from old runs */
+ wipe_files();
+
+ /* reset the open handles array */
+ memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0]));
+ num_open_handles = 0;
+
+ /* reset the counts from previous runs */
+ for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
+ gen_ops[i].count = 0;
+ gen_ops[i].success_count = 0;
+ }
+
+ for (op=0; op<options.numops; op++) {
+ int instance, which_op;
+ bool ret;
+
+ if (op_parms[op].disabled) continue;
+
+ srandom(op_parms[op].seed);
+
+ instance = gen_int_range(0, NINSTANCES-1);
+
+ /* generate a non-ignored operation */
+ do {
+ which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1);
+ } while (ignore_pattern(gen_ops[which_op].name) ||
+ gen_ops[which_op].smb2 != options.smb2);
+
+ DEBUG(3,("Generating op %s on instance %d\n",
+ gen_ops[which_op].name, instance));
+
+ current_op.seed = op_parms[op].seed;
+ current_op.opnum = op;
+ current_op.name = gen_ops[which_op].name;
+ current_op.status = NT_STATUS_OK;
+ talloc_free(current_op.mem_ctx);
+ current_op.mem_ctx = talloc_named(NULL, 0, "%s", current_op.name);
+
+ ret = gen_ops[which_op].handler(instance);
+
+ gen_ops[which_op].count++;
+ if (NT_STATUS_IS_OK(current_op.status)) {
+ gen_ops[which_op].success_count++;
+ }
+
+ if (!ret) {
+ printf("Failed at operation %d - %s\n",
+ op, gen_ops[which_op].name);
+ return op;
+ }
+
+ if (op % 100 == 0) {
+ printf("%d\n", op);
+ }
+ }
+
+ for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
+ printf("Op %-10s got %d/%d success\n",
+ gen_ops[i].name,
+ gen_ops[i].success_count,
+ gen_ops[i].count);
+ }
+
+ return op;
+}
+
+/*
+ perform a backtracking analysis of the minimal set of operations
+ to generate an error
+*/
+static void backtrack_analyze(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx)
+{
+ int chunk, ret;
+ const char *mismatch = current_op.mismatch;
+
+ chunk = options.numops / 2;
+
+ do {
+ int base;
+ for (base=0;
+ chunk > 0 && base+chunk < options.numops && options.numops > 1; ) {
+ int i, max;
+
+ chunk = MIN(chunk, options.numops / 2);
+
+ /* mark this range as disabled */
+ max = MIN(options.numops, base+chunk);
+ for (i=base;i<max; i++) {
+ op_parms[i].disabled = true;
+ }
+ printf("Testing %d ops with %d-%d disabled\n",
+ options.numops, base, max-1);
+ ret = run_test(ev, lp_ctx);
+ printf("Completed %d of %d ops\n", ret, options.numops);
+ for (i=base;i<max; i++) {
+ op_parms[i].disabled = false;
+ }
+ if (ret == options.numops) {
+ /* this chunk is needed */
+ base += chunk;
+ } else if (mismatch != current_op.mismatch &&
+ strcmp(mismatch, current_op.mismatch)) {
+ base += chunk;
+ printf("Different error in backtracking\n");
+ } else if (ret < base) {
+ printf("damn - inconsistent errors! found early error\n");
+ options.numops = ret+1;
+ base = 0;
+ } else {
+ /* it failed - this chunk isn't needed for a failure */
+ memmove(&op_parms[base], &op_parms[max],
+ sizeof(op_parms[0]) * (options.numops - max));
+ options.numops = (ret+1) - (max - base);
+ }
+ }
+
+ if (chunk == 2) {
+ chunk = 1;
+ } else {
+ chunk *= 0.4;
+ }
+
+ if (options.analyze_continuous && chunk == 0 && options.numops != 1) {
+ chunk = 1;
+ }
+ } while (chunk > 0);
+
+ printf("Reduced to %d ops\n", options.numops);
+ ret = run_test(ev, lp_ctx);
+ if (ret != options.numops - 1) {
+ printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops);
+ }
+}
+
+/*
+ start the main gentest process
+*/
+static bool start_gentest(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx)
+{
+ int op;
+ int ret;
+
+ /* allocate the open_handles array */
+ open_handles = calloc(options.max_open_handles, sizeof(open_handles[0]));
+ if (open_handles == NULL) {
+ printf("Unable to allocate memory for open_handles array.\n");
+ exit(1);
+ }
+
+ srandom(options.seed);
+ op_parms = calloc(options.numops, sizeof(op_parms[0]));
+ if (op_parms == NULL) {
+ printf("Unable to allocate memory for op_parms.\n");
+ exit(1);
+ }
+
+ /* generate the seeds - after this everything is deterministic */
+ if (options.use_preset_seeds) {
+ int numops;
+ char **preset = file_lines_load(options.seeds_file, &numops, 0, NULL);
+ if (!preset) {
+ printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno));
+ exit(1);
+ }
+ if (numops < options.numops) {
+ options.numops = numops;
+ }
+ for (op=0;op<options.numops;op++) {
+ if (!preset[op]) {
+ printf("Not enough seeds in %s\n", options.seeds_file);
+ exit(1);
+ }
+ op_parms[op].seed = atoi(preset[op]);
+ }
+ printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file);
+ } else {
+ for (op=0; op<options.numops; op++) {
+ op_parms[op].seed = random();
+ }
+ }
+
+ ret = run_test(ev, lp_ctx);
+
+ if (ret != options.numops && options.analyze) {
+ options.numops = ret+1;
+ backtrack_analyze(ev, lp_ctx);
+ } else if (options.analyze_always) {
+ backtrack_analyze(ev, lp_ctx);
+ } else if (options.analyze_continuous) {
+ while (run_test(ev, lp_ctx) == options.numops) ;
+ }
+
+ return ret == options.numops;
+}
+
+
+static void usage(poptContext pc)
+{
+ printf(
+"Usage:\n\
+ gentest //server1/share1 //server2/share2 [options..]\n\
+");
+ poptPrintUsage(pc, stdout, 0);
+}
+
+/**
+ split a UNC name into server and share names
+*/
+static bool split_unc_name(const char *unc, char **server, char **share)
+{
+ char *p = strdup(unc);
+ if (!p) return false;
+ all_string_sub(p, "\\", "/", 0);
+ if (strncmp(p, "//", 2) != 0) return false;
+
+ (*server) = p+2;
+ p = strchr(*server, '/');
+ if (!p) return false;
+
+ *p = 0;
+ (*share) = p+1;
+
+ return true;
+}
+
+
+
+/****************************************************************************
+ main program
+****************************************************************************/
+int main(int argc, const char *argv[])
+{
+ int opt;
+ int i, username_count=0;
+ bool ret;
+ char *ignore_file=NULL;
+ struct tevent_context *ev;
+ struct loadparm_context *lp_ctx;
+ poptContext pc;
+ int argc_new;
+ char **argv_new;
+ enum {
+ OPT_UNCLIST=1000,
+ OPT_USER1,
+ OPT_USER2,
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"smb2", 0, POPT_ARG_NONE, &options.smb2, 0, "use SMB2 protocol", NULL},
+ {"seed", 0, POPT_ARG_INT, &options.seed, 0, "Seed to use for randomizer", NULL},
+ {"num-ops", 0, POPT_ARG_INT, &options.numops, 0, "num ops", NULL},
+ {"oplocks", 0, POPT_ARG_NONE, &options.use_oplocks,0, "use oplocks", NULL},
+ {"showall", 0, POPT_ARG_NONE, &options.showall, 0, "display all operations", NULL},
+ {"analyse", 0, POPT_ARG_NONE, &options.analyze, 0, "do backtrack analysis", NULL},
+ {"analysealways", 0, POPT_ARG_NONE, &options.analyze_always, 0, "analysis always", NULL},
+ {"analysecontinuous", 0, POPT_ARG_NONE, &options.analyze_continuous, 0, "analysis continuous", NULL},
+ {"ignore", 0, POPT_ARG_STRING, &ignore_file, 0, "ignore from file", NULL},
+ {"preset", 0, POPT_ARG_NONE, &options.use_preset_seeds, 0, "use preset seeds", NULL},
+ {"fast", 0, POPT_ARG_NONE, &options.fast_reconnect, 0, "use fast reconnect", NULL},
+ {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
+ {"seedsfile", 0, POPT_ARG_STRING, &options.seeds_file, 0, "seed file", NULL},
+ {"user1", 0, POPT_ARG_STRING, NULL, OPT_USER1, "Set first network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
+ {"user2", 0, POPT_ARG_STRING, NULL, OPT_USER2, "Set second network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
+ {"maskindexing", 0, POPT_ARG_NONE, &options.mask_indexing, 0, "mask out the indexed file attrib", NULL},
+ {"noeas", 0, POPT_ARG_NONE, &options.no_eas, 0, "don't use extended attributes", NULL},
+ {"noacls", 0, POPT_ARG_NONE, &options.no_acls, 0, "don't use ACLs", NULL},
+ {"skip-cleanup", 0, POPT_ARG_NONE, &options.skip_cleanup, 0, "don't delete files at start", NULL},
+ {"valid", 0, POPT_ARG_NONE, &options.valid, 0, "generate only valid fields", NULL},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+ POPT_LEGACY_S4
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ok;
+
+ memset(&bad_smb2_handle, 0xFF, sizeof(bad_smb2_handle));
+
+ setlinebuf(stdout);
+ options.seed = time(NULL);
+ options.numops = 1000;
+ options.max_open_handles = 20;
+ options.seeds_file = "gentest_seeds.dat";
+
+ mem_ctx = talloc_named_const(NULL, 0, "gentest_ctx");
+ if (mem_ctx == NULL) {
+ printf("Unable to allocate gentest_ctx\n");
+ exit(1);
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+ servers[0].credentials = cli_credentials_init(mem_ctx);
+ servers[1].credentials = cli_credentials_init(mem_ctx);
+ cli_credentials_guess(servers[0].credentials, lp_ctx);
+ cli_credentials_guess(servers[1].credentials, lp_ctx);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_UNCLIST:
+ lpcfg_set_cmdline(lp_ctx, "torture:unclist", poptGetOptArg(pc));
+ break;
+ case OPT_USER1:
+ cli_credentials_parse_string(servers[0].credentials,
+ poptGetOptArg(pc),
+ CRED_SPECIFIED);
+ username_count++;
+ break;
+ case OPT_USER2:
+ cli_credentials_parse_string(servers[1].credentials,
+ poptGetOptArg(pc),
+ CRED_SPECIFIED);
+ username_count++;
+ break;
+ case POPT_ERROR_BADOPT:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ if (ignore_file) {
+ options.ignore_patterns = file_lines_load(ignore_file, NULL, 0, NULL);
+ }
+
+ argv_new = discard_const_p(char *, poptGetArgs(pc));
+ argc_new = argc;
+ for (i=0; i<argc; i++) {
+ if (argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (!(argc_new >= 3)) {
+ usage(pc);
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+
+ setlinebuf(stdout);
+
+ setup_logging("gentest", DEBUG_STDOUT);
+
+ if (argc < 3 || argv[1][0] == '-') {
+ usage(pc);
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+
+ setup_logging(argv[0], DEBUG_STDOUT);
+
+ for (i=0;i<NSERVERS;i++) {
+ const char *share = argv[1+i];
+ if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) {
+ printf("Invalid share name '%s'\n", share);
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return -1;
+ }
+ }
+
+ if (username_count == 0) {
+ usage(pc);
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return -1;
+ }
+ if (username_count == 1) {
+ servers[1].credentials = servers[0].credentials;
+ }
+
+ printf("seed=%u\n", options.seed);
+
+ ev = s4_event_context_init(mem_ctx);
+
+ gensec_init();
+
+ ret = start_gentest(ev, lp_ctx);
+
+ if (ret) {
+ printf("gentest completed - no errors\n");
+ } else {
+ printf("gentest failed\n");
+ }
+
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return ret?0:-1;
+}
diff --git a/source4/torture/gpo/apply.c b/source4/torture/gpo/apply.c
new file mode 100644
index 0000000..560408f
--- /dev/null
+++ b/source4/torture/gpo/apply.c
@@ -0,0 +1,390 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) David Mulder 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "param/param.h"
+#include "param/loadparm.h"
+#include "torture/smbtorture.h"
+#include "lib/util/mkdir_p.h"
+#include "dsdb/samdb/samdb.h"
+#include "auth/session.h"
+#include "lib/ldb/include/ldb.h"
+#include "torture/gpo/proto.h"
+#include <unistd.h>
+#include "lib/util/samba_util.h"
+#include "util/tevent_ntstatus.h"
+
+#undef strncasecmp
+
+struct torture_suite *gpo_apply_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "apply");
+
+ torture_suite_add_simple_test(suite, "gpo_param_from_gpo",
+ torture_gpo_system_access_policies);
+
+ suite->description = talloc_strdup(suite, "Group Policy apply tests");
+
+ return suite;
+}
+
+static int exec_wait(struct torture_context *tctx, const char **gpo_update_cmd)
+{
+ NTSTATUS status;
+ int ret = 0;
+ struct tevent_req *req;
+
+ req = samba_runcmd_send(tctx,
+ tctx->ev,
+ timeval_current_ofs(100, 0),
+ 2, 0,
+ gpo_update_cmd,
+ "gpo_reload_cmd", NULL);
+ if (req == NULL) {
+ return -1;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, tctx->ev, &status)) {
+ return -1;
+ }
+ if (samba_runcmd_recv(req, &ret) != 0) {
+ return -1;
+ }
+ return ret;
+}
+
+static int unix2nttime(const char *sval)
+{
+ return (strtoll(sval, NULL, 10) * -1 / 60 / 60 / 24 / 10000000);
+}
+
+#define GPODIR "addom.samba.example.com/Policies/"\
+ "{31B2F340-016D-11D2-945F-00C04FB984F9}/MACHINE/Microsoft/"\
+ "Windows NT/SecEdit"
+#define GPOFILE "GptTmpl.inf"
+#define GPTTMPL "[System Access]\n\
+MinimumPasswordAge = %d\n\
+MaximumPasswordAge = %d\n\
+MinimumPasswordLength = %d\n\
+PasswordComplexity = %d\n\
+"
+#define GPTINI "addom.samba.example.com/Policies/"\
+ "{31B2F340-016D-11D2-945F-00C04FB984F9}/GPT.INI"
+
+bool torture_gpo_system_access_policies(struct torture_context *tctx)
+{
+ TALLOC_CTX *ctx = talloc_new(tctx);
+ int ret, vers = 0, i;
+ const char *sysvol_path = NULL, *gpo_dir = NULL;
+ const char *gpo_file = NULL, *gpt_file = NULL;
+ struct ldb_context *samdb = NULL;
+ struct ldb_result *result;
+ const char *attrs[] = {
+ "minPwdAge",
+ "maxPwdAge",
+ "minPwdLength",
+ "pwdProperties",
+ NULL
+ };
+ FILE *fp = NULL;
+ const char **gpo_update_cmd;
+ const char **gpo_unapply_cmd;
+ const char **gpo_update_force_cmd;
+ int minpwdcases[] = { 0, 1, 998 };
+ int maxpwdcases[] = { 0, 1, 999 };
+ int pwdlencases[] = { 0, 1, 14 };
+ int pwdpropcases[] = { 0, 1, 1 };
+ struct ldb_message *old_message = NULL;
+ const char **itr;
+ int gpo_update_len = 0;
+
+ sysvol_path = lpcfg_path(lpcfg_service(tctx->lp_ctx, "sysvol"),
+ lpcfg_default_service(tctx->lp_ctx), tctx);
+ torture_assert(tctx, sysvol_path, "Failed to fetch the sysvol path");
+
+ /* Ensure the sysvol path exists */
+ gpo_dir = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPODIR);
+ mkdir_p(gpo_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ gpo_file = talloc_asprintf(ctx, "%s/%s", gpo_dir, GPOFILE);
+
+ /* Get the gpo update command */
+ gpo_update_cmd = lpcfg_gpo_update_command(tctx->lp_ctx);
+ torture_assert(tctx, gpo_update_cmd && gpo_update_cmd[0],
+ "Failed to fetch the gpo update command");
+
+ /* Open and read the samba db and store the initial password settings */
+ samdb = samdb_connect(ctx,
+ tctx->ev,
+ tctx->lp_ctx,
+ system_session(tctx->lp_ctx),
+ NULL,
+ 0);
+ torture_assert(tctx, samdb, "Failed to connect to the samdb");
+
+ ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb),
+ LDB_SCOPE_BASE, attrs, NULL);
+ torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1,
+ "Searching the samdb failed");
+
+ old_message = result->msgs[0];
+
+ for (i = 0; i < 3; i++) {
+ /* Write out the sysvol */
+ if ( (fp = fopen(gpo_file, "w")) ) {
+ fputs(talloc_asprintf(ctx, GPTTMPL, minpwdcases[i],
+ maxpwdcases[i], pwdlencases[i],
+ pwdpropcases[i]), fp);
+ fclose(fp);
+ }
+
+ /* Update the version in the GPT.INI */
+ gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI);
+ if ( (fp = fopen(gpt_file, "r")) ) {
+ char line[256];
+ while (fgets(line, 256, fp)) {
+ if (strncasecmp(line, "Version=", 8) == 0) {
+ vers = atoi(line+8);
+ break;
+ }
+ }
+ fclose(fp);
+ }
+ if ( (fp = fopen(gpt_file, "w")) ) {
+ char *data = talloc_asprintf(ctx,
+ "[General]\nVersion=%d\n",
+ ++vers);
+ fputs(data, fp);
+ fclose(fp);
+ }
+
+ /* Run the gpo update command */
+ ret = exec_wait(tctx, gpo_update_cmd);
+
+ torture_assert(tctx, ret == 0,
+ "Failed to execute the gpo update command");
+ ret = ldb_search(samdb, ctx, &result,
+ ldb_get_default_basedn(samdb),
+ LDB_SCOPE_BASE, attrs, NULL);
+ torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1,
+ "Searching the samdb failed");
+
+ /* minPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(
+ ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[0],
+ "")), minpwdcases[i],
+ "The minPwdAge was not applied");
+
+ /* maxPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(
+ ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[1],
+ "")), maxpwdcases[i],
+ "The maxPwdAge was not applied");
+
+ /* minPwdLength */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[2],
+ -1),
+ pwdlencases[i],
+ "The minPwdLength was not applied");
+
+ /* pwdProperties */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[3],
+ -1),
+ pwdpropcases[i],
+ "The pwdProperties were not applied");
+ }
+
+ /* Reset settings, then verify a reapply doesn't force them back */
+ for (i = 0; i < old_message->num_elements; i++) {
+ old_message->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+ ret = ldb_modify(samdb, old_message);
+ torture_assert(tctx, ret == 0, "Failed to reset password settings.");
+
+ ret = exec_wait(tctx, gpo_update_cmd);
+ torture_assert(tctx, ret == 0,
+ "Failed to execute the gpo update command");
+
+ /* Validate that the apply did nothing (without --force param) */
+ ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb),
+ LDB_SCOPE_BASE, attrs, NULL);
+ torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1,
+ "Searching the samdb failed");
+ /* minPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[0],
+ "")),
+ unix2nttime(ldb_msg_find_attr_as_string(old_message,
+ attrs[0],
+ "")
+ ),
+ "The minPwdAge was re-applied");
+ /* maxPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[1],
+ "")),
+ unix2nttime(ldb_msg_find_attr_as_string(old_message,
+ attrs[1],
+ "")
+ ),
+ "The maxPwdAge was re-applied");
+ /* minPwdLength */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[2],
+ -1),
+ ldb_msg_find_attr_as_int(
+ old_message,
+ attrs[2],
+ -2),
+ "The minPwdLength was re-applied");
+ /* pwdProperties */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[3],
+ -1),
+ ldb_msg_find_attr_as_int(
+ old_message,
+ attrs[3],
+ -2),
+ "The pwdProperties were re-applied");
+
+ for (itr = gpo_update_cmd; *itr != NULL; itr++) {
+ gpo_update_len++;
+ }
+
+ /* Run gpupdate --force and verify settings are re-applied */
+ gpo_update_force_cmd = talloc_array(ctx, const char*, gpo_update_len+2);
+ for (i = 0; i < gpo_update_len; i++) {
+ gpo_update_force_cmd[i] = talloc_strdup(gpo_update_force_cmd,
+ gpo_update_cmd[i]);
+ }
+ gpo_update_force_cmd[i] = talloc_asprintf(gpo_update_force_cmd,
+ "--force");
+ gpo_update_force_cmd[i+1] = NULL;
+ ret = exec_wait(tctx, gpo_update_force_cmd);
+ torture_assert(tctx, ret == 0,
+ "Failed to execute the gpupdate --force command");
+
+ ret = ldb_search(samdb, ctx, &result,
+ ldb_get_default_basedn(samdb),
+ LDB_SCOPE_BASE, attrs, NULL);
+ torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1,
+ "Searching the samdb failed");
+
+ /* minPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(
+ ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[0],
+ "")), minpwdcases[2],
+ "The minPwdAge was not applied");
+
+ /* maxPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(
+ ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[1],
+ "")), maxpwdcases[2],
+ "The maxPwdAge was not applied");
+
+ /* minPwdLength */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[2],
+ -1),
+ pwdlencases[2],
+ "The minPwdLength was not applied");
+
+ /* pwdProperties */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[3],
+ -1),
+ pwdpropcases[2],
+ "The pwdProperties were not applied");
+
+ /* Unapply the settings and verify they are removed */
+ gpo_unapply_cmd = talloc_array(ctx, const char*, gpo_update_len+2);
+ for (i = 0; i < gpo_update_len; i++) {
+ gpo_unapply_cmd[i] = talloc_strdup(gpo_unapply_cmd,
+ gpo_update_cmd[i]);
+ }
+ gpo_unapply_cmd[i] = talloc_asprintf(gpo_unapply_cmd, "--unapply");
+ gpo_unapply_cmd[i+1] = NULL;
+ ret = exec_wait(tctx, gpo_unapply_cmd);
+ torture_assert(tctx, ret == 0,
+ "Failed to execute the gpo unapply command");
+ ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb),
+ LDB_SCOPE_BASE, attrs, NULL);
+ torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1,
+ "Searching the samdb failed");
+ /* minPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[0],
+ "")),
+ unix2nttime(ldb_msg_find_attr_as_string(old_message,
+ attrs[0],
+ "")
+ ),
+ "The minPwdAge was not unapplied");
+ /* maxPwdAge */
+ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string(
+ result->msgs[0],
+ attrs[1],
+ "")),
+ unix2nttime(ldb_msg_find_attr_as_string(old_message,
+ attrs[1],
+ "")
+ ),
+ "The maxPwdAge was not unapplied");
+ /* minPwdLength */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[2],
+ -1),
+ ldb_msg_find_attr_as_int(
+ old_message,
+ attrs[2],
+ -2),
+ "The minPwdLength was not unapplied");
+ /* pwdProperties */
+ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int(
+ result->msgs[0],
+ attrs[3],
+ -1),
+ ldb_msg_find_attr_as_int(
+ old_message,
+ attrs[3],
+ -2),
+ "The pwdProperties were not unapplied");
+
+ talloc_free(ctx);
+ return true;
+}
diff --git a/source4/torture/gpo/gpo.c b/source4/torture/gpo/gpo.c
new file mode 100644
index 0000000..4a06809
--- /dev/null
+++ b/source4/torture/gpo/gpo.c
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) David Mulder 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/gpo/proto.h"
+
+NTSTATUS torture_gpo_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "gpo");
+
+ torture_suite_add_suite(suite, gpo_apply_suite(suite));
+
+ suite->description = talloc_strdup(suite, "Group Policy tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/gpo/wscript_build b/source4/torture/gpo/wscript_build
new file mode 100644
index 0000000..d7b131f
--- /dev/null
+++ b/source4/torture/gpo/wscript_build
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_GPO',
+ source='''
+ gpo.c
+ apply.c
+ ''',
+ subsystem='smbtorture',
+ deps='torture samba-util-core ldb',
+ internal_module=True,
+ autoproto='proto.h',
+ init_function='torture_gpo_init'
+ )
diff --git a/source4/torture/krb5/kdc-canon-heimdal.c b/source4/torture/krb5/kdc-canon-heimdal.c
new file mode 100644
index 0000000..392329a
--- /dev/null
+++ b/source4/torture/krb5/kdc-canon-heimdal.c
@@ -0,0 +1,1091 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Validate the krb5 pac generation routines
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "torture/smbtorture.h"
+#include "torture/krb5/proto.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "source4/auth/kerberos/kerberos.h"
+#include "source4/auth/kerberos/kerberos_util.h"
+#include "lib/util/util_net.h"
+#include "auth/auth.h"
+#include "auth/auth_sam_reply.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+
+#undef strcasecmp
+
+#define TEST_CANONICALIZE 0x0000001
+#define TEST_ENTERPRISE 0x0000002
+#define TEST_UPPER_USERNAME 0x0000008
+#define TEST_WIN2K 0x0000020
+#define TEST_UPN 0x0000040
+#define TEST_S4U2SELF 0x0000080
+#define TEST_REMOVEDOLLAR 0x0000100
+#define TEST_AS_REQ_SPN 0x0000200
+#define TEST_ALL 0x00003FF
+
+struct test_data {
+ const char *test_name;
+ const char *realm;
+ const char *real_realm;
+ const char *real_domain;
+ const char *username;
+ const char *real_username;
+ bool canonicalize;
+ bool enterprise;
+ bool upper_username;
+ bool win2k;
+ bool upn;
+ bool other_upn_suffix;
+ bool s4u2self;
+ bool removedollar;
+ bool as_req_spn;
+ bool spn_is_upn;
+ const char *krb5_service;
+ const char *krb5_hostname;
+};
+
+struct torture_krb5_context {
+ struct smb_krb5_context *smb_krb5_context;
+ struct torture_context *tctx;
+ struct addrinfo *server;
+ struct test_data *test_data;
+ int packet_count;
+};
+
+struct pac_data {
+ const char *principal_name;
+};
+
+/*
+ * A helper function which avoids touching the local databases to
+ * generate the session info, as we just want to verify the principal
+ * name that we found in the ticket not the full local token
+ */
+static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ DATA_BLOB *pac_blob,
+ const char *principal_name,
+ const struct tsocket_address *remote_address,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS nt_status;
+ struct auth_user_info_dc *user_info_dc;
+ TALLOC_CTX *tmp_ctx;
+ struct pac_data *pac_data;
+
+ if (pac_blob == NULL) {
+ DBG_ERR("pac_blob missing\n");
+ return NT_STATUS_NO_IMPERSONATION_TOKEN;
+ }
+
+ tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data);
+
+ pac_data->principal_name = talloc_strdup(pac_data, principal_name);
+ if (!pac_data->principal_name) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
+ *pac_blob,
+ smb_krb5_context->krb5_context,
+ &user_info_dc, NULL, NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
+ session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+ }
+
+ session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
+ nt_status = auth_generate_session_info(mem_ctx,
+ NULL,
+ NULL,
+ user_info_dc, session_info_flags,
+ session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/* Check to see if we can pass the PAC across to the NETLOGON server for validation */
+
+/* Also happens to be a really good one-step verification of our Kerberos stack */
+
+static bool test_accept_ticket(struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ const char *principal,
+ DATA_BLOB client_to_server)
+{
+ NTSTATUS status;
+ struct gensec_security *gensec_server_context;
+ DATA_BLOB server_to_client;
+ struct auth4_context *auth_context;
+ struct auth_session_info *session_info;
+ struct pac_data *pac_data;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+
+ torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
+
+ auth_context = talloc_zero(tmp_ctx, struct auth4_context);
+ torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
+
+ auth_context->generate_session_info_pac = test_generate_session_info_pac;
+
+ status = gensec_server_start(tctx,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ auth_context, &gensec_server_context);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+ status = gensec_set_credentials(gensec_server_context, credentials);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+ status = gensec_start_mech_by_name(gensec_server_context, "krb5");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (server) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ /* Do a client-server update dance */
+ status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+
+ /* Extract the PAC using Samba's code */
+
+ status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+ pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
+
+ torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context");
+ torture_assert(tctx, pac_data->principal_name != NULL, "principal_name not present");
+ torture_assert_str_equal(tctx, pac_data->principal_name, principal, "wrong principal name");
+ return true;
+}
+
+/*
+ * This function is set in torture_krb5_init_context_canon as krb5
+ * send_and_recv function. This allows us to override what server the
+ * test is aimed at, and to inspect the packets just before they are
+ * sent to the network, and before they are processed on the recv
+ * side.
+ *
+ */
+static krb5_error_code test_krb5_send_to_realm_canon_override(struct smb_krb5_context *smb_krb5_context,
+ void *data, /* struct torture_krb5_context */
+ krb5_const_realm realm,
+ time_t timeout,
+ const krb5_data *send_buf,
+ krb5_data *recv_buf)
+{
+ krb5_error_code k5ret;
+
+ struct torture_krb5_context *test_context
+ = talloc_get_type_abort(data, struct torture_krb5_context);
+
+ SMB_ASSERT(smb_krb5_context == test_context->smb_krb5_context);
+
+ k5ret = smb_krb5_send_and_recv_func_forced_tcp(smb_krb5_context,
+ test_context->server,
+ timeout,
+ send_buf,
+ recv_buf);
+ if (k5ret != 0) {
+ return k5ret;
+ }
+
+ test_context->packet_count++;
+
+ return k5ret;
+}
+
+static int test_context_destructor(struct torture_krb5_context *test_context)
+{
+ freeaddrinfo(test_context->server);
+ return 0;
+}
+
+
+static bool torture_krb5_init_context_canon(struct torture_context *tctx,
+ struct test_data *test_data,
+ struct torture_krb5_context **torture_krb5_context)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ krb5_error_code k5ret;
+ bool ok;
+
+ struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
+ torture_assert(tctx, test_context != NULL, "Failed to allocate");
+
+ test_context->test_data = test_data;
+ test_context->tctx = tctx;
+
+ k5ret = smb_krb5_init_context(test_context, tctx->lp_ctx, &test_context->smb_krb5_context);
+ torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
+
+ ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
+ torture_assert(tctx, ok, "Failed to parse target server");
+
+ talloc_set_destructor(test_context, test_context_destructor);
+
+ set_sockaddr_port(test_context->server->ai_addr, 88);
+
+ k5ret = smb_krb5_set_send_to_kdc_func(test_context->smb_krb5_context,
+ test_krb5_send_to_realm_canon_override,
+ NULL, /* send_to_kdc */
+ test_context);
+ torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
+ *torture_krb5_context = test_context;
+ return true;
+}
+
+
+static bool torture_krb5_as_req_canon(struct torture_context *tctx, const void *tcase_data)
+{
+ krb5_error_code k5ret;
+ krb5_get_init_creds_opt *krb_options = NULL;
+ struct test_data *test_data = talloc_get_type_abort(tcase_data, struct test_data);
+ krb5_principal principal;
+ krb5_principal krbtgt_other;
+ krb5_principal expected_principal;
+ const char *principal_string = NULL;
+ char *krbtgt_other_string;
+ int principal_flags;
+ const char *expected_principal_string = NULL;
+ char *expected_unparse_principal_string;
+ int expected_principal_flags;
+ char *got_principal_string;
+ char *assertion_message;
+ const char *password = cli_credentials_get_password(
+ samba_cmdline_get_creds());
+ krb5_context k5_context;
+ struct torture_krb5_context *test_context;
+ bool ok;
+ krb5_creds my_creds;
+ krb5_creds *server_creds;
+ krb5_ccache ccache;
+ krb5_auth_context auth_context;
+ char *cc_name;
+ krb5_data in_data, enc_ticket;
+ krb5_get_creds_opt opt;
+
+ const char *spn = NULL;
+ const char *spn_real_realm = NULL;
+ const char *upn = torture_setting_string(tctx, "krb5-upn", "");
+ test_data->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
+ test_data->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
+
+ /*
+ * If we have not passed a UPN on the command line,
+ * then skip the UPN tests.
+ */
+ if (test_data->upn && upn[0] == '\0') {
+ torture_skip(tctx, "This test needs a UPN specified as --option=torture:krb5-upn=user@example.com to run");
+ }
+
+ /*
+ * If we have not passed a SPN on the command line,
+ * then skip the SPN tests.
+ */
+ if (test_data->as_req_spn && test_data->krb5_hostname[0] == '\0') {
+ torture_skip(tctx, "This test needs a hostname specified as --option=torture:krb5-hostname=hostname.example.com and optionally --option=torture:krb5-service=service (defaults to host) to run");
+ }
+
+ if (test_data->removedollar &&
+ !torture_setting_bool(tctx, "run_removedollar_test", false))
+ {
+ torture_skip(tctx, "--option=torture:run_removedollar_test=true not specified");
+ }
+
+ test_data->realm = test_data->real_realm;
+
+ if (test_data->upn) {
+ char *p;
+ test_data->username = talloc_strdup(test_data, upn);
+ p = strchr(test_data->username, '@');
+ if (p) {
+ *p = '\0';
+ p++;
+ }
+ /*
+ * Test the UPN behaviour carefully. We can
+ * test in two different modes, depending on
+ * what UPN has been set up for us.
+ *
+ * If the UPN is in our realm, then we do all the tests with this name also.
+ *
+ * If the UPN is not in our realm, then we
+ * expect the tests that replace the realm to
+ * fail (as it won't match)
+ */
+ if (strcasecmp(p, test_data->real_realm) != 0) {
+ test_data->other_upn_suffix = true;
+ } else {
+ test_data->other_upn_suffix = false;
+ }
+
+ /*
+ * This lets us test the combination of the UPN prefix
+ * with a valid domain, without adding even more
+ * combinations
+ */
+ test_data->realm = p;
+ }
+
+ ok = torture_krb5_init_context_canon(tctx, test_data, &test_context);
+ torture_assert(tctx, ok, "torture_krb5_init_context failed");
+ k5_context = test_context->smb_krb5_context->krb5_context;
+
+ test_data->realm = strupper_talloc(test_data, test_data->realm);
+ if (test_data->upper_username) {
+ test_data->username = strupper_talloc(test_data, test_data->username);
+ } else {
+ test_data->username = talloc_strdup(test_data, test_data->username);
+ }
+
+ if (test_data->removedollar) {
+ char *p;
+
+ p = strchr_m(test_data->username, '$');
+ torture_assert(tctx, p != NULL, talloc_asprintf(tctx,
+ "username[%s] contains no '$'\n",
+ test_data->username));
+ *p = '\0';
+ }
+
+ spn = talloc_asprintf(test_data, "%s/%s@%s",
+ test_data->krb5_service,
+ test_data->krb5_hostname,
+ test_data->realm);
+
+ spn_real_realm = talloc_asprintf(test_data, "%s/%s@%s",
+ test_data->krb5_service,
+ test_data->krb5_hostname,
+ test_data->real_realm);
+
+ if (!test_data->canonicalize && test_data->enterprise) {
+ torture_skip(tctx,
+ "This test combination "
+ "is skipped intentionally");
+ }
+
+ if (test_data->as_req_spn) {
+ if (test_data->enterprise) {
+ torture_skip(tctx,
+ "This test combination "
+ "is skipped intentionally");
+ }
+ principal_string = spn;
+ } else {
+ principal_string = talloc_asprintf(test_data,
+ "%s@%s",
+ test_data->username,
+ test_data->realm);
+
+ }
+
+ test_data->spn_is_upn
+ = (strcasecmp(upn, spn) == 0);
+
+ /*
+ * If we are set to canonicalize, we get back the fixed UPPER
+ * case realm, and the real username (ie matching LDAP
+ * samAccountName)
+ *
+ * Otherwise, if we are set to enterprise, we
+ * get back the whole principal as-sent
+ *
+ * Finally, if we are not set to canonicalize, we get back the
+ * fixed UPPER case realm, but the as-sent username
+ */
+ if (test_data->as_req_spn && !test_data->spn_is_upn) {
+ expected_principal_string = spn;
+ } else if (test_data->canonicalize) {
+ expected_principal_string = talloc_asprintf(test_data,
+ "%s@%s",
+ test_data->real_username,
+ test_data->real_realm);
+ } else if (test_data->as_req_spn && test_data->spn_is_upn) {
+ expected_principal_string = spn_real_realm;
+ } else {
+ expected_principal_string = talloc_asprintf(test_data,
+ "%s@%s",
+ test_data->username,
+ test_data->real_realm);
+ }
+
+ if (test_data->enterprise) {
+ principal_flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
+ } else {
+ if (test_data->upn && test_data->other_upn_suffix) {
+ torture_skip(tctx, "UPN test for UPN with other UPN suffix only runs with enterprise principals");
+ }
+ principal_flags = 0;
+ }
+
+ if (test_data->canonicalize) {
+ expected_principal_flags = 0;
+ } else {
+ expected_principal_flags = principal_flags;
+ }
+
+ torture_assert_int_equal(tctx,
+ krb5_parse_name_flags(k5_context,
+ principal_string,
+ principal_flags,
+ &principal),
+ 0, "krb5_parse_name_flags failed");
+ torture_assert_int_equal(tctx,
+ krb5_parse_name_flags(k5_context,
+ expected_principal_string,
+ expected_principal_flags,
+ &expected_principal),
+ 0, "krb5_parse_name_flags failed");
+
+ if (test_data->as_req_spn) {
+ if (test_data->upn) {
+ krb5_principal_set_type(k5_context,
+ principal,
+ KRB5_NT_PRINCIPAL);
+ krb5_principal_set_type(k5_context,
+ expected_principal,
+ KRB5_NT_PRINCIPAL);
+ } else {
+ krb5_principal_set_type(k5_context,
+ principal,
+ KRB5_NT_SRV_HST);
+ krb5_principal_set_type(k5_context,
+ expected_principal,
+ KRB5_NT_SRV_HST);
+ }
+ }
+
+ torture_assert_int_equal(tctx,
+ krb5_unparse_name(k5_context,
+ expected_principal,
+ &expected_unparse_principal_string),
+ 0, "krb5_unparse_name failed");
+ /*
+ * Prepare a AS-REQ and run the TEST_AS_REQ tests
+ *
+ */
+
+ test_context->packet_count = 0;
+
+ /*
+ * Set the canonicalize flag if this test requires it
+ */
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_alloc(k5_context, &krb_options),
+ 0, "krb5_get_init_creds_opt_alloc failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_set_canonicalize(k5_context,
+ krb_options,
+ test_data->canonicalize),
+ 0, "krb5_get_init_creds_opt_set_canonicalize failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_set_win2k(k5_context,
+ krb_options,
+ test_data->win2k),
+ 0, "krb5_get_init_creds_opt_set_win2k failed");
+
+ k5ret = krb5_get_init_creds_password(k5_context, &my_creds, principal,
+ password, NULL, NULL, 0,
+ NULL, krb_options);
+
+ if (test_context->test_data->as_req_spn
+ && !test_context->test_data->spn_is_upn) {
+ torture_assert_int_equal(tctx, k5ret,
+ KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN,
+ "Got wrong error_code from "
+ "krb5_get_init_creds_password");
+ /* We can't proceed with more checks */
+ return true;
+ } else {
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_get_init_creds_password for %s failed: %s",
+ principal_string,
+ smb_get_krb5_error_message(k5_context, k5ret, tctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ }
+
+ torture_assert(tctx,
+ test_context->packet_count > 1,
+ "Expected krb5_get_init_creds_password to send more packets");
+
+ /*
+ * Assert that the reply was with the correct type of
+ * principal, depending on the flags we set
+ */
+ if (test_data->canonicalize == false && test_data->as_req_spn) {
+ torture_assert_int_equal(tctx,
+ krb5_principal_get_type(k5_context,
+ my_creds.client),
+ KRB5_NT_SRV_HST,
+ "smb_krb5_init_context gave incorrect client->name.name_type");
+ } else {
+ torture_assert_int_equal(tctx,
+ krb5_principal_get_type(k5_context,
+ my_creds.client),
+ KRB5_NT_PRINCIPAL,
+ "smb_krb5_init_context gave incorrect client->name.name_type");
+ }
+
+ torture_assert_int_equal(tctx,
+ krb5_unparse_name(k5_context,
+ my_creds.client, &got_principal_string), 0,
+ "krb5_unparse_name failed");
+
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
+ got_principal_string, expected_principal_string);
+ krb5_xfree(got_principal_string);
+
+ torture_assert(tctx, krb5_principal_compare(k5_context,
+ my_creds.client, expected_principal),
+ assertion_message);
+
+
+ torture_assert_int_equal(tctx,
+ krb5_principal_get_type(k5_context,
+ my_creds.server), KRB5_NT_SRV_INST,
+ "smb_krb5_init_context gave incorrect server->name.name_type");
+
+ torture_assert_int_equal(tctx,
+ krb5_principal_get_num_comp(k5_context,
+ my_creds.server), 2,
+ "smb_krb5_init_context gave incorrect number of components in my_creds.server->name");
+
+ torture_assert_str_equal(tctx,
+ krb5_principal_get_comp_string(k5_context,
+ my_creds.server, 0),
+ "krbtgt",
+ "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[0]");
+
+ if (test_data->canonicalize) {
+ torture_assert_str_equal(tctx,
+ krb5_principal_get_comp_string(k5_context,
+ my_creds.server, 1),
+ test_data->real_realm,
+
+ "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
+ } else {
+ torture_assert_str_equal(tctx,
+ krb5_principal_get_comp_string(k5_context,
+ my_creds.server, 1),
+ test_data->realm,
+
+ "smb_krb5_init_context gave incorrect my_creds.server->name.name_string[1]");
+ }
+ torture_assert_str_equal(tctx,
+ krb5_principal_get_realm(k5_context,
+ my_creds.server),
+ test_data->real_realm,
+ "smb_krb5_init_context gave incorrect my_creds.server->realm");
+
+ /* Store the result of the 'kinit' above into a memory ccache */
+ cc_name = talloc_asprintf(tctx, "MEMORY:%s", test_data->test_name);
+ torture_assert_int_equal(tctx, krb5_cc_resolve(k5_context, cc_name,
+ &ccache),
+ 0, "krb5_cc_resolve failed");
+
+ torture_assert_int_equal(tctx, krb5_cc_initialize(k5_context,
+ ccache, my_creds.client),
+ 0, "krb5_cc_initialize failed");
+
+ torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
+ ccache, &my_creds),
+ 0, "krb5_cc_store_cred failed");
+
+ /*
+ * Prepare a TGS-REQ and run the TEST_TGS_REQ_KRBTGT_CANON tests
+ *
+ * This tests krb5_get_creds behaviour, which allows us to set
+ * the KRB5_GC_CANONICALIZE option against the krbtgt/ principal
+ */
+
+ krbtgt_other_string = talloc_asprintf(test_data, "krbtgt/%s@%s", test_data->real_domain, test_data->real_realm);
+ torture_assert_int_equal(tctx,
+ krb5_make_principal(k5_context, &krbtgt_other,
+ test_data->real_realm, "krbtgt",
+ test_data->real_domain, NULL),
+ 0, "krb5_make_principal failed");
+
+ test_context->packet_count = 0;
+
+ torture_assert_int_equal(tctx,
+ krb5_get_creds_opt_alloc(k5_context, &opt),
+ 0, "krb5_get_creds_opt_alloc");
+
+ krb5_get_creds_opt_add_options(k5_context,
+ opt,
+ KRB5_GC_CANONICALIZE);
+
+ krb5_get_creds_opt_add_options(k5_context,
+ opt,
+ KRB5_GC_NO_STORE);
+
+ /* Confirm if we can get a ticket krbtgt/realm that we got back with the initial kinit */
+ k5ret = krb5_get_creds(k5_context, opt, ccache, krbtgt_other, &server_creds);
+
+ {
+ /*
+ * In these situations, the code above does not store a
+ * principal in the credentials cache matching what
+ * krb5_get_creds() needs without talking to the KDC, so the
+ * test fails with looping detected because when we set
+ * canonicalize we confuse the client libs.
+ *
+ */
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_get_creds for %s should have failed with looping detected: %s",
+ krbtgt_other_string,
+ smb_get_krb5_error_message(k5_context, k5ret,
+ tctx));
+
+ torture_assert_int_equal(tctx, k5ret, KRB5_GET_IN_TKT_LOOP, assertion_message);
+ torture_assert_int_equal(tctx,
+ test_context->packet_count,
+ 2, "Expected krb5_get_creds to send packets");
+ }
+
+ /*
+ * Prepare a TGS-REQ and run the TEST_TGS_REQ_CANON tests
+ *
+ * This tests krb5_get_creds behaviour, which allows us to set
+ * the KRB5_GC_CANONICALIZE option
+ */
+
+ test_context->packet_count = 0;
+
+ torture_assert_int_equal(tctx,
+ krb5_get_creds_opt_alloc(k5_context, &opt),
+ 0, "krb5_get_creds_opt_alloc");
+
+ krb5_get_creds_opt_add_options(k5_context,
+ opt,
+ KRB5_GC_CANONICALIZE);
+
+ krb5_get_creds_opt_add_options(k5_context,
+ opt,
+ KRB5_GC_NO_STORE);
+
+ if (test_data->s4u2self) {
+ torture_assert_int_equal(tctx,
+ krb5_get_creds_opt_set_impersonate(k5_context,
+ opt,
+ principal),
+ 0, "krb5_get_creds_opt_set_impersonate failed");
+ }
+
+ /* Confirm if we can get a ticket to our own name */
+ k5ret = krb5_get_creds(k5_context, opt, ccache, principal, &server_creds);
+
+ /*
+ * In these situations, the code above does not store a
+ * principal in the credentials cache matching what
+ * krb5_get_creds() needs, so the test fails.
+ *
+ */
+ {
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_get_creds for %s failed: %s",
+ principal_string,
+ smb_get_krb5_error_message(k5_context, k5ret,
+ tctx));
+
+ /*
+ * Only machine accounts (strictly, accounts with a
+ * servicePrincipalName) can expect this test to succeed
+ */
+ if (torture_setting_bool(tctx, "expect_machine_account", false)
+ && (test_data->enterprise
+ || test_data->spn_is_upn
+ || test_data->upn == false)) {
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ torture_assert_int_equal(tctx, krb5_cc_store_cred(k5_context,
+ ccache, server_creds),
+ 0, "krb5_cc_store_cred failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_free_creds(k5_context,
+ server_creds),
+ 0, "krb5_free_cred_contents failed");
+
+ torture_assert_int_equal(tctx,
+ test_context->packet_count,
+ 1, "Expected krb5_get_creds to send one packet");
+
+ } else {
+ torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
+ assertion_message);
+ /* Account for get_cred_kdc_capath() and get_cred_kdc_referral() fallback */
+ torture_assert_int_equal(tctx,
+ test_context->packet_count,
+ 2, "Expected krb5_get_creds to send 2 packets");
+ }
+ }
+
+ /*
+ * Confirm getting a ticket to pass to the server, running
+ * either the TEST_TGS_REQ or TEST_SELF_TRUST_TGS_REQ stage.
+ *
+ * This triggers the client to attempt to get a
+ * cross-realm ticket between the alternate names of
+ * the server, and we need to confirm that behaviour.
+ *
+ */
+
+ test_context->packet_count = 0;
+ torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
+ 0, "krb5_auth_con_init failed");
+
+ in_data.length = 0;
+ k5ret = krb5_mk_req_exact(k5_context,
+ &auth_context,
+ AP_OPTS_USE_SUBKEY,
+ principal,
+ &in_data, ccache,
+ &enc_ticket);
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_mk_req_exact for %s failed: %s",
+ principal_string,
+ smb_get_krb5_error_message(k5_context, k5ret, tctx));
+
+ /*
+ * Only machine accounts (strictly, accounts with a
+ * servicePrincipalName) can expect this test to succeed
+ */
+ if (torture_setting_bool(tctx, "expect_machine_account", false)
+ && (test_data->enterprise ||
+ (test_context->test_data->as_req_spn
+ || test_context->test_data->spn_is_upn)
+ || test_data->upn == false)) {
+ DATA_BLOB client_to_server;
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ client_to_server = data_blob_const(enc_ticket.data, enc_ticket.length);
+
+ /* This is very weird */
+ if (test_data->canonicalize == false
+ && test_context->test_data->as_req_spn
+ && test_context->test_data->spn_is_upn
+ && test_context->test_data->s4u2self) {
+
+ torture_assert(tctx,
+ test_accept_ticket(tctx,
+ samba_cmdline_get_creds(),
+ spn_real_realm,
+ client_to_server),
+ "test_accept_ticket failed - failed to accept the ticket we just created");
+ } else if (test_data->canonicalize == true
+ && test_context->test_data->as_req_spn
+ && test_context->test_data->spn_is_upn
+ && test_context->test_data->s4u2self) {
+
+ torture_assert(tctx,
+ test_accept_ticket(tctx,
+ samba_cmdline_get_creds(),
+ expected_principal_string,
+ client_to_server),
+ "test_accept_ticket failed - failed to accept the ticket we just created");
+ } else if (test_data->canonicalize == true
+ && test_data->enterprise == false
+ && test_context->test_data->upn
+ && test_context->test_data->spn_is_upn
+ && test_context->test_data->s4u2self) {
+
+ torture_assert(tctx,
+ test_accept_ticket(tctx,
+ samba_cmdline_get_creds(),
+ expected_principal_string,
+ client_to_server),
+ "test_accept_ticket failed - failed to accept the ticket we just created");
+ } else if (test_data->canonicalize == false
+ && test_context->test_data->upn
+ && test_context->test_data->spn_is_upn
+ && test_context->test_data->s4u2self) {
+
+ const char *accept_expected_principal_string
+ = talloc_asprintf(test_data,
+ "%s@%s",
+ test_data->username,
+ test_data->real_realm);
+
+ torture_assert(tctx,
+ test_accept_ticket(tctx,
+ samba_cmdline_get_creds(),
+ accept_expected_principal_string,
+ client_to_server),
+ "test_accept_ticket failed - failed to accept the ticket we just created");
+ } else {
+
+ torture_assert(tctx,
+ test_accept_ticket(tctx,
+ samba_cmdline_get_creds(),
+ expected_unparse_principal_string,
+ client_to_server),
+ "test_accept_ticket failed - failed to accept the ticket we just created");
+ }
+ krb5_data_free(&enc_ticket);
+ } else {
+ torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN,
+ assertion_message);
+ }
+
+ /*
+ * Confirm getting a ticket to pass to the server, running
+ * the TEST_TGS_REQ_HOST, TEST_TGS_REQ_HOST_SRV_INST, TEST_TGS_REQ_HOST_SRV_HST stage
+ *
+ * This triggers the client to attempt to get a
+ * cross-realm ticket between the alternate names of
+ * the server, and we need to confirm that behaviour.
+ *
+ */
+
+ if (*test_data->krb5_service && *test_data->krb5_hostname) {
+ krb5_principal host_principal_srv_inst;
+ /*
+ * This tries to guess when the krb5 libs will ask for a
+ * cross-realm ticket, and when they will just ask the KDC
+ * directly.
+ */
+ test_context->packet_count = 0;
+ torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
+ 0, "krb5_auth_con_init failed");
+
+ in_data.length = 0;
+ k5ret = krb5_mk_req(k5_context,
+ &auth_context,
+ 0,
+ test_data->krb5_service,
+ test_data->krb5_hostname,
+ &in_data, ccache,
+ &enc_ticket);
+
+ {
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_mk_req for %s/%s failed: %s",
+ test_data->krb5_service,
+ test_data->krb5_hostname,
+ smb_get_krb5_error_message(k5_context, k5ret, tctx));
+
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ if (test_data->spn_is_upn == false) {
+ /*
+ * Only in these cases would the above
+ * code have needed to send packets to
+ * the network
+ */
+ torture_assert(tctx,
+ test_context->packet_count > 0,
+ "Expected krb5_get_creds to send packets");
+ }
+ }
+
+
+ test_context->packet_count = 0;
+
+ torture_assert_int_equal(tctx,
+ krb5_make_principal(k5_context, &host_principal_srv_inst,
+ test_data->real_realm,
+ strupper_talloc(tctx, test_data->krb5_service),
+ test_data->krb5_hostname,
+ NULL),
+ 0, "krb5_make_principal failed");
+
+ krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_INST);
+
+ torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
+ 0, "krb5_auth_con_init failed");
+
+ in_data.length = 0;
+ k5ret = krb5_mk_req_exact(k5_context,
+ &auth_context,
+ 0,
+ host_principal_srv_inst,
+ &in_data, ccache,
+ &enc_ticket);
+ krb5_free_principal(k5_context, host_principal_srv_inst);
+ {
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
+ test_data->krb5_service,
+ test_data->krb5_hostname,
+ smb_get_krb5_error_message(k5_context, k5ret, tctx));
+
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ /*
+ * Only in these cases would the above code have needed to
+ * send packets to the network
+ */
+ torture_assert(tctx,
+ test_context->packet_count > 0,
+ "Expected krb5_get_creds to send packets");
+ }
+
+
+ test_context->packet_count = 0;
+
+ torture_assert_int_equal(tctx,
+ krb5_make_principal(k5_context, &host_principal_srv_inst,
+ test_data->real_realm,
+ test_data->krb5_service,
+ strupper_talloc(tctx, test_data->krb5_hostname),
+ NULL),
+ 0, "krb5_make_principal failed");
+
+ krb5_principal_set_type(k5_context, host_principal_srv_inst, KRB5_NT_SRV_HST);
+
+ torture_assert_int_equal(tctx, krb5_auth_con_init(k5_context, &auth_context),
+ 0, "krb5_auth_con_init failed");
+
+ in_data.length = 0;
+ k5ret = krb5_mk_req_exact(k5_context,
+ &auth_context,
+ 0,
+ host_principal_srv_inst,
+ &in_data, ccache,
+ &enc_ticket);
+ krb5_free_principal(k5_context, host_principal_srv_inst);
+ {
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_mk_req for %s/%s KRB5_NT_SRV_INST failed: %s",
+ test_data->krb5_service,
+ test_data->krb5_hostname,
+ smb_get_krb5_error_message(k5_context, k5ret, tctx));
+
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ /*
+ * Only in these cases would the above code have needed to
+ * send packets to the network
+ */
+ torture_assert(tctx,
+ test_context->packet_count > 0,
+ "Expected krb5_get_creds to send packets");
+ }
+ }
+
+ /*
+ * Confirm getting a ticket for the same krbtgt/realm that we
+ * got back with the initial ticket, running the
+ * TEST_TGS_REQ_KRBTGT stage.
+ *
+ */
+
+ test_context->packet_count = 0;
+
+ in_data.length = 0;
+ k5ret = krb5_mk_req_exact(k5_context,
+ &auth_context,
+ 0,
+ my_creds.server,
+ &in_data, ccache,
+ &enc_ticket);
+
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_mk_req_exact for %s failed: %s",
+ principal_string,
+ smb_get_krb5_error_message(k5_context, k5ret, tctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ krb5_free_principal(k5_context, principal);
+ krb5_get_init_creds_opt_free(k5_context, krb_options);
+
+ torture_assert_int_equal(tctx, krb5_free_cred_contents(k5_context, &my_creds),
+ 0, "krb5_free_cred_contents failed");
+
+ return true;
+}
+
+struct torture_suite *torture_krb5_canon(TALLOC_CTX *mem_ctx)
+{
+ unsigned int i;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "canon");
+ suite->description = talloc_strdup(suite, "Kerberos Canonicalisation tests");
+
+ for (i = 0; i < TEST_ALL; i++) {
+ char *name = talloc_asprintf(suite, "%s.%s.%s.%s.%s.%s",
+ (i & TEST_CANONICALIZE) ? "canon" : "no-canon",
+ (i & TEST_ENTERPRISE) ? "enterprise" : "no-enterprise",
+ (i & TEST_UPPER_USERNAME) ? "uc-user" : "lc-user",
+ (i & TEST_WIN2K) ? "win2k" : "no-win2k",
+ (i & TEST_UPN) ? "upn" :
+ ((i & TEST_AS_REQ_SPN) ? "spn" :
+ ((i & TEST_REMOVEDOLLAR) ? "removedollar" : "samaccountname")),
+ (i & TEST_S4U2SELF) ? "s4u2self" : "normal");
+ struct torture_suite *sub_suite = torture_suite_create(mem_ctx, name);
+
+ struct test_data *test_data = talloc_zero(suite, struct test_data);
+ if (i & TEST_UPN) {
+ if (i & TEST_AS_REQ_SPN) {
+ continue;
+ }
+ }
+ if ((i & TEST_UPN) || (i & TEST_AS_REQ_SPN)) {
+ if (i & TEST_REMOVEDOLLAR) {
+ continue;
+ }
+ }
+
+ test_data->test_name = name;
+ test_data->real_realm
+ = strupper_talloc(test_data,
+ cli_credentials_get_realm(
+ samba_cmdline_get_creds()));
+ test_data->real_domain = cli_credentials_get_domain(
+ samba_cmdline_get_creds());
+ test_data->username = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ test_data->real_username = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ test_data->canonicalize = (i & TEST_CANONICALIZE) != 0;
+ test_data->enterprise = (i & TEST_ENTERPRISE) != 0;
+ test_data->upper_username = (i & TEST_UPPER_USERNAME) != 0;
+ test_data->win2k = (i & TEST_WIN2K) != 0;
+ test_data->upn = (i & TEST_UPN) != 0;
+ test_data->s4u2self = (i & TEST_S4U2SELF) != 0;
+ test_data->removedollar = (i & TEST_REMOVEDOLLAR) != 0;
+ test_data->as_req_spn = (i & TEST_AS_REQ_SPN) != 0;
+ torture_suite_add_simple_tcase_const(sub_suite, name, torture_krb5_as_req_canon,
+ test_data);
+ torture_suite_add_suite(suite, sub_suite);
+
+ }
+ return suite;
+}
diff --git a/source4/torture/krb5/kdc-heimdal.c b/source4/torture/krb5/kdc-heimdal.c
new file mode 100644
index 0000000..d665977
--- /dev/null
+++ b/source4/torture/krb5/kdc-heimdal.c
@@ -0,0 +1,1065 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Validate the krb5 pac generation routines
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "torture/smbtorture.h"
+#include "torture/winbind/proto.h"
+#include "torture/krb5/proto.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "source4/auth/kerberos/kerberos.h"
+#include "source4/auth/kerberos/kerberos_util.h"
+#include "lib/util/util_net.h"
+
+#define krb5_is_app_tag(dat,tag) \
+ ((dat != NULL) && (dat)->length && \
+ (((((char *)(dat)->data)[0] & ~0x20) == ((tag) | 0x40))))
+
+#define krb5_is_krb_error(dat) krb5_is_app_tag(dat, 30)
+
+enum torture_krb5_test {
+ TORTURE_KRB5_TEST_PLAIN,
+ TORTURE_KRB5_TEST_PAC_REQUEST,
+ TORTURE_KRB5_TEST_BREAK_PW,
+ TORTURE_KRB5_TEST_CLOCK_SKEW,
+ TORTURE_KRB5_TEST_AES,
+ TORTURE_KRB5_TEST_RC4,
+ TORTURE_KRB5_TEST_AES_RC4,
+
+ /*
+ * This is in and out of the client.
+ * Out refers to requests, in refers to replies
+ */
+ TORTURE_KRB5_TEST_CHANGE_SERVER_OUT,
+ TORTURE_KRB5_TEST_CHANGE_SERVER_IN,
+ TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH,
+};
+
+struct torture_krb5_context {
+ struct torture_context *tctx;
+ struct addrinfo *server;
+ enum torture_krb5_test test;
+ int packet_count;
+ AS_REQ as_req;
+ AS_REP as_rep;
+ const char *krb5_service;
+ const char *krb5_hostname;
+};
+
+/*
+ * Confirm that the outgoing packet meets certain expectations. This
+ * should be extended to further assert the correct and expected
+ * behaviour of the krb5 libs, so we know what we are sending to the
+ * server.
+ *
+ */
+
+static bool torture_krb5_pre_send_test(struct torture_krb5_context *test_context, krb5_data *send_buf)
+{
+ size_t used;
+ switch (test_context->test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ case TORTURE_KRB5_TEST_AES:
+ case TORTURE_KRB5_TEST_RC4:
+ case TORTURE_KRB5_TEST_AES_RC4:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
+ torture_assert_int_equal(test_context->tctx,
+ decode_AS_REQ(send_buf->data, send_buf->length, &test_context->as_req, &used), 0,
+ "decode_AS_REQ failed");
+ torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno, 5, "Got wrong as_req->pvno");
+ break;
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
+ {
+ AS_REQ mod_as_req;
+ krb5_error_code k5ret;
+ krb5_data modified_send_buf;
+ torture_assert_int_equal(test_context->tctx,
+ decode_AS_REQ(send_buf->data, send_buf->length, &test_context->as_req, &used), 0,
+ "decode_AS_REQ failed");
+ torture_assert_int_equal(test_context->tctx, used, send_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx, test_context->as_req.pvno, 5, "Got wrong as_req->pvno");
+
+ /* Only change it if configured with --option=torture:krb5-hostname= */
+ if (test_context->krb5_hostname[0] == '\0') {
+ break;
+ }
+
+ mod_as_req = test_context->as_req;
+
+ torture_assert_int_equal(test_context->tctx,
+ mod_as_req.req_body.sname->name_string.len, 2,
+ "Sending wrong mod_as_req.req_body->sname.name_string.len");
+ free(mod_as_req.req_body.sname->name_string.val[0]);
+ free(mod_as_req.req_body.sname->name_string.val[1]);
+ mod_as_req.req_body.sname->name_string.val[0] = strdup(test_context->krb5_service);
+ mod_as_req.req_body.sname->name_string.val[1] = strdup(test_context->krb5_hostname);
+
+ ASN1_MALLOC_ENCODE(AS_REQ, modified_send_buf.data, modified_send_buf.length,
+ &mod_as_req, &used, k5ret);
+ torture_assert_int_equal(test_context->tctx,
+ k5ret, 0,
+ "encode_AS_REQ failed");
+
+ *send_buf = modified_send_buf;
+ break;
+ }
+ }
+ return true;
+}
+
+static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
+ const krb5_data *reply,
+ krb5_error_code expected_error,
+ bool check_pa_data)
+{
+ KRB_ERROR error = { 0 };
+ size_t used = 0;
+ int rc;
+
+ rc = decode_KRB_ERROR(reply->data, reply->length, &error, &used);
+ torture_assert_int_equal(test_context->tctx,
+ rc, 0,
+ "decode_KRB_ERROR failed");
+
+ torture_assert_int_equal(test_context->tctx,
+ used, reply->length,
+ "length mismatch");
+ torture_assert_int_equal(test_context->tctx,
+ error.pvno, 5,
+ "Got wrong error.pvno");
+ torture_assert_int_equal(test_context->tctx,
+ error.error_code, expected_error - KRB5KDC_ERR_NONE,
+ "Got wrong error.error_code");
+
+ if (check_pa_data) {
+ METHOD_DATA m;
+ size_t len;
+ int i;
+ bool found_enc_ts = false;
+ bool found_etype_info2 = false;
+ torture_assert(test_context->tctx,
+ error.e_data != NULL,
+ "No e-data returned");
+
+ rc = decode_METHOD_DATA(error.e_data->data,
+ error.e_data->length,
+ &m,
+ &len);
+ torture_assert_int_equal(test_context->tctx,
+ rc, 0,
+ "Got invalid method data");
+
+ torture_assert(test_context->tctx,
+ m.len > 0,
+ "No PA_DATA given");
+ for (i = 0; i < m.len; i++) {
+ if (m.val[i].padata_type == KRB5_PADATA_ENC_TIMESTAMP) {
+ found_enc_ts = true;
+ }
+ else if (m.val[i].padata_type == KRB5_PADATA_ETYPE_INFO2) {
+ found_etype_info2 = true;
+ }
+ }
+ torture_assert(test_context->tctx,
+ found_etype_info2,
+ "PADATA_ETYPE_INFO2 not found");
+ if (expected_error != KRB5KDC_ERR_PREAUTH_FAILED)
+ torture_assert(test_context->tctx,
+ found_enc_ts,
+ "Encrypted timestamp not found");
+ }
+
+ free_KRB_ERROR(&error);
+
+ return true;
+}
+
+static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_context,
+ const krb5_data *reply,
+ const krb5_enctype* allowed_enctypes)
+{
+ ENCTYPE reply_enctype = { 0 };
+ size_t used = 0;
+ int rc;
+ int expected_enctype = ETYPE_NULL;
+
+ rc = decode_AS_REP(reply->data,
+ reply->length,
+ &test_context->as_rep,
+ &used);
+ torture_assert_int_equal(test_context->tctx,
+ rc, 0,
+ "decode_AS_REP failed");
+ torture_assert_int_equal(test_context->tctx,
+ used, reply->length,
+ "length mismatch");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.pvno, 5,
+ "Got wrong as_rep->pvno");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.ticket.tkt_vno, 5,
+ "Got wrong as_rep->ticket.tkt_vno");
+ torture_assert(test_context->tctx,
+ test_context->as_rep.ticket.enc_part.kvno,
+ "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
+
+ if (test_context->as_req.padata) {
+ /*
+ * If the AS-REQ contains a PA-ENC-TIMESTAMP, then
+ * that encryption type is used to determine the reply
+ * enctype.
+ */
+ int i = 0;
+ const PA_DATA *pa = krb5_find_padata(test_context->as_req.padata->val,
+ test_context->as_req.padata->len,
+ KRB5_PADATA_ENC_TIMESTAMP,
+ &i);
+ if (pa) {
+ EncryptedData ed;
+ size_t len;
+ krb5_error_code ret = decode_EncryptedData(pa->padata_value.data,
+ pa->padata_value.length,
+ &ed, &len);
+ torture_assert_int_equal(test_context->tctx,
+ ret,
+ 0,
+ "decode_EncryptedData failed");
+ expected_enctype = ed.etype;
+ free_EncryptedData(&ed);
+ }
+ }
+ if (expected_enctype == ETYPE_NULL) {
+ /*
+ * Otherwise, find the strongest enctype contained in
+ * the AS-REQ supported enctypes list.
+ */
+ const krb5_enctype *p = NULL;
+
+ for (p = krb5_kerberos_enctypes(NULL); *p != (krb5_enctype)ETYPE_NULL; ++p) {
+ int j;
+
+ if ((*p == (krb5_enctype)ETYPE_AES256_CTS_HMAC_SHA1_96 ||
+ *p == (krb5_enctype)ETYPE_AES128_CTS_HMAC_SHA1_96) &&
+ !test_context->as_req.req_body.kdc_options.canonicalize)
+ {
+ /*
+ * AES encryption types are only used here when
+ * we set the canonicalize flag, as the salt
+ * needs to match.
+ */
+ continue;
+ }
+
+ for (j = 0; j < test_context->as_req.req_body.etype.len; ++j) {
+ krb5_enctype etype = test_context->as_req.req_body.etype.val[j];
+ if (*p == etype) {
+ expected_enctype = etype;
+ break;
+ }
+ }
+
+ if (expected_enctype != (krb5_enctype)ETYPE_NULL) {
+ break;
+ }
+ }
+ }
+
+ {
+ /* Ensure the enctype to check against is an expected type. */
+ const krb5_enctype *p = NULL;
+ bool found = false;
+ for (p = allowed_enctypes; *p != (krb5_enctype)ETYPE_NULL; ++p) {
+ if (*p == expected_enctype) {
+ found = true;
+ break;
+ }
+ }
+
+ torture_assert(test_context->tctx,
+ found,
+ "Calculated enctype not in allowed list");
+ }
+
+ reply_enctype = test_context->as_rep.enc_part.etype;
+ torture_assert_int_equal(test_context->tctx,
+ reply_enctype, expected_enctype,
+ "Ticket encrypted with invalid algorithm");
+
+ return true;
+}
+
+/*
+ * Confirm that the incoming packet from the KDC meets certain
+ * expectations. This uses a switch and the packet count to work out
+ * what test we are in, and where in the test we are, so we can assert
+ * on the expected reply packets from the KDC.
+ *
+ */
+
+static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_context, krb5_data *recv_buf)
+{
+ KRB_ERROR error;
+ size_t used;
+ bool ok;
+
+ switch (test_context->test)
+ {
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
+ case TORTURE_KRB5_TEST_PLAIN:
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
+ && (test_context->packet_count == 1)) {
+ torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
+ torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
+ "Got wrong error.error_code");
+ free_KRB_ERROR(&error);
+ } else {
+ torture_assert_int_equal(test_context->tctx,
+ decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
+ "decode_AS_REP failed");
+ torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.pvno, 5,
+ "Got wrong as_rep->pvno");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.ticket.tkt_vno, 5,
+ "Got wrong as_rep->ticket.tkt_vno");
+ torture_assert(test_context->tctx,
+ test_context->as_rep.ticket.enc_part.kvno,
+ "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
+ if (test_context->test == TORTURE_KRB5_TEST_PLAIN) {
+ if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
+ torture_assert_int_not_equal(test_context->tctx,
+ *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
+ 0, "Did not get a RODC number in the KVNO");
+ } else {
+ torture_assert_int_equal(test_context->tctx,
+ *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
+ 0, "Unexpecedly got a RODC number in the KVNO");
+ }
+ }
+ free_AS_REP(&test_context->as_rep);
+ }
+ torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
+ free_AS_REQ(&test_context->as_req);
+ break;
+
+ /*
+ * Confirm correct error codes when we ask for the PAC. This behaviour is rather odd...
+ */
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
+ && (test_context->packet_count == 1)) {
+ torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
+ torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
+ "Got wrong error.error_code");
+ free_KRB_ERROR(&error);
+ } else {
+ torture_assert_int_equal(test_context->tctx,
+ decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
+ "decode_AS_REP failed");
+ torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx, test_context->as_rep.pvno, 5, "Got wrong as_rep->pvno");
+ free_AS_REP(&test_context->as_rep);
+ }
+ torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
+ free_AS_REQ(&test_context->as_req);
+ break;
+
+ /*
+ * Confirm correct error codes when we deliberately send the wrong password
+ */
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if (test_context->packet_count == 1) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_FAILED,
+ true);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ }
+ torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
+ free_AS_REQ(&test_context->as_req);
+ break;
+
+ /*
+ * Confirm correct error codes when we deliberately skew the client clock
+ */
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if (test_context->packet_count == 1) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KRB_AP_ERR_SKEW,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ }
+ torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
+ free_AS_REQ(&test_context->as_req);
+ break;
+ case TORTURE_KRB5_TEST_AES:
+ torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES\n");
+
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if (krb5_is_krb_error(recv_buf)) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KRB_ERR_RESPONSE_TOO_BIG,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else {
+ const krb5_enctype allowed_enctypes[] = {
+ KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ ETYPE_NULL
+ };
+ ok = torture_check_krb5_as_rep_enctype(test_context,
+ recv_buf,
+ allowed_enctypes);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_as_rep_enctype failed");
+ }
+
+ torture_assert(test_context->tctx,
+ test_context->packet_count < 3,
+ "Too many packets");
+ break;
+ case TORTURE_KRB5_TEST_RC4:
+ torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_RC4\n");
+
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if (krb5_is_krb_error(recv_buf)) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KRB_ERR_RESPONSE_TOO_BIG,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else {
+ const krb5_enctype allowed_enctypes[] = {
+ KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
+ ETYPE_NULL
+ };
+ ok = torture_check_krb5_as_rep_enctype(test_context,
+ recv_buf,
+ allowed_enctypes);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_as_rep_enctype failed");
+ }
+
+ torture_assert(test_context->tctx,
+ test_context->packet_count < 3,
+ "Too many packets");
+ break;
+ case TORTURE_KRB5_TEST_AES_RC4:
+ torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES_RC4\n");
+
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if (krb5_is_krb_error(recv_buf)) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KRB_ERR_RESPONSE_TOO_BIG,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else {
+ const krb5_enctype allowed_enctypes[] = {
+ KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
+ ETYPE_NULL
+ };
+ ok = torture_check_krb5_as_rep_enctype(test_context,
+ recv_buf,
+ allowed_enctypes);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_as_rep_enctype failed");
+ }
+
+ torture_assert(test_context->tctx,
+ test_context->packet_count < 3,
+ "Too many packets");
+ break;
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
+ {
+ AS_REP mod_as_rep;
+ krb5_error_code k5ret;
+ krb5_data modified_recv_buf;
+ if (test_context->packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ recv_buf,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert(test_context->tctx,
+ ok,
+ "torture_check_krb5_error failed");
+ } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
+ && (test_context->packet_count == 1)) {
+ torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
+ torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
+ "Got wrong error.error_code");
+ free_KRB_ERROR(&error);
+ } else {
+ torture_assert_int_equal(test_context->tctx,
+ decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
+ "decode_AS_REP failed");
+ torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.pvno, 5,
+ "Got wrong as_rep->pvno");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.ticket.tkt_vno, 5,
+ "Got wrong as_rep->ticket.tkt_vno");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep.ticket.sname.name_string.len, 2,
+ "Got wrong as_rep->ticket.sname.name_string.len");
+ free(test_context->as_rep.ticket.sname.name_string.val[0]);
+ free(test_context->as_rep.ticket.sname.name_string.val[1]);
+ test_context->as_rep.ticket.sname.name_string.val[0] = strdup("bad");
+ test_context->as_rep.ticket.sname.name_string.val[1] = strdup("mallory");
+
+ mod_as_rep = test_context->as_rep;
+
+ ASN1_MALLOC_ENCODE(AS_REP, modified_recv_buf.data, modified_recv_buf.length,
+ &mod_as_rep, &used, k5ret);
+ torture_assert_int_equal(test_context->tctx,
+ k5ret, 0,
+ "encode_AS_REQ failed");
+ krb5_data_free(recv_buf);
+
+ *recv_buf = modified_recv_buf;
+ free_AS_REQ(&test_context->as_req);
+ }
+ torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
+
+ break;
+ }
+ }
+
+
+ return true;
+}
+
+
+/*
+ * This function is set in torture_krb5_init_context as krb5
+ * send_and_recv function. This allows us to override what server the
+ * test is aimed at, and to inspect the packets just before they are
+ * sent to the network, and before they are processed on the recv
+ * side.
+ *
+ * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
+ * functions are implement the actual tests.
+ *
+ * When this asserts, the caller will get a spurious 'cannot contact
+ * any KDC' message.
+ *
+ */
+static krb5_error_code test_krb5_send_to_realm_override(
+ struct smb_krb5_context *smb_krb5_context,
+ void *data, /* struct torture_krb5_context */
+ krb5_const_realm realm,
+ time_t timeout,
+ const krb5_data *send_buf,
+ krb5_data *recv_buf)
+{
+ krb5_error_code k5ret;
+ bool ok;
+ krb5_data modified_send_buf = *send_buf;
+
+ struct torture_krb5_context *test_context
+ = talloc_get_type_abort(data, struct torture_krb5_context);
+
+ ok = torture_krb5_pre_send_test(test_context, &modified_send_buf);
+ if (ok == false) {
+ return EINVAL;
+ }
+
+ k5ret = smb_krb5_send_and_recv_func_forced_tcp(smb_krb5_context,
+ test_context->server,
+ timeout,
+ &modified_send_buf,
+ recv_buf);
+ if (k5ret != 0) {
+ return k5ret;
+ }
+ ok = torture_krb5_post_recv_test(test_context, recv_buf);
+ if (ok == false) {
+ return EINVAL;
+ }
+
+ test_context->packet_count++;
+
+ return k5ret;
+}
+
+static int test_context_destructor(struct torture_krb5_context *test_context)
+{
+ freeaddrinfo(test_context->server);
+ return 0;
+}
+
+
+static bool torture_krb5_init_context(struct torture_context *tctx,
+ enum torture_krb5_test test,
+ struct smb_krb5_context **smb_krb5_context)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ krb5_error_code k5ret;
+ bool ok;
+
+ struct torture_krb5_context *test_context = talloc_zero(tctx, struct torture_krb5_context);
+ torture_assert(tctx, test_context != NULL, "Failed to allocate");
+
+ test_context->test = test;
+ test_context->tctx = tctx;
+
+ test_context->krb5_service = torture_setting_string(tctx, "krb5-service", "host");
+ test_context->krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
+
+ k5ret = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context);
+ torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
+
+ ok = interpret_string_addr_internal(&test_context->server, host, AI_NUMERICHOST);
+ torture_assert(tctx, ok, "Failed to parse target server");
+
+ talloc_set_destructor(test_context, test_context_destructor);
+
+ set_sockaddr_port(test_context->server->ai_addr, 88);
+
+ k5ret = smb_krb5_set_send_to_kdc_func((*smb_krb5_context),
+ test_krb5_send_to_realm_override,
+ NULL, /* send_to_kdc */
+ test_context);
+ torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
+ return true;
+}
+
+static bool torture_krb5_as_req_creds(struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ enum torture_krb5_test test)
+{
+ krb5_error_code k5ret;
+ bool ok;
+ krb5_creds my_creds;
+ krb5_principal principal;
+ struct smb_krb5_context *smb_krb5_context;
+ krb5_context k5_context;
+ enum credentials_obtained obtained;
+ const char *error_string;
+ const char *password = cli_credentials_get_password(credentials);
+ const char *expected_principal_string;
+ krb5_get_init_creds_opt *krb_options = NULL;
+ const char *realm;
+ const char *krb5_hostname = torture_setting_string(tctx, "krb5-hostname", "");
+
+
+ ok = torture_krb5_init_context(tctx, test, &smb_krb5_context);
+ torture_assert(tctx, ok, "torture_krb5_init_context failed");
+ k5_context = smb_krb5_context->krb5_context;
+
+ expected_principal_string
+ = cli_credentials_get_principal(credentials,
+ tctx);
+
+ realm = strupper_talloc(tctx, cli_credentials_get_realm(credentials));
+ k5ret = principal_from_credentials(tctx, credentials, smb_krb5_context,
+ &principal, &obtained, &error_string);
+ torture_assert_int_equal(tctx, k5ret, 0, error_string);
+
+ switch (test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
+ break;
+
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options),
+ 0, "krb5_get_init_creds_opt_alloc failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_set_pac_request(smb_krb5_context->krb5_context, krb_options, true),
+ 0, "krb5_get_init_creds_opt_set_pac_request failed");
+ break;
+
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ password = "NOT the password";
+ break;
+
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ torture_assert_int_equal(tctx,
+ krb5_set_real_time(smb_krb5_context->krb5_context, time(NULL) + 3600, 0),
+ 0, "krb5_set_real_time failed");
+ break;
+
+ case TORTURE_KRB5_TEST_AES: {
+ static krb5_enctype etype_list[] = { KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 };
+
+ k5ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ k5ret, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+ krb5_get_init_creds_opt_set_etype_list(krb_options,
+ etype_list,
+ 1);
+ break;
+ }
+ case TORTURE_KRB5_TEST_RC4: {
+ static krb5_enctype etype_list[] = { KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 };
+
+ k5ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ k5ret, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+ krb5_get_init_creds_opt_set_etype_list(krb_options,
+ etype_list,
+ 1);
+ break;
+ }
+ case TORTURE_KRB5_TEST_AES_RC4: {
+ static krb5_enctype etype_list[] = { KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ KRB5_ENCTYPE_ARCFOUR_HMAC_MD5 };
+
+ k5ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ k5ret, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+ krb5_get_init_creds_opt_set_etype_list(krb_options,
+ etype_list,
+ 2);
+ break;
+ }
+
+ } /* end switch */
+
+ k5ret = krb5_get_init_creds_password(smb_krb5_context->krb5_context, &my_creds, principal,
+ password, NULL, NULL, 0,
+ NULL, krb_options);
+ krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options);
+
+ switch (test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_IN:
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ case TORTURE_KRB5_TEST_AES:
+ case TORTURE_KRB5_TEST_RC4:
+ case TORTURE_KRB5_TEST_AES_RC4:
+ {
+ char *got_principal_string;
+ char *assertion_message;
+ torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_principal_get_type(k5_context,
+ my_creds.client),
+ KRB5_NT_PRINCIPAL,
+ "smb_krb5_init_context gave incorrect client->name.name_type");
+
+ torture_assert_int_equal(tctx,
+ krb5_unparse_name(k5_context,
+ my_creds.client,
+ &got_principal_string), 0,
+ "krb5_unparse_name failed");
+
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
+ got_principal_string, expected_principal_string);
+ krb5_xfree(got_principal_string);
+
+ torture_assert(tctx, krb5_principal_compare(k5_context,
+ my_creds.client,
+ principal),
+ assertion_message);
+
+
+ torture_assert_str_equal(tctx,
+ my_creds.server->name.name_string.val[0],
+ "krbtgt",
+ "Mismatch in name between AS_REP and expected response, expected krbtgt");
+ torture_assert_str_equal(tctx,
+ my_creds.server->name.name_string.val[1],
+ realm,
+ "Mismatch in realm part of krbtgt/ in AS_REP, expected krbtgt/REALM@REALM");
+
+ torture_assert_str_equal(tctx,
+ my_creds.server->realm,
+ realm,
+ "Mismatch in server realm in AS_REP, expected krbtgt/REALM@REALM");
+
+ break;
+ }
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_PREAUTH_FAILED, "krb5_get_init_creds_password should have failed");
+ return true;
+
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ torture_assert_int_equal(tctx, k5ret, KRB5KRB_AP_ERR_SKEW, "krb5_get_init_creds_password should have failed");
+ return true;
+
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_OUT:
+ case TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH:
+ {
+ char *got_principal_string;
+ char *assertion_message;
+
+ if (krb5_hostname[0] != '\0') {
+ torture_assert_int_equal(tctx, k5ret, KRB5KRB_AP_ERR_BAD_INTEGRITY, "krb5_get_init_creds_password should have failed");
+ return true;
+ }
+
+ torture_assert_int_equal(tctx, k5ret, 0, "krb5_get_init_creds_password failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_principal_get_type(k5_context,
+ my_creds.client),
+ KRB5_NT_PRINCIPAL,
+ "smb_krb5_init_context gave incorrect client->name.name_type");
+
+ torture_assert_int_equal(tctx,
+ krb5_unparse_name(k5_context,
+ my_creds.client,
+ &got_principal_string), 0,
+ "krb5_unparse_name failed");
+
+ assertion_message = talloc_asprintf(tctx,
+ "krb5_get_init_creds_password returned a different principal %s to what was expected %s",
+ got_principal_string, expected_principal_string);
+ krb5_xfree(got_principal_string);
+
+ torture_assert(tctx, krb5_principal_compare(k5_context,
+ my_creds.client,
+ principal),
+ assertion_message);
+
+ break;
+ }
+ }
+
+ k5ret = krb5_free_cred_contents(smb_krb5_context->krb5_context, &my_creds);
+ torture_assert_int_equal(tctx, k5ret, 0, "krb5_free_creds failed");
+
+ return true;
+}
+
+static bool torture_krb5_as_req_cmdline(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_PLAIN);
+}
+
+static bool torture_krb5_as_req_pac_request(struct torture_context *tctx)
+{
+ if (torture_setting_bool(tctx, "expect_rodc", false)) {
+ torture_skip(tctx, "This test needs further investigation in the RODC case against a Windows DC, in particular with non-cached users");
+ }
+ return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_PAC_REQUEST);
+}
+
+static bool torture_krb5_as_req_break_pw(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_BREAK_PW);
+}
+
+static bool torture_krb5_as_req_clock_skew(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_CLOCK_SKEW);
+}
+
+static bool torture_krb5_as_req_aes(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_AES);
+}
+
+static bool torture_krb5_as_req_rc4(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_RC4);
+}
+
+static bool torture_krb5_as_req_aes_rc4(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_AES_RC4);
+}
+
+/* Checking for the "Orpheus' Lyre" attack */
+static bool torture_krb5_as_req_change_server_out(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_CHANGE_SERVER_OUT);
+}
+
+static bool torture_krb5_as_req_change_server_in(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_CHANGE_SERVER_IN);
+}
+
+static bool torture_krb5_as_req_change_server_both(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_CHANGE_SERVER_BOTH);
+}
+
+NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "krb5");
+ struct torture_suite *kdc_suite = torture_suite_create(suite, "kdc");
+ suite->description = talloc_strdup(suite, "Kerberos tests");
+ kdc_suite->description = talloc_strdup(kdc_suite, "Kerberos KDC tests");
+
+ torture_suite_add_simple_test(kdc_suite, "as-req-cmdline",
+ torture_krb5_as_req_cmdline);
+
+ torture_suite_add_simple_test(kdc_suite, "as-req-pac-request",
+ torture_krb5_as_req_pac_request);
+
+ torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
+ torture_krb5_as_req_break_pw);
+
+ torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew",
+ torture_krb5_as_req_clock_skew);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-aes",
+ torture_krb5_as_req_aes);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-rc4",
+ torture_krb5_as_req_rc4);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-aes-rc4",
+ torture_krb5_as_req_aes_rc4);
+
+ /*
+ * This is in and out of the client.
+ * Out refers to requests, in refers to replies
+ */
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-change-server-in",
+ torture_krb5_as_req_change_server_in);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-change-server-out",
+ torture_krb5_as_req_change_server_out);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-change-server-both",
+ torture_krb5_as_req_change_server_both);
+
+ torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite));
+ torture_suite_add_suite(suite, kdc_suite);
+
+ torture_register_suite(ctx, suite);
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/krb5/kdc-mit.c b/source4/torture/krb5/kdc-mit.c
new file mode 100644
index 0000000..5085966
--- /dev/null
+++ b/source4/torture/krb5/kdc-mit.c
@@ -0,0 +1,795 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Validate the krb5 pac generation routines
+
+ Copyright (c) 2016 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "system/time.h"
+#include "torture/smbtorture.h"
+#include "torture/winbind/proto.h"
+#include "torture/krb5/proto.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "source4/auth/kerberos/kerberos.h"
+#include "source4/auth/kerberos/kerberos_util.h"
+#include "lib/util/util_net.h"
+
+#define krb5_is_app_tag(dat,tag) \
+ ((dat != NULL) && (dat)->length && \
+ ((((dat)->data[0] & ~0x20) == ((tag) | 0x40))))
+
+#define krb5_is_as_req(dat) krb5_is_app_tag(dat, 10)
+#define krb5_is_as_rep(dat) krb5_is_app_tag(dat, 11)
+#define krb5_is_krb_error(dat) krb5_is_app_tag(dat, 30)
+
+enum torture_krb5_test {
+ TORTURE_KRB5_TEST_PLAIN,
+ TORTURE_KRB5_TEST_PAC_REQUEST,
+ TORTURE_KRB5_TEST_BREAK_PW,
+ TORTURE_KRB5_TEST_CLOCK_SKEW,
+ TORTURE_KRB5_TEST_AES,
+ TORTURE_KRB5_TEST_RC4,
+ TORTURE_KRB5_TEST_AES_RC4,
+};
+
+struct torture_krb5_context {
+ struct torture_context *tctx;
+ krb5_context krb5_context;
+ enum torture_krb5_test test;
+ int recv_packet_count;
+ krb5_kdc_req *as_req;
+ krb5_kdc_rep *as_rep;
+};
+
+krb5_error_code decode_krb5_error(const krb5_data *output, krb5_error **rep);
+
+krb5_error_code decode_krb5_as_req(const krb5_data *output, krb5_kdc_req **req);
+krb5_error_code decode_krb5_as_rep(const krb5_data *output, krb5_kdc_rep **rep);
+
+krb5_error_code decode_krb5_padata_sequence(const krb5_data *output, krb5_pa_data ***rep);
+
+void krb5_free_kdc_req(krb5_context ctx, krb5_kdc_req *req);
+void krb5_free_kdc_rep(krb5_context ctx, krb5_kdc_rep *rep);
+void krb5_free_pa_data(krb5_context ctx, krb5_pa_data **data);
+
+static bool torture_check_krb5_as_req(struct torture_krb5_context *test_context,
+ krb5_context context,
+ const krb5_data *message)
+{
+ krb5_error_code code;
+ int nktypes;
+
+ code = decode_krb5_as_req(message, &test_context->as_req);
+ torture_assert_int_equal(test_context->tctx,
+ code, 0,
+ "decode_as_req failed");
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_req->msg_type,
+ KRB5_AS_REQ,
+ "Not a AS REQ");
+
+ nktypes = test_context->as_req->nktypes;
+ torture_assert_int_not_equal(test_context->tctx,
+ nktypes, 0,
+ "No keytypes");
+
+ return true;
+}
+
+static krb5_error_code torture_krb5_pre_send_test(krb5_context context,
+ void *data,
+ const krb5_data *realm,
+ const krb5_data *message,
+ krb5_data **new_message_out,
+ krb5_data **new_reply_out)
+{
+ bool ok;
+ struct torture_krb5_context *test_context =
+ (struct torture_krb5_context *)data;
+
+ switch (test_context->test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ case TORTURE_KRB5_TEST_AES:
+ case TORTURE_KRB5_TEST_RC4:
+ case TORTURE_KRB5_TEST_AES_RC4:
+ ok = torture_check_krb5_as_req(test_context,
+ context,
+ message);
+ if (!ok) {
+ return KRB5KDC_ERR_BADOPTION;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * We need these function to validate packets because our torture macros
+ * do a 'return false' on error.
+ */
+static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
+ krb5_context context,
+ const krb5_data *reply,
+ krb5_error_code error_code,
+ bool check_pa_data)
+
+{
+ krb5_error *krb_error;
+ krb5_error_code code;
+
+ code = decode_krb5_error(reply, &krb_error);
+ torture_assert_int_equal(test_context->tctx,
+ code,
+ 0,
+ "decode_krb5_error failed");
+
+ torture_assert_int_equal(test_context->tctx,
+ krb_error->error,
+ error_code - KRB5KDC_ERR_NONE,
+ "Got wrong error code");
+
+ if (check_pa_data) {
+ krb5_pa_data **d, **pa_data = NULL;
+ bool timestamp_found = false;
+
+ torture_assert_int_not_equal(test_context->tctx,
+ krb_error->e_data.length, 0,
+ "No e-data returned");
+
+ code = decode_krb5_padata_sequence(&krb_error->e_data,
+ &pa_data);
+ torture_assert_int_equal(test_context->tctx,
+ code,
+ 0,
+ "decode_krb5_padata_sequence failed");
+
+ for (d = pa_data; d != NULL; d++) {
+ if ((*d)->pa_type == KRB5_PADATA_ENC_TIMESTAMP) {
+ timestamp_found = true;
+ break;
+ }
+ }
+ torture_assert(test_context->tctx,
+ timestamp_found,
+ "Encrypted timestamp not found");
+
+ krb5_free_pa_data(context, pa_data);
+ }
+
+ krb5_free_error(context, krb_error);
+
+ return true;
+}
+
+static bool torture_check_krb5_as_rep(struct torture_krb5_context *test_context,
+ krb5_context context,
+ const krb5_data *reply)
+{
+ krb5_error_code code;
+ bool ok;
+
+ code = decode_krb5_as_rep(reply, &test_context->as_rep);
+ torture_assert_int_equal(test_context->tctx,
+ code,
+ 0,
+ "decode_krb5_as_rep failed");
+
+ torture_assert(test_context->tctx,
+ test_context->as_rep->ticket->enc_part.kvno,
+ "No KVNO set");
+
+ ok = torture_setting_bool(test_context->tctx,
+ "expect_cached_at_rodc",
+ false);
+ if (ok) {
+ torture_assert_int_not_equal(test_context->tctx,
+ test_context->as_rep->ticket->enc_part.kvno & 0xFFFF0000,
+ 0,
+ "Did not get a RODC number in the KVNO");
+ } else {
+ torture_assert_int_equal(test_context->tctx,
+ test_context->as_rep->ticket->enc_part.kvno & 0xFFFF0000,
+ 0,
+ "Unexpecedly got a RODC number in the KVNO");
+ }
+
+ return true;
+}
+
+static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_context,
+ krb5_context context,
+ const krb5_data *reply,
+ krb5_enctype expected_enctype)
+{
+ krb5_enctype reply_enctype;
+ bool ok;
+
+ ok = torture_check_krb5_as_rep(test_context,
+ context,
+ reply);
+ if (!ok) {
+ return false;
+ }
+
+ reply_enctype = test_context->as_rep->enc_part.enctype;
+
+ torture_assert_int_equal(test_context->tctx,
+ reply_enctype, expected_enctype,
+ "Ticket encrypted with invalid algorithm");
+
+ return true;
+}
+
+static krb5_error_code torture_krb5_post_recv_test(krb5_context context,
+ void *data,
+ krb5_error_code kdc_code,
+ const krb5_data *realm,
+ const krb5_data *message,
+ const krb5_data *reply,
+ krb5_data **new_reply_out)
+{
+ struct torture_krb5_context *test_context =
+ (struct torture_krb5_context *)data;
+ krb5_error_code code;
+ bool ok = true;
+
+ torture_comment(test_context->tctx,
+ "PACKET COUNT = %d\n",
+ test_context->recv_packet_count);
+
+ torture_comment(test_context->tctx,
+ "KRB5_AS_REP = %d\n",
+ krb5_is_as_req(reply));
+
+ torture_comment(test_context->tctx,
+ "KRB5_ERROR = %d\n",
+ krb5_is_krb_error(reply));
+
+ torture_comment(test_context->tctx,
+ "KDC ERROR CODE = %d\n",
+ kdc_code);
+
+ switch (test_context->test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ } else {
+ ok = torture_check_krb5_as_rep(test_context,
+ context,
+ reply);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_as_rep failed");
+ }
+
+ torture_assert_goto(test_context->tctx,
+ test_context->recv_packet_count < 2,
+ ok,
+ out,
+ "Too many packets");
+
+ break;
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KRB_ERR_RESPONSE_TOO_BIG,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ } else if (test_context->recv_packet_count == 1) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ } else if (krb5_is_krb_error(reply)) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KRB_ERR_RESPONSE_TOO_BIG,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ } else {
+ ok = torture_check_krb5_as_rep(test_context,
+ context,
+ reply);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_as_rep failed");
+ }
+
+ torture_assert_goto(test_context->tctx,
+ test_context->recv_packet_count < 3,
+ ok,
+ out,
+ "Too many packets");
+ break;
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ if (!ok) {
+ goto out;
+ }
+ } else if (test_context->recv_packet_count == 1) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_FAILED,
+ true);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ }
+
+ torture_assert_goto(test_context->tctx,
+ test_context->recv_packet_count < 2,
+ ok,
+ out,
+ "Too many packets");
+ break;
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ if (!ok) {
+ goto out;
+ }
+ } else if (test_context->recv_packet_count == 1) {
+ /*
+ * This only works if kdc_timesync 0 is set in krb5.conf
+ *
+ * See commit 5f39a4438eafd693a3eb8366bbc3901efe62e538
+ * in the MIT Kerberos source tree.
+ */
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KRB_AP_ERR_SKEW,
+ false);
+ torture_assert_goto(test_context->tctx,
+ ok,
+ ok,
+ out,
+ "torture_check_krb5_error failed");
+ }
+
+ torture_assert_goto(test_context->tctx,
+ test_context->recv_packet_count < 2,
+ ok,
+ out,
+ "Too many packets");
+ break;
+ case TORTURE_KRB5_TEST_AES:
+ torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES\n");
+
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ if (!ok) {
+ goto out;
+ }
+ } else {
+ ok = torture_check_krb5_as_rep_enctype(test_context,
+ context,
+ reply,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+ if (!ok) {
+ goto out;
+ }
+ }
+ break;
+ case TORTURE_KRB5_TEST_RC4:
+ torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_RC4\n");
+
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ if (!ok) {
+ goto out;
+ }
+ } else {
+ ok = torture_check_krb5_as_rep_enctype(test_context,
+ context,
+ reply,
+ ENCTYPE_ARCFOUR_HMAC);
+ if (!ok) {
+ goto out;
+ }
+ }
+ break;
+ case TORTURE_KRB5_TEST_AES_RC4:
+ torture_comment(test_context->tctx, "TORTURE_KRB5_TEST_AES_RC4\n");
+
+ if (test_context->recv_packet_count == 0) {
+ ok = torture_check_krb5_error(test_context,
+ context,
+ reply,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
+ false);
+ if (!ok) {
+ goto out;
+ }
+ } else {
+ ok = torture_check_krb5_as_rep_enctype(test_context,
+ context,
+ reply,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+ if (!ok) {
+ goto out;
+ }
+ }
+ break;
+ }
+
+ code = kdc_code;
+out:
+ if (!ok) {
+ code = EINVAL;
+ }
+
+ /* Cleanup */
+ krb5_free_kdc_req(test_context->krb5_context, test_context->as_req);
+ krb5_free_kdc_rep(test_context->krb5_context, test_context->as_rep);
+
+ test_context->recv_packet_count++;
+
+ return code;
+}
+
+static bool torture_krb5_init_context(struct torture_context *tctx,
+ enum torture_krb5_test test,
+ struct smb_krb5_context **smb_krb5_context)
+{
+ krb5_error_code code;
+
+ struct torture_krb5_context *test_context = talloc_zero(tctx,
+ struct torture_krb5_context);
+ torture_assert(tctx, test_context != NULL, "Failed to allocate");
+
+ test_context->test = test;
+ test_context->tctx = tctx;
+
+ code = smb_krb5_init_context(tctx, tctx->lp_ctx, smb_krb5_context);
+ torture_assert_int_equal(tctx, code, 0, "smb_krb5_init_context failed");
+
+ test_context->krb5_context = (*smb_krb5_context)->krb5_context;
+
+ krb5_set_kdc_send_hook((*smb_krb5_context)->krb5_context,
+ torture_krb5_pre_send_test,
+ test_context);
+
+ krb5_set_kdc_recv_hook((*smb_krb5_context)->krb5_context,
+ torture_krb5_post_recv_test,
+ test_context);
+
+ return true;
+}
+static bool torture_krb5_as_req_creds(struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ enum torture_krb5_test test)
+{
+ krb5_get_init_creds_opt *krb_options = NULL;
+ struct smb_krb5_context *smb_krb5_context;
+ enum credentials_obtained obtained;
+ const char *error_string;
+ const char *password;
+ krb5_principal principal;
+ krb5_error_code code;
+ krb5_creds my_creds;
+ bool ok;
+
+ ok = torture_krb5_init_context(tctx, test, &smb_krb5_context);
+ torture_assert(tctx, ok, "torture_krb5_init_context failed");
+
+ code = principal_from_credentials(tctx,
+ credentials,
+ smb_krb5_context,
+ &principal,
+ &obtained,
+ &error_string);
+ torture_assert_int_equal(tctx, code, 0, error_string);
+
+ password = cli_credentials_get_password(credentials);
+
+ switch (test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ break;
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+ code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ code, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+ code = krb5_get_init_creds_opt_set_pac_request(smb_krb5_context->krb5_context,
+ krb_options,
+ 1);
+ torture_assert_int_equal(tctx,
+ code, 0,
+ "krb5_get_init_creds_opt_set_pac_request failed");
+#endif
+ break;
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ password = "NOT the password";
+ break;
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ code = krb5_set_real_time(smb_krb5_context->krb5_context,
+ time(NULL) + 3600,
+ 0);
+ torture_assert_int_equal(tctx,
+ code, 0,
+ "krb5_set_real_time failed");
+ break;
+ case TORTURE_KRB5_TEST_AES: {
+ krb5_enctype etype[] = { ENCTYPE_AES256_CTS_HMAC_SHA1_96 };
+
+ code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ code, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+ krb5_get_init_creds_opt_set_etype_list(krb_options,
+ etype,
+ 1);
+ break;
+ }
+ case TORTURE_KRB5_TEST_RC4: {
+ krb5_enctype etype[] = { ENCTYPE_ARCFOUR_HMAC };
+
+ code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ code, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+ krb5_get_init_creds_opt_set_etype_list(krb_options,
+ etype,
+ 1);
+ break;
+ }
+ case TORTURE_KRB5_TEST_AES_RC4: {
+ krb5_enctype etype[] = { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_ARCFOUR_HMAC };
+
+ code = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context,
+ &krb_options);
+ torture_assert_int_equal(tctx,
+ code, 0,
+ "krb5_get_init_creds_opt_alloc failed");
+
+
+ krb5_get_init_creds_opt_set_etype_list(krb_options,
+ etype,
+ 2);
+ break;
+ }
+ }
+
+ code = krb5_get_init_creds_password(smb_krb5_context->krb5_context,
+ &my_creds,
+ principal,
+ password,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ krb_options);
+ krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context,
+ krb_options);
+
+ switch (test)
+ {
+ case TORTURE_KRB5_TEST_PLAIN:
+ case TORTURE_KRB5_TEST_PAC_REQUEST:
+ case TORTURE_KRB5_TEST_AES:
+ case TORTURE_KRB5_TEST_RC4:
+ case TORTURE_KRB5_TEST_AES_RC4:
+ torture_assert_int_equal(tctx,
+ code,
+ 0,
+ "krb5_get_init_creds_password failed");
+ break;
+ case TORTURE_KRB5_TEST_BREAK_PW:
+ torture_assert_int_equal(tctx,
+ code,
+ KRB5KDC_ERR_PREAUTH_FAILED,
+ "krb5_get_init_creds_password should "
+ "have failed");
+ return true;
+ case TORTURE_KRB5_TEST_CLOCK_SKEW:
+ torture_assert_int_equal(tctx,
+ code,
+ KRB5KRB_AP_ERR_SKEW,
+ "krb5_get_init_creds_password should "
+ "have failed");
+ return true;
+ }
+
+ krb5_free_cred_contents(smb_krb5_context->krb5_context,
+ &my_creds);
+
+ return true;
+}
+
+static bool torture_krb5_as_req_cmdline(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_PLAIN);
+}
+
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+static bool torture_krb5_as_req_pac_request(struct torture_context *tctx)
+{
+ bool ok;
+
+ ok = torture_setting_bool(tctx, "expect_rodc", false);
+ if (ok) {
+ torture_skip(tctx,
+ "This test needs further investigation in the "
+ "RODC case against a Windows DC, in particular "
+ "with non-cached users");
+ }
+ return torture_krb5_as_req_creds(tctx, samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_PAC_REQUEST);
+}
+#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST */
+
+static bool torture_krb5_as_req_break_pw(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_BREAK_PW);
+}
+
+static bool torture_krb5_as_req_clock_skew(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_CLOCK_SKEW);
+}
+
+static bool torture_krb5_as_req_aes(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_AES);
+}
+
+static bool torture_krb5_as_req_rc4(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_RC4);
+}
+
+static bool torture_krb5_as_req_aes_rc4(struct torture_context *tctx)
+{
+ return torture_krb5_as_req_creds(tctx,
+ samba_cmdline_get_creds(),
+ TORTURE_KRB5_TEST_AES_RC4);
+}
+
+NTSTATUS torture_krb5_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "krb5");
+ struct torture_suite *kdc_suite = torture_suite_create(suite, "kdc");
+ suite->description = talloc_strdup(suite, "Kerberos tests");
+ kdc_suite->description = talloc_strdup(kdc_suite, "Kerberos KDC tests");
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-cmdline",
+ torture_krb5_as_req_cmdline);
+
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
+ /* Only available with MIT Kerveros 1.15 and newer */
+ torture_suite_add_simple_test(kdc_suite, "as-req-pac-request",
+ torture_krb5_as_req_pac_request);
+#endif
+
+ torture_suite_add_simple_test(kdc_suite, "as-req-break-pw",
+ torture_krb5_as_req_break_pw);
+
+ /* This only works if kdc_timesync 0 is set in krb5.conf */
+ torture_suite_add_simple_test(kdc_suite, "as-req-clock-skew",
+ torture_krb5_as_req_clock_skew);
+
+#if 0
+ torture_suite_add_suite(kdc_suite, torture_krb5_canon(kdc_suite));
+#endif
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-aes",
+ torture_krb5_as_req_aes);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-rc4",
+ torture_krb5_as_req_rc4);
+
+ torture_suite_add_simple_test(kdc_suite,
+ "as-req-aes-rc4",
+ torture_krb5_as_req_aes_rc4);
+
+ torture_suite_add_suite(suite, kdc_suite);
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/krb5/wscript_build b/source4/torture/krb5/wscript_build
new file mode 100644
index 0000000..f59aa88
--- /dev/null
+++ b/source4/torture/krb5/wscript_build
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'):
+ if bld.CONFIG_SET('SAMBA4_USES_HEIMDAL'):
+ bld.SAMBA_MODULE('TORTURE_KRB5',
+ source='kdc-heimdal.c kdc-canon-heimdal.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_krb5_init',
+ deps='authkrb5 torture KERBEROS_UTIL',
+ internal_module=True)
+ else:
+ bld.SAMBA_MODULE('TORTURE_KRB5',
+ source='kdc-mit.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_krb5_init',
+ deps='authkrb5 torture KERBEROS_UTIL',
+ internal_module=True)
diff --git a/source4/torture/ldap/basic.c b/source4/torture/ldap/basic.c
new file mode 100644
index 0000000..ff9207e
--- /dev/null
+++ b/source4/torture/ldap/basic.c
@@ -0,0 +1,1004 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "ldb_wrap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "lib/cmdline/cmdline.h"
+
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+
+#undef strcasecmp
+
+static bool test_bind_sasl(struct torture_context *tctx,
+ struct ldap_connection *conn, struct cli_credentials *creds)
+{
+ NTSTATUS status;
+ bool ret = true;
+
+ printf("Testing sasl bind as user\n");
+
+ status = torture_ldap_bind_sasl(conn, creds, tctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_multibind(struct ldap_connection *conn, const char *userdn, const char *password)
+{
+ NTSTATUS status, expected;
+ bool ok;
+
+ printf("Testing multiple binds on a single connection as anonymous and user\n");
+
+ status = torture_ldap_bind(conn, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("1st bind as anonymous failed with %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ expected = NT_STATUS_LDAP(LDAP_STRONG_AUTH_REQUIRED);
+ status = torture_ldap_bind(conn, userdn, password);
+
+ ok = NT_STATUS_EQUAL(status, expected);
+ if (!ok) {
+ printf("2nd bind as authenticated user should have "
+ "failed with: %s, got %s\n",
+ nt_errstr(expected),
+ nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_search_rootDSE(struct ldap_connection *conn, const char **basedn,
+ const char ***partitions)
+{
+ bool ret = true;
+ struct ldap_message *msg, *result;
+ struct ldap_request *req;
+ int i;
+ struct ldap_SearchResEntry *r;
+ NTSTATUS status;
+
+ printf("Testing RootDSE Search\n");
+
+ *basedn = NULL;
+
+ if (partitions != NULL) {
+ *partitions = const_str_list(str_list_make_empty(conn));
+ }
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ return false;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+ msg->r.SearchRequest.basedn = "";
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = false;
+ msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
+ msg->r.SearchRequest.num_attributes = 0;
+ msg->r.SearchRequest.attributes = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (req == NULL) {
+ printf("Could not setup ldap search\n");
+ return false;
+ }
+
+ status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("search failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ printf("received %d replies\n", req->num_replies);
+
+ r = &result->r.SearchResultEntry;
+
+ DEBUG(1,("\tdn: %s\n", r->dn));
+ for (i=0; i<r->num_attributes; i++) {
+ unsigned int j;
+ for (j=0; j<r->attributes[i].num_values; j++) {
+ DEBUG(1,("\t%s: %d %.*s\n", r->attributes[i].name,
+ (int)r->attributes[i].values[j].length,
+ (int)r->attributes[i].values[j].length,
+ (char *)r->attributes[i].values[j].data));
+ if (!(*basedn) &&
+ strcasecmp("defaultNamingContext",r->attributes[i].name)==0) {
+ *basedn = talloc_asprintf(conn, "%.*s",
+ (int)r->attributes[i].values[j].length,
+ (char *)r->attributes[i].values[j].data);
+ }
+ if ((partitions != NULL) &&
+ (strcasecmp("namingContexts", r->attributes[i].name) == 0)) {
+ char *entry = talloc_asprintf(conn, "%.*s",
+ (int)r->attributes[i].values[j].length,
+ (char *)r->attributes[i].values[j].data);
+ *partitions = str_list_add(*partitions, entry);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool test_search_rootDSE_empty_substring(struct ldap_connection *conn)
+{
+ bool ret = true;
+ struct ldap_message *msg, *result;
+ struct ldap_request *req;
+ NTSTATUS status;
+
+ printf("Testing RootDSE Search with objectclass= substring filter\n");
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ return false;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+ msg->r.SearchRequest.basedn = "";
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = false;
+ msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
+ msg->r.SearchRequest.tree->operation = LDB_OP_SUBSTRING;
+ msg->r.SearchRequest.tree->u.substring.attr = "objectclass";
+ msg->r.SearchRequest.tree->u.substring.start_with_wildcard = 1;
+ msg->r.SearchRequest.tree->u.substring.end_with_wildcard = 1;
+ msg->r.SearchRequest.tree->u.substring.chunks = NULL;
+ msg->r.SearchRequest.num_attributes = 0;
+ msg->r.SearchRequest.attributes = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (req == NULL) {
+ printf("Could not setup ldap search\n");
+ return false;
+ }
+
+ status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("looking for search result reply failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ printf("received %d replies\n", req->num_replies);
+
+ return ret;
+}
+
+static bool test_search_auth_empty_substring(struct ldap_connection *conn, const char *basedn)
+{
+ bool ret = true;
+ struct ldap_message *msg, *result;
+ struct ldap_request *req;
+ NTSTATUS status;
+ struct ldap_Result *r;
+
+ printf("Testing authenticated base Search with objectclass= substring filter\n");
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ return false;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+ msg->r.SearchRequest.basedn = basedn;
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = false;
+ msg->r.SearchRequest.tree = ldb_parse_tree(msg, "(objectclass=*)");
+ msg->r.SearchRequest.tree->operation = LDB_OP_SUBSTRING;
+ msg->r.SearchRequest.tree->u.substring.attr = "objectclass";
+ msg->r.SearchRequest.tree->u.substring.start_with_wildcard = 1;
+ msg->r.SearchRequest.tree->u.substring.end_with_wildcard = 1;
+ msg->r.SearchRequest.tree->u.substring.chunks = NULL;
+ msg->r.SearchRequest.num_attributes = 0;
+ msg->r.SearchRequest.attributes = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (req == NULL) {
+ printf("Could not setup ldap search\n");
+ return false;
+ }
+
+ status = ldap_result_one(req, &result, LDAP_TAG_SearchResultDone);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("looking for search result done failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ printf("received %d replies\n", req->num_replies);
+
+ r = &result->r.SearchResultDone;
+
+ if (r->resultcode != LDAP_SUCCESS) {
+ printf("search result done gave error - %s\n", ldb_strerror(r->resultcode));
+ return false;
+ }
+
+ return ret;
+}
+
+static bool test_compare_sasl(struct ldap_connection *conn, const char *basedn)
+{
+ struct ldap_message *msg, *rep;
+ struct ldap_request *req;
+ const char *val;
+ NTSTATUS status;
+
+ printf("Testing SASL Compare: %s\n", basedn);
+
+ if (!basedn) {
+ return false;
+ }
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ return false;
+ }
+
+ msg->type = LDAP_TAG_CompareRequest;
+ msg->r.CompareRequest.dn = basedn;
+ msg->r.CompareRequest.attribute = talloc_strdup(msg, "objectClass");
+ val = "domain";
+ msg->r.CompareRequest.value = data_blob_talloc(msg, val, strlen(val));
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_CompareResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap compare request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ DEBUG(5,("Code: %d DN: [%s] ERROR:[%s] REFERRAL:[%s]\n",
+ rep->r.CompareResponse.resultcode,
+ rep->r.CompareResponse.dn,
+ rep->r.CompareResponse.errormessage,
+ rep->r.CompareResponse.referral));
+
+ return true;
+}
+
+/*
+ * This takes an AD error message and splits it into the WERROR code
+ * (WERR_DS_GENERIC if none found) and the reason (remaining string).
+ */
+static WERROR ad_error(const char *err_msg, char **reason)
+{
+ WERROR err = W_ERROR(strtol(err_msg, reason, 16));
+
+ if ((reason != NULL) && (*reason[0] != ':')) {
+ return WERR_DS_GENERIC_ERROR; /* not an AD std error message */
+ }
+
+ if (reason != NULL) {
+ *reason += 2; /* skip ": " */
+ }
+ return err;
+}
+
+/* This has to be done using the LDAP API since the LDB API does only transmit
+ * the error code and not the error message. */
+static bool test_error_codes(struct torture_context *tctx,
+ struct ldap_connection *conn, const char *basedn)
+{
+ struct ldap_message *msg, *rep;
+ struct ldap_request *req;
+ const char *err_code_str;
+ char *endptr;
+ WERROR err;
+ NTSTATUS status;
+
+ printf("Testing the most important error code -> error message conversions!\n");
+
+ if (!basedn) {
+ return false;
+ }
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ return false;
+ }
+
+ printf(" Try a wrong addition\n");
+
+ msg->type = LDAP_TAG_AddRequest;
+ msg->r.AddRequest.dn = basedn;
+ msg->r.AddRequest.num_attributes = 0;
+ msg->r.AddRequest.attributes = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_AddResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap add request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.AddResponse.resultcode == 0)
+ || (rep->r.AddResponse.errormessage == NULL)
+ || (strtol(rep->r.AddResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.AddResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_DS_REFERRAL))
+ || (rep->r.AddResponse.resultcode != LDAP_REFERRAL)) {
+ return false;
+ }
+ if ((rep->r.AddResponse.referral == NULL)
+ || (strstr(rep->r.AddResponse.referral, basedn) == NULL)) {
+ return false;
+ }
+
+ printf(" Try another wrong addition\n");
+
+ msg->type = LDAP_TAG_AddRequest;
+ msg->r.AddRequest.dn = "";
+ msg->r.AddRequest.num_attributes = 0;
+ msg->r.AddRequest.attributes = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_AddResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap add request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.AddResponse.resultcode == 0)
+ || (rep->r.AddResponse.errormessage == NULL)
+ || (strtol(rep->r.AddResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.AddResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_DS_ROOT_MUST_BE_NC) &&
+ !W_ERROR_EQUAL(err, WERR_DS_NAMING_VIOLATION))
+ || (rep->r.AddResponse.resultcode != LDAP_NAMING_VIOLATION)) {
+ return false;
+ }
+
+ printf(" Try a wrong modification\n");
+
+ msg->type = LDAP_TAG_ModifyRequest;
+ msg->r.ModifyRequest.dn = basedn;
+ msg->r.ModifyRequest.num_mods = 0;
+ msg->r.ModifyRequest.mods = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_ModifyResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap modifification request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.ModifyResponse.resultcode == 0)
+ || (rep->r.ModifyResponse.errormessage == NULL)
+ || (strtol(rep->r.ModifyResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.ModifyResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
+ !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
+ || (rep->r.ModifyResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
+ return false;
+ }
+
+ printf(" Try another wrong modification\n");
+
+ msg->type = LDAP_TAG_ModifyRequest;
+ msg->r.ModifyRequest.dn = "";
+ msg->r.ModifyRequest.num_mods = 0;
+ msg->r.ModifyRequest.mods = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_ModifyResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap modifification request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.ModifyResponse.resultcode == 0)
+ || (rep->r.ModifyResponse.errormessage == NULL)
+ || (strtol(rep->r.ModifyResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.ModifyResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
+ !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
+ || (rep->r.ModifyResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
+ return false;
+ }
+
+ printf(" Try a wrong removal\n");
+
+ msg->type = LDAP_TAG_DelRequest;
+ msg->r.DelRequest.dn = basedn;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_DelResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap removal request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.DelResponse.resultcode == 0)
+ || (rep->r.DelResponse.errormessage == NULL)
+ || (strtol(rep->r.DelResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.DelResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_DS_CANT_DELETE) &&
+ !W_ERROR_EQUAL(err, WERR_DS_UNWILLING_TO_PERFORM))
+ || (rep->r.DelResponse.resultcode != LDAP_UNWILLING_TO_PERFORM)) {
+ return false;
+ }
+
+ printf(" Try another wrong removal\n");
+
+ msg->type = LDAP_TAG_DelRequest;
+ msg->r.DelRequest.dn = "";
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_DelResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap removal request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.DelResponse.resultcode == 0)
+ || (rep->r.DelResponse.errormessage == NULL)
+ || (strtol(rep->r.DelResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.DelResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_DS_OBJ_NOT_FOUND) &&
+ !W_ERROR_EQUAL(err, WERR_DS_NO_SUCH_OBJECT))
+ || (rep->r.DelResponse.resultcode != LDAP_NO_SUCH_OBJECT)) {
+ return false;
+ }
+
+ printf(" Try a wrong rename\n");
+
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = basedn;
+ msg->r.ModifyDNRequest.newrdn = "dc=test";
+ msg->r.ModifyDNRequest.deleteolddn = true;
+ msg->r.ModifyDNRequest.newsuperior = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap rename request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.ModifyDNResponse.resultcode == 0)
+ || (rep->r.ModifyDNResponse.errormessage == NULL)
+ || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_DS_NO_PARENT_OBJECT) &&
+ !W_ERROR_EQUAL(err, WERR_DS_GENERIC_ERROR))
+ || (rep->r.ModifyDNResponse.resultcode != LDAP_OTHER)) {
+ return false;
+ }
+
+ printf(" Try another wrong rename\n");
+
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = basedn;
+ msg->r.ModifyDNRequest.newrdn = basedn;
+ msg->r.ModifyDNRequest.deleteolddn = true;
+ msg->r.ModifyDNRequest.newsuperior = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap rename request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.ModifyDNResponse.resultcode == 0)
+ || (rep->r.ModifyDNResponse.errormessage == NULL)
+ || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
+ !W_ERROR_EQUAL(err, WERR_DS_NAMING_VIOLATION))
+ || (rep->r.ModifyDNResponse.resultcode != LDAP_NAMING_VIOLATION)) {
+ return false;
+ }
+
+ printf(" Try another wrong rename\n");
+
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = basedn;
+ msg->r.ModifyDNRequest.newrdn = "";
+ msg->r.ModifyDNRequest.deleteolddn = true;
+ msg->r.ModifyDNRequest.newsuperior = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap rename request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.ModifyDNResponse.resultcode == 0)
+ || (rep->r.ModifyDNResponse.errormessage == NULL)
+ || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_INVALID_PARAMETER) &&
+ !W_ERROR_EQUAL(err, WERR_DS_PROTOCOL_ERROR))
+ || (rep->r.ModifyDNResponse.resultcode != LDAP_PROTOCOL_ERROR)) {
+ return false;
+ }
+
+ printf(" Try another wrong rename\n");
+
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = "";
+ msg->r.ModifyDNRequest.newrdn = "cn=temp";
+ msg->r.ModifyDNRequest.deleteolddn = true;
+ msg->r.ModifyDNRequest.newsuperior = NULL;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_result_one(req, &rep, LDAP_TAG_ModifyDNResponse);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap rename request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if ((rep->r.ModifyDNResponse.resultcode == 0)
+ || (rep->r.ModifyDNResponse.errormessage == NULL)
+ || (strtol(rep->r.ModifyDNResponse.errormessage, &endptr,16) <= 0)
+ || (*endptr != ':')) {
+ printf("Invalid error message!\n");
+ return false;
+ }
+
+ err = ad_error(rep->r.ModifyDNResponse.errormessage, &endptr);
+ err_code_str = win_errstr(err);
+ printf(" - Errorcode: %s; Reason: %s\n", err_code_str, endptr);
+ if ((!W_ERROR_EQUAL(err, WERR_DS_OBJ_NOT_FOUND) &&
+ !W_ERROR_EQUAL(err, WERR_DS_NO_SUCH_OBJECT))
+ || (rep->r.ModifyDNResponse.resultcode != LDAP_NO_SUCH_OBJECT)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_referrals(struct torture_context *tctx, TALLOC_CTX *mem_ctx,
+ const char *url, const char *basedn, const char **partitions)
+{
+ struct ldb_context *ldb;
+ struct ldb_result *res;
+ const char * const *attrs = { NULL };
+ struct ldb_dn *dn1, *dn2;
+ int ret;
+ int i, j, k;
+ char *tempstr;
+ bool found, l_found;
+
+ printf("Testing referrals\n");
+
+ if (partitions[0] == NULL) {
+ printf("Partitions list empty!\n");
+ return false;
+ }
+
+ if (strcmp(partitions[0], basedn) != 0) {
+ printf("The first (root) partition DN should be the base DN!\n");
+ return false;
+ }
+
+ ldb = ldb_wrap_connect(mem_ctx, tctx->ev, tctx->lp_ctx, url,
+ NULL, samba_cmdline_get_creds(), 0);
+
+ /* "partitions[i]" are the partitions for which we search the parents */
+ for (i = 1; partitions[i] != NULL; i++) {
+ dn1 = ldb_dn_new(mem_ctx, ldb, partitions[i]);
+ if (dn1 == NULL) {
+ printf("Out of memory\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ /* search using base scope */
+ /* "partitions[j]" are the parent candidates */
+ for (j = str_list_length(partitions) - 1; j >= 0; --j) {
+ dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]);
+ if (dn2 == NULL) {
+ printf("Out of memory\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ ret = ldb_search(ldb, mem_ctx, &res, dn2,
+ LDB_SCOPE_BASE, attrs,
+ "(foo=bar)");
+ if (ret != LDB_SUCCESS) {
+ printf("%s", ldb_errstring(ldb));
+ talloc_free(ldb);
+ return false;
+ }
+
+ if (res->refs != NULL) {
+ printf("There shouldn't be generated any referrals in the base scope!\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ talloc_free(res);
+ talloc_free(dn2);
+ }
+
+ /* search using onelevel scope */
+ found = false;
+ /* "partitions[j]" are the parent candidates */
+ for (j = str_list_length(partitions) - 1; j >= 0; --j) {
+ dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]);
+ if (dn2 == NULL) {
+ printf("Out of memory\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ ret = ldb_search(ldb, mem_ctx, &res, dn2,
+ LDB_SCOPE_ONELEVEL, attrs,
+ "(foo=bar)");
+ if (ret != LDB_SUCCESS) {
+ printf("%s", ldb_errstring(ldb));
+ talloc_free(ldb);
+ return false;
+ }
+
+ tempstr = talloc_asprintf(mem_ctx, "/%s??base",
+ partitions[i]);
+ if (tempstr == NULL) {
+ printf("Out of memory\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ /* Try to find or find not a matching referral */
+ l_found = false;
+ for (k = 0; (!l_found) && (res->refs != NULL)
+ && (res->refs[k] != NULL); k++) {
+ if (strstr(res->refs[k], tempstr) != NULL) {
+ l_found = true;
+ }
+ }
+
+ talloc_free(tempstr);
+
+ if ((!found) && (ldb_dn_compare_base(dn2, dn1) == 0)
+ && (ldb_dn_compare(dn2, dn1) != 0)) {
+ /* This is a referral candidate */
+ if (!l_found) {
+ printf("A required referral hasn't been found on onelevel scope (%s -> %s)!\n", partitions[j], partitions[i]);
+ talloc_free(ldb);
+ return false;
+ }
+ found = true;
+ } else {
+ /* This isn't a referral candidate */
+ if (l_found) {
+ printf("A unrequired referral has been found on onelevel scope (%s -> %s)!\n", partitions[j], partitions[i]);
+ talloc_free(ldb);
+ return false;
+ }
+ }
+
+ talloc_free(res);
+ talloc_free(dn2);
+ }
+
+ /* search using subtree scope */
+ found = false;
+ /* "partitions[j]" are the parent candidates */
+ for (j = str_list_length(partitions) - 1; j >= 0; --j) {
+ dn2 = ldb_dn_new(mem_ctx, ldb, partitions[j]);
+ if (dn2 == NULL) {
+ printf("Out of memory\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ ret = ldb_search(ldb, mem_ctx, &res, dn2,
+ LDB_SCOPE_SUBTREE, attrs,
+ "(foo=bar)");
+ if (ret != LDB_SUCCESS) {
+ printf("%s", ldb_errstring(ldb));
+ talloc_free(ldb);
+ return false;
+ }
+
+ tempstr = talloc_asprintf(mem_ctx, "/%s",
+ partitions[i]);
+ if (tempstr == NULL) {
+ printf("Out of memory\n");
+ talloc_free(ldb);
+ return false;
+ }
+
+ /* Try to find or find not a matching referral */
+ l_found = false;
+ for (k = 0; (!l_found) && (res->refs != NULL)
+ && (res->refs[k] != NULL); k++) {
+ if (strstr(res->refs[k], tempstr) != NULL) {
+ l_found = true;
+ }
+ }
+
+ talloc_free(tempstr);
+
+ if ((!found) && (ldb_dn_compare_base(dn2, dn1) == 0)
+ && (ldb_dn_compare(dn2, dn1) != 0)) {
+ /* This is a referral candidate */
+ if (!l_found) {
+ printf("A required referral hasn't been found on subtree scope (%s -> %s)!\n", partitions[j], partitions[i]);
+ talloc_free(ldb);
+ return false;
+ }
+ found = true;
+ } else {
+ /* This isn't a referral candidate */
+ if (l_found) {
+ printf("A unrequired referral has been found on subtree scope (%s -> %s)!\n", partitions[j], partitions[i]);
+ talloc_free(ldb);
+ return false;
+ }
+ }
+
+ talloc_free(res);
+ talloc_free(dn2);
+ }
+
+ talloc_free(dn1);
+ }
+
+ talloc_free(ldb);
+
+ return true;
+}
+
+static bool test_abandon_request(struct torture_context *tctx,
+ struct ldap_connection *conn, const char *basedn)
+{
+ struct ldap_message *msg;
+ struct ldap_request *req;
+ NTSTATUS status;
+
+ printf("Testing the AbandonRequest with an old message id!\n");
+
+ if (!basedn) {
+ return false;
+ }
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ return false;
+ }
+
+ printf(" Try a AbandonRequest for an old message id\n");
+
+ msg->type = LDAP_TAG_AbandonRequest;
+ msg->r.AbandonRequest.messageid = 1;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ return false;
+ }
+
+ status = ldap_request_wait(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap abandon request - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_ldap_basic(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct ldap_connection *conn;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ const char *userdn = torture_setting_string(torture, "ldap_userdn", NULL);
+ const char *secret = torture_setting_string(torture, "ldap_secret", NULL);
+ const char *url;
+ const char *basedn;
+ const char **partitions;
+
+ mem_ctx = talloc_init("torture_ldap_basic");
+
+ url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
+
+ status = torture_ldap_connection(torture, &conn, url);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ if (!test_search_rootDSE(conn, &basedn, &partitions)) {
+ ret = false;
+ }
+
+ if (!test_search_rootDSE_empty_substring(conn)) {
+ ret = false;
+ }
+
+ /* other bind tests here */
+
+ if (!test_multibind(conn, userdn, secret)) {
+ ret = false;
+ }
+
+ if (!test_bind_sasl(torture, conn, samba_cmdline_get_creds())) {
+ ret = false;
+ }
+
+ if (!test_search_auth_empty_substring(conn, basedn)) {
+ ret = false;
+ }
+
+ if (!test_compare_sasl(conn, basedn)) {
+ ret = false;
+ }
+
+ /* error codes test here */
+
+ if (!test_error_codes(torture, conn, basedn)) {
+ ret = false;
+ }
+
+ /* referrals test here */
+
+ if (!test_referrals(torture, mem_ctx, url, basedn, partitions)) {
+ ret = false;
+ }
+
+ if (!test_abandon_request(torture, conn, basedn)) {
+ ret = false;
+ }
+
+ /* if there are no more tests we are closing */
+ torture_ldap_close(conn);
+ talloc_free(mem_ctx);
+
+ torture_assert(torture, ret, "torture_ldap_basic failed");
+
+ return ret;
+}
+
diff --git a/source4/torture/ldap/cldap.c b/source4/torture/ldap/cldap.c
new file mode 100644
index 0000000..a021f4c
--- /dev/null
+++ b/source4/torture/ldap/cldap.c
@@ -0,0 +1,179 @@
+/*
+ Unix SMB/CIFS Implementation.
+
+ test CLDAP operations
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Matthias Dieter Wallnöfer 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "libcli/cldap/cldap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+
+#define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status")
+
+#define CHECK_VAL(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value");
+
+#define CHECK_STRING(v, correct) torture_assert_str_equal(tctx, v, correct, "incorrect value");
+
+/*
+ convert a ldap result message to a ldb message. This allows us to
+ use the convenient ldif dump routines in ldb to print out cldap
+ search results
+*/
+static struct ldb_message *ldap_msg_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldap_SearchResEntry *res)
+{
+ struct ldb_message *msg;
+
+ msg = ldb_msg_new(mem_ctx);
+ msg->dn = ldb_dn_new(msg, ldb, res->dn);
+ msg->num_elements = res->num_attributes;
+ msg->elements = talloc_steal(msg, res->attributes);
+ return msg;
+}
+
+/*
+ dump a set of cldap results
+*/
+static void cldap_dump_results(struct cldap_search *search)
+{
+ struct ldb_ldif ldif;
+ struct ldb_context *ldb;
+
+ if (!search || !(search->out.response)) {
+ return;
+ }
+
+ /* we need a ldb context to use ldb_ldif_write_file() */
+ ldb = ldb_init(NULL, NULL);
+
+ ZERO_STRUCT(ldif);
+ ldif.msg = ldap_msg_to_ldb(ldb, ldb, search->out.response);
+
+ ldb_ldif_write_file(ldb, stdout, &ldif);
+
+ talloc_free(ldb);
+}
+
+/*
+ test generic cldap operations
+*/
+static bool test_cldap_generic(struct torture_context *tctx, const char *dest)
+{
+ struct cldap_socket *cldap;
+ NTSTATUS status;
+ struct cldap_search search;
+ const char *attrs1[] = { "currentTime", "highestCommittedUSN", NULL };
+ const char *attrs2[] = { "currentTime", "highestCommittedUSN", "netlogon", NULL };
+ const char *attrs3[] = { "netlogon", NULL };
+ struct tsocket_address *dest_addr;
+ const char *ip;
+ struct nbt_name nbt_name;
+ int ret;
+
+ make_nbt_name_server(&nbt_name, dest);
+
+ status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx,"Failed to resolve %s: %s",
+ nbt_name.name, nt_errstr(status)));
+
+ ret = tsocket_address_inet_from_strings(tctx, "ip",
+ ip,
+ lpcfg_cldap_port(tctx->lp_ctx),
+ &dest_addr);
+ CHECK_VAL(ret, 0);
+
+ /* cldap_socket_init should now know about the dest. address */
+ status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(search);
+ search.in.dest_address = NULL;
+ search.in.dest_port = 0;
+ search.in.timeout = 10;
+ search.in.retries = 3;
+
+ status = cldap_search(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("fetching whole rootDSE\n");
+ search.in.filter = "(objectclass=*)";
+ search.in.attributes = NULL;
+
+ status = cldap_search(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (DEBUGLVL(3)) cldap_dump_results(&search);
+
+ printf("fetching currentTime and USN\n");
+ search.in.filter = "(objectclass=*)";
+ search.in.attributes = attrs1;
+
+ status = cldap_search(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (DEBUGLVL(3)) cldap_dump_results(&search);
+
+ printf("Testing currentTime, USN and netlogon\n");
+ search.in.filter = "(objectclass=*)";
+ search.in.attributes = attrs2;
+
+ status = cldap_search(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (DEBUGLVL(3)) cldap_dump_results(&search);
+
+ printf("Testing objectClass=* and netlogon\n");
+ search.in.filter = "(objectclass=*)";
+ search.in.attributes = attrs3;
+
+ status = cldap_search(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (DEBUGLVL(3)) cldap_dump_results(&search);
+
+ printf("Testing a false expression\n");
+ search.in.filter = "(&(objectclass=*)(highestCommittedUSN=2))";
+ search.in.attributes = attrs1;
+
+ status = cldap_search(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (DEBUGLVL(3)) cldap_dump_results(&search);
+
+ return true;
+}
+
+bool torture_cldap(struct torture_context *torture)
+{
+ bool ret = true;
+ const char *host = torture_setting_string(torture, "host", NULL);
+
+ ret &= test_cldap_generic(torture, host);
+
+ return ret;
+}
+
diff --git a/source4/torture/ldap/cldapbench.c b/source4/torture/ldap/cldapbench.c
new file mode 100644
index 0000000..9b6f7f2
--- /dev/null
+++ b/source4/torture/ldap/cldapbench.c
@@ -0,0 +1,233 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP benchmark test
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/cldap/cldap.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/ldap/ldap_client.h"
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+
+#define CHECK_VAL(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value");
+
+struct bench_state {
+ struct torture_context *tctx;
+ int pass_count, fail_count;
+};
+
+static void request_netlogon_handler(struct tevent_req *req)
+{
+ struct cldap_netlogon io;
+ struct bench_state *state = tevent_req_callback_data(req, struct bench_state);
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ io.in.version = 6;
+ status = cldap_netlogon_recv(req, tmp_ctx, &io);
+ talloc_free(req);
+ if (NT_STATUS_IS_OK(status)) {
+ state->pass_count++;
+ } else {
+ state->fail_count++;
+ }
+ talloc_free(tmp_ctx);
+}
+
+/*
+ benchmark cldap netlogon calls
+*/
+static bool bench_cldap_netlogon(struct torture_context *tctx, const char *address)
+{
+ struct cldap_socket *cldap;
+ int num_sent=0;
+ struct timeval tv = timeval_current();
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ struct cldap_netlogon search;
+ struct bench_state *state;
+ NTSTATUS status;
+ struct tsocket_address *dest_addr;
+ int ret;
+
+ ret = tsocket_address_inet_from_strings(tctx, "ip",
+ address,
+ lpcfg_cldap_port(tctx->lp_ctx),
+ &dest_addr);
+ CHECK_VAL(ret, 0);
+
+ status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
+ torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
+
+ state = talloc_zero(tctx, struct bench_state);
+ state->tctx = tctx;
+
+ ZERO_STRUCT(search);
+ search.in.dest_address = NULL;
+ search.in.dest_port = 0;
+ search.in.acct_control = -1;
+ search.in.version = 6;
+
+ printf("Running CLDAP/netlogon for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ while (num_sent - (state->pass_count+state->fail_count) < 10) {
+ struct tevent_req *req;
+ req = cldap_netlogon_send(state, tctx->ev,
+ cldap, &search);
+
+ tevent_req_set_callback(req, request_netlogon_handler, state);
+
+ num_sent++;
+ if (num_sent % 50 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ printf("%.1f queries per second (%d failures) \r",
+ state->pass_count / timeval_elapsed(&tv),
+ state->fail_count);
+ fflush(stdout);
+ }
+ }
+ }
+
+ tevent_loop_once(tctx->ev);
+ }
+
+ while (num_sent != (state->pass_count + state->fail_count)) {
+ tevent_loop_once(tctx->ev);
+ }
+
+ printf("%.1f queries per second (%d failures) \n",
+ state->pass_count / timeval_elapsed(&tv),
+ state->fail_count);
+
+ talloc_free(cldap);
+ return true;
+}
+
+static void request_rootdse_handler(struct tevent_req *req)
+{
+ struct cldap_search io;
+ struct bench_state *state = tevent_req_callback_data(req, struct bench_state);
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ status = cldap_search_recv(req, tmp_ctx, &io);
+ talloc_free(req);
+ if (NT_STATUS_IS_OK(status)) {
+ state->pass_count++;
+ } else {
+ state->fail_count++;
+ }
+ talloc_free(tmp_ctx);
+}
+
+/*
+ benchmark cldap netlogon calls
+*/
+static bool bench_cldap_rootdse(struct torture_context *tctx, const char *address)
+{
+ struct cldap_socket *cldap;
+ int num_sent=0;
+ struct timeval tv = timeval_current();
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ struct cldap_search search;
+ struct bench_state *state;
+ NTSTATUS status;
+ struct tsocket_address *dest_addr;
+ int ret;
+
+ ret = tsocket_address_inet_from_strings(tctx, "ip",
+ address,
+ lpcfg_cldap_port(tctx->lp_ctx),
+ &dest_addr);
+ CHECK_VAL(ret, 0);
+
+ /* cldap_socket_init should now know about the dest. address */
+ status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
+ torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
+
+ state = talloc_zero(tctx, struct bench_state);
+
+ ZERO_STRUCT(search);
+ search.in.dest_address = NULL;
+ search.in.dest_port = 0;
+ search.in.filter = "(objectClass=*)";
+ search.in.timeout = 2;
+ search.in.retries = 1;
+
+ printf("Running CLDAP/rootdse for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ while (num_sent - (state->pass_count+state->fail_count) < 10) {
+ struct tevent_req *req;
+ req = cldap_search_send(state, tctx->ev, cldap, &search);
+
+ tevent_req_set_callback(req, request_rootdse_handler, state);
+
+ num_sent++;
+ if (num_sent % 50 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ printf("%.1f queries per second (%d failures) \r",
+ state->pass_count / timeval_elapsed(&tv),
+ state->fail_count);
+ fflush(stdout);
+ }
+ }
+ }
+
+ tevent_loop_once(tctx->ev);
+ }
+
+ while (num_sent != (state->pass_count + state->fail_count)) {
+ tevent_loop_once(tctx->ev);
+ }
+
+ printf("%.1f queries per second (%d failures) \n",
+ state->pass_count / timeval_elapsed(&tv),
+ state->fail_count);
+
+ talloc_free(cldap);
+ return true;
+}
+
+/*
+ benchmark how fast a CLDAP server can respond to a series of parallel
+ requests
+*/
+bool torture_bench_cldap(struct torture_context *torture)
+{
+ const char *address;
+ struct nbt_name name;
+ NTSTATUS status;
+ bool ret = true;
+
+ make_nbt_name_server(&name, torture_setting_string(torture, "host", NULL));
+
+ /* do an initial name resolution to find its IP */
+ status = resolve_name_ex(lpcfg_resolve_context(torture->lp_ctx),
+ 0, 0, &name, torture, &address, torture->ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to resolve %s - %s\n",
+ name.name, nt_errstr(status));
+ return false;
+ }
+
+ ret &= bench_cldap_netlogon(torture, address);
+ ret &= bench_cldap_rootdse(torture, address);
+
+ return ret;
+}
diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c
new file mode 100644
index 0000000..c33fda7
--- /dev/null
+++ b/source4/torture/ldap/common.c
@@ -0,0 +1,135 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "libcli/ldap/ldap_client.h"
+#include "torture/smbtorture.h"
+#include "torture/ldap/proto.h"
+
+NTSTATUS torture_ldap_bind(struct ldap_connection *conn, const char *userdn, const char *password)
+{
+ NTSTATUS status;
+
+ status = ldap_bind_simple(conn, userdn, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to bind with provided credentials - %s\n",
+ nt_errstr(status));
+ }
+
+ return status;
+}
+
+NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn,
+ struct cli_credentials *creds,
+ struct loadparm_context *lp_ctx)
+{
+ NTSTATUS status;
+
+ status = ldap_bind_sasl(conn, creds, lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed sasl bind with provided credentials - %s\n",
+ nt_errstr(status));
+ }
+
+ return status;
+}
+
+/* open a ldap connection to a server */
+NTSTATUS torture_ldap_connection(struct torture_context *tctx,
+ struct ldap_connection **conn,
+ const char *url)
+{
+ NTSTATUS status;
+
+ if (!url) {
+ printf("You must specify a url string\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *conn = ldap4_new_connection(tctx, tctx->lp_ctx, tctx->ev);
+
+ status = ldap_connect(*conn, url);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect to ldap server '%s' - %s\n",
+ url, nt_errstr(status));
+ }
+
+ return status;
+}
+
+/* close an ldap connection to a server */
+NTSTATUS torture_ldap_close(struct ldap_connection *conn)
+{
+ struct ldap_message *msg;
+ struct ldap_request *req;
+ NTSTATUS status;
+
+ printf("Closing the connection...\n");
+
+ msg = new_ldap_message(conn);
+ if (!msg) {
+ talloc_free(conn);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ printf(" Try a UnbindRequest\n");
+
+ msg->type = LDAP_TAG_UnbindRequest;
+
+ req = ldap_request_send(conn, msg);
+ if (!req) {
+ talloc_free(conn);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ldap_request_wait(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("error in ldap unbind request - %s\n", nt_errstr(status));
+ talloc_free(conn);
+ return status;
+ }
+
+ talloc_free(conn);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS torture_ldap_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ldap");
+ torture_suite_add_simple_test(suite, "bench-cldap", torture_bench_cldap);
+ torture_suite_add_simple_test(suite, "basic", torture_ldap_basic);
+ torture_suite_add_simple_test(suite, "sort", torture_ldap_sort);
+ torture_suite_add_simple_test(suite, "cldap", torture_cldap);
+ torture_suite_add_simple_test(suite, "netlogon-udp", torture_netlogon_udp);
+ torture_suite_add_simple_test(suite, "netlogon-tcp", torture_netlogon_tcp);
+ torture_suite_add_simple_test(suite, "schema", torture_ldap_schema);
+ torture_suite_add_simple_test(suite, "uptodatevector", torture_ldap_uptodatevector);
+ torture_suite_add_simple_test(suite, "nested-search", test_ldap_nested_search);
+ torture_suite_add_simple_test(
+ suite, "session-expiry", torture_ldap_session_expiry);
+
+ suite->description = talloc_strdup(suite, "LDAP and CLDAP tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/ldap/ldap_sort.c b/source4/torture/ldap/ldap_sort.c
new file mode 100644
index 0000000..b28bd95
--- /dev/null
+++ b/source4/torture/ldap/ldap_sort.c
@@ -0,0 +1,158 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Test LDB attribute functions
+
+ Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008-2009
+ Copyright (C) Matthieu Patou <mat@matws.net> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include <ldb.h>
+#include <ldb_errors.h>
+#include "ldb_wrap.h"
+#include "param/param.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/ldap/ldap_client.h"
+#include "torture/smbtorture.h"
+#include "torture/ldap/proto.h"
+#include <ctype.h>
+
+bool torture_ldap_sort(struct torture_context *torture)
+{
+ struct ldb_context *ldb;
+
+ bool ret = false;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ char *url;
+ codepoint_t j;
+ struct ldb_message_element *elem;
+ struct ldb_message *msg;
+
+ struct ldb_server_sort_control **control;
+ struct ldb_request *req;
+ struct ldb_result *ctx;
+ struct ldb_val *prev = NULL;
+ const char *prev_txt = NULL;
+ int prev_len = 0;
+ struct ldb_val *cur = NULL;
+ const char *cur_txt = NULL;
+ int cur_len = 0;
+ struct ldb_dn *dn;
+
+
+ /* TALLOC_CTX* ctx;*/
+
+ url = talloc_asprintf(torture, "ldap://%s/", host);
+
+ ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+ torture_assert(torture, ldb, "Failed to make LDB connection to target");
+
+ ctx = talloc_zero(ldb, struct ldb_result);
+
+ control = talloc_array(ctx, struct ldb_server_sort_control *, 2);
+ control[0] = talloc(control, struct ldb_server_sort_control);
+ control[0]->attributeName = talloc_strdup(control, "cn");
+ control[0]->orderingRule = NULL;
+ control[0]->reverse = 0;
+ control[1] = NULL;
+
+ dn = ldb_get_default_basedn(ldb);
+ ldb_dn_add_child_fmt(dn, "cn=users");
+ ret = ldb_build_search_req(&req, ldb, ctx,
+ dn,
+ LDB_SCOPE_SUBTREE,
+ "(objectClass=*)", NULL,
+ NULL,
+ ctx, ldb_search_default_callback, NULL);
+ torture_assert(torture, ret == LDB_SUCCESS, "Failed to build search request");
+
+ ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, control);
+ torture_assert(torture, ret == LDB_SUCCESS, "Failed to add control to search request");
+
+ ret = ldb_request(ldb, req);
+ torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb));
+
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb));
+
+ ret = true;
+ if (ctx->count > 1) {
+ unsigned int i;
+ for (i=0;i<ctx->count;i++) {
+ msg = ctx->msgs[i];
+ elem = ldb_msg_find_element(msg,"cn");
+ torture_assert_not_null(torture, elem, "msg lacks CN");
+ cur = elem->values;
+ torture_comment(torture, "cn: %s\n",cur->data);
+ if (prev != NULL)
+ {
+ /* Do only the ascii case right now ... */
+ cur_txt = (const char *) cur->data;
+ cur_len = cur->length;
+ prev_txt = (const char *) prev->data;
+ prev_len = prev->length;
+ /* Remove leading whitespace as the sort function do so ... */
+ while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;}
+ while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;}
+ while( *(cur_txt) && *(prev_txt) && cur_len && prev_len ) {
+ j = toupper_m(*(prev_txt))-toupper_m(*(cur_txt));
+ if ( j > 0 ) {
+ /* Just check that is not due to trailing white space in prev_txt
+ * That is to say *cur_txt = 0 and prev_txt = 20 */
+ /* Remove trailing whitespace */
+ while ( *prev_txt == ' ' ) { prev_txt++; prev_len--;}
+ while ( *cur_txt == ' ' ) { cur_txt++; cur_len--;}
+ /* Now that potential whitespace are removed if we are at the end
+ * of the cur_txt then it means that in fact strings were identical
+ */
+ torture_assert(torture, *cur_txt && *prev_txt, "Data wrongly sorted");
+ break;
+ }
+ else
+ {
+ if ( j == 0 )
+ {
+ if ( *(cur_txt) == ' ') {
+ while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;}
+ while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;}
+ }
+ cur_txt++;
+ prev_txt++;
+ prev_len--;
+ cur_len--;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ if ( ret != 1 ) {
+ break;
+ }
+ }
+ prev = cur;
+ }
+
+ }
+
+ return ret;
+}
diff --git a/source4/torture/ldap/nested_search.c b/source4/torture/ldap/nested_search.c
new file mode 100644
index 0000000..8f4d71b
--- /dev/null
+++ b/source4/torture/ldap/nested_search.c
@@ -0,0 +1,206 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ BRIEF FILE DESCRIPTION
+
+ Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ldb.h"
+#include "ldb_wrap.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/ldap/ldap_client.h"
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+
+#define torture_assert_res(torture_ctx,expr,cmt,_res) \
+ if (!(expr)) { \
+ torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \
+ return _res; \
+ }
+
+
+struct nested_search_context {
+ struct torture_context *tctx;
+ struct ldb_dn *root_dn;
+ struct ldb_context *ldb;
+ struct ldb_result *ldb_res;
+};
+
+/*
+ * ldb_search handler - used to executed a nested
+ * ldap search request during LDB_REPLY_ENTRY handling
+ */
+static int nested_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ unsigned int i;
+ int res;
+ struct nested_search_context *sctx;
+ struct ldb_result *ldb_res;
+ struct ldb_message *ldb_msg;
+ static const char *attrs[] = {
+ "rootDomainNamingContext",
+ "configurationNamingContext",
+ "schemaNamingContext",
+ "defaultNamingContext",
+ NULL
+ };
+ enum ldb_reply_type type;
+
+ sctx = talloc_get_type(req->context, struct nested_search_context);
+
+ type = ares->type;
+ /* sanity check */
+ switch (type) {
+ case LDB_REPLY_ENTRY:
+ torture_comment(sctx->tctx, "nested_search_callback: LDB_REPLY_ENTRY\n");
+ ldb_msg = ares->message;
+ torture_assert_res(sctx->tctx, ldb_msg, "ares->message is NULL!", LDB_ERR_OPERATIONS_ERROR);
+ torture_assert_res(sctx->tctx, ldb_msg->num_elements, "No elements returned!", LDB_ERR_OPERATIONS_ERROR);
+ torture_assert_res(sctx->tctx, ldb_msg->elements, "elements member is NULL!", LDB_ERR_OPERATIONS_ERROR);
+ break;
+ case LDB_REPLY_DONE:
+ torture_comment(sctx->tctx, "nested_search_callback: LDB_REPLY_DONE\n");
+ break;
+ case LDB_REPLY_REFERRAL:
+ torture_comment(sctx->tctx, "nested_search_callback: LDB_REPLY_REFERRAL\n");
+ break;
+ }
+
+ /* switch context and let default handler do its job */
+ req->context = sctx->ldb_res;
+ res = ldb_search_default_callback(req, ares);
+ req->context = sctx;
+ if (res != LDB_SUCCESS) {
+ return res;
+ }
+
+ /* not a search reply, then get out */
+ if (type != LDB_REPLY_ENTRY) {
+ return res;
+ }
+
+
+ res = ldb_search(sctx->ldb, sctx, &ldb_res, sctx->root_dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)");
+ if (res != LDB_SUCCESS) {
+ torture_warning(sctx->tctx,
+ "Search on RootDSE failed in search_entry handler: %s",
+ ldb_errstring(sctx->ldb));
+ return LDB_SUCCESS;
+ }
+
+ torture_assert_res(sctx->tctx, ldb_res->count == 1, "One message expected here", LDB_ERR_OPERATIONS_ERROR);
+
+ ldb_msg = ldb_res->msgs[0];
+ torture_assert_res(sctx->tctx, ldb_msg->num_elements == (ARRAY_SIZE(attrs)-1),
+ "Search returned different number of elts than requested", LDB_ERR_OPERATIONS_ERROR);
+ for (i = 0; i < ldb_msg->num_elements; i++) {
+ const char *msg;
+ struct ldb_message_element *elt1;
+ struct ldb_message_element *elt2;
+
+ elt2 = &ldb_msg->elements[i];
+ msg = talloc_asprintf(sctx, "Processing element: %s", elt2->name);
+ elt1 = ldb_msg_find_element(sctx->ldb_res->msgs[0], elt2->name);
+ torture_assert_res(sctx->tctx, elt1, msg, LDB_ERR_OPERATIONS_ERROR);
+
+ /* compare elements */
+ torture_assert_res(sctx->tctx, elt2->flags == elt1->flags, "", LDB_ERR_OPERATIONS_ERROR);
+ torture_assert_res(sctx->tctx, elt2->num_values == elt1->num_values, "", LDB_ERR_OPERATIONS_ERROR);
+ }
+ /* TODO: check returned result */
+
+ return LDB_SUCCESS;
+}
+
+/**
+ * Test nested search execution against RootDSE
+ * on remote LDAP server.
+ */
+bool test_ldap_nested_search(struct torture_context *tctx)
+{
+ int ret;
+ char *url;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ struct ldb_request *req;
+ struct nested_search_context *sctx;
+ static const char *attrs[] = {
+/*
+ "rootDomainNamingContext",
+ "configurationNamingContext",
+ "schemaNamingContext",
+ "defaultNamingContext",
+*/
+ "*",
+ NULL
+ };
+
+ sctx = talloc_zero(tctx, struct nested_search_context);
+ torture_assert(tctx, sctx, "Not enough memory");
+ sctx->tctx = tctx;
+
+ url = talloc_asprintf(sctx, "ldap://%s/", host);
+ if (!url) {
+ torture_assert(tctx, url, "Not enough memory");
+ }
+
+ torture_comment(tctx, "Connecting to: %s\n", url);
+ sctx->ldb = ldb_wrap_connect(sctx, tctx->ev, tctx->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+ torture_assert(tctx, sctx->ldb, "Failed to create ldb connection");
+
+ /* prepare context for searching */
+ sctx->root_dn = ldb_dn_new(sctx, sctx->ldb, NULL);
+ sctx->ldb_res = talloc_zero(sctx, struct ldb_result);
+
+ /* build search request */
+ ret = ldb_build_search_req(&req,
+ sctx->ldb,
+ sctx,
+ sctx->root_dn, LDB_SCOPE_BASE,
+ "(objectClass=*)", attrs, NULL,
+ sctx, nested_search_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Allocating request failed: %s", ldb_errstring(sctx->ldb));
+ return false;
+ }
+
+ ret = ldb_request(sctx->ldb, req);
+ if (ret != LDB_SUCCESS) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Search failed: %s", ldb_errstring(sctx->ldb));
+ return false;
+ }
+
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ ": Search error: %s", ldb_errstring(sctx->ldb));
+ return false;
+ }
+
+ /* TODO: check returned result */
+
+ talloc_free(sctx);
+ return true;
+}
+
diff --git a/source4/torture/ldap/netlogon.c b/source4/torture/ldap/netlogon.c
new file mode 100644
index 0000000..0bddb3e
--- /dev/null
+++ b/source4/torture/ldap/netlogon.c
@@ -0,0 +1,668 @@
+/*
+ Unix SMB/CIFS Implementation.
+
+ test CLDAP/LDAP netlogon operations
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Matthias Dieter Wallnöfer 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "libcli/cldap/cldap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "libcli/resolve/resolve.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "param/param.h"
+#include "../lib/tsocket/tsocket.h"
+
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+
+#undef strcasecmp
+
+#define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status")
+
+#define CHECK_VAL(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value");
+
+#define CHECK_STRING(v, correct) torture_assert_str_equal(tctx, v, correct, "incorrect value");
+
+typedef NTSTATUS (*request_netlogon_t)(void *con,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io);
+
+typedef NTSTATUS (*request_rootdse_t)(void *con,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_search *io);
+
+/*
+ test netlogon operations
+*/
+static bool test_ldap_netlogon(struct torture_context *tctx,
+ request_netlogon_t request_netlogon,
+ void *cldap,
+ const char *dest)
+{
+ NTSTATUS status;
+ struct cldap_netlogon search, empty_search;
+ struct netlogon_samlogon_response n1;
+ struct GUID guid;
+ int i;
+
+ ZERO_STRUCT(search);
+ search.in.dest_address = NULL;
+ search.in.dest_port = 0;
+ search.in.acct_control = -1;
+ search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
+ search.in.map_response = true;
+
+ empty_search = search;
+
+ printf("Trying without any attributes\n");
+ search = empty_search;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ n1 = search.out.netlogon;
+
+ search.in.user = "Administrator";
+ search.in.realm = n1.data.nt5_ex.dns_domain;
+ search.in.host = "__cldap_torture__";
+
+ printf("Scanning for netlogon levels\n");
+ for (i=0;i<256;i++) {
+ search.in.version = i;
+ printf("Trying netlogon level %d\n", i);
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ printf("Scanning for netlogon level bits\n");
+ for (i=0;i<31;i++) {
+ search.in.version = (1<<i);
+ printf("Trying netlogon level 0x%x\n", i);
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ search.in.version = NETLOGON_NT_VERSION_5|NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_IP;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying with User=NULL\n");
+ search.in.user = NULL;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+ torture_assert(tctx,
+ strstr(search.out.netlogon.data.nt5_ex.pdc_name, "\\\\") == NULL,
+ "PDC name should not be in UNC form");
+
+ printf("Trying with User=Administrator\n");
+ search.in.user = "Administrator";
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
+ torture_assert(tctx,
+ strstr(search.out.netlogon.data.nt5_ex.pdc_name, "\\\\") == NULL,
+ "PDC name should not be in UNC form");
+
+ search.in.version = NETLOGON_NT_VERSION_5;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying with User=NULL\n");
+ search.in.user = NULL;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+ torture_assert(tctx,
+ strstr(search.out.netlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ printf("Trying with User=Administrator\n");
+ search.in.user = "Administrator";
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
+ torture_assert(tctx,
+ strstr(search.out.netlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
+
+ printf("Trying with a GUID\n");
+ search.in.realm = NULL;
+ search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid);
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
+ CHECK_STRING(GUID_string(tctx, &search.out.netlogon.data.nt5_ex.domain_uuid), search.in.domain_guid);
+ torture_assert(tctx,
+ strstr(search.out.netlogon.data.nt5_ex.pdc_name, "\\\\") == NULL,
+ "PDC name should not be in UNC form");
+
+ printf("Trying with a incorrect GUID\n");
+ guid = GUID_random();
+ search.in.user = NULL;
+ search.in.domain_guid = GUID_string(tctx, &guid);
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
+
+ printf("Trying with a AAC\n");
+ search.in.acct_control = ACB_WSTRUST|ACB_SVRTRUST;
+ search.in.realm = n1.data.nt5_ex.dns_domain;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+
+ printf("Trying with a zero AAC\n");
+ search.in.acct_control = 0x0;
+ search.in.realm = n1.data.nt5_ex.dns_domain;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+
+ printf("Trying with a zero AAC and user=Administrator\n");
+ search.in.acct_control = 0x0;
+ search.in.user = "Administrator";
+ search.in.realm = n1.data.nt5_ex.dns_domain;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "Administrator");
+
+ printf("Trying with a bad AAC\n");
+ search.in.user = NULL;
+ search.in.acct_control = 0xFF00FF00;
+ search.in.realm = n1.data.nt5_ex.dns_domain;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+
+ printf("Trying with a user only\n");
+ search = empty_search;
+ search.in.user = "Administrator";
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.forest, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.domain_name, n1.data.nt5_ex.domain_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.pdc_name, n1.data.nt5_ex.pdc_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.server_site, n1.data.nt5_ex.server_site);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.client_site, n1.data.nt5_ex.client_site);
+
+ printf("Trying with just a bad username\n");
+ search.in.user = "___no_such_user___";
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.forest, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.domain_name, n1.data.nt5_ex.domain_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.pdc_name, n1.data.nt5_ex.pdc_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.server_site, n1.data.nt5_ex.server_site);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.client_site, n1.data.nt5_ex.client_site);
+
+ printf("Trying with just a bad domain\n");
+ search = empty_search;
+ search.in.realm = "___no_such_domain___";
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
+
+ printf("Trying with a incorrect domain and correct guid\n");
+ search.in.domain_guid = GUID_string(tctx, &n1.data.nt5_ex.domain_uuid);
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.forest, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.domain_name, n1.data.nt5_ex.domain_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.pdc_name, n1.data.nt5_ex.pdc_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.server_site, n1.data.nt5_ex.server_site);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.client_site, n1.data.nt5_ex.client_site);
+
+ printf("Trying with a incorrect domain and incorrect guid\n");
+ search.in.domain_guid = GUID_string(tctx, &guid);
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_NOT_FOUND);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.forest, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.domain_name, n1.data.nt5_ex.domain_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.pdc_name, n1.data.nt5_ex.pdc_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.server_site, n1.data.nt5_ex.server_site);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.client_site, n1.data.nt5_ex.client_site);
+
+ printf("Trying with a incorrect GUID and correct domain\n");
+ search.in.domain_guid = GUID_string(tctx, &guid);
+ search.in.realm = n1.data.nt5_ex.dns_domain;
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(search.out.netlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.forest, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.domain_name, n1.data.nt5_ex.domain_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.pdc_name, n1.data.nt5_ex.pdc_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, "");
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.server_site, n1.data.nt5_ex.server_site);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.client_site, n1.data.nt5_ex.client_site);
+
+ printf("Proof other results\n");
+ search.in.user = "Administrator";
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.forest, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.dns_domain, n1.data.nt5_ex.dns_domain);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.domain_name, n1.data.nt5_ex.domain_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.pdc_name, n1.data.nt5_ex.pdc_name);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.user_name, search.in.user);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.server_site, n1.data.nt5_ex.server_site);
+ CHECK_STRING(search.out.netlogon.data.nt5_ex.client_site, n1.data.nt5_ex.client_site);
+
+ return true;
+}
+
+/*
+ test cldap netlogon server type flags
+*/
+static bool test_ldap_netlogon_flags(struct torture_context *tctx,
+ request_netlogon_t request_netlogon,
+ void *cldap,
+ const char *dest)
+{
+ NTSTATUS status;
+ struct cldap_netlogon search;
+ struct netlogon_samlogon_response n1;
+ uint32_t server_type = 0;
+
+ printf("Printing out netlogon server type flags: %s\n", dest);
+
+ ZERO_STRUCT(search);
+ search.in.dest_address = NULL;
+ search.in.dest_port = 0;
+ search.in.acct_control = -1;
+ search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
+ search.in.map_response = true;
+
+ status = request_netlogon(cldap, tctx, &search);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ n1 = search.out.netlogon;
+ if (n1.ntver == NETLOGON_NT_VERSION_5)
+ server_type = n1.data.nt5.server_type;
+ else if (n1.ntver == NETLOGON_NT_VERSION_5EX)
+ server_type = n1.data.nt5_ex.server_type;
+
+ printf("The word is: %i\n", server_type);
+ if (server_type & NBT_SERVER_PDC)
+ printf("NBT_SERVER_PDC ");
+ if (server_type & NBT_SERVER_GC)
+ printf("NBT_SERVER_GC ");
+ if (server_type & NBT_SERVER_LDAP)
+ printf("NBT_SERVER_LDAP ");
+ if (server_type & NBT_SERVER_DS)
+ printf("NBT_SERVER_DS ");
+ if (server_type & NBT_SERVER_KDC)
+ printf("NBT_SERVER_KDC ");
+ if (server_type & NBT_SERVER_TIMESERV)
+ printf("NBT_SERVER_TIMESERV ");
+ if (server_type & NBT_SERVER_CLOSEST)
+ printf("NBT_SERVER_CLOSEST ");
+ if (server_type & NBT_SERVER_WRITABLE)
+ printf("NBT_SERVER_WRITABLE ");
+ if (server_type & NBT_SERVER_GOOD_TIMESERV)
+ printf("NBT_SERVER_GOOD_TIMESERV ");
+ if (server_type & NBT_SERVER_NDNC)
+ printf("NBT_SERVER_NDNC ");
+ if (server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6)
+ printf("NBT_SERVER_SELECT_SECRET_DOMAIN_6");
+ if (server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6)
+ printf("NBT_SERVER_FULL_SECRET_DOMAIN_6");
+ if (server_type & NBT_SERVER_ADS_WEB_SERVICE)
+ printf("NBT_SERVER_ADS_WEB_SERVICE ");
+ if (server_type & NBT_SERVER_DS_8)
+ printf("NBT_SERVER_DS_8 ");
+ if (server_type & NBT_SERVER_DS_9)
+ printf("NBT_SERVER_DS_9 ");
+ if (server_type & NBT_SERVER_DS_10)
+ printf("NBT_SERVER_DS_10 ");
+ if (server_type & NBT_SERVER_HAS_DNS_NAME)
+ printf("NBT_SERVER_HAS_DNS_NAME ");
+ if (server_type & NBT_SERVER_IS_DEFAULT_NC)
+ printf("NBT_SERVER_IS_DEFAULT_NC ");
+ if (server_type & NBT_SERVER_FOREST_ROOT)
+ printf("NBT_SERVER_FOREST_ROOT ");
+
+ printf("\n");
+
+ return true;
+}
+
+static NTSTATUS tcp_ldap_rootdse(void *data,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_search *io)
+{
+ struct ldap_connection *conn = talloc_get_type(data,
+ struct ldap_connection);
+ struct ldap_message *msg, *result;
+ struct ldap_request *req;
+ int i;
+ NTSTATUS status;
+
+ msg = new_ldap_message(mem_ctx);
+ if (!msg) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+ msg->r.SearchRequest.basedn = "";
+ msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE;
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = false;
+ msg->r.SearchRequest.tree = ldb_parse_tree(msg, io->in.filter);
+ msg->r.SearchRequest.num_attributes = str_list_length(io->in.attributes);
+ msg->r.SearchRequest.attributes = io->in.attributes;
+
+ req = ldap_request_send(conn, msg);
+ if (req == NULL) {
+ printf("Could not setup ldap search\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ZERO_STRUCT(io->out);
+ for (i = 0; i < 2; ++i) {
+ status = ldap_result_n(req, i, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ switch (result->type) {
+ case LDAP_TAG_SearchResultEntry:
+ if (i != 0) {
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ }
+ io->out.response = &result->r.SearchResultEntry;
+ break;
+ case LDAP_TAG_SearchResultDone:
+ io->out.result = &result->r.SearchResultDone;
+ if (io->out.result->resultcode != LDAP_SUCCESS) {
+ return NT_STATUS_LDAP(io->out.result->resultcode);
+ }
+
+ return NT_STATUS_OK;
+ default:
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS tcp_ldap_netlogon(void *conn,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io)
+{
+ struct cldap_search search;
+ struct ldap_SearchResEntry *res;
+ NTSTATUS status;
+ DATA_BLOB *blob;
+
+ ZERO_STRUCT(search);
+ search.in.attributes = (const char *[]) { "netlogon", NULL };
+ search.in.filter = cldap_netlogon_create_filter(mem_ctx, io);
+ if (search.in.filter == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = tcp_ldap_rootdse(conn, mem_ctx, &search);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ res = search.out.response;
+ if (res == NULL) {
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ if (res->num_attributes != 1 ||
+ strcasecmp(res->attributes[0].name, "netlogon") != 0 ||
+ res->attributes[0].num_values != 1 ||
+ res->attributes[0].values->length < 2) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ blob = res->attributes[0].values;
+ status = pull_netlogon_samlogon_response(blob, mem_ctx,
+ &io->out.netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (io->in.map_response) {
+ map_netlogon_samlogon_response(&io->out.netlogon);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS udp_ldap_rootdse(void *data, TALLOC_CTX *mem_ctx,
+ struct cldap_search *io)
+{
+ struct cldap_socket *cldap = talloc_get_type(data,
+ struct cldap_socket);
+
+ return cldap_search(cldap, mem_ctx, io);
+}
+
+static bool test_netlogon_extra_attrs(struct torture_context *tctx,
+ request_rootdse_t request_rootdse,
+ void *conn)
+{
+ struct cldap_search io;
+ NTSTATUS status;
+ const char *attrs[] = {
+ "netlogon",
+ "supportedCapabilities",
+ NULL
+ };
+ const char *attrs2[] = { "netlogon", "*", NULL };
+ struct ldb_message ldbmsg = { NULL, 0, NULL };
+
+ ZERO_STRUCT(io);
+ io.in.dest_address = NULL;
+ io.in.dest_port = 0;
+ io.in.timeout = 2;
+ io.in.retries = 2;
+ /* Additional attributes may be requested next to netlogon */
+ torture_comment(tctx, "Requesting netlogon with additional attribute\n");
+ io.in.filter =
+ talloc_asprintf(tctx, "(&"
+ "(NtVer=%s)(AAC=%s)"
+ /* Query for LDAP_CAP_ACTIVE_DIRECTORY_OID */
+ "(supportedCapabilities=1.2.840.113556.1.4.800)"
+ ")",
+ ldap_encode_ndr_uint32(tctx,
+ NETLOGON_NT_VERSION_5EX),
+ ldap_encode_ndr_uint32(tctx, 0));
+ torture_assert(tctx, io.in.filter != NULL, "OOM");
+ io.in.attributes = attrs;
+ status = request_rootdse(conn, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_assert(tctx, io.out.response != NULL, "No Entries found.");
+ CHECK_VAL(io.out.response->num_attributes, 2);
+
+ /* netlogon + '*' attr return zero results */
+ torture_comment(tctx, "Requesting netlogon and '*' attributes\n");
+ io.in.attributes = attrs2;
+ status = request_rootdse(conn, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_assert(tctx, io.out.response != NULL, "No Entries found.");
+ ldbmsg.num_elements = io.out.response->num_attributes;
+ ldbmsg.elements = io.out.response->attributes;
+ torture_assert(tctx, ldb_msg_find_element(&ldbmsg, "netlogon") != NULL,
+ "Attribute netlogon not found in Result Entry\n");
+
+ /* Wildcards are not allowed in filters when netlogon is requested. */
+ torture_comment(tctx, "Requesting netlogon with invalid attr filter\n");
+ io.in.filter =
+ talloc_asprintf(tctx,
+ "(&(NtVer=%s)(AAC=%s)(supportedCapabilities=*))",
+ ldap_encode_ndr_uint32(tctx,
+ NETLOGON_NT_VERSION_5EX),
+ ldap_encode_ndr_uint32(tctx, 0));
+ torture_assert(tctx, io.in.filter != NULL, "OOM");
+ io.in.attributes = attrs;
+ status = request_rootdse(conn, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_assert(tctx, io.out.response == NULL,
+ "A wildcard filter should return no entries.");
+
+ return true;
+}
+
+/*
+ Bug #11392: Huawei Unified Storage System S5500 V3 sends no NtVer
+ [MS-ADTS] Section 7.3.3.2 "Domain Controller Response to an LDAP Ping"
+*/
+static bool test_netlogon_huawei(struct torture_context *tctx,
+ request_rootdse_t request_rootdse,
+ void *conn)
+{
+ struct cldap_search io;
+ struct netlogon_samlogon_response n1;
+ NTSTATUS status;
+ const char *attrs[] = {
+ "netlogon",
+ NULL
+ };
+ struct ldb_message ldbmsg = { NULL, 0, NULL };
+
+ ZERO_STRUCT(io);
+ io.in.dest_address = NULL;
+ io.in.dest_port = 0;
+ io.in.timeout = 2;
+ io.in.retries = 2;
+
+ torture_comment(tctx, "Requesting netlogon without NtVer filter\n");
+ io.in.filter = talloc_asprintf(tctx, "(&(DnsDomain=%s))",
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ torture_assert(tctx, io.in.filter != NULL, "OOM");
+ io.in.attributes = attrs;
+ status = request_rootdse(conn, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_assert(tctx, io.out.response != NULL, "No Entries found.");
+ CHECK_VAL(io.out.response->num_attributes, 1);
+
+ ldbmsg.num_elements = io.out.response->num_attributes;
+ ldbmsg.elements = io.out.response->attributes;
+ torture_assert(tctx, ldb_msg_find_element(&ldbmsg, "netlogon") != NULL,
+ "Attribute netlogon not found in Result Entry\n");
+
+ status = pull_netlogon_samlogon_response(
+ io.out.response->attributes[0].values,
+ tctx,
+ &n1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(n1.ntver, NETLOGON_NT_VERSION_5);
+
+ return true;
+}
+
+bool torture_netlogon_tcp(struct torture_context *tctx)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ bool ret = true;
+ NTSTATUS status;
+ struct ldap_connection *conn;
+ TALLOC_CTX *mem_ctx;
+ const char *url;
+
+ mem_ctx = talloc_init("torture_ldap_netlogon");
+
+ url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
+
+ status = torture_ldap_connection(tctx, &conn, url);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ret &= test_ldap_netlogon(tctx, tcp_ldap_netlogon, conn, host);
+ ret &= test_ldap_netlogon_flags(tctx, tcp_ldap_netlogon, conn, host);
+ ret &= test_netlogon_extra_attrs(tctx, tcp_ldap_rootdse, conn);
+
+ return ret;
+}
+
+static NTSTATUS udp_ldap_netlogon(void *data,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io)
+{
+ struct cldap_socket *cldap = talloc_get_type(data,
+ struct cldap_socket);
+
+ return cldap_netlogon(cldap, mem_ctx, io);
+}
+
+bool torture_netlogon_udp(struct torture_context *tctx)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *ip;
+ struct nbt_name nbt_name;
+ bool ret = true;
+ int r;
+ struct cldap_socket *cldap;
+ NTSTATUS status;
+ struct tsocket_address *dest_addr;
+
+ make_nbt_name_server(&nbt_name, host);
+
+ status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx,"Failed to resolve %s: %s",
+ nbt_name.name, nt_errstr(status)));
+
+ r = tsocket_address_inet_from_strings(tctx, "ip",
+ ip,
+ lpcfg_cldap_port(tctx->lp_ctx),
+ &dest_addr);
+ CHECK_VAL(r, 0);
+
+ /* cldap_socket_init should now know about the dest. address */
+ status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= test_ldap_netlogon(tctx, udp_ldap_netlogon, cldap, host);
+ ret &= test_ldap_netlogon_flags(tctx, udp_ldap_netlogon, cldap, host);
+ ret &= test_netlogon_extra_attrs(tctx, udp_ldap_rootdse, cldap);
+ ret &= test_netlogon_huawei(tctx, udp_ldap_rootdse, cldap);
+
+ return ret;
+}
diff --git a/source4/torture/ldap/schema.c b/source4/torture/ldap/schema.c
new file mode 100644
index 0000000..06313bc
--- /dev/null
+++ b/source4/torture/ldap/schema.c
@@ -0,0 +1,408 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP schema tests
+
+ Copyright (C) Stefan Metzmacher 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "libcli/ldap/ldap_client.h"
+#include "lib/cmdline/cmdline.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "../lib/util/dlinklist.h"
+
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+
+
+struct test_rootDSE {
+ const char *defaultdn;
+ const char *rootdn;
+ const char *configdn;
+ const char *schemadn;
+};
+
+struct test_schema_ctx {
+ struct ldb_context *ldb;
+
+ struct ldb_paged_control *ctrl;
+ uint32_t count;
+ bool pending;
+
+ int (*callback)(void *, struct ldb_context *ldb, struct ldb_message *);
+ void *private_data;
+};
+
+static bool test_search_rootDSE(struct ldb_context *ldb, struct test_rootDSE *root)
+{
+ int ret;
+ struct ldb_message *msg;
+ struct ldb_result *r;
+
+ d_printf("Testing RootDSE Search\n");
+
+ ret = ldb_search(ldb, ldb, &r, ldb_dn_new(ldb, ldb, NULL),
+ LDB_SCOPE_BASE, NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ return false;
+ } else if (r->count != 1) {
+ talloc_free(r);
+ return false;
+ }
+
+ msg = r->msgs[0];
+
+ root->defaultdn = ldb_msg_find_attr_as_string(msg, "defaultNamingContext", NULL);
+ talloc_steal(ldb, root->defaultdn);
+ root->rootdn = ldb_msg_find_attr_as_string(msg, "rootDomainNamingContext", NULL);
+ talloc_steal(ldb, root->rootdn);
+ root->configdn = ldb_msg_find_attr_as_string(msg, "configurationNamingContext", NULL);
+ talloc_steal(ldb, root->configdn);
+ root->schemadn = ldb_msg_find_attr_as_string(msg, "schemaNamingContext", NULL);
+ talloc_steal(ldb, root->schemadn);
+
+ talloc_free(r);
+
+ return true;
+}
+
+static int test_schema_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct test_schema_ctx *actx;
+ int ret = LDB_SUCCESS;
+
+ actx = talloc_get_type(req->context, struct test_schema_ctx);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ actx->count++;
+ ret = actx->callback(actx->private_data, actx->ldb, ares->message);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ break;
+
+ case LDB_REPLY_DONE:
+ if (ares->controls) {
+ struct ldb_paged_control *ctrl = NULL;
+ int i;
+
+ for (i=0; ares->controls[i]; i++) {
+ if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[i]->oid) == 0) {
+ ctrl = talloc_get_type(ares->controls[i]->data, struct ldb_paged_control);
+ break;
+ }
+ }
+
+ if (!ctrl) break;
+
+ talloc_free(actx->ctrl->cookie);
+ actx->ctrl->cookie = talloc_steal(actx->ctrl->cookie, ctrl->cookie);
+ actx->ctrl->cookie_len = ctrl->cookie_len;
+
+ if (actx->ctrl->cookie_len > 0) {
+ actx->pending = true;
+ }
+ }
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+
+ default:
+ d_printf("%s: unknown Reply Type %u\n", __location__, ares->type);
+ return ldb_request_done(req, LDB_ERR_OTHER);
+ }
+
+ if (talloc_free(ares) == -1) {
+ d_printf("talloc_free failed\n");
+ actx->pending = 0;
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ret) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static bool test_create_schema_type(struct ldb_context *ldb, struct test_rootDSE *root,
+ const char *filter,
+ int (*callback)(void *, struct ldb_context *ldb, struct ldb_message *),
+ void *private_data)
+{
+ struct ldb_control **ctrl;
+ struct ldb_paged_control *control;
+ struct ldb_request *req;
+ int ret;
+ struct test_schema_ctx *actx;
+
+ actx = talloc(ldb, struct test_schema_ctx);
+ actx->ldb = ldb;
+ actx->private_data = private_data;
+ actx->callback= callback;
+
+ ctrl = talloc_array(actx, struct ldb_control *, 2);
+ ctrl[0] = talloc(ctrl, struct ldb_control);
+ ctrl[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
+ ctrl[0]->critical = true;
+ control = talloc(ctrl[0], struct ldb_paged_control);
+ control->size = 1000;
+ control->cookie = NULL;
+ control->cookie_len = 0;
+ ctrl[0]->data = control;
+ ctrl[1] = NULL;
+
+ ret = ldb_build_search_req(&req, ldb, actx,
+ ldb_dn_new(actx, ldb, root->schemadn),
+ LDB_SCOPE_SUBTREE,
+ filter, NULL,
+ ctrl,
+ actx, test_schema_search_callback,
+ NULL);
+
+ actx->ctrl = control;
+ actx->count = 0;
+again:
+ actx->pending = false;
+
+ ret = ldb_request(ldb, req);
+ if (ret != LDB_SUCCESS) {
+ d_printf("search failed - %s\n", ldb_errstring(ldb));
+ talloc_free(actx);
+ return false;
+ }
+
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ d_printf("search error - %s\n", ldb_errstring(ldb));
+ talloc_free(actx);
+ return false;
+ }
+
+ if (actx->pending)
+ goto again;
+
+ d_printf("filter[%s] count[%u]\n", filter, actx->count);
+ talloc_free(actx);
+ return true;
+}
+
+static int test_add_attribute(void *ptr, struct ldb_context *ldb, struct ldb_message *msg)
+{
+ struct dsdb_schema *schema = talloc_get_type(ptr, struct dsdb_schema);
+ WERROR status;
+
+ status = dsdb_set_attribute_from_ldb(ldb, schema, msg);
+ if (!W_ERROR_IS_OK(status)) {
+ goto failed;
+ }
+
+ return LDB_SUCCESS;
+failed:
+ return LDB_ERR_OTHER;
+}
+
+static int test_add_class(void *ptr, struct ldb_context *ldb, struct ldb_message *msg)
+{
+ struct dsdb_schema *schema = talloc_get_type(ptr, struct dsdb_schema);
+ WERROR status;
+
+ status = dsdb_set_class_from_ldb(schema, msg);
+ if (!W_ERROR_IS_OK(status)) {
+ goto failed;
+ }
+
+ return LDB_SUCCESS;
+failed:
+ return LDB_ERR_OTHER;
+}
+
+static bool test_create_schema(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema **_schema)
+{
+ bool ret = true;
+ struct dsdb_schema *schema;
+
+ schema = talloc_zero(ldb, struct dsdb_schema);
+
+ d_printf("Fetching attributes...\n");
+ ret &= test_create_schema_type(ldb, root, "(objectClass=attributeSchema)",
+ test_add_attribute, schema);
+ d_printf("Fetching objectClasses...\n");
+ ret &= test_create_schema_type(ldb, root, "(objectClass=classSchema)",
+ test_add_class, schema);
+
+ if (ret == true) {
+ *_schema = schema;
+ }
+ return ret;
+}
+
+static bool test_dump_not_replicated(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
+{
+ struct dsdb_attribute *a;
+ uint32_t a_i = 1;
+
+ d_printf("Dumping not replicated attributes\n");
+
+ for (a=schema->attributes; a; a = a->next) {
+ if (!(a->systemFlags & 0x00000001)) continue;
+ d_printf("attr[%4u]: '%s'\n", a_i++,
+ a->lDAPDisplayName);
+ }
+
+ return true;
+}
+
+static bool test_dump_partial(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
+{
+ struct dsdb_attribute *a;
+ uint32_t a_i = 1;
+
+ d_printf("Dumping attributes which are provided by the global catalog\n");
+
+ for (a=schema->attributes; a; a = a->next) {
+ if (!(a->systemFlags & 0x00000002) && !a->isMemberOfPartialAttributeSet) continue;
+ d_printf("attr[%4u]: %u %u '%s'\n", a_i++,
+ a->systemFlags & 0x00000002, a->isMemberOfPartialAttributeSet,
+ a->lDAPDisplayName);
+ }
+
+ return true;
+}
+
+static bool test_dump_contructed(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
+{
+ struct dsdb_attribute *a;
+ uint32_t a_i = 1;
+
+ d_printf("Dumping constructed attributes\n");
+
+ for (a=schema->attributes; a; a = a->next) {
+ if (!(a->systemFlags & 0x00000004)) continue;
+ d_printf("attr[%4u]: '%s'\n", a_i++,
+ a->lDAPDisplayName);
+ }
+
+ return true;
+}
+
+static bool test_dump_sorted_syntax(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
+{
+ struct dsdb_attribute *a;
+ uint32_t a_i = 1;
+ uint32_t i;
+ const char *syntaxes[] = {
+ "2.5.5.0",
+ "2.5.5.1",
+ "2.5.5.2",
+ "2.5.5.3",
+ "2.5.5.4",
+ "2.5.5.5",
+ "2.5.5.6",
+ "2.5.5.7",
+ "2.5.5.8",
+ "2.5.5.9",
+ "2.5.5.10",
+ "2.5.5.11",
+ "2.5.5.12",
+ "2.5.5.13",
+ "2.5.5.14",
+ "2.5.5.15",
+ "2.5.5.16",
+ "2.5.5.17"
+ };
+
+ d_printf("Dumping attribute syntaxes\n");
+
+ for (i=0; i < ARRAY_SIZE(syntaxes); i++) {
+ for (a=schema->attributes; a; a = a->next) {
+ char *om_hex;
+
+ if (strcmp(syntaxes[i], a->attributeSyntax_oid) != 0) continue;
+
+ om_hex = data_blob_hex_string_upper(ldb, &a->oMObjectClass);
+ if (!om_hex) {
+ return false;
+ }
+
+ d_printf("attr[%4u]: %s %u '%s' '%s'\n", a_i++,
+ a->attributeSyntax_oid, a->oMSyntax,
+ om_hex, a->lDAPDisplayName);
+ talloc_free(om_hex);
+ }
+ }
+
+ return true;
+}
+
+static bool test_dump_not_in_filtered_replica(struct ldb_context *ldb, struct test_rootDSE *root, struct dsdb_schema *schema)
+{
+ struct dsdb_attribute *a;
+ uint32_t a_i = 1;
+
+ d_printf("Dumping attributes not in filtered replica\n");
+
+ for (a=schema->attributes; a; a = a->next) {
+ if (!dsdb_attribute_is_attr_in_filtered_replica(a)) {
+ d_printf("attr[%4u]: '%s'\n", a_i++,
+ a->lDAPDisplayName);
+ }
+ }
+ return true;
+}
+
+bool torture_ldap_schema(struct torture_context *torture)
+{
+ struct ldb_context *ldb;
+ bool ret = true;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ char *url;
+ struct test_rootDSE rootDSE;
+ struct dsdb_schema *schema = NULL;
+
+ ZERO_STRUCT(rootDSE);
+
+ url = talloc_asprintf(torture, "ldap://%s/", host);
+
+ ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+ if (!ldb) goto failed;
+
+ ret &= test_search_rootDSE(ldb, &rootDSE);
+ if (!ret) goto failed;
+ ret &= test_create_schema(ldb, &rootDSE, &schema);
+ if (!ret) goto failed;
+
+ ret &= test_dump_not_replicated(ldb, &rootDSE, schema);
+ ret &= test_dump_partial(ldb, &rootDSE, schema);
+ ret &= test_dump_contructed(ldb, &rootDSE, schema);
+ ret &= test_dump_sorted_syntax(ldb, &rootDSE, schema);
+ ret &= test_dump_not_in_filtered_replica(ldb, &rootDSE, schema);
+
+failed:
+ return ret;
+}
diff --git a/source4/torture/ldap/session_expiry.c b/source4/torture/ldap/session_expiry.c
new file mode 100644
index 0000000..e910662
--- /dev/null
+++ b/source4/torture/ldap/session_expiry.c
@@ -0,0 +1,122 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Test LDB attribute functions
+ *
+ * Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008-2009
+ * Copyright (C) Matthieu Patou <mat@matws.net> 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include <ldb.h>
+#include <ldb_errors.h>
+#include "ldb_wrap.h"
+#include "param/param.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/ldap/ldap_client.h"
+#include "torture/smbtorture.h"
+#include "torture/ldap/proto.h"
+
+bool torture_ldap_session_expiry(struct torture_context *torture)
+{
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ struct ldb_context *ldb = NULL;
+ const char *url = NULL;
+ bool ret = false;
+ bool ok;
+ struct ldb_dn *rootdn = NULL;
+ struct ldb_result *result = NULL;
+ int rc = LDB_SUCCESS;
+
+ /*
+ * Further down we request a ticket lifetime of 4
+ * seconds. Give the server 10 seconds for this to kick in
+ */
+ const struct timeval endtime = timeval_current_ofs(10, 0);
+
+ url = talloc_asprintf(torture, "ldap://%s/", host);
+ torture_assert_goto(
+ torture, url!=NULL, ret, fail, "talloc_asprintf failed");
+
+ cli_credentials_set_kerberos_state(credentials,
+ CRED_USE_KERBEROS_REQUIRED,
+ CRED_SPECIFIED);
+
+ ok = lpcfg_set_option(
+ torture->lp_ctx, "gensec_gssapi:requested_life_time=4");
+ torture_assert_goto(
+ torture, ok, ret, fail, "lpcfg_set_option failed");
+
+ ldb = ldb_wrap_connect(
+ torture,
+ torture->ev,
+ torture->lp_ctx,
+ url,
+ NULL,
+ credentials,
+ 0);
+ torture_assert_goto(
+ torture, ldb!=NULL, ret, fail, "ldb_wrap_connect failed");
+
+ rootdn = ldb_dn_new(ldb, ldb, NULL);
+ torture_assert_goto(
+ torture, rootdn!=NULL, ret, fail, "ldb_dn_new failed");
+
+ rc = ldb_search(
+ ldb, /* ldb */
+ ldb, /* mem_ctx */
+ &result, /* result */
+ rootdn, /* base */
+ LDB_SCOPE_BASE, /* scope */
+ NULL, /* attrs */
+ "(objectclass=*)"); /* exp_fmt */
+ torture_assert_goto(
+ torture, rc==LDB_SUCCESS, ret, fail, "1st ldb_search failed");
+
+ do {
+ smb_msleep(1000);
+
+ rc = ldb_search(
+ ldb, /* ldb */
+ ldb, /* mem_ctx */
+ &result, /* result */
+ rootdn, /* base */
+ LDB_SCOPE_BASE, /* scope */
+ NULL, /* attrs */
+ "(objectclass=*)"); /* exp_fmt */
+ printf("ldb_search returned %s\n", ldb_strerror(rc));
+ TALLOC_FREE(result);
+
+ if (rc != LDB_SUCCESS) {
+ break;
+ }
+ } while (!timeval_expired(&endtime));
+
+ torture_assert_goto(
+ torture,
+ rc==LDB_ERR_PROTOCOL_ERROR,
+ ret,
+ fail,
+ "expected LDB_ERR_PROTOCOL_ERROR after 4 seconds");
+
+ ret = true;
+fail:
+ TALLOC_FREE(ldb);
+ return ret;
+}
diff --git a/source4/torture/ldap/uptodatevector.c b/source4/torture/ldap/uptodatevector.c
new file mode 100644
index 0000000..01c85ab
--- /dev/null
+++ b/source4/torture/ldap/uptodatevector.c
@@ -0,0 +1,173 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP replUpToDateVector tests
+
+ Copyright (C) Stefan Metzmacher 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+#include "libcli/ldap/ldap_client.h"
+#include "lib/cmdline/cmdline.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+
+#include "torture/torture.h"
+#include "torture/ldap/proto.h"
+
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+
+#include "param/param.h"
+
+static bool test_check_uptodatevector(struct torture_context *torture,
+ struct ldb_context *ldb,
+ struct ldb_dn *partition_dn)
+{
+ bool ok = true;
+ uint32_t i;
+ int ret;
+ enum ndr_err_code ndr_err;
+ struct ldb_result *r;
+ const struct ldb_val *utdv_val1;
+ struct replUpToDateVectorBlob utdv1;
+ static const char *attrs[] = {
+ "uSNChanged",
+ "replUpToDateVector",
+ "description",
+ NULL
+ };
+
+ torture_comment(torture, "Check replUpToDateVector on partition[%s]\n",
+ ldb_dn_get_linearized(partition_dn));
+
+ ret = ldb_search(ldb, torture, &r, partition_dn, LDB_SCOPE_BASE, attrs,
+ "(objectClass=*)");
+ if (ret != LDB_SUCCESS) {
+ return false;
+ } else if (r->count != 1) {
+ talloc_free(r);
+ return false;
+ }
+
+ ZERO_STRUCT(utdv1);
+ utdv_val1 = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
+ if (utdv_val1) {
+ ndr_err = ndr_pull_struct_blob_all(utdv_val1, torture,
+ &utdv1,
+ (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ }
+
+ for (i=0; i < 2; i++) {
+ const struct ldb_val *utdv_val;
+ struct replUpToDateVectorBlob utdv;
+ struct ldb_message *msg;
+ char *description;
+ uint32_t j;
+ bool no_match = false;
+
+ /* make a 'modify' msg, and only for serverReference */
+ msg = ldb_msg_new(torture);
+ if (!msg) return false;
+ msg->dn = partition_dn;
+
+ description = talloc_asprintf(msg, "torture replUpToDateVector[%u]", i);
+ if (!description) return false;
+
+ ret = ldb_msg_add_string(msg, "description", description);
+ if (ret != 0) return false;
+
+ for (j=0;j<msg->num_elements;j++) {
+ msg->elements[j].flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ ret = ldb_modify(ldb, msg);
+ if (ret != LDB_SUCCESS) return false;
+
+ ret = ldb_search(ldb, msg, &r, partition_dn, LDB_SCOPE_BASE,
+ attrs, "(objectClass=*)");
+ if (ret != LDB_SUCCESS) {
+ return false;
+ } else if (r->count != 1) {
+ talloc_free(r);
+ return false;
+ }
+
+ ZERO_STRUCT(utdv);
+ utdv_val = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
+ if (utdv_val) {
+ ndr_err = ndr_pull_struct_blob_all(utdv_val, torture,
+ &utdv,
+ (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ }
+
+ if (!utdv_val1 && utdv_val) {
+ no_match = true;
+ } else if (utdv_val1 && !utdv_val) {
+ no_match = true;
+ } else if (!utdv_val1 && !utdv_val) {
+ } else if (utdv_val1->length != utdv_val->length) {
+ no_match = true;
+ } else if (utdv_val1->length && memcmp(utdv_val1->data, utdv_val->data, utdv_val->length) != 0) {
+ no_match = true;
+ }
+
+ torture_comment(torture, "[%u]: uSNChanged[%llu] description[%s] replUpToDateVector[%s]\n", i,
+ (unsigned long long)ldb_msg_find_attr_as_uint64(r->msgs[0], "uSNChanged", 0),
+ ldb_msg_find_attr_as_string(r->msgs[0], "description", NULL),
+ (no_match ? "changed!: not ok" : "not changed: ok"));
+
+ if (no_match) {
+ NDR_PRINT_DEBUG(replUpToDateVectorBlob, &utdv1);
+ NDR_PRINT_DEBUG(replUpToDateVectorBlob, &utdv);
+ ok = false;
+ }
+
+ talloc_free(msg);
+ }
+
+ return ok;
+}
+
+bool torture_ldap_uptodatevector(struct torture_context *torture)
+{
+ struct ldb_context *ldb;
+ bool ret = true;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ char *url;
+
+ url = talloc_asprintf(torture, "ldap://%s/", host);
+ if (!url) goto failed;
+
+ ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+ if (!ldb) goto failed;
+
+ ret &= test_check_uptodatevector(torture, ldb, ldb_get_default_basedn(ldb));
+ ret &= test_check_uptodatevector(torture, ldb, ldb_get_config_basedn(ldb));
+ ret &= test_check_uptodatevector(torture, ldb, ldb_get_schema_basedn(ldb));
+
+ return ret;
+failed:
+ return false;
+}
diff --git a/source4/torture/ldb/ldb.c b/source4/torture/ldb/ldb.c
new file mode 100644
index 0000000..69bd57e
--- /dev/null
+++ b/source4/torture/ldb/ldb.c
@@ -0,0 +1,1794 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Test LDB attribute functions
+
+ Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include <ldb.h>
+#include <ldb-samba/ldb_wrap.h>
+#include <ldb_errors.h>
+#include <ldb_module.h>
+#include "lib/ldb-samba/ldif_handlers.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "param/param.h"
+#include "torture/smbtorture.h"
+#include "torture/local/proto.h"
+#include <time.h>
+
+static const char *sid = "S-1-5-21-4177067393-1453636373-93818737";
+static const char *hex_sid = "01040000000000051500000081fdf8f815bba456718f9705";
+static const char *guid = "975ac5fa-35d9-431d-b86a-845bcd34fff9";
+static const char *guid2 = "{975ac5fa-35d9-431d-b86a-845bcd34fff9}";
+static const char *hex_guid = "fac55a97d9351d43b86a845bcd34fff9";
+
+static const char *prefix_map_newline = "2:1.2.840.113556.1.2\n5:2.16.840.1.101.2.2.3";
+static const char *prefix_map_semi = "2:1.2.840.113556.1.2;5:2.16.840.1.101.2.2.3";
+
+/**
+ * This is the hex code derived from the tdbdump for
+ * "st/ad_dc/private/sam.ldb.d/DC=ADDC,DC=SAMBA,DC=EXAMPLE,DC=COM.ldb"
+ * key "DN=CN=DDA1D01D-4BD7-4C49-A184-46F9241B560E,CN=OPERATIONS,CN=DOMAINUPDATES,CN=SYSTEM,DC=ADDC,DC=SAMBA,DC=EXAMPLE,DC=COM\00"
+ * -- adrianc
+ */
+
+static const uint8_t dda1d01d_bin_v1[] = {
+ 0x67, 0x19, 0x01, 0x26, 0x0d, 0x00, 0x00, 0x00, 0x43, 0x4e, 0x3d, 0x64, 0x64, 0x61, 0x31, 0x64,
+ 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d, 0x61, 0x31,
+ 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30, 0x65, 0x2c,
+ 0x43, 0x4e, 0x3d, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x43, 0x4e,
+ 0x3d, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x43,
+ 0x4e, 0x3d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x64, 0x63,
+ 0x2c, 0x44, 0x43, 0x3d, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2c, 0x44, 0x43, 0x3d, 0x65, 0x78, 0x61,
+ 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x44, 0x43, 0x3d, 0x63, 0x6f, 0x6d, 0x00, 0x6f, 0x62, 0x6a, 0x65,
+ 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x74, 0x6f, 0x70, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
+ 0x72, 0x00, 0x63, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x64, 0x64, 0x61,
+ 0x31, 0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d,
+ 0x61, 0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30,
+ 0x65, 0x00, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x43, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x32, 0x30, 0x31,
+ 0x35, 0x30, 0x37, 0x30, 0x38, 0x32, 0x32, 0x34, 0x33, 0x31, 0x30, 0x2e, 0x30, 0x5a, 0x00, 0x77,
+ 0x68, 0x65, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x32, 0x30, 0x31, 0x35, 0x30, 0x37, 0x30, 0x38, 0x32, 0x32, 0x34, 0x33, 0x31,
+ 0x30, 0x2e, 0x30, 0x5a, 0x00, 0x75, 0x53, 0x4e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x33, 0x34, 0x36, 0x37, 0x00, 0x75, 0x53, 0x4e,
+ 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x33, 0x34, 0x36, 0x37, 0x00, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41, 0x64, 0x76, 0x61, 0x6e,
+ 0x63, 0x65, 0x64, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x6c, 0x79, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x54, 0x52, 0x55, 0x45, 0x00, 0x6e, 0x54, 0x53, 0x65, 0x63, 0x75, 0x72,
+ 0x69, 0x74, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x18, 0x05, 0x00, 0x00, 0x01, 0x00, 0x17, 0x8c, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e,
+ 0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00,
+ 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x00, 0x02,
+ 0x00, 0x00, 0x04, 0x00, 0x78, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x5a, 0x38, 0x00, 0x20, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xbe, 0x3b, 0x0e, 0xf3, 0xf0, 0x9f, 0xd1, 0x11, 0xb6, 0x03,
+ 0x00, 0x00, 0xf8, 0x03, 0x67, 0xc1, 0xa5, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+ 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x5a, 0x38, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xbf, 0x3b,
+ 0x0e, 0xf3, 0xf0, 0x9f, 0xd1, 0x11, 0xb6, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x67, 0xc1, 0xa5, 0x7a,
+ 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x54, 0x04, 0x17, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e,
+ 0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x94, 0x00,
+ 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x1a,
+ 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x42, 0x16, 0x4c, 0xc0, 0x20,
+ 0xd0, 0x11, 0xa7, 0x68, 0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+ 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x42, 0x16, 0x4c, 0xc0, 0x20, 0xd0, 0x11, 0xa7, 0x68,
+ 0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+ 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+ 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x10, 0x20, 0x20, 0x5f, 0xa5, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2,
+ 0xd4, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e,
+ 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02,
+ 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x20,
+ 0x20, 0x5f, 0xa5, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0xba, 0x7a,
+ 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a,
+ 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x0a, 0xbc, 0xa9, 0x79,
+ 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+ 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x0a, 0xbc, 0xa9, 0x79, 0xd0, 0x11, 0x90, 0x20,
+ 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+ 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+ 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x42, 0x2f, 0xba, 0x59, 0xa2, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2,
+ 0xd3, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e,
+ 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02,
+ 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x42, 0x2f,
+ 0xba, 0x59, 0xa2, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd3, 0xcf, 0xba, 0x7a,
+ 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a,
+ 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x88, 0x70, 0x03, 0xe1, 0x0a,
+ 0xd2, 0x11, 0xb4, 0x22, 0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+ 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x88, 0x70, 0x03, 0xe1, 0x0a, 0xd2, 0x11, 0xb4, 0x22,
+ 0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+ 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+ 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83,
+ 0xf6, 0x08, 0x86, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30,
+ 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a,
+ 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c,
+ 0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83, 0xf6, 0x08, 0x9c, 0x7a, 0x96, 0xbf, 0xe6, 0x0d,
+ 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83,
+ 0xf6, 0x08, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30,
+ 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a,
+ 0x2c, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14,
+ 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x2c, 0x00, 0x94, 0x00,
+ 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85,
+ 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+ 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x2c, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30,
+ 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02,
+ 0x00, 0x00, 0x05, 0x12, 0x28, 0x00, 0x30, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xde, 0x47,
+ 0xe6, 0x91, 0x6f, 0xd9, 0x70, 0x4b, 0x95, 0x57, 0xd6, 0x3f, 0xf4, 0xf3, 0xcc, 0xd8, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x00, 0xff, 0x01,
+ 0x0f, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd,
+ 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x07, 0x02, 0x00, 0x00, 0x00, 0x12,
+ 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00,
+ 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x12, 0x18, 0x00, 0xbd, 0x01, 0x0f, 0x00, 0x01, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x6e,
+ 0x61, 0x6d, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x64, 0x64, 0x61, 0x31,
+ 0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d, 0x61,
+ 0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30, 0x65,
+ 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x47, 0x55, 0x49, 0x44, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x57, 0x93, 0x1e, 0x29, 0x25, 0x49, 0xe5, 0x40, 0x9d, 0x98, 0x36, 0x07,
+ 0x11, 0x9e, 0xbd, 0xe5, 0x00, 0x72, 0x65, 0x70, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74,
+ 0x79, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x90, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xa9, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x19, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x03, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00,
+ 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58, 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96,
+ 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
+ 0x79, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x55, 0x49, 0x44, 0x3d,
+ 0x35, 0x32, 0x34, 0x32, 0x39, 0x30, 0x33, 0x38, 0x2d, 0x65, 0x34, 0x33, 0x35, 0x2d, 0x34, 0x66,
+ 0x65, 0x33, 0x2d, 0x39, 0x36, 0x34, 0x65, 0x2d, 0x38, 0x30, 0x64, 0x61, 0x31, 0x35, 0x34, 0x39,
+ 0x39, 0x63, 0x39, 0x63, 0x3e, 0x3b, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+ 0x65, 0x72, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2c, 0x43, 0x4e, 0x3d,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44, 0x43,
+ 0x3d, 0x61, 0x64, 0x64, 0x63, 0x2c, 0x44, 0x43, 0x3d, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2c, 0x44,
+ 0x43, 0x3d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x44, 0x43, 0x3d, 0x63, 0x6f, 0x6d,
+ 0x00
+};
+
+static const uint8_t dda1d01d_bin_v2[] = {
+ 0x68, 0x19, 0x01, 0x26, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x43, 0x4e, 0x3d, 0x64,
+ 0x64, 0x61, 0x31, 0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34,
+ 0x39, 0x2d, 0x61, 0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35,
+ 0x36, 0x30, 0x65, 0x2c, 0x43, 0x4e, 0x3d, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2c, 0x44, 0x43, 0x3d,
+ 0x61, 0x64, 0x64, 0x63, 0x2c, 0x44, 0x43, 0x3d, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2c, 0x44, 0x43,
+ 0x3d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x44, 0x43, 0x3d, 0x63, 0x6f, 0x6d, 0x00,
+ 0x5b, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x63, 0x2e, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2e, 0x65,
+ 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x79, 0x73, 0x74, 0x65,
+ 0x6d, 0x2f, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x2f,
+ 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x64, 0x64, 0x61, 0x31, 0x64,
+ 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d, 0x61, 0x31,
+ 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30, 0x65, 0x00,
+ 0x33, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c,
+ 0x61, 0x73, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x03, 0x09, 0x02, 0x00, 0x00, 0x00, 0x63,
+ 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x24, 0x0c, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x73, 0x74,
+ 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0b,
+ 0x00, 0x00, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x77, 0x68, 0x65, 0x6e, 0x43, 0x68, 0x61,
+ 0x6e, 0x67, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x75,
+ 0x53, 0x4e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04,
+ 0x0a, 0x00, 0x00, 0x00, 0x75, 0x53, 0x4e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x04, 0x16, 0x00, 0x00, 0x00, 0x73, 0x68, 0x6f, 0x77, 0x49, 0x6e, 0x41,
+ 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x56, 0x69, 0x65, 0x77, 0x4f, 0x6e, 0x6c, 0x79, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x14, 0x00, 0x00, 0x00, 0x6e, 0x54, 0x53, 0x65, 0x63, 0x75,
+ 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x04, 0x00, 0x00, 0x00, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x24, 0x0a, 0x00, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x47,
+ 0x55, 0x49, 0x44, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x14, 0x00, 0x00, 0x00, 0x72, 0x65,
+ 0x70, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61,
+ 0x74, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x90, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x6f, 0x62,
+ 0x6a, 0x65, 0x63, 0x74, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x76, 0x74, 0x6f, 0x70, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
+ 0x00, 0x64, 0x64, 0x61, 0x31, 0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64, 0x37, 0x2d, 0x34,
+ 0x63, 0x34, 0x39, 0x2d, 0x61, 0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39, 0x32, 0x34, 0x31,
+ 0x62, 0x35, 0x36, 0x30, 0x65, 0x00, 0x34, 0x00, 0x32, 0x30, 0x31, 0x35, 0x30, 0x37, 0x30, 0x38,
+ 0x32, 0x32, 0x34, 0x33, 0x31, 0x30, 0x2e, 0x30, 0x5a, 0x00, 0x32, 0x30, 0x31, 0x35, 0x30, 0x37,
+ 0x30, 0x38, 0x32, 0x32, 0x34, 0x33, 0x31, 0x30, 0x2e, 0x30, 0x5a, 0x00, 0x33, 0x34, 0x36, 0x37,
+ 0x00, 0x33, 0x34, 0x36, 0x37, 0x00, 0x54, 0x52, 0x55, 0x45, 0x00, 0x01, 0x00, 0x14, 0x8c, 0x14,
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x01,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5,
+ 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e,
+ 0x5e, 0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x78, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07,
+ 0x5a, 0x38, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xbe, 0x3b, 0x0e, 0xf3, 0xf0,
+ 0x9f, 0xd1, 0x11, 0xb6, 0x03, 0x00, 0x00, 0xf8, 0x03, 0x67, 0xc1, 0xa5, 0x7a, 0x96, 0xbf, 0xe6,
+ 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x5a, 0x38, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0xbf, 0x3b, 0x0e, 0xf3, 0xf0, 0x9f, 0xd1, 0x11, 0xb6, 0x03, 0x00, 0x00, 0xf8,
+ 0x03, 0x67, 0xc1, 0xa5, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00,
+ 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x54, 0x04, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5,
+ 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xff,
+ 0x01, 0x0f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0x94, 0x00, 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0b,
+ 0x00, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x16, 0x4c, 0xc0, 0x20, 0xd0, 0x11, 0xa7, 0x68, 0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29, 0x14,
+ 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05,
+ 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x42, 0x16, 0x4c, 0xc0,
+ 0x20, 0xd0, 0x11, 0xa7, 0x68, 0x00, 0xaa, 0x00, 0x6e, 0x05, 0x29, 0xba, 0x7a, 0x96, 0xbf, 0xe6,
+ 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x5f, 0xa5, 0x79, 0xd0, 0x11, 0x90,
+ 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b,
+ 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20,
+ 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x5f, 0xa5, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f,
+ 0xc2, 0xd4, 0xcf, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00,
+ 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a,
+ 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40,
+ 0xc2, 0x0a, 0xbc, 0xa9, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0x14,
+ 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05,
+ 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0xc2, 0x0a, 0xbc, 0xa9,
+ 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd4, 0xcf, 0xba, 0x7a, 0x96, 0xbf, 0xe6,
+ 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x42, 0x2f, 0xba, 0x59, 0xa2, 0x79, 0xd0, 0x11, 0x90,
+ 0x20, 0x00, 0xc0, 0x4f, 0xc2, 0xd3, 0xcf, 0x14, 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b,
+ 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20,
+ 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x42, 0x2f, 0xba, 0x59, 0xa2, 0x79, 0xd0, 0x11, 0x90, 0x20, 0x00, 0xc0, 0x4f,
+ 0xc2, 0xd3, 0xcf, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00,
+ 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a,
+ 0x02, 0x00, 0x00, 0x05, 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8,
+ 0x88, 0x70, 0x03, 0xe1, 0x0a, 0xd2, 0x11, 0xb4, 0x22, 0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0x14,
+ 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05,
+ 0x1a, 0x3c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x88, 0x70, 0x03, 0xe1,
+ 0x0a, 0xd2, 0x11, 0xb4, 0x22, 0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0xba, 0x7a, 0x96, 0xbf, 0xe6,
+ 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85,
+ 0x4e, 0x00, 0xa0, 0xc9, 0x83, 0xf6, 0x08, 0x86, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2,
+ 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09,
+ 0x00, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6d,
+ 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85, 0x4e, 0x00, 0xa0, 0xc9, 0x83, 0xf6, 0x08, 0x9c,
+ 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x05, 0x1a, 0x38, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6d, 0x9e, 0xc6, 0xb7, 0xc7, 0x2c, 0xd2, 0x11, 0x85,
+ 0x4e, 0x00, 0xa0, 0xc9, 0x83, 0xf6, 0x08, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2,
+ 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x09,
+ 0x00, 0x00, 0x00, 0x05, 0x1a, 0x2c, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14,
+ 0xcc, 0x28, 0x48, 0x37, 0x14, 0xbc, 0x45, 0x9b, 0x07, 0xad, 0x6f, 0x01, 0x5e, 0x5f, 0x28, 0x01,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05,
+ 0x1a, 0x2c, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x7a, 0x96, 0xbf, 0xe6,
+ 0x0d, 0xd0, 0x11, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x1a, 0x2c, 0x00, 0x94,
+ 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0xba, 0x7a, 0x96, 0xbf, 0xe6, 0x0d, 0xd0, 0x11, 0xa2,
+ 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20,
+ 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x05, 0x12, 0x28, 0x00, 0x30, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xde, 0x47, 0xe6, 0x91, 0x6f, 0xd9, 0x70, 0x4b, 0x95, 0x57, 0xd6, 0x3f, 0xf4,
+ 0xf3, 0xcc, 0xd8, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x24, 0x00, 0xff, 0x01, 0x0f, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15,
+ 0x00, 0x00, 0x00, 0x9a, 0xbd, 0x91, 0x7d, 0xd5, 0xe0, 0x11, 0x3c, 0x6e, 0x5e, 0x1a, 0x4b, 0x07,
+ 0x02, 0x00, 0x00, 0x00, 0x12, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x12, 0x18, 0x00, 0xbd,
+ 0x01, 0x0f, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20,
+ 0x02, 0x00, 0x00, 0x00, 0x64, 0x64, 0x61, 0x31, 0x64, 0x30, 0x31, 0x64, 0x2d, 0x34, 0x62, 0x64,
+ 0x37, 0x2d, 0x34, 0x63, 0x34, 0x39, 0x2d, 0x61, 0x31, 0x38, 0x34, 0x2d, 0x34, 0x36, 0x66, 0x39,
+ 0x32, 0x34, 0x31, 0x62, 0x35, 0x36, 0x30, 0x65, 0x00, 0x57, 0x93, 0x1e, 0x29, 0x25, 0x49, 0xe5,
+ 0x40, 0x9d, 0x98, 0x36, 0x07, 0x11, 0x9e, 0xbd, 0xe5, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x01, 0x02, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x09, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x7e, 0x38, 0xae, 0x0b, 0x03, 0x00, 0x00, 0x00, 0x9d, 0xcd, 0xcd, 0x57, 0xee, 0x58,
+ 0x6e, 0x4e, 0x96, 0x99, 0xcc, 0x7d, 0xe1, 0x96, 0xf1, 0x05, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x55, 0x49, 0x44,
+ 0x3d, 0x35, 0x32, 0x34, 0x32, 0x39, 0x30, 0x33, 0x38, 0x2d, 0x65, 0x34, 0x33, 0x35, 0x2d, 0x34,
+ 0x66, 0x65, 0x33, 0x2d, 0x39, 0x36, 0x34, 0x65, 0x2d, 0x38, 0x30, 0x64, 0x61, 0x31, 0x35, 0x34,
+ 0x39, 0x39, 0x63, 0x39, 0x63, 0x3e, 0x3b, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2c, 0x43, 0x4e,
+ 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44,
+ 0x43, 0x3d, 0x61, 0x64, 0x64, 0x63, 0x2c, 0x44, 0x43, 0x3d, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x2c,
+ 0x44, 0x43, 0x3d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c, 0x44, 0x43, 0x3d, 0x63, 0x6f,
+ 0x6d, 0x00
+};
+
+static const char dda1d01d_ldif[] = ""
+"dn: CN=dda1d01d-4bd7-4c49-a184-46f9241b560e,CN=Operations,CN=DomainUpdates,CN=System,DC=addc,DC=samba,DC=example,DC=com\n"
+"objectClass: top\n"
+"objectClass: container\n"
+"cn: dda1d01d-4bd7-4c49-a184-46f9241b560e\n"
+"instanceType: 4\n"
+"whenCreated: 20150708224310.0Z\n"
+"whenChanged: 20150708224310.0Z\n"
+"uSNCreated: 3467\n"
+"uSNChanged: 3467\n"
+"showInAdvancedViewOnly: TRUE\n"
+"nTSecurityDescriptor: O:S-1-5-21-2106703258-1007804629-1260019310-512G:S-1-5-2\n"
+" 1-2106703258-1007804629-1260019310-512D:AI(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-\n"
+" 1-5-21-2106703258-1007804629-1260019310-512)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;\n"
+" SY)(A;;LCRPLORC;;;AU)(OA;CIIOID;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828c\n"
+" c14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;4c164200-20c0-11d0-a768-00aa\n"
+" 006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;5f202010-79a5-\n"
+" 11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;\n"
+" 5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)\n"
+" (OA;CIIOID;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad\n"
+" 6f015e5f28;RU)(OA;CIIOID;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de\n"
+" 6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3c\n"
+" f;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;59ba2f42-79a2-11d0-90\n"
+" 20-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;037088f\n"
+" 8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CII\n"
+" OID;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa00304\n"
+" 9e2;RU)(OA;CIIOID;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-\n"
+" a285-00aa003049e2;ED)(OA;CIIOID;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967\n"
+" a9c-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIOID;RP;b7c69e6d-2cc7-11d2-854e-00a0\n"
+" c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIOID;LCRPLORC;;4828cc1\n"
+" 4-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;LCRPLORC;;bf967a9c-0de6-11d0-a285\n"
+" -00aa003049e2;RU)(OA;CIIOID;LCRPLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU\n"
+" )(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)(A;CIID;CCDCLCSWRPW\n"
+" PDTLOCRSDRCWDWO;;;S-1-5-21-2106703258-1007804629-1260019310-519)(A;CIID;LC;;;\n"
+" RU)(A;CIID;CCLCSWRPWPLOCRSDRCWDWO;;;BA)S:AI(OU;CIIOIDSA;WP;f30e3bbe-9ff0-11d1\n"
+" -b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CIIOIDSA;WP;f3\n"
+" 0e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)\n"
+"name: dda1d01d-4bd7-4c49-a184-46f9241b560e\n"
+"objectGUID: 291e9357-4925-40e5-9d98-3607119ebde5\n"
+"replPropertyMetaData:: AQAAAAAAAAAIAAAAAAAAAAAAAAABAAAAfjiuCwMAAACdzc1X7lhuTpa\n"
+" ZzH3hlvEFiw0AAAAAAACLDQAAAAAAAAEAAgABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0A\n"
+" AAAAAACLDQAAAAAAAAIAAgABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAA\n"
+" AAAAKkAAgABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAAAAAABkBAgABAA\n"
+" AAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAAAAAAAEACQABAAAAfjiuCwMAAAC\n"
+" dzc1X7lhuTpaZzH3hlvEFiw0AAAAAAACLDQAAAAAAAA4DCQABAAAAfjiuCwMAAACdzc1X7lhuTpaZ\n"
+" zH3hlvEFiw0AAAAAAACLDQAAAAAAAAMAAAABAAAAfjiuCwMAAACdzc1X7lhuTpaZzH3hlvEFiw0AA\n"
+" AAAAACLDQAAAAAAAA==\n"
+"objectCategory: <GUID=52429038-e435-4fe3-964e-80da15499c9c>;CN=Container,CN=Sc\n"
+" hema,CN=Configuration,DC=addc,DC=samba,DC=example,DC=com\n\n";
+
+static const char *dda1d01d_ldif_reduced = ""
+"dn: CN=dda1d01d-4bd7-4c49-a184-46f9241b560e,CN=Operations,CN=DomainUpdates,CN=System,DC=addc,DC=samba,DC=example,DC=com\n"
+"objectClass: top\n"
+"objectClass: container\n"
+"instanceType: 4\n"
+"whenChanged: 20150708224310.0Z\n"
+"uSNCreated: 3467\n"
+"showInAdvancedViewOnly: TRUE\n"
+"name: dda1d01d-4bd7-4c49-a184-46f9241b560e\n\n";
+
+static bool torture_ldb_attrs(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ const struct ldb_schema_attribute *attr;
+ struct ldb_val string_sid_blob, binary_sid_blob;
+ struct ldb_val string_guid_blob, string_guid_blob2, binary_guid_blob;
+ struct ldb_val string_prefix_map_newline_blob, string_prefix_map_semi_blob, string_prefix_map_blob;
+ struct ldb_val prefix_map_blob;
+
+ DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
+ DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);
+
+ torture_assert(torture,
+ ldb = ldb_init(mem_ctx, torture->ev),
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture,
+ ldb_register_samba_handlers(ldb), LDB_SUCCESS,
+ "Failed to register Samba handlers");
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ /* Test SID behaviour */
+ torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "objectSid"),
+ "Failed to get objectSid schema attribute");
+
+ string_sid_blob = data_blob_string_const(sid);
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_read_fn(ldb, mem_ctx,
+ &string_sid_blob, &binary_sid_blob), 0,
+ "Failed to parse string SID");
+
+ torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob,
+ "Read SID into blob form failed");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_read_fn(ldb, mem_ctx,
+ &sid_blob, &binary_sid_blob), -1,
+ "Should have failed to parse binary SID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_write_fn(ldb, mem_ctx, &binary_sid_blob, &string_sid_blob), 0,
+ "Failed to parse binary SID");
+
+ torture_assert_data_blob_equal(torture,
+ string_sid_blob, data_blob_string_const(sid),
+ "Write SID into string form failed");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &binary_sid_blob, &string_sid_blob), 0,
+ "Failed to compare binary and string SID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_sid_blob, &binary_sid_blob), 0,
+ "Failed to compare string and binary binary SID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_sid_blob, &string_sid_blob), 0,
+ "Failed to compare string and string SID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &binary_sid_blob, &binary_sid_blob), 0,
+ "Failed to compare binary and binary SID");
+
+ torture_assert(torture, attr->syntax->comparison_fn(ldb, mem_ctx, &guid_blob, &binary_sid_blob) != 0,
+ "Failed to distinguish binary GUID and binary SID");
+
+
+ /* Test GUID behaviour */
+ torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "objectGUID"),
+ "Failed to get objectGUID schema attribute");
+
+ string_guid_blob = data_blob_string_const(guid);
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_read_fn(ldb, mem_ctx,
+ &string_guid_blob, &binary_guid_blob), 0,
+ "Failed to parse string GUID");
+
+ torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
+ "Read GUID into blob form failed");
+
+ string_guid_blob2 = data_blob_string_const(guid2);
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_read_fn(ldb, mem_ctx,
+ &string_guid_blob2, &binary_guid_blob), 0,
+ "Failed to parse string GUID");
+
+ torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
+ "Read GUID into blob form failed");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_read_fn(ldb, mem_ctx,
+ &guid_blob, &binary_guid_blob), 0,
+ "Failed to parse binary GUID");
+
+ torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
+ "Read GUID into blob form failed");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_write_fn(ldb, mem_ctx, &binary_guid_blob, &string_guid_blob), 0,
+ "Failed to print binary GUID as string");
+
+ torture_assert_data_blob_equal(torture, string_sid_blob, data_blob_string_const(sid),
+ "Write SID into string form failed");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &binary_guid_blob, &string_guid_blob), 0,
+ "Failed to compare binary and string GUID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_guid_blob, &binary_guid_blob), 0,
+ "Failed to compare string and binary binary GUID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_guid_blob, &string_guid_blob), 0,
+ "Failed to compare string and string GUID");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &binary_guid_blob, &binary_guid_blob), 0,
+ "Failed to compare binary and binary GUID");
+
+ string_prefix_map_newline_blob = data_blob_string_const(prefix_map_newline);
+
+ string_prefix_map_semi_blob = data_blob_string_const(prefix_map_semi);
+
+ /* Test prefixMap behaviour */
+ torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "prefixMap"),
+ "Failed to get prefixMap schema attribute");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_prefix_map_newline_blob, &string_prefix_map_semi_blob), 0,
+ "Failed to compare prefixMap with newlines and prefixMap with semicolons");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_read_fn(ldb, mem_ctx, &string_prefix_map_newline_blob, &prefix_map_blob), 0,
+ "Failed to read prefixMap with newlines");
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_prefix_map_newline_blob, &prefix_map_blob), 0,
+ "Failed to compare prefixMap with newlines and prefixMap binary");
+
+ torture_assert_int_equal(torture,
+ attr->syntax->ldif_write_fn(ldb, mem_ctx, &prefix_map_blob, &string_prefix_map_blob), 0,
+ "Failed to write prefixMap");
+ torture_assert_int_equal(torture,
+ attr->syntax->comparison_fn(ldb, mem_ctx, &string_prefix_map_blob, &prefix_map_blob), 0,
+ "Failed to compare prefixMap ldif write and prefixMap binary");
+
+ torture_assert_data_blob_equal(torture, string_prefix_map_blob, string_prefix_map_semi_blob,
+ "Failed to compare prefixMap ldif write and prefixMap binary");
+
+
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+static bool torture_ldb_dn_attrs(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ const struct ldb_dn_extended_syntax *attr;
+ struct ldb_val string_sid_blob, binary_sid_blob;
+ struct ldb_val string_guid_blob, binary_guid_blob;
+ struct ldb_val hex_sid_blob, hex_guid_blob;
+
+ DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
+ DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);
+
+ torture_assert(torture,
+ ldb = ldb_init(mem_ctx, torture->ev),
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture,
+ ldb_register_samba_handlers(ldb), LDB_SUCCESS,
+ "Failed to register Samba handlers");
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ /* Test SID behaviour */
+ torture_assert(torture, attr = ldb_dn_extended_syntax_by_name(ldb, "SID"),
+ "Failed to get SID DN syntax");
+
+ string_sid_blob = data_blob_string_const(sid);
+
+ torture_assert_int_equal(torture,
+ attr->read_fn(ldb, mem_ctx,
+ &string_sid_blob, &binary_sid_blob), 0,
+ "Failed to parse string SID");
+
+ torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob,
+ "Read SID into blob form failed");
+
+ hex_sid_blob = data_blob_string_const(hex_sid);
+
+ torture_assert_int_equal(torture,
+ attr->read_fn(ldb, mem_ctx,
+ &hex_sid_blob, &binary_sid_blob), 0,
+ "Failed to parse HEX SID");
+
+ torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob,
+ "Read SID into blob form failed");
+
+ torture_assert_int_equal(torture,
+ attr->read_fn(ldb, mem_ctx,
+ &sid_blob, &binary_sid_blob), -1,
+ "Should have failed to parse binary SID");
+
+ torture_assert_int_equal(torture,
+ attr->write_hex_fn(ldb, mem_ctx, &sid_blob, &hex_sid_blob), 0,
+ "Failed to parse binary SID");
+
+ torture_assert_data_blob_equal(torture,
+ hex_sid_blob, data_blob_string_const(hex_sid),
+ "Write SID into HEX string form failed");
+
+ torture_assert_int_equal(torture,
+ attr->write_clear_fn(ldb, mem_ctx, &sid_blob, &string_sid_blob), 0,
+ "Failed to parse binary SID");
+
+ torture_assert_data_blob_equal(torture,
+ string_sid_blob, data_blob_string_const(sid),
+ "Write SID into clear string form failed");
+
+
+ /* Test GUID behaviour */
+ torture_assert(torture, attr = ldb_dn_extended_syntax_by_name(ldb, "GUID"),
+ "Failed to get GUID DN syntax");
+
+ string_guid_blob = data_blob_string_const(guid);
+
+ torture_assert_int_equal(torture,
+ attr->read_fn(ldb, mem_ctx,
+ &string_guid_blob, &binary_guid_blob), 0,
+ "Failed to parse string GUID");
+
+ torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
+ "Read GUID into blob form failed");
+
+ hex_guid_blob = data_blob_string_const(hex_guid);
+
+ torture_assert_int_equal(torture,
+ attr->read_fn(ldb, mem_ctx,
+ &hex_guid_blob, &binary_guid_blob), 0,
+ "Failed to parse HEX GUID");
+
+ torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob,
+ "Read GUID into blob form failed");
+
+ torture_assert_int_equal(torture,
+ attr->read_fn(ldb, mem_ctx,
+ &guid_blob, &binary_guid_blob), -1,
+ "Should have failed to parse binary GUID");
+
+ torture_assert_int_equal(torture,
+ attr->write_hex_fn(ldb, mem_ctx, &guid_blob, &hex_guid_blob), 0,
+ "Failed to parse binary GUID");
+
+ torture_assert_data_blob_equal(torture,
+ hex_guid_blob, data_blob_string_const(hex_guid),
+ "Write GUID into HEX string form failed");
+
+ torture_assert_int_equal(torture,
+ attr->write_clear_fn(ldb, mem_ctx, &guid_blob, &string_guid_blob), 0,
+ "Failed to parse binary GUID");
+
+ torture_assert_data_blob_equal(torture,
+ string_guid_blob, data_blob_string_const(guid),
+ "Write GUID into clear string form failed");
+
+
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+static bool torture_ldb_dn_extended(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_dn *dn, *dn2;
+
+ DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
+ DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);
+
+ const char *dn_str = "cn=admin,cn=users,dc=samba,dc=org";
+
+ torture_assert(torture,
+ ldb = ldb_init(mem_ctx, torture->ev),
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture,
+ ldb_register_samba_handlers(ldb), LDB_SUCCESS,
+ "Failed to register Samba handlers");
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ /* Check behaviour of a normal DN */
+ torture_assert(torture,
+ dn = ldb_dn_new(mem_ctx, ldb, dn_str),
+ "Failed to create a 'normal' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate 'normal' DN");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == false,
+ "Should not find plain DN to be 'extended'");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL,
+ "Should not find an SID on plain DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL,
+ "Should not find an GUID on plain DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "WKGUID") == NULL,
+ "Should not find an WKGUID on plain DN");
+
+ /* Now make an extended DN */
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;<SID=%s>;%s",
+ guid, sid, dn_str),
+ "Failed to create an 'extended' DN");
+
+ torture_assert(torture,
+ dn2 = ldb_dn_copy(mem_ctx, dn),
+ "Failed to copy the 'extended' DN");
+ talloc_free(dn);
+ dn = dn2;
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate 'extended' DN");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == true,
+ "Should find extended DN to be 'extended'");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL,
+ "Should find an SID on extended DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL,
+ "Should find an GUID on extended DN");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob,
+ "Extended DN SID incorrect");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob,
+ "Extended DN GUID incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), dn_str,
+ "linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_casefold(dn), strupper_talloc(mem_ctx, dn_str),
+ "casefolded DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_component_name(dn, 0), "cn",
+ "component zero incorrect");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_component_val(dn, 0), data_blob_string_const("admin"),
+ "component zero incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1),
+ talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s",
+ guid, sid, dn_str),
+ "Clear extended linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0),
+ talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s",
+ hex_guid, hex_sid, dn_str),
+ "HEX extended linearized DN incorrect");
+
+ torture_assert(torture, ldb_dn_remove_child_components(dn, 1) == true,
+ "Failed to remove DN child");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == false,
+ "Extended DN flag should be cleared after child element removal");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL,
+ "Should not find an SID on DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL,
+ "Should not find an GUID on DN");
+
+
+ /* TODO: test setting these in the other order, and ensure it still comes out 'GUID first' */
+ torture_assert_int_equal(torture, ldb_dn_set_extended_component(dn, "GUID", &guid_blob), 0,
+ "Failed to set a GUID on DN");
+
+ torture_assert_int_equal(torture, ldb_dn_set_extended_component(dn, "SID", &sid_blob), 0,
+ "Failed to set a SID on DN");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob,
+ "Extended DN SID incorrect");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob,
+ "Extended DN GUID incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "cn=users,dc=samba,dc=org",
+ "linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1),
+ talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s",
+ guid, sid, "cn=users,dc=samba,dc=org"),
+ "Clear extended linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0),
+ talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s",
+ hex_guid, hex_sid, "cn=users,dc=samba,dc=org"),
+ "HEX extended linearized DN incorrect");
+
+ /* Now check a 'just GUID' DN (clear format) */
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>",
+ guid),
+ "Failed to create an 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate 'extended' DN");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == true,
+ "Should find extended DN to be 'extended'");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL,
+ "Should not find an SID on this DN");
+
+ torture_assert_int_equal(torture, ldb_dn_get_comp_num(dn), 0,
+ "Should not find an 'normal' component on this DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL,
+ "Should find an GUID on this DN");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob,
+ "Extended DN GUID incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "",
+ "linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1),
+ talloc_asprintf(mem_ctx, "<GUID=%s>",
+ guid),
+ "Clear extended linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0),
+ talloc_asprintf(mem_ctx, "<GUID=%s>",
+ hex_guid),
+ "HEX extended linearized DN incorrect");
+
+ /* Now check a 'just GUID' DN (HEX format) */
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>",
+ hex_guid),
+ "Failed to create an 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate 'extended' DN");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == true,
+ "Should find extended DN to be 'extended'");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL,
+ "Should not find an SID on this DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL,
+ "Should find an GUID on this DN");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob,
+ "Extended DN GUID incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "",
+ "linearized DN incorrect");
+
+ /* Now check a 'just SID' DN (clear format) */
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>",
+ sid),
+ "Failed to create an 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate 'extended' DN");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == true,
+ "Should find extended DN to be 'extended'");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL,
+ "Should not find an SID on this DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL,
+ "Should find an SID on this DN");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob,
+ "Extended DN SID incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "",
+ "linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1),
+ talloc_asprintf(mem_ctx, "<SID=%s>",
+ sid),
+ "Clear extended linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0),
+ talloc_asprintf(mem_ctx, "<SID=%s>",
+ hex_sid),
+ "HEX extended linearized DN incorrect");
+
+ /* Now check a 'just SID' DN (HEX format) */
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>",
+ hex_sid),
+ "Failed to create an 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate 'extended' DN");
+
+ torture_assert(torture, ldb_dn_has_extended(dn) == true,
+ "Should find extended DN to be 'extended'");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL,
+ "Should not find an SID on this DN");
+
+ torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL,
+ "Should find an SID on this DN");
+
+ torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob,
+ "Extended DN SID incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "",
+ "linearized DN incorrect");
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+
+static bool torture_ldb_dn(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_dn *dn;
+ struct ldb_dn *child_dn;
+ struct ldb_dn *typo_dn;
+ struct ldb_dn *special_dn;
+ struct ldb_val val;
+
+ torture_assert(torture,
+ ldb = ldb_init(mem_ctx, torture->ev),
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture,
+ ldb_register_samba_handlers(ldb), LDB_SUCCESS,
+ "Failed to register Samba handlers");
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ /* Check behaviour of a normal DN */
+ torture_assert(torture,
+ dn = ldb_dn_new(mem_ctx, ldb, NULL),
+ "Failed to create a NULL DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn),
+ "Failed to validate NULL DN");
+
+ torture_assert(torture,
+ ldb_dn_add_base_fmt(dn, "dc=org"),
+ "Failed to add base DN");
+
+ torture_assert(torture,
+ ldb_dn_add_child_fmt(dn, "dc=samba"),
+ "Failed to add base DN");
+
+ torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "dc=samba,dc=org",
+ "linearized DN incorrect");
+
+ torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), "dc=samba,dc=org",
+ "extended linearized DN incorrect");
+
+ /* Check child DN comparisons */
+ torture_assert(torture,
+ child_dn = ldb_dn_new(mem_ctx, ldb, "CN=users,DC=SAMBA,DC=org"),
+ "Failed to create child DN");
+
+ torture_assert(torture,
+ ldb_dn_compare(dn, child_dn) != 0,
+ "Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should != 0");
+
+ torture_assert(torture,
+ ldb_dn_compare_base(child_dn, dn) != 0,
+ "Base Comparison of CN=users,DC=SAMBA,DC=org and dc=samba,dc=org should != 0");
+
+ torture_assert(torture,
+ ldb_dn_compare_base(dn, child_dn) == 0,
+ "Base Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should == 0");
+
+ /* Check comparisons with a truncated DN */
+ torture_assert(torture,
+ typo_dn = ldb_dn_new(mem_ctx, ldb, "c=samba,dc=org"),
+ "Failed to create 'typo' DN");
+
+ torture_assert(torture,
+ ldb_dn_compare(dn, typo_dn) != 0,
+ "Comparison on dc=samba,dc=org and c=samba,dc=org should != 0");
+
+ torture_assert(torture,
+ ldb_dn_compare_base(typo_dn, dn) != 0,
+ "Base Comparison of c=samba,dc=org and dc=samba,dc=org should != 0");
+
+ torture_assert(torture,
+ ldb_dn_compare_base(dn, typo_dn) != 0,
+ "Base Comparison on dc=samba,dc=org and c=samba,dc=org should != 0");
+
+ /* Check comparisons with a special DN */
+ torture_assert(torture,
+ special_dn = ldb_dn_new(mem_ctx, ldb, "@special_dn"),
+ "Failed to create 'special' DN");
+
+ torture_assert(torture,
+ ldb_dn_compare(dn, special_dn) != 0,
+ "Comparison on dc=samba,dc=org and @special_dn should != 0");
+
+ torture_assert(torture,
+ ldb_dn_compare_base(special_dn, dn) > 0,
+ "Base Comparison of @special_dn and dc=samba,dc=org should > 0");
+
+ torture_assert(torture,
+ ldb_dn_compare_base(dn, special_dn) < 0,
+ "Base Comparison on dc=samba,dc=org and @special_dn should < 0");
+
+ /* Check DN based on MS-ADTS:3.1.1.5.1.2 Naming Constraints*/
+ torture_assert(torture,
+ dn = ldb_dn_new(mem_ctx, ldb, "CN=New\nLine,DC=SAMBA,DC=org"),
+ "Failed to create a DN with 0xA in it");
+
+ /* this is a warning until we work out how the DEL: CNs work */
+ if (ldb_dn_validate(dn) != false) {
+ torture_warning(torture,
+ "should have failed to validate a DN with 0xA in it");
+ }
+
+ /* Escaped comma */
+ torture_assert(torture,
+ dn = ldb_dn_new(mem_ctx, ldb, "CN=A\\,comma,DC=SAMBA,DC=org"),
+ "Failed to create a DN with an escaped comma in it");
+
+
+ val = data_blob_const("CN=Zer\0,DC=SAMBA,DC=org", 23);
+ torture_assert(torture,
+ NULL == ldb_dn_from_ldb_val(mem_ctx, ldb, &val),
+ "should fail to create a DN with 0x0 in it");
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+static bool torture_ldb_dn_invalid_extended(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_dn *dn;
+
+ const char *dn_str = "cn=admin,cn=users,dc=samba,dc=org";
+
+ torture_assert(torture,
+ ldb = ldb_init(mem_ctx, torture->ev),
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture,
+ ldb_register_samba_handlers(ldb), LDB_SUCCESS,
+ "Failed to register Samba handlers");
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ /* Check behaviour of a normal DN */
+ torture_assert(torture,
+ dn = ldb_dn_new(mem_ctx, ldb, "samba,dc=org"),
+ "Failed to create a 'normal' invalid DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'normal' invalid DN");
+
+ /* Now make an extended DN */
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<PID=%s>;%s",
+ sid, dn_str),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>%s",
+ sid, dn_str),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;",
+ sid),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;",
+ hex_sid),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>;",
+ hex_guid),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>;",
+ guid),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ torture_assert(torture,
+ dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=>"),
+ "Failed to create an invalid 'extended' DN");
+
+ torture_assert(torture,
+ ldb_dn_validate(dn) == false,
+ "should have failed to validate 'extended' DN");
+
+ return true;
+}
+
+static bool helper_ldb_message_compare(struct torture_context *torture,
+ struct ldb_message *a,
+ struct ldb_message *b)
+{
+ int i;
+
+ if (a->num_elements != b->num_elements) {
+ return false;
+ }
+
+ for (i = 0; i < a->num_elements; i++) {
+ int j;
+ struct ldb_message_element x = a->elements[i];
+ struct ldb_message_element y = b->elements[i];
+
+ torture_comment(torture, "#%s\n", x.name);
+ torture_assert_int_equal(torture, x.flags, y.flags,
+ "Flags do not match");
+ torture_assert_str_equal(torture, x.name, y.name,
+ "Names do not match in field");
+ torture_assert_int_equal(torture, x.num_values, y.num_values,
+ "Number of values do not match");
+
+ /*
+ * Records cannot round trip via the SDDL string with a
+ * nTSecurityDescriptor field.
+ *
+ * Parsing from SDDL and diffing the NDR dump output gives the
+ * following:
+ *
+ * in: struct decode_security_descriptor
+ * sd: struct security_descriptor
+ * revision : SECURITY_DESCRIPTOR_REVISION_1 (1)
+ *- type : 0x8c14 (35860)
+ *- 0: SEC_DESC_OWNER_DEFAULTED
+ *- 0: SEC_DESC_GROUP_DEFAULTED
+ *+ type : 0x8c17 (35863)
+ *+ 1: SEC_DESC_OWNER_DEFAULTED
+ *+ 1: SEC_DESC_GROUP_DEFAULTED
+ * 1: SEC_DESC_DACL_PRESENT
+ * 0: SEC_DESC_DACL_DEFAULTED
+ * 1: SEC_DESC_SACL_PRESENT
+ */
+ if (strcmp(x.name, "nTSecurityDescriptor") == 0) {
+ continue;
+ }
+ for (j = 0; j < x.num_values; j++) {
+ torture_assert_int_equal(torture, x.values[j].length,
+ y.values[j].length,
+ "Does not match in length");
+ torture_assert_mem_equal(torture,
+ x.values[j].data,
+ y.values[j].data,
+ x.values[j].length,
+ "Does not match in data");
+ }
+ }
+ return true;
+}
+
+static bool torture_ldb_unpack(struct torture_context *torture,
+ const void *data_p)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_val data = *discard_const_p(struct ldb_val, data_p);
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ const char *ldif_text = dda1d01d_ldif;
+ struct ldb_ldif ldif;
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL, NULL, NULL);
+ torture_assert(torture,
+ ldb != NULL,
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture, ldb_unpack_data(ldb, &data, msg), 0,
+ "ldb_unpack_data failed");
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msg;
+ ldif_text = ldb_ldif_write_string(ldb, mem_ctx, &ldif);
+
+ torture_assert_int_equal(torture,
+ strcmp(ldif_text, dda1d01d_ldif), 0,
+ "ldif form differs from binary form");
+ return true;
+}
+
+static bool torture_ldb_unpack_flags(struct torture_context *torture,
+ const void *data_p)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_val data = *discard_const_p(struct ldb_val, data_p);
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ const char *ldif_text = dda1d01d_ldif;
+ struct ldb_ldif ldif;
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL, NULL, NULL);
+ torture_assert(torture,
+ ldb != NULL,
+ "Failed to init ldb");
+
+ torture_assert_int_equal(torture,
+ ldb_unpack_data_flags(ldb, &data, msg,
+ LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC),
+ 0,
+ "ldb_unpack_data failed");
+
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msg;
+ ldif_text = ldb_ldif_write_string(ldb, mem_ctx, &ldif);
+
+ torture_assert_int_equal(torture,
+ strcmp(ldif_text, dda1d01d_ldif), 0,
+ "ldif form differs from binary form");
+
+ torture_assert_int_equal(torture,
+ ldb_unpack_data_flags(ldb, &data, msg,
+ LDB_UNPACK_DATA_FLAG_NO_DN),
+ 0,
+ "ldb_unpack_data failed");
+
+ torture_assert(torture,
+ msg->dn == NULL,
+ "msg->dn should be NULL");
+
+ return true;
+}
+
+static bool torture_ldb_unpack_data_corrupt(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+
+ uint8_t bin[] = {0x68, 0x19, 0x01, 0x26, /* version */
+ 1, 0, 0, 0, /* num elements */
+ 4, 0, 0, 0, /* dn length */
+ 'D', 'N', '=', 'A', 0, /* dn with null term */
+ 2, 0, 0, 0, /* canonicalized dn length */
+ '/', 'A', 0, /* canonicalized dn with null term */
+ 18, 0, 0, 0, /* size of name and sizes section + 4 (this field) */
+ 3, 0, 0, 0, /* el name length */
+ 'a', 'b', 'c', 0, /* name with null term */
+ 1, 0, 0, 0, 1, /* num values and length width */
+ 1, /* value lengths */
+ '1', 0}; /* values for abc */
+
+ struct ldb_val binary = data_blob_const(bin, sizeof(bin));
+ struct ldb_val bin_copy;
+ struct ldb_message *msg;
+
+ int i, j, current, expect_rcode, ret;
+ const char *comment;
+
+ /*
+ * List of corruptible byte ranges. First 12 bytes are corruptible,
+ * next 4 bytes are not, next 5 bytes are corruptible, etc.
+ */
+ uint8_t corrupt_bytes[] = {12, 4, 5, 2, 9, 3, 7, 2};
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL,NULL,NULL);
+ torture_assert(torture, ldb != NULL, "Failed to init ldb");
+
+ current = 0;
+ for (i=0; i<sizeof(corrupt_bytes); i++) {
+ expect_rcode = i % 2 == 0 ? -1 : 0;
+
+ for (j=0; j<corrupt_bytes[i]; j++, current++) {
+ bin_copy.data = talloc_size(NULL, binary.length);
+ memcpy(bin_copy.data, binary.data, binary.length);
+ bin_copy.length = binary.length;
+ msg = ldb_msg_new(bin_copy.data);
+
+ bin_copy.data[current]++;
+
+ ret = ldb_unpack_data(ldb, &bin_copy, msg);
+
+ comment = talloc_asprintf(
+ bin_copy.data,
+ "Expected unpack rcode for index %d "
+ "(corrupt bytes index %d) "
+ "to be %d but got %d",
+ current,
+ i,
+ expect_rcode,
+ ret);
+ torture_assert_int_equal(torture, ret, expect_rcode,
+ comment);
+
+ talloc_free(bin_copy.data);
+ }
+ }
+
+ return true;
+}
+
+static bool torture_ldb_pack_data_v2(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_val binary;
+
+ uint8_t bin[] = {0x68, 0x19, 0x01, 0x26, /* version */
+ 2, 0, 0, 0, /* num elements */
+ 4, 0, 0, 0, /* dn length */
+ 'D', 'N', '=', 'A', 0, /* dn with null term */
+ 2, 0, 0, 0, /* canonicalized dn length */
+ '/', 'A', 0, /* canonicalized dn with null term */
+ 42, 0, 0, 0, /* distance from here to values section */
+ 3, 0, 0, 0, /* el name length */
+ 'a', 'b', 'c', 0, /* name with null term */
+ 4, 0, 0, 0, 1, /* num values and length width */
+ 1, 1, 1, 1, /* value lengths */
+ 3, 0, 0, 0, /* el name length */
+ 'd', 'e', 'f', 0, /* name def with null term */
+ 4, 0, 0, 0, 2, /* num of values and length width */
+ 1, 0, 1, 0, 1, 0, 0, 1, /* value lengths */
+ '1', 0, '2', 0, '3', 0, '4', 0, /* values for abc */
+ '5', 0, '6', 0, '7', 0}; /* first 3 values for def */
+
+ char eight_256[257] =\
+ "88888888888888888888888888888888888888888888888888888888888"
+ "88888888888888888888888888888888888888888888888888888888888"
+ "88888888888888888888888888888888888888888888888888888888888"
+ "88888888888888888888888888888888888888888888888888888888888"
+ "88888888888888888888"; /* def's 4th value */
+
+ struct ldb_val vals[4] = {{.data=discard_const_p(uint8_t, "1"),
+ .length=1},
+ {.data=discard_const_p(uint8_t, "2"),
+ .length=1},
+ {.data=discard_const_p(uint8_t, "3"),
+ .length=1},
+ {.data=discard_const_p(uint8_t, "4"),
+ .length=1}};
+ struct ldb_val vals2[4] = {{.data=discard_const_p(uint8_t,"5"),
+ .length=1},
+ {.data=discard_const_p(uint8_t, "6"),
+ .length=1},
+ {.data=discard_const_p(uint8_t, "7"),
+ .length=1},
+ {.data=discard_const_p(uint8_t, eight_256),
+ .length=256}};
+ struct ldb_message_element els[2] = {{.name=discard_const_p(char, "abc"),
+ .num_values=4, .values=vals},
+ {.name=discard_const_p(char, "def"),
+ .num_values=4, .values=vals2}};
+ struct ldb_message msg = {.num_elements=2, .elements=els};
+
+ uint8_t *expect_bin;
+ struct ldb_val expect_bin_ldb;
+ size_t expect_size = sizeof(bin) + sizeof(eight_256);
+ expect_bin = talloc_size(NULL, expect_size);
+ memcpy(expect_bin, bin, sizeof(bin));
+ memcpy(expect_bin + sizeof(bin), eight_256, sizeof(eight_256));
+ expect_bin_ldb = data_blob_const(expect_bin, expect_size);
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL,NULL,NULL);
+ torture_assert(torture, ldb != NULL, "Failed to init ldb");
+
+ msg.dn = ldb_dn_new(NULL, ldb, "DN=A");
+
+ torture_assert_int_equal(torture,
+ ldb_pack_data(ldb, &msg, &binary,
+ LDB_PACKING_FORMAT_V2),
+ 0, "ldb_pack_data failed");
+
+ torture_assert_int_equal(torture, expect_bin_ldb.length,
+ binary.length,
+ "packed data length not as expected");
+
+ torture_assert_mem_equal(torture,
+ expect_bin_ldb.data,
+ binary.data,
+ binary.length,
+ "packed data not as expected");
+ talloc_free(expect_bin);
+ TALLOC_FREE(msg.dn);
+
+ return true;
+}
+
+static bool torture_ldb_pack_data_v2_special(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_val binary;
+
+ uint8_t bin[] = {0x68, 0x19, 0x01, 0x26, /* version */
+ 1, 0, 0, 0, /* num elements */
+ 2, 0, 0, 0, /* dn length */
+ '@', 'A', 0, /* dn with null term */
+ 0, 0, 0, 0, /* canonicalized dn length */
+ 0, /* no canonicalized dn, just null term */
+ 18, 0, 0, 0, /* distance from here to values section */
+ 3, 0, 0, 0, /* el name length */
+ 'a', 'b', 'c', 0, /* name with null term */
+ 1, 0, 0, 0, 1, /* num values and length width */
+ 1, /* value lengths */
+ '1', 0}; /* values for abc */
+
+ struct ldb_val vals[1] = {{.data=discard_const_p(uint8_t, "1"),
+ .length=1}};
+ struct ldb_message_element els[1] = {{.name=discard_const_p(char,
+ "abc"),
+ .num_values=1, .values=vals}};
+ struct ldb_message msg = {.num_elements=1, .elements=els};
+
+ struct ldb_val expect_bin_ldb;
+ expect_bin_ldb = data_blob_const(bin, sizeof(bin));
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL,NULL,NULL);
+ torture_assert(torture, ldb != NULL, "Failed to init ldb");
+
+ msg.dn = ldb_dn_new(NULL, ldb, "@A");
+
+ torture_assert_int_equal(torture,
+ ldb_pack_data(ldb, &msg, &binary,
+ LDB_PACKING_FORMAT_V2),
+ 0, "ldb_pack_data failed");
+
+ torture_assert_int_equal(torture, expect_bin_ldb.length,
+ binary.length,
+ "packed data length not as expected");
+
+ torture_assert_mem_equal(torture,
+ expect_bin_ldb.data,
+ binary.data,
+ binary.length,
+ "packed data not as expected");
+
+ TALLOC_FREE(msg.dn);
+
+ return true;
+}
+
+static bool torture_ldb_parse_ldif(struct torture_context *torture,
+ const void *data_p)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ const char *ldif_text = dda1d01d_ldif;
+ struct ldb_context *ldb;
+ struct ldb_ldif *ldif;
+ struct ldb_val binary;
+ struct ldb_val data = *discard_const_p(struct ldb_val, data_p);
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL,NULL,NULL);
+ torture_assert(torture,
+ ldb != NULL,
+ "Failed to init ldb");
+
+ ldif = ldb_ldif_read_string(ldb, &ldif_text);
+ torture_assert(torture,
+ ldif != NULL,
+ "ldb_ldif_read_string failed");
+ torture_assert_int_equal(torture, ldif->changetype, LDB_CHANGETYPE_NONE,
+ "changetype is incorrect");
+ torture_assert_int_equal(torture,
+ ldb_pack_data(ldb, ldif->msg, &binary,
+ LDB_PACKING_FORMAT_V2),
+ 0, "ldb_pack_data failed");
+
+ torture_assert_int_equal(torture, ldb_unpack_data(ldb, &data, msg), 0,
+ "ldb_unpack_data failed");
+
+ torture_assert(torture,
+ helper_ldb_message_compare(torture, ldif->msg, msg),
+ "Forms differ in memory");
+
+ return true;
+}
+
+static bool torture_ldb_pack_format_perf(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ char *unp_ldif_text = talloc_strndup(mem_ctx, dda1d01d_ldif,
+ sizeof(dda1d01d_ldif)-1);
+ const char *ldif_text;
+ struct ldb_context *ldb;
+ struct ldb_ldif *ldif;
+ struct ldb_val binary;
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ int ret, i;
+ clock_t start, diff;
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL,NULL,NULL);
+ torture_assert(torture,
+ ldb != NULL,
+ "Failed to init ldb");
+
+ unp_ldif_text[sizeof(dda1d01d_ldif)-2] = '\0';
+ ldif_text = unp_ldif_text;
+
+ for (i=0; i<10000; i++) {
+ ldif_text = talloc_asprintf_append(
+ discard_const_p(char, ldif_text),
+ "member: fillerfillerfillerfillerfillerfiller"
+ "fillerfillerfillerfillerfillerfillerfiller"
+ "fillerfillerfillerfillerfiller-group%d\n", i);
+ }
+
+ ldif = ldb_ldif_read_string(ldb, &ldif_text);
+ torture_assert(torture,
+ ldif != NULL,
+ "ldb_ldif_read_string failed");
+ torture_assert_int_equal(torture, ldif->changetype, LDB_CHANGETYPE_NONE,
+ "changetype is incorrect");
+ torture_assert_int_equal(torture,
+ ldb_pack_data(ldb, ldif->msg, &binary,
+ LDB_PACKING_FORMAT_V2),
+ 0, "ldb_pack_data failed");
+
+ ret = ldb_unpack_data(ldb, &binary, msg);
+ torture_assert_int_equal(torture, ret, 0,
+ "ldb_unpack_data failed");
+
+ torture_assert(torture,
+ helper_ldb_message_compare(torture, ldif->msg, msg),
+ "Forms differ in memory");
+
+ i = 0;
+ start = clock();
+ while (true) {
+ ldb_pack_data(ldb, ldif->msg, &binary, LDB_PACKING_FORMAT_V2);
+ i++;
+
+ if (i >= 1000) {
+ break;
+ }
+ }
+ diff = (clock() - start) * 1000 / CLOCKS_PER_SEC;
+ printf("\n%d pack runs took: %ldms\n", i, (long)diff);
+
+ i = 0;
+ start = clock();
+ while (true) {
+ ldb_unpack_data(ldb, &binary, msg);
+ i++;
+
+ if (i >= 1000) {
+ break;
+ }
+ }
+ diff = (clock() - start) * 1000 / CLOCKS_PER_SEC;
+ printf("%d unpack runs took: %ldms\n", i, (long)diff);
+
+ return true;
+}
+
+static bool torture_ldb_unpack_and_filter(struct torture_context *torture,
+ const void *data_p)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ struct ldb_context *ldb;
+ struct ldb_val data = *discard_const_p(struct ldb_val, data_p);
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ const char *lookup_names[] = {"instanceType", "nonexistent",
+ "whenChanged", "objectClass",
+ "uSNCreated", "showInAdvancedViewOnly",
+ "name", "cnNotHere", NULL};
+ const char *ldif_text;
+ struct ldb_ldif ldif;
+
+ ldb = samba_ldb_init(mem_ctx, torture->ev, NULL, NULL, NULL);
+ torture_assert(torture,
+ ldb != NULL,
+ "Failed to init samba");
+
+ torture_assert_int_equal(torture,
+ ldb_unpack_data(ldb, &data, msg),
+ 0, "ldb_unpack_data failed");
+
+ torture_assert_int_equal(torture, msg->num_elements, 13,
+ "Got wrong count of elements");
+
+ torture_assert_int_equal(torture,
+ ldb_filter_attrs_in_place(msg, lookup_names),
+ 0, "ldb_filter_attrs_in_place failed");
+
+ /* Compare data in binary form */
+ torture_assert_int_equal(torture, msg->num_elements, 6,
+ "Got wrong number of parsed elements");
+
+ torture_assert_str_equal(torture, msg->elements[0].name, "objectClass",
+ "First element has wrong name");
+ torture_assert_int_equal(torture, msg->elements[0].num_values, 2,
+ "First element has wrong count of values");
+ torture_assert_int_equal(torture,
+ msg->elements[0].values[0].length, 3,
+ "First element's first value is of wrong length");
+ torture_assert_mem_equal(torture,
+ msg->elements[0].values[0].data, "top", 3,
+ "First element's first value is incorrect");
+ torture_assert_int_equal(torture,
+ msg->elements[0].values[1].length, strlen("container"),
+ "First element's second value is of wrong length");
+ torture_assert_mem_equal(torture, msg->elements[0].values[1].data,
+ "container", strlen("container"),
+ "First element's second value is incorrect");
+
+ torture_assert_str_equal(torture, msg->elements[1].name, "instanceType",
+ "Second element has wrong name");
+ torture_assert_int_equal(torture, msg->elements[1].num_values, 1,
+ "Second element has too many values");
+ torture_assert_int_equal(torture, msg->elements[1].values[0].length, 1,
+ "Second element's value is of wrong length");
+ torture_assert_mem_equal(torture, msg->elements[1].values[0].data,
+ "4", 1,
+ "Second element's value is incorrect");
+
+ torture_assert_str_equal(torture, msg->elements[2].name, "whenChanged",
+ "Third element has wrong name");
+ torture_assert_int_equal(torture, msg->elements[2].num_values, 1,
+ "Third element has too many values");
+ torture_assert_int_equal(torture, msg->elements[2].values[0].length,
+ strlen("20150708224310.0Z"),
+ "Third element's value is of wrong length");
+ torture_assert_mem_equal(torture, msg->elements[2].values[0].data,
+ "20150708224310.0Z", strlen("20150708224310.0Z"),
+ "Third element's value is incorrect");
+
+ torture_assert_str_equal(torture, msg->elements[3].name, "uSNCreated",
+ "Fourth element has wrong name");
+ torture_assert_int_equal(torture, msg->elements[3].num_values, 1,
+ "Fourth element has too many values");
+ torture_assert_int_equal(torture, msg->elements[3].values[0].length, 4,
+ "Fourth element's value is of wrong length");
+ torture_assert_mem_equal(torture, msg->elements[3].values[0].data,
+ "3467", 4,
+ "Fourth element's value is incorrect");
+
+ torture_assert_str_equal(torture, msg->elements[4].name, "showInAdvancedViewOnly",
+ "Fifth element has wrong name");
+ torture_assert_int_equal(torture, msg->elements[4].num_values, 1,
+ "Fifth element has too many values");
+ torture_assert_int_equal(torture, msg->elements[4].values[0].length, 4,
+ "Fifth element's value is of wrong length");
+ torture_assert_mem_equal(torture, msg->elements[4].values[0].data,
+ "TRUE", 4,
+ "Fourth element's value is incorrect");
+
+ torture_assert_str_equal(torture, msg->elements[5].name, "name",
+ "Sixth element has wrong name");
+ torture_assert_int_equal(torture, msg->elements[5].num_values, 1,
+ "Sixth element has too many values");
+ torture_assert_int_equal(torture, msg->elements[5].values[0].length,
+ strlen("dda1d01d-4bd7-4c49-a184-46f9241b560e"),
+ "Sixth element's value is of wrong length");
+ torture_assert_mem_equal(torture, msg->elements[5].values[0].data,
+ "dda1d01d-4bd7-4c49-a184-46f9241b560e",
+ strlen("dda1d01d-4bd7-4c49-a184-46f9241b560e"),
+ "Sixth element's value is incorrect");
+
+ /* Compare data in ldif form */
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = msg;
+ ldif_text = ldb_ldif_write_string(ldb, mem_ctx, &ldif);
+
+ torture_assert_str_equal(torture, ldif_text, dda1d01d_ldif_reduced,
+ "Expected fields did not match");
+
+ return true;
+}
+
+struct torture_suite *torture_ldb(TALLOC_CTX *mem_ctx)
+{
+ int i;
+ struct ldb_val *bins = talloc_array(mem_ctx, struct ldb_val, 2);
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "ldb");
+
+ if (suite == NULL) {
+ return NULL;
+ }
+
+ bins[0] = data_blob_const(dda1d01d_bin_v1, sizeof(dda1d01d_bin_v1));
+ bins[1] = data_blob_const(dda1d01d_bin_v2, sizeof(dda1d01d_bin_v2));
+
+ torture_suite_add_simple_test(suite, "attrs", torture_ldb_attrs);
+ torture_suite_add_simple_test(suite, "dn-attrs", torture_ldb_dn_attrs);
+ torture_suite_add_simple_test(suite, "dn-extended",
+ torture_ldb_dn_extended);
+ torture_suite_add_simple_test(suite, "dn-invalid-extended",
+ torture_ldb_dn_invalid_extended);
+ torture_suite_add_simple_test(suite, "dn", torture_ldb_dn);
+ torture_suite_add_simple_test(suite, "pack-format-perf",
+ torture_ldb_pack_format_perf);
+ torture_suite_add_simple_test(suite, "pack-data-v2",
+ torture_ldb_pack_data_v2);
+ torture_suite_add_simple_test(suite, "pack-data-special-v2",
+ torture_ldb_pack_data_v2_special);
+ torture_suite_add_simple_test(suite, "unpack-corrupt-v2",
+ torture_ldb_unpack_data_corrupt);
+
+ for (i=0; i<2; i++) {
+ torture_suite_add_simple_tcase_const(suite,
+ talloc_asprintf(mem_ctx, "unpack-data-v%d", i+1),
+ torture_ldb_unpack, &bins[i]);
+ torture_suite_add_simple_tcase_const(suite,
+ talloc_asprintf(mem_ctx, "unpack-data-flags-v%d", i+1),
+ torture_ldb_unpack_flags, &bins[i]);
+ torture_suite_add_simple_tcase_const(suite,
+ talloc_asprintf(mem_ctx, "parse-ldif-v%d", i+1),
+ torture_ldb_parse_ldif, &bins[i]);
+ torture_suite_add_simple_tcase_const(suite,
+ talloc_asprintf(mem_ctx,
+ "unpack-data-and-filter-v%d", i+1),
+ torture_ldb_unpack_and_filter, &bins[i]);
+ }
+
+ suite->description = talloc_strdup(suite, "LDB (samba-specific behaviour) tests");
+
+ return suite;
+}
diff --git a/source4/torture/libnet/domain.c b/source4/torture/libnet/domain.c
new file mode 100644
index 0000000..c1cfc91
--- /dev/null
+++ b/source4/torture/libnet/domain.c
@@ -0,0 +1,117 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/proto.h"
+
+static bool test_domainopen(struct torture_context *tctx,
+ struct libnet_context *net_ctx, TALLOC_CTX *mem_ctx,
+ struct lsa_String *domname,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct libnet_DomainOpen io;
+
+ ZERO_STRUCT(io);
+
+ torture_comment(tctx, "opening domain\n");
+
+ io.in.domain_name = talloc_strdup(mem_ctx, domname->string);
+ io.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ status = libnet_DomainOpen(net_ctx, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Composite domain open failed for domain '%s' - %s\n",
+ domname->string, nt_errstr(status));
+ return false;
+ }
+
+ *domain_handle = io.out.domain_handle;
+ return true;
+}
+
+
+static bool test_cleanup(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ struct samr_Close r;
+ struct policy_handle handle;
+
+ r.in.handle = domain_handle;
+ r.out.handle = &handle;
+
+ torture_comment(tctx, "closing domain handle\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Close_r(b, mem_ctx, &r),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Close failed");
+
+ return true;
+}
+
+
+bool torture_domainopen(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct libnet_context *net_ctx;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct policy_handle h;
+ struct lsa_String name;
+
+ mem_ctx = talloc_init("test_domain_open");
+
+ net_ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+
+ status = torture_rpc_connection(torture,
+ &net_ctx->samr.pipe,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ name.string = lpcfg_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ if (!test_domainopen(torture, net_ctx, mem_ctx, &name, &h)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_cleanup(torture, net_ctx->samr.pipe->binding_handle, mem_ctx, &h)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/groupinfo.c b/source4/torture/libnet/groupinfo.c
new file mode 100644
index 0000000..a738ab3
--- /dev/null
+++ b/source4/torture/libnet/groupinfo.c
@@ -0,0 +1,128 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libnet/libnet.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/proto.h"
+
+#define TEST_GROUPNAME "libnetgroupinfotest"
+
+
+static bool test_groupinfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 *domain_sid, const char* group_name,
+ uint32_t *rid)
+{
+ const uint16_t level = 5;
+ NTSTATUS status;
+ struct libnet_rpc_groupinfo group;
+ struct dom_sid *group_sid;
+
+ group_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid);
+
+ ZERO_STRUCT(group);
+
+ group.in.domain_handle = *domain_handle;
+ group.in.sid = dom_sid_string(mem_ctx, group_sid);
+ group.in.level = level; /* this should be extended */
+
+ torture_comment(tctx, "Testing sync libnet_rpc_groupinfo (SID argument)\n");
+ status = libnet_rpc_groupinfo(tctx->ev, p->binding_handle, mem_ctx, &group);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to call sync libnet_rpc_userinfo - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ZERO_STRUCT(group);
+
+ group.in.domain_handle = *domain_handle;
+ group.in.sid = NULL;
+ group.in.groupname = TEST_GROUPNAME;
+ group.in.level = level;
+
+ printf("Testing sync libnet_rpc_groupinfo (groupname argument)\n");
+ status = libnet_rpc_groupinfo(tctx->ev, p->binding_handle, mem_ctx, &group);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to call sync libnet_rpc_groupinfo - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_groupinfo(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct policy_handle h;
+ struct lsa_String name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+ struct dcerpc_binding_handle *b;
+
+ mem_ctx = talloc_init("test_userinfo");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ name.string = lpcfg_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ if (!test_domain_open(torture, b, &name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_create(torture, b, mem_ctx, &h, TEST_GROUPNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_groupinfo(torture, p, mem_ctx, &h, &sid, TEST_GROUPNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_cleanup(torture, b, mem_ctx, &h, TEST_GROUPNAME)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/groupman.c b/source4/torture/libnet/groupman.c
new file mode 100644
index 0000000..8cd49db
--- /dev/null
+++ b/source4/torture/libnet/groupman.c
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/libnet/grouptest.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/proto.h"
+
+
+static bool test_groupadd(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_rpc_groupadd group;
+
+ ZERO_STRUCT(group);
+
+ group.in.domain_handle = *domain_handle;
+ group.in.groupname = name;
+
+ printf("Testing libnet_rpc_groupadd\n");
+
+ status = libnet_rpc_groupadd(tctx->ev, p->binding_handle,
+ mem_ctx, &group);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_groupadd - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return ret;
+}
+
+
+bool torture_groupadd(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ const char *name = TEST_GROUPNAME;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+
+ mem_ctx = talloc_init("test_groupadd");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ torture_assert_ntstatus_ok(torture, status, "RPC connection");
+ b = p->binding_handle;
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ if (!test_domain_open(torture, b, &domain_name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_groupadd(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_cleanup(torture, b, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/grouptest.h b/source4/torture/libnet/grouptest.h
new file mode 100644
index 0000000..8b65e6e
--- /dev/null
+++ b/source4/torture/libnet/grouptest.h
@@ -0,0 +1,20 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define TEST_GROUPNAME "libnetgrptest"
diff --git a/source4/torture/libnet/libnet.c b/source4/torture/libnet/libnet.c
new file mode 100644
index 0000000..faf7bca
--- /dev/null
+++ b/source4/torture/libnet/libnet.c
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "libnet/libnet.h"
+#include "torture/libnet/proto.h"
+
+NTSTATUS torture_net_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "net");
+
+ torture_suite_add_simple_test(suite, "userinfo", torture_userinfo);
+ torture_suite_add_simple_test(suite, "useradd", torture_useradd);
+ torture_suite_add_simple_test(suite, "userdel", torture_userdel);
+ torture_suite_add_simple_test(suite, "usermod", torture_usermod);
+ torture_suite_add_simple_test(suite, "domopen", torture_domainopen);
+ torture_suite_add_simple_test(suite, "groupinfo", torture_groupinfo);
+ torture_suite_add_simple_test(suite, "groupadd", torture_groupadd);
+ torture_suite_add_simple_test(suite, "api.lookup", torture_lookup);
+ torture_suite_add_simple_test(suite, "api.lookuphost", torture_lookup_host);
+ torture_suite_add_simple_test(suite, "api.lookuppdc", torture_lookup_pdc);
+ torture_suite_add_simple_test(suite, "api.lookupname", torture_lookup_sam_name);
+ torture_suite_add_simple_test(suite, "api.createuser", torture_createuser);
+ torture_suite_add_simple_test(suite, "api.deleteuser", torture_deleteuser);
+ torture_suite_add_simple_test(suite, "api.modifyuser", torture_modifyuser);
+ torture_suite_add_simple_test(suite, "api.userinfo", torture_userinfo_api);
+ torture_suite_add_simple_test(suite, "api.userlist", torture_userlist);
+ torture_suite_add_simple_test(suite, "api.groupinfo", torture_groupinfo_api);
+ torture_suite_add_simple_test(suite, "api.grouplist", torture_grouplist);
+ torture_suite_add_simple_test(suite, "api.creategroup", torture_creategroup);
+ torture_suite_add_simple_test(suite, "api.rpcconn.bind", torture_rpc_connect_binding);
+ torture_suite_add_simple_test(suite, "api.rpcconn.srv", torture_rpc_connect_srv);
+ torture_suite_add_simple_test(suite, "api.rpcconn.pdc", torture_rpc_connect_pdc);
+ torture_suite_add_simple_test(suite, "api.rpcconn.dc", torture_rpc_connect_dc);
+ torture_suite_add_simple_test(suite, "api.rpcconn.dcinfo", torture_rpc_connect_dc_info);
+ torture_suite_add_simple_test(suite, "api.listshares", torture_listshares);
+ torture_suite_add_simple_test(suite, "api.delshare", torture_delshare);
+ torture_suite_add_simple_test(suite, "api.domopenlsa", torture_domain_open_lsa);
+ torture_suite_add_simple_test(suite, "api.domcloselsa", torture_domain_close_lsa);
+ torture_suite_add_simple_test(suite, "api.domopensamr", torture_domain_open_samr);
+ torture_suite_add_simple_test(suite, "api.domclosesamr", torture_domain_close_samr);
+ torture_suite_add_simple_test(suite, "api.become.dc", torture_net_become_dc);
+ torture_suite_add_simple_test(suite, "api.domlist", torture_domain_list);
+
+ suite->description = talloc_strdup(suite, "libnet convenience interface tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c
new file mode 100644
index 0000000..45d386b
--- /dev/null
+++ b/source4/torture/libnet/libnet_BecomeDC.c
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libnet_BecomeDC() tests
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libnet/libnet.h"
+#include "dsdb/samdb/samdb.h"
+#include "../lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "system/time.h"
+#include "ldb_wrap.h"
+#include "auth/auth.h"
+#include "param/param.h"
+#include "param/provision.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/libnet/proto.h"
+
+bool torture_net_become_dc(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct libnet_BecomeDC b;
+ struct libnet_UnbecomeDC u;
+ struct libnet_vampire_cb_state *s;
+ struct ldb_message *msg;
+ int ldb_ret;
+ uint32_t i;
+ char *private_dir;
+ const char *address;
+ struct nbt_name name;
+ const char *netbios_name;
+ struct cli_credentials *machine_account;
+ struct test_join *tj;
+ struct loadparm_context *lp_ctx;
+ struct ldb_context *ldb;
+ struct libnet_context *ctx;
+ struct dsdb_schema *schema;
+
+ char *location = NULL;
+ torture_assert_ntstatus_ok(torture, torture_temp_dir(torture, "libnet_BecomeDC", &location),
+ "torture_temp_dir should return NT_STATUS_OK" );
+
+ netbios_name = lpcfg_parm_string(torture->lp_ctx, NULL, "become dc", "smbtorture dc");
+ if (!netbios_name || !netbios_name[0]) {
+ netbios_name = "smbtorturedc";
+ }
+
+ make_nbt_name_server(&name, torture_setting_string(torture, "host", NULL));
+
+ /* do an initial name resolution to find its IP */
+ status = resolve_name_ex(lpcfg_resolve_context(torture->lp_ctx),
+ 0, 0,
+ &name, torture, &address, torture->ev);
+ torture_assert_ntstatus_ok(torture, status, talloc_asprintf(torture,
+ "Failed to resolve %s - %s\n",
+ name.name, nt_errstr(status)));
+
+
+ /* Join domain as a member server. */
+ tj = torture_join_domain(torture, netbios_name,
+ ACB_WSTRUST,
+ &machine_account);
+ torture_assert(torture, tj, talloc_asprintf(torture,
+ "%s failed to join domain as workstation\n",
+ netbios_name));
+
+ s = libnet_vampire_cb_state_init(torture, torture->lp_ctx, torture->ev,
+ netbios_name,
+ torture_join_dom_netbios_name(tj),
+ torture_join_dom_dns_name(tj),
+ location);
+ torture_assert(torture, s, "libnet_vampire_cb_state_init");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ ZERO_STRUCT(b);
+ b.in.domain_dns_name = torture_join_dom_dns_name(tj);
+ b.in.domain_netbios_name = torture_join_dom_netbios_name(tj);
+ b.in.domain_sid = torture_join_sid(tj);
+ b.in.source_dsa_address = address;
+ b.in.dest_dsa_netbios_name = netbios_name;
+
+ b.in.callbacks.private_data = s;
+ b.in.callbacks.check_options = libnet_vampire_cb_check_options;
+ b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db;
+ b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk;
+ b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk;
+ b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk;
+
+ status = libnet_BecomeDC(ctx, s, &b);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, cleanup, talloc_asprintf(torture,
+ "libnet_BecomeDC() failed - %s %s\n",
+ nt_errstr(status), b.out.error_string));
+ ldb = libnet_vampire_cb_ldb(s);
+
+ msg = ldb_msg_new(s);
+ torture_assert_int_equal_goto(torture, (msg?1:0), 1, ret, cleanup,
+ "ldb_msg_new() failed\n");
+ msg->dn = ldb_dn_new(msg, ldb, "@ROOTDSE");
+ torture_assert_int_equal_goto(torture, (msg->dn?1:0), 1, ret, cleanup,
+ "ldb_msg_new(@ROOTDSE) failed\n");
+
+ ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
+ torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup,
+ "ldb_msg_add_string(msg, isSynchronized, TRUE) failed\n");
+
+ for (i=0; i < msg->num_elements; i++) {
+ msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ torture_comment(torture, "mark ROOTDSE with isSynchronized=TRUE\n");
+ ldb_ret = ldb_modify(libnet_vampire_cb_ldb(s), msg);
+ torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup,
+ "ldb_modify() failed\n");
+
+ /* commit the transaction now we know the secrets were written
+ * out properly
+ */
+ ldb_ret = ldb_transaction_commit(ldb);
+ torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup,
+ "ldb_transaction_commit() failed\n");
+
+ /* reopen the ldb */
+ talloc_unlink(s, ldb);
+
+ lp_ctx = libnet_vampire_cb_lp_ctx(s);
+ private_dir = talloc_asprintf(s, "%s/%s", location, "private");
+ lpcfg_set_cmdline(lp_ctx, "private dir", private_dir);
+ torture_comment(torture, "Reopen the SAM LDB with system credentials and all replicated data: %s\n", private_dir);
+ ldb = samdb_connect(s,
+ torture->ev,
+ lp_ctx,
+ system_session(lp_ctx),
+ NULL,
+ 0);
+ torture_assert_goto(torture, ldb != NULL, ret, cleanup,
+ talloc_asprintf(torture,
+ "Failed to open '%s/sam.ldb'\n", private_dir));
+
+ torture_assert_goto(torture, dsdb_uses_global_schema(ldb), ret, cleanup,
+ "Uses global schema");
+
+ schema = dsdb_get_schema(ldb, s);
+ torture_assert_goto(torture, schema != NULL, ret, cleanup,
+ "Failed to get loaded dsdb_schema\n");
+
+ /* Make sure we get this from the command line */
+ if (lpcfg_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) {
+ talloc_free(s);
+ return ret;
+ }
+
+cleanup:
+ ZERO_STRUCT(u);
+ u.in.domain_dns_name = torture_join_dom_dns_name(tj);
+ u.in.domain_netbios_name = torture_join_dom_netbios_name(tj);
+ u.in.source_dsa_address = address;
+ u.in.dest_dsa_netbios_name = netbios_name;
+
+ status = libnet_UnbecomeDC(ctx, s, &u);
+ torture_assert_ntstatus_ok(torture, status, talloc_asprintf(torture,
+ "libnet_UnbecomeDC() failed - %s %s\n",
+ nt_errstr(status), u.out.error_string));
+
+ /* Leave domain. */
+ torture_leave_domain(torture, tj);
+
+ talloc_free(s);
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_domain.c b/source4/torture/libnet/libnet_domain.c
new file mode 100644
index 0000000..2444000
--- /dev/null
+++ b/source4/torture/libnet/libnet_domain.c
@@ -0,0 +1,440 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "torture/libnet/proto.h"
+
+
+static bool test_opendomain_samr(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname,
+ uint32_t *access_mask, struct dom_sid **sid_p)
+{
+ struct policy_handle h, domain_handle;
+ struct samr_Connect r1;
+ struct samr_LookupDomain r2;
+ struct dom_sid2 *sid = NULL;
+ struct samr_OpenDomain r3;
+
+ torture_comment(tctx, "connecting\n");
+
+ *access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ r1.in.system_name = 0;
+ r1.in.access_mask = *access_mask;
+ r1.out.connect_handle = &h;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Connect_r(b, mem_ctx, &r1),
+ "Connect failed");
+ torture_assert_ntstatus_ok(tctx, r1.out.result,
+ "Connect failed");
+
+ r2.in.connect_handle = &h;
+ r2.in.domain_name = domname;
+ r2.out.sid = &sid;
+
+ torture_comment(tctx, "domain lookup on %s\n", domname->string);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_LookupDomain_r(b, mem_ctx, &r2),
+ "LookupDomain failed");
+ torture_assert_ntstatus_ok(tctx, r2.out.result,
+ "LookupDomain failed");
+
+ r3.in.connect_handle = &h;
+ r3.in.access_mask = *access_mask;
+ r3.in.sid = *sid_p = *r2.out.sid;
+ r3.out.domain_handle = &domain_handle;
+
+ torture_comment(tctx, "opening domain\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenDomain_r(b, mem_ctx, &r3),
+ "OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, r3.out.result,
+ "OpenDomain failed");
+
+ *handle = domain_handle;
+
+ return true;
+}
+
+
+static bool test_opendomain_lsa(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname,
+ uint32_t *access_mask)
+{
+ struct lsa_OpenPolicy2 open;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+
+ *access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ ZERO_STRUCT(attr);
+ ZERO_STRUCT(qos);
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.sec_qos = &qos;
+
+ open.in.system_name = domname->string;
+ open.in.attr = &attr;
+ open.in.access_mask = *access_mask;
+ open.out.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_OpenPolicy2_r(b, mem_ctx, &open),
+ "OpenPolicy2 failed");
+ torture_assert_ntstatus_ok(tctx, open.out.result,
+ "OpenPolicy2 failed");
+
+ return true;
+}
+
+bool torture_domain_open_lsa(struct torture_context *torture)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_context *ctx;
+ struct libnet_DomainOpen r;
+ struct lsa_Close lsa_close;
+ struct policy_handle h;
+ const char *domain_name;
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lpcfg_workgroup(torture->lp_ctx);
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ torture_comment(torture, "failed to create libnet context\n");
+ return false;
+ }
+
+ ctx->cred = samba_cmdline_get_creds();
+
+ ZERO_STRUCT(r);
+ r.in.type = DOMAIN_LSA;
+ r.in.domain_name = domain_name;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ status = libnet_DomainOpen(ctx, torture, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "failed to open domain on lsa service: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(lsa_close);
+ lsa_close.in.handle = &ctx->lsa.handle;
+ lsa_close.out.handle = &h;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_lsa_Close_r(ctx->lsa.pipe->binding_handle, ctx, &lsa_close),
+ "failed to close domain on lsa service");
+ torture_assert_ntstatus_ok(torture, lsa_close.out.result,
+ "failed to close domain on lsa service");
+
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+
+bool torture_domain_close_lsa(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx=NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct dcerpc_binding *binding;
+ uint32_t access_mask;
+ struct policy_handle h;
+ struct dcerpc_pipe *p;
+ struct libnet_DomainClose r;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ torture_comment(torture, "failed to create libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->cred = samba_cmdline_get_creds();
+
+ mem_ctx = talloc_init("torture_domain_close_lsa");
+ status = dcerpc_pipe_connect_b(mem_ctx, &p, binding, &ndr_table_lsarpc,
+ samba_cmdline_get_creds(),
+ torture->ev, torture->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "failed to connect to server: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+
+ if (!test_opendomain_lsa(torture, p->binding_handle, torture, &h, &domain_name, &access_mask)) {
+ torture_comment(torture, "failed to open domain on lsa service\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->lsa.pipe = p;
+ ctx->lsa.name = domain_name.string;
+ ctx->lsa.access_mask = access_mask;
+ ctx->lsa.handle = h;
+
+ ZERO_STRUCT(r);
+ r.in.type = DOMAIN_LSA;
+ r.in.domain_name = domain_name.string;
+
+ status = libnet_DomainClose(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+ return ret;
+}
+
+
+bool torture_domain_open_samr(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct libnet_context *ctx;
+ TALLOC_CTX *mem_ctx;
+ struct policy_handle domain_handle, handle;
+ struct libnet_DomainOpen io;
+ struct samr_Close r;
+ const char *domain_name;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_domainopen_lsa");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lpcfg_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ torture_comment(torture, "opening domain\n");
+
+ io.in.type = DOMAIN_SAMR;
+ io.in.domain_name = domain_name;
+ io.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ status = libnet_DomainOpen(ctx, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "Composite domain open failed for domain '%s' - %s\n",
+ domain_name, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ domain_handle = ctx->samr.handle;
+
+ r.in.handle = &domain_handle;
+ r.out.handle = &handle;
+
+ torture_comment(torture, "closing domain handle\n");
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_Close_r(ctx->samr.pipe->binding_handle, mem_ctx, &r),
+ "Close failed");
+ torture_assert_ntstatus_ok(torture, r.out.result,
+ "Close failed");
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+
+ return ret;
+}
+
+
+bool torture_domain_close_samr(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct dcerpc_binding *binding;
+ uint32_t access_mask;
+ struct policy_handle h;
+ struct dcerpc_pipe *p;
+ struct libnet_DomainClose r;
+ struct dom_sid *sid;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ torture_comment(torture, "failed to create libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->cred = samba_cmdline_get_creds();
+
+ mem_ctx = talloc_init("torture_domain_close_samr");
+ status = dcerpc_pipe_connect_b(mem_ctx, &p, binding, &ndr_table_samr,
+ ctx->cred, torture->ev, torture->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "failed to connect to server: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ domain_name.string = talloc_strdup(mem_ctx, lpcfg_workgroup(torture->lp_ctx));
+
+ if (!test_opendomain_samr(torture, p->binding_handle, torture, &h, &domain_name, &access_mask, &sid)) {
+ torture_comment(torture, "failed to open domain on samr service\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->samr.pipe = p;
+ ctx->samr.name = talloc_steal(ctx, domain_name.string);
+ ctx->samr.access_mask = access_mask;
+ ctx->samr.handle = h;
+ ctx->samr.sid = talloc_steal(ctx, sid);
+
+ ZERO_STRUCT(r);
+ r.in.type = DOMAIN_SAMR;
+ r.in.domain_name = domain_name.string;
+
+ status = libnet_DomainClose(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+ return ret;
+}
+
+
+bool torture_domain_list(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct dcerpc_binding *binding;
+ struct libnet_context *ctx;
+ struct libnet_DomainList r;
+ int i;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ torture_comment(torture, "failed to create libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->cred = samba_cmdline_get_creds();
+
+ mem_ctx = talloc_init("torture_domain_close_samr");
+
+ /*
+ * querying the domain list using default buffer size
+ */
+
+ ZERO_STRUCT(r);
+ r.in.hostname = dcerpc_binding_get_string_option(binding, "host");
+
+ status = libnet_DomainList(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(torture, "Received list or domains (everything in one piece):\n");
+
+ for (i = 0; i < r.out.count; i++) {
+ torture_comment(torture, "Name[%d]: %s\n", i, r.out.domains[i].name);
+ }
+
+ /*
+ * querying the domain list using specified (much smaller) buffer size
+ */
+
+ ctx->samr.buf_size = 32;
+
+ ZERO_STRUCT(r);
+ r.in.hostname = dcerpc_binding_get_string_option(binding, "host");
+
+ status = libnet_DomainList(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(torture, "Received list or domains (collected in more than one round):\n");
+
+ for (i = 0; i < r.out.count; i++) {
+ torture_comment(torture, "Name[%d]: %s\n", i, r.out.domains[i].name);
+ }
+
+done:
+ torture_comment(torture, "\nStatus: %s\n", nt_errstr(status));
+
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_group.c b/source4/torture/libnet/libnet_group.c
new file mode 100644
index 0000000..e3e2030
--- /dev/null
+++ b/source4/torture/libnet/libnet_group.c
@@ -0,0 +1,210 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/libnet/proto.h"
+#include "param/param.h"
+
+
+#define TEST_GROUPNAME "libnetgrouptest"
+
+
+bool torture_groupinfo_api(struct torture_context *torture)
+{
+ const char *name = TEST_GROUPNAME;
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL, *prep_mem_ctx;
+ struct libnet_context *ctx = NULL;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct libnet_GroupInfo req;
+
+ prep_mem_ctx = talloc_init("prepare torture group info");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ if (!test_domain_open(torture, p->binding_handle, &domain_name, prep_mem_ctx, &h, NULL)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_create(torture, p->binding_handle, prep_mem_ctx, &h, name, NULL)) {
+ ret = false;
+ goto done;
+ }
+
+ mem_ctx = talloc_init("torture group info");
+
+ if (!test_libnet_context_init(torture, true, &ctx)) {
+ return false;
+ }
+
+ ZERO_STRUCT(req);
+
+ req.in.domain_name = domain_name.string;
+ req.in.level = GROUP_INFO_BY_NAME;
+ req.in.data.group_name = name;
+
+ status = libnet_GroupInfo(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_GroupInfo call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_cleanup(torture, ctx->samr.pipe->binding_handle,
+ mem_ctx, &ctx->samr.handle, TEST_GROUPNAME)) {
+ torture_comment(torture, "cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, mem_ctx, &ctx->samr.handle)) {
+ torture_comment(torture, "domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_grouplist(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct libnet_GroupList req;
+ int i;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ mem_ctx = talloc_init("torture group list");
+
+ ZERO_STRUCT(req);
+
+ torture_comment(torture, "listing group accounts:\n");
+
+ do {
+ req.in.domain_name = domain_name.string;
+ req.in.page_size = 128;
+ req.in.resume_index = req.out.resume_index;
+
+ status = libnet_GroupList(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) break;
+
+ for (i = 0; i < req.out.count; i++) {
+ torture_comment(torture, "\tgroup: %s, sid=%s\n",
+ req.out.groups[i].groupname, req.out.groups[i].sid);
+ }
+
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (!(NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES))) {
+ torture_comment(torture, "libnet_GroupList call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, mem_ctx, &ctx->samr.handle)) {
+ torture_comment(torture, "domain close failed\n");
+ ret = false;
+ }
+
+ if (!test_lsa_close_handle(torture,
+ ctx->lsa.pipe->binding_handle, mem_ctx, &ctx->lsa.handle)) {
+ torture_comment(torture, "lsa domain close failed\n");
+ ret = false;
+ }
+
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_creategroup(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct libnet_CreateGroup req;
+
+ mem_ctx = talloc_init("test_creategroup");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ req.in.group_name = TEST_GROUPNAME;
+ req.in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+ req.out.error_string = NULL;
+
+ status = libnet_CreateGroup(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_CreateGroup call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_cleanup(torture, ctx->samr.pipe->binding_handle,
+ mem_ctx, &ctx->samr.handle, TEST_GROUPNAME)) {
+ torture_comment(torture, "cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, mem_ctx, &ctx->samr.handle)) {
+ torture_comment(torture, "domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_lookup.c b/source4/torture/libnet/libnet_lookup.c
new file mode 100644
index 0000000..e6e23dc
--- /dev/null
+++ b/source4/torture/libnet/libnet_lookup.c
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libnet/libnet.h"
+#include "libcli/libcli.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/libnet/proto.h"
+#include "param/param.h"
+
+
+bool torture_lookup(struct torture_context *torture)
+{
+ bool ret;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_Lookup lookup;
+ struct dcerpc_binding *binding;
+
+ mem_ctx = talloc_init("test_lookup");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ lookup.in.hostname = torture_setting_string(torture, "host", NULL);
+ if (lookup.in.hostname == NULL) {
+ status = torture_rpc_binding(torture, &binding);
+ if (NT_STATUS_IS_OK(status)) {
+ lookup.in.hostname = dcerpc_binding_get_string_option(binding, "host");
+ }
+ }
+
+ lookup.in.type = NBT_NAME_CLIENT;
+ lookup.in.resolve_ctx = NULL;
+ lookup.out.address = NULL;
+
+ status = libnet_Lookup(ctx, mem_ctx, &lookup);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "Couldn't lookup name %s: %s\n", lookup.in.hostname, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ret = true;
+
+ torture_comment(torture, "Name [%s] found at address: %s.\n", lookup.in.hostname, *lookup.out.address);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_lookup_host(struct torture_context *torture)
+{
+ bool ret;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_Lookup lookup;
+ struct dcerpc_binding *binding;
+
+ mem_ctx = talloc_init("test_lookup_host");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ lookup.in.hostname = torture_setting_string(torture, "host", NULL);
+ if (lookup.in.hostname == NULL) {
+ status = torture_rpc_binding(torture, &binding);
+ if (NT_STATUS_IS_OK(status)) {
+ lookup.in.hostname = dcerpc_binding_get_string_option(binding, "host");
+ }
+ }
+
+ lookup.in.resolve_ctx = NULL;
+ lookup.out.address = NULL;
+
+ status = libnet_LookupHost(ctx, mem_ctx, &lookup);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "Couldn't lookup host %s: %s\n", lookup.in.hostname, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ret = true;
+
+ torture_comment(torture, "Host [%s] found at address: %s.\n", lookup.in.hostname, *lookup.out.address);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_lookup_pdc(struct torture_context *torture)
+{
+ bool ret;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_LookupDCs *lookup;
+ int i;
+
+ mem_ctx = talloc_init("test_lookup_pdc");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ talloc_steal(ctx, mem_ctx);
+
+ lookup = talloc(mem_ctx, struct libnet_LookupDCs);
+ if (!lookup) {
+ ret = false;
+ goto done;
+ }
+
+ lookup->in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+ lookup->in.name_type = NBT_NAME_PDC;
+
+ status = libnet_LookupDCs(ctx, mem_ctx, lookup);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "Couldn't lookup pdc %s: %s\n", lookup->in.domain_name,
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ret = true;
+
+ torture_comment(torture, "DCs of domain [%s] found.\n", lookup->in.domain_name);
+ for (i = 0; i < lookup->out.num_dcs; i++) {
+ torture_comment(torture, "\tDC[%d]: name=%s, address=%s\n", i, lookup->out.dcs[i].name,
+ lookup->out.dcs[i].address);
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_lookup_sam_name(struct torture_context *torture)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_LookupName r;
+ bool ret = true;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ mem_ctx = talloc_init("torture lookup sam name");
+ if (mem_ctx == NULL) return false;
+
+ r.in.name = "Administrator";
+ r.in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+
+ status = libnet_LookupName(ctx, mem_ctx, &r);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "libnet_LookupName: failed");
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_rpc.c b/source4/torture/libnet/libnet_rpc.c
new file mode 100644
index 0000000..9820432
--- /dev/null
+++ b/source4/torture/libnet/libnet_rpc.c
@@ -0,0 +1,230 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libnet/libnet.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/libnet/proto.h"
+#include "param/param.h"
+
+
+static bool test_connect_service(struct torture_context *tctx,
+ struct libnet_context *ctx,
+ const struct ndr_interface_table *iface,
+ const char *binding_string,
+ const char *hostname,
+ const enum libnet_RpcConnect_level level,
+ bool badcreds, NTSTATUS expected_status)
+{
+ NTSTATUS status;
+ struct libnet_RpcConnect connect_r;
+ ZERO_STRUCT(connect_r);
+
+ connect_r.level = level;
+ connect_r.in.binding = binding_string;
+ connect_r.in.name = hostname;
+ connect_r.in.dcerpc_iface = iface;
+
+ /* if bad credentials are needed, set baduser%badpassword instead
+ of default commandline-passed credentials */
+ if (badcreds) {
+ cli_credentials_set_username(ctx->cred, "baduser", CRED_SPECIFIED);
+ cli_credentials_set_password(ctx->cred, "badpassword", CRED_SPECIFIED);
+ }
+
+ status = libnet_RpcConnect(ctx, ctx, &connect_r);
+
+ if (!NT_STATUS_EQUAL(status, expected_status)) {
+ torture_comment(tctx, "Connecting to rpc service %s on %s.\n\tFAILED. Expected: %s."
+ "Received: %s\n",
+ connect_r.in.dcerpc_iface->name, connect_r.in.binding, nt_errstr(expected_status),
+ nt_errstr(status));
+
+ return false;
+ }
+
+ torture_comment(tctx, "PASSED. Expected: %s, received: %s\n", nt_errstr(expected_status),
+ nt_errstr(status));
+
+ if (connect_r.level == LIBNET_RPC_CONNECT_DC_INFO && NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Domain Controller Info:\n");
+ torture_comment(tctx, "\tDomain Name:\t %s\n", connect_r.out.domain_name);
+ torture_comment(tctx, "\tDomain SID:\t %s\n", dom_sid_string(ctx, connect_r.out.domain_sid));
+ torture_comment(tctx, "\tRealm:\t\t %s\n", connect_r.out.realm);
+ torture_comment(tctx, "\tGUID:\t\t %s\n", GUID_string(ctx, connect_r.out.guid));
+
+ } else if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Error string: %s\n", connect_r.out.error_string);
+ }
+
+ return true;
+}
+
+
+static bool torture_rpc_connect(struct torture_context *torture,
+ const enum libnet_RpcConnect_level level,
+ const char *bindstr, const char *hostname)
+{
+ struct libnet_context *ctx;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ torture_comment(torture, "Testing connection to LSA interface\n");
+
+ if (!test_connect_service(torture, ctx, &ndr_table_lsarpc, bindstr,
+ hostname, level, false, NT_STATUS_OK)) {
+ torture_comment(torture, "failed to connect LSA interface\n");
+ return false;
+ }
+
+ torture_comment(torture, "Testing connection to SAMR interface\n");
+ if (!test_connect_service(torture, ctx, &ndr_table_samr, bindstr,
+ hostname, level, false, NT_STATUS_OK)) {
+ torture_comment(torture, "failed to connect SAMR interface\n");
+ return false;
+ }
+
+ torture_comment(torture, "Testing connection to SRVSVC interface\n");
+ if (!test_connect_service(torture, ctx, &ndr_table_srvsvc, bindstr,
+ hostname, level, false, NT_STATUS_OK)) {
+ torture_comment(torture, "failed to connect SRVSVC interface\n");
+ return false;
+ }
+
+ torture_comment(torture, "Testing connection to LSA interface with wrong credentials\n");
+ if (!test_connect_service(torture, ctx, &ndr_table_lsarpc, bindstr,
+ hostname, level, true, NT_STATUS_LOGON_FAILURE)) {
+ torture_comment(torture, "failed to test wrong credentials on LSA interface\n");
+ return false;
+ }
+
+ torture_comment(torture, "Testing connection to SAMR interface with wrong credentials\n");
+ if (!test_connect_service(torture, ctx, &ndr_table_samr, bindstr,
+ hostname, level, true, NT_STATUS_LOGON_FAILURE)) {
+ torture_comment(torture, "failed to test wrong credentials on SAMR interface\n");
+ return false;
+ }
+
+ talloc_free(ctx);
+
+ return true;
+}
+
+
+bool torture_rpc_connect_srv(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_SERVER;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *host;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ host = dcerpc_binding_get_string_option(binding, "host");
+
+ return torture_rpc_connect(torture, level, NULL, host);
+}
+
+
+bool torture_rpc_connect_pdc(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_PDC;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *domain_name;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lpcfg_workgroup(torture->lp_ctx);
+ return torture_rpc_connect(torture, level, NULL, domain_name);
+}
+
+
+bool torture_rpc_connect_dc(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_DC;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *domain_name;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lpcfg_workgroup(torture->lp_ctx);
+ return torture_rpc_connect(torture, level, NULL, domain_name);
+}
+
+
+bool torture_rpc_connect_dc_info(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_DC_INFO;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *domain_name;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lpcfg_workgroup(torture->lp_ctx);
+ return torture_rpc_connect(torture, level, NULL, domain_name);
+}
+
+
+bool torture_rpc_connect_binding(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_BINDING;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *bindstr;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ bindstr = dcerpc_binding_string(torture, binding);
+
+ return torture_rpc_connect(torture, level, bindstr, NULL);
+}
diff --git a/source4/torture/libnet/libnet_share.c b/source4/torture/libnet/libnet_share.c
new file mode 100644
index 0000000..da74b99
--- /dev/null
+++ b/source4/torture/libnet/libnet_share.c
@@ -0,0 +1,285 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Gregory LEOCADIE <gleocadie@idealx.com> 2005
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libnet/libnet.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "torture/libnet/proto.h"
+
+
+#define TEST_SHARENAME "libnetsharetest"
+
+
+static void test_displayshares(struct torture_context *tctx,
+ struct libnet_ListShares s)
+{
+ int i, j;
+
+ struct share_type {
+ enum srvsvc_ShareType type;
+ const char *desc;
+ } share_types[] = {
+ { STYPE_DISKTREE, "STYPE_DISKTREE" },
+ { STYPE_DISKTREE_TEMPORARY, "STYPE_DISKTREE_TEMPORARY" },
+ { STYPE_DISKTREE_HIDDEN, "STYPE_DISKTREE_HIDDEN" },
+ { STYPE_PRINTQ, "STYPE_PRINTQ" },
+ { STYPE_PRINTQ_TEMPORARY, "STYPE_PRINTQ_TEMPORARY" },
+ { STYPE_PRINTQ_HIDDEN, "STYPE_PRINTQ_HIDDEN" },
+ { STYPE_DEVICE, "STYPE_DEVICE" },
+ { STYPE_DEVICE_TEMPORARY, "STYPE_DEVICE_TEMPORARY" },
+ { STYPE_DEVICE_HIDDEN, "STYPE_DEVICE_HIDDEN" },
+ { STYPE_IPC, "STYPE_IPC" },
+ { STYPE_IPC_TEMPORARY, "STYPE_IPC_TEMPORARY" },
+ { STYPE_IPC_HIDDEN, "STYPE_IPC_HIDDEN" }
+ };
+
+ switch (s.in.level) {
+ case 0:
+ for (i = 0; i < s.out.ctr.ctr0->count; i++) {
+ struct srvsvc_NetShareInfo0 *info = &s.out.ctr.ctr0->array[i];
+ torture_comment(tctx, "\t[%d] %s\n", i, info->name);
+ }
+ break;
+
+ case 1:
+ for (i = 0; i < s.out.ctr.ctr1->count; i++) {
+ struct srvsvc_NetShareInfo1 *info = &s.out.ctr.ctr1->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) {
+ torture_comment(tctx,
+ "\t[%d] %s (%s)\t%s\n",
+ i,
+ info->name,
+ info->comment,
+ share_types[j].desc);
+ break;
+ }
+ }
+ }
+ break;
+
+ case 2:
+ for (i = 0; i < s.out.ctr.ctr2->count; i++) {
+ struct srvsvc_NetShareInfo2 *info = &s.out.ctr.ctr2->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) {
+ torture_comment(tctx,
+ "\t[%d] %s\t%s\n"
+ "\t %s\n"
+ "\t [perms=0x%08x, "
+ "max_usr=%d, "
+ "cur_usr=%d, "
+ "path=%s, "
+ "pass=%s]\n",
+ i,
+ info->name,
+ share_types[j].desc,
+ info->comment,
+ info->permissions,
+ info->max_users,
+ info->current_users,
+ info->path,
+ info->password);
+ break;
+ }
+ }
+ }
+ break;
+
+ case 501:
+ for (i = 0; i < s.out.ctr.ctr501->count; i++) {
+ struct srvsvc_NetShareInfo501 *info = &s.out.ctr.ctr501->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) {
+ torture_comment(tctx,
+ "\t[%d] %s"
+ "\t%s "
+ "[csc_policy=0x%08x]\n"
+ "\t %s\n",
+ i,
+ info->name,
+ share_types[j].desc,
+ info->csc_policy,
+ info->comment);
+ break;
+ }
+ }
+ }
+ break;
+
+ case 502:
+ for (i = 0; i < s.out.ctr.ctr502->count; i++) {
+ struct srvsvc_NetShareInfo502 *info = &s.out.ctr.ctr502->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) {
+ torture_comment(tctx,
+ "\t[%d] %s\t%s\n"
+ "\t %s\n"
+ "\t [perms=0x%08x, "
+ "max_usr=%d, "
+ "cur_usr=%d, "
+ "path=%s, pass=%s]\n",
+ i,
+ info->name,
+ share_types[j].desc,
+ info->comment,
+ info->permissions,
+ info->max_users,
+ info->current_users,
+ info->path,
+ info->password);
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+
+bool torture_listshares(struct torture_context *torture)
+{
+ struct libnet_ListShares share;
+ NTSTATUS status;
+ uint32_t levels[] = { 0, 1, 2, 501, 502 };
+ int i;
+ bool ret = true;
+ struct libnet_context* libnetctx;
+ struct dcerpc_binding *binding;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("test_listshares");
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ libnetctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (!libnetctx) {
+ torture_comment(torture, "Couldn't allocate libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ libnetctx->cred = samba_cmdline_get_creds();
+
+ torture_comment(torture, "Testing libnet_ListShare\n");
+
+ share.in.server_name = dcerpc_binding_get_string_option(binding, "host");
+
+ for (i = 0; i < ARRAY_SIZE(levels); i++) {
+ share.in.level = levels[i];
+ torture_comment(torture, "Testing libnet_ListShare level %u\n", share.in.level);
+
+ status = libnet_ListShares(libnetctx, mem_ctx, &share);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_ListShare level %u failed - %s\n", share.in.level, share.out.error_string);
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(torture, "listing shares:\n");
+ test_displayshares(torture, share);
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+static bool test_addshare(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b, TALLOC_CTX *mem_ctx, const char *host,
+ const char* share)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareAdd add;
+ union srvsvc_NetShareInfo info;
+ struct srvsvc_NetShareInfo2 i;
+
+ ZERO_STRUCT(i);
+ ZERO_STRUCT(info);
+ ZERO_STRUCT(add);
+
+ i.name = share;
+ i.type = STYPE_DISKTREE;
+ i.path = "C:\\WINDOWS\\TEMP";
+ i.max_users = 5;
+ i.comment = "Comment to the test share";
+ i.password = NULL;
+ i.permissions = 0x0;
+
+ info.info2 = &i;
+
+ add.in.server_unc = host;
+ add.in.level = 2;
+ add.in.info = &info;
+ add.in.parm_error = NULL;
+
+ status = dcerpc_srvsvc_NetShareAdd_r(b, mem_ctx, &add);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to add a new share\n");
+ return false;
+ }
+
+ torture_comment(tctx, "share added\n");
+ return true;
+}
+
+
+bool torture_delshare(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding *binding;
+ struct libnet_context* libnetctx;
+ const char *host;
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_DelShare share;
+
+ host = torture_setting_string(torture, "host", NULL);
+ status = torture_rpc_binding(torture, &binding);
+ torture_assert_ntstatus_ok(torture, status, "Failed to get binding");
+
+ libnetctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ libnetctx->cred = samba_cmdline_get_creds();
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_srvsvc);
+
+ torture_assert_ntstatus_ok(torture, status, "Failed to get rpc connection");
+
+ if (!test_addshare(torture, p->binding_handle, torture, host, TEST_SHARENAME)) {
+ return false;
+ }
+
+ share.in.server_name = dcerpc_binding_get_string_option(binding, "host");
+ share.in.share_name = TEST_SHARENAME;
+
+ status = libnet_DelShare(libnetctx, torture, &share);
+ torture_assert_ntstatus_ok(torture, status, "Failed to delete share");
+
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_user.c b/source4/torture/libnet/libnet_user.c
new file mode 100644
index 0000000..9029827
--- /dev/null
+++ b/source4/torture/libnet/libnet_user.c
@@ -0,0 +1,520 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "lib/cmdline/cmdline.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/libnet/usertest.h"
+#include "torture/libnet/proto.h"
+#include "param/param.h"
+
+
+
+bool torture_createuser(struct torture_context *torture)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx = NULL;
+ struct libnet_CreateUser req;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_createuser");
+
+ if (!test_libnet_context_init(torture, true, &ctx)) {
+ return false;
+ }
+
+ req.in.user_name = TEST_USERNAME;
+ req.in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+ req.out.error_string = NULL;
+
+ status = libnet_CreateUser(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_CreateUser call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, ctx->samr.pipe->binding_handle,
+ mem_ctx, &ctx->samr.handle, TEST_USERNAME)) {
+ torture_comment(torture, "cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, mem_ctx, &ctx->samr.handle)) {
+ torture_comment(torture, "domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_deleteuser(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ const char *name = TEST_USERNAME;
+ struct libnet_context *ctx = NULL;
+ struct libnet_DeleteUser req;
+ bool ret = false;
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ torture_assert_ntstatus_ok(torture, status, "torture_rpc_connection() failed");
+
+ mem_ctx = talloc_init("torture_deleteuser");
+
+ /*
+ * Pre-create a user to be deleted later
+ */
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ ret = test_domain_open(torture, p->binding_handle, &domain_name, mem_ctx, &h, NULL);
+ torture_assert_goto(torture, ret, ret, done, "test_domain_open() failed");
+
+ ret = test_user_create(torture, p->binding_handle, mem_ctx, &h, name, NULL);
+ torture_assert_goto(torture, ret, ret, done, "test_user_create() failed");
+
+ /*
+ * Delete the user using libnet layer
+ */
+ ret = test_libnet_context_init(torture, true, &ctx);
+ torture_assert_goto(torture, ret, ret, done, "test_libnet_context_init() failed");
+
+ req.in.user_name = TEST_USERNAME;
+ req.in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+
+ status = libnet_DeleteUser(ctx, mem_ctx, &req);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done, "libnet_DeleteUser() failed");
+
+ /* mark test as successful */
+ ret = true;
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+/*
+ Generate testing set of random changes
+*/
+
+static void set_test_changes(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r,
+ int num_changes, char **user_name, enum test_fields req_change)
+{
+ const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
+ const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
+ const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
+ const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED),
+ (ACB_NORMAL | ACB_PWNOEXP),
+ (ACB_NORMAL | ACB_PW_EXPIRED) };
+ const char *homedir, *homedrive, *logonscript;
+ struct timeval now;
+ int i, testfld;
+
+ torture_comment(tctx, "Fields to change: [");
+
+ for (i = 0; i < num_changes && i <= USER_FIELD_LAST; i++) {
+ const char *fldname;
+
+ testfld = (req_change == none) ? (random() % USER_FIELD_LAST) + 1 : req_change;
+
+ /* get one in case we hit time field this time */
+ gettimeofday(&now, NULL);
+
+ switch (testfld) {
+ case acct_name:
+ continue_if_field_set(r->in.account_name);
+ r->in.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
+ (int)(random() % 100));
+ fldname = "account_name";
+
+ /* update the test's user name in case it's about to change */
+ *user_name = talloc_strdup(mem_ctx, r->in.account_name);
+ break;
+
+ case acct_full_name:
+ continue_if_field_set(r->in.full_name);
+ r->in.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME,
+ (unsigned int)random(), (unsigned int)random());
+ fldname = "full_name";
+ break;
+
+ case acct_description:
+ continue_if_field_set(r->in.description);
+ r->in.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION,
+ (long)random());
+ fldname = "description";
+ break;
+
+ case acct_home_directory:
+ continue_if_field_set(r->in.home_directory);
+ homedir = home_dirs[random() % ARRAY_SIZE(home_dirs)];
+ r->in.home_directory = talloc_strdup(mem_ctx, homedir);
+ fldname = "home_dir";
+ break;
+
+ case acct_home_drive:
+ continue_if_field_set(r->in.home_drive);
+ homedrive = home_drives[random() % ARRAY_SIZE(home_drives)];
+ r->in.home_drive = talloc_strdup(mem_ctx, homedrive);
+ fldname = "home_drive";
+ break;
+
+ case acct_comment:
+ continue_if_field_set(r->in.comment);
+ r->in.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT,
+ (unsigned long)random(), (unsigned long)random());
+ fldname = "comment";
+ break;
+
+ case acct_logon_script:
+ continue_if_field_set(r->in.logon_script);
+ logonscript = logon_scripts[random() % ARRAY_SIZE(logon_scripts)];
+ r->in.logon_script = talloc_strdup(mem_ctx, logonscript);
+ fldname = "logon_script";
+ break;
+
+ case acct_profile_path:
+ continue_if_field_set(r->in.profile_path);
+ r->in.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH,
+ (unsigned long)random(), (unsigned int)random());
+ fldname = "profile_path";
+ break;
+
+ case acct_expiry:
+ continue_if_field_set(r->in.acct_expiry);
+ now = timeval_add(&now, (random() % (31*24*60*60)), 0);
+ r->in.acct_expiry = (struct timeval *)talloc_memdup(mem_ctx, &now, sizeof(now));
+ fldname = "acct_expiry";
+ break;
+
+ case acct_flags:
+ continue_if_field_set(r->in.acct_flags);
+ r->in.acct_flags = flags[random() % ARRAY_SIZE(flags)];
+ fldname = "acct_flags";
+ break;
+
+ default:
+ fldname = "unknown_field";
+ }
+
+ torture_comment(tctx, ((i < num_changes - 1) ? "%s," : "%s"), fldname);
+
+ /* disable requested field (it's supposed to be the only one used) */
+ if (req_change != none) req_change = none;
+ }
+
+ torture_comment(tctx, "]\n");
+}
+
+
+#define TEST_STR_FLD(fld) \
+ if (!strequal(req.in.fld, user_req.out.fld)) { \
+ torture_comment(torture, "failed to change '%s'\n", #fld); \
+ ret = false; \
+ goto cleanup; \
+ }
+
+#define TEST_TIME_FLD(fld) \
+ if (timeval_compare(req.in.fld, user_req.out.fld)) { \
+ torture_comment(torture, "failed to change '%s'\n", #fld); \
+ ret = false; \
+ goto cleanup; \
+ }
+
+#define TEST_NUM_FLD(fld) \
+ if (req.in.fld != user_req.out.fld) { \
+ torture_comment(torture, "failed to change '%s'\n", #fld); \
+ ret = false; \
+ goto cleanup; \
+ }
+
+
+bool torture_modifyuser(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *prep_mem_ctx;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ char *name;
+ struct libnet_context *ctx = NULL;
+ struct libnet_ModifyUser req;
+ struct libnet_UserInfo user_req;
+ int fld;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+
+ prep_mem_ctx = talloc_init("prepare test_deleteuser");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+ b = p->binding_handle;
+
+ name = talloc_strdup(prep_mem_ctx, TEST_USERNAME);
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ if (!test_domain_open(torture, b, &domain_name, prep_mem_ctx, &h, NULL)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, b, prep_mem_ctx, &h, name, NULL)) {
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(torture, "Testing change of all fields - each single one in turn\n");
+
+ if (!test_libnet_context_init(torture, true, &ctx)) {
+ return false;
+ }
+
+ for (fld = USER_FIELD_FIRST; fld <= USER_FIELD_LAST; fld++) {
+ ZERO_STRUCT(req);
+ req.in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+ req.in.user_name = name;
+
+ set_test_changes(torture, torture, &req, 1, &name, fld);
+
+ status = libnet_ModifyUser(ctx, torture, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_ModifyUser call failed: %s\n", nt_errstr(status));
+ ret = false;
+ continue;
+ }
+
+ ZERO_STRUCT(user_req);
+ user_req.in.domain_name = lpcfg_workgroup(torture->lp_ctx);
+ user_req.in.data.user_name = name;
+ user_req.in.level = USER_INFO_BY_NAME;
+
+ status = libnet_UserInfo(ctx, torture, &user_req);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_UserInfo call failed: %s\n", nt_errstr(status));
+ ret = false;
+ continue;
+ }
+
+ switch (fld) {
+ case acct_name: TEST_STR_FLD(account_name);
+ break;
+ case acct_full_name: TEST_STR_FLD(full_name);
+ break;
+ case acct_comment: TEST_STR_FLD(comment);
+ break;
+ case acct_description: TEST_STR_FLD(description);
+ break;
+ case acct_home_directory: TEST_STR_FLD(home_directory);
+ break;
+ case acct_home_drive: TEST_STR_FLD(home_drive);
+ break;
+ case acct_logon_script: TEST_STR_FLD(logon_script);
+ break;
+ case acct_profile_path: TEST_STR_FLD(profile_path);
+ break;
+ case acct_expiry: TEST_TIME_FLD(acct_expiry);
+ break;
+ case acct_flags: TEST_NUM_FLD(acct_flags);
+ break;
+ default:
+ break;
+ }
+ }
+
+cleanup:
+ if (!test_user_cleanup(torture, ctx->samr.pipe->binding_handle,
+ torture, &ctx->samr.handle, TEST_USERNAME)) {
+ torture_comment(torture, "cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, torture, &ctx->samr.handle)) {
+ torture_comment(torture, "domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(prep_mem_ctx);
+ return ret;
+}
+
+
+bool torture_userinfo_api(struct torture_context *torture)
+{
+ const char *name = TEST_USERNAME;
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL, *prep_mem_ctx;
+ struct libnet_context *ctx = NULL;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct libnet_UserInfo req;
+ struct dcerpc_binding_handle *b;
+
+ prep_mem_ctx = talloc_init("prepare torture user info");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ if (!test_domain_open(torture, b, &domain_name, prep_mem_ctx, &h, NULL)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, b, prep_mem_ctx, &h, name, NULL)) {
+ ret = false;
+ goto done;
+ }
+
+ mem_ctx = talloc_init("torture user info");
+
+ if (!test_libnet_context_init(torture, true, &ctx)) {
+ return false;
+ }
+
+ ZERO_STRUCT(req);
+
+ req.in.domain_name = domain_name.string;
+ req.in.data.user_name = name;
+ req.in.level = USER_INFO_BY_NAME;
+
+ status = libnet_UserInfo(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "libnet_UserInfo call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, ctx->samr.pipe->binding_handle,
+ mem_ctx, &ctx->samr.handle, TEST_USERNAME)) {
+ torture_comment(torture, "cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, mem_ctx, &ctx->samr.handle)) {
+ torture_comment(torture, "domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_userlist(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct libnet_UserList req;
+ int i;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = samba_cmdline_get_creds();
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ mem_ctx = talloc_init("torture user list");
+
+ ZERO_STRUCT(req);
+
+ torture_comment(torture, "listing user accounts:\n");
+
+ do {
+
+ req.in.domain_name = domain_name.string;
+ req.in.page_size = 128;
+ req.in.resume_index = req.out.resume_index;
+
+ status = libnet_UserList(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) break;
+
+ for (i = 0; i < req.out.count; i++) {
+ torture_comment(torture, "\tuser: %s, sid=%s\n",
+ req.out.users[i].username, req.out.users[i].sid);
+ }
+
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (!(NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES))) {
+ torture_comment(torture, "libnet_UserList call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close_handle(torture,
+ ctx->samr.pipe->binding_handle, mem_ctx, &ctx->samr.handle)) {
+ torture_comment(torture, "samr domain close failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_lsa_close_handle(torture,
+ ctx->lsa.pipe->binding_handle, mem_ctx, &ctx->lsa.handle)) {
+ torture_comment(torture, "lsa domain close failed\n");
+ ret = false;
+ }
+
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/python/samr-test.py b/source4/torture/libnet/python/samr-test.py
new file mode 100644
index 0000000..4181e56
--- /dev/null
+++ b/source4/torture/libnet/python/samr-test.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Usage:
+# export ACCOUNT_NAME=kamen
+# export NEW_PASS=test
+# export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
+# PYTHONPATH="$samba4srcdir/torture/libnet/python" $SUBUNITRUN samr-test -Ukma-exch.devel/Administrator%333
+#
+
+import os
+
+from samba import net
+import samba.tests
+
+if "ACCOUNT_NAME" not in os.environ.keys():
+ raise Exception("Please supply ACCOUNT_NAME in environment")
+
+if "NEW_PASS" not in os.environ.keys():
+ raise Exception("Please supply NEW_PASS in environment")
+
+account_name = os.environ["ACCOUNT_NAME"]
+new_pass = os.environ["NEW_PASS"]
+
+#
+# Tests start here
+#
+
+
+class Libnet_SetPwdTest(samba.tests.TestCase):
+
+ ########################################################################################
+
+ def test_SetPassword(self):
+ creds = self.get_credentials()
+ net.SetPassword(account_name=account_name,
+ domain_name=creds.get_domain(),
+ newpassword=new_pass,
+ credentials=creds)
+
+ ########################################################################################
diff --git a/source4/torture/libnet/userinfo.c b/source4/torture/libnet/userinfo.c
new file mode 100644
index 0000000..897273b
--- /dev/null
+++ b/source4/torture/libnet/userinfo.c
@@ -0,0 +1,192 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libnet/libnet.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/proto.h"
+
+
+#define TEST_USERNAME "libnetuserinfotest"
+
+static bool test_userinfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 *domain_sid, const char* user_name,
+ uint32_t *rid)
+{
+ const uint16_t level = 5;
+ NTSTATUS status;
+ struct libnet_rpc_userinfo user;
+ struct dom_sid *user_sid;
+
+ user_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid);
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = dom_sid_string(mem_ctx, user_sid);
+ user.in.level = level; /* this should be extended */
+
+ torture_comment(tctx, "Testing sync libnet_rpc_userinfo (SID argument)\n");
+ status = libnet_rpc_userinfo(tctx->ev, p->binding_handle, mem_ctx, &user);
+ torture_assert_ntstatus_ok(tctx, status, "Calling sync libnet_rpc_userinfo() failed");
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = NULL;
+ user.in.username = user_name;
+ user.in.level = level;
+
+ torture_comment(tctx, "Testing sync libnet_rpc_userinfo (username argument)\n");
+ status = libnet_rpc_userinfo(tctx->ev, p->binding_handle, mem_ctx, &user);
+ torture_assert_ntstatus_ok(tctx, status, "Calling sync libnet_rpc_userinfo failed");
+
+ return true;
+}
+
+
+static bool test_userinfo_async(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 *domain_sid, const char* user_name,
+ uint32_t *rid)
+{
+ const uint16_t level = 10;
+ NTSTATUS status;
+ struct composite_context *c;
+ struct libnet_rpc_userinfo user;
+ struct dom_sid *user_sid;
+
+ user_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid);
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = dom_sid_string(mem_ctx, user_sid);
+ user.in.level = level; /* this should be extended */
+
+ torture_comment(tctx, "Testing async libnet_rpc_userinfo (SID argument)\n");
+
+ c = libnet_rpc_userinfo_send(mem_ctx, tctx->ev, p->binding_handle, &user, msg_handler);
+ torture_assert(tctx, c != NULL, "Failed to call async libnet_rpc_userinfo_send");
+
+ status = libnet_rpc_userinfo_recv(c, mem_ctx, &user);
+ torture_assert_ntstatus_ok(tctx, status, "Calling async libnet_rpc_userinfo_recv failed");
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = NULL;
+ user.in.username = user_name;
+ user.in.level = level;
+
+ torture_comment(tctx, "Testing async libnet_rpc_userinfo (username argument)\n");
+
+ c = libnet_rpc_userinfo_send(mem_ctx, tctx->ev, p->binding_handle, &user, msg_handler);
+ torture_assert(tctx, c != NULL, "Failed to call async libnet_rpc_userinfo_send");
+
+ status = libnet_rpc_userinfo_recv(c, mem_ctx, &user);
+ torture_assert_ntstatus_ok(tctx, status, "Calling async libnet_rpc_userinfo_recv failed");
+
+ return true;
+}
+
+
+bool torture_userinfo(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct policy_handle h;
+ struct lsa_String name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+ struct dcerpc_binding_handle *b;
+
+ mem_ctx = talloc_init("test_userinfo");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ name.string = lpcfg_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ if (!test_domain_open(torture, b, &name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, b, mem_ctx, &h, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_userinfo(torture, p, mem_ctx, &h, &sid, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, b, mem_ctx, &h, TEST_USERNAME)) {
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Testing asynchronous version and monitor messages
+ */
+ if (!test_domain_open(torture, b, &name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, b, mem_ctx, &h, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_userinfo_async(torture, p, mem_ctx, &h, &sid, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, b, mem_ctx, &h, TEST_USERNAME)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/userman.c b/source4/torture/libnet/userman.c
new file mode 100644
index 0000000..8c49bb6
--- /dev/null
+++ b/source4/torture/libnet/userman.c
@@ -0,0 +1,473 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/libnet/usertest.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+
+#include "torture/libnet/proto.h"
+
+
+static bool test_useradd(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_rpc_useradd user;
+
+ user.in.domain_handle = *domain_handle;
+ user.in.username = name;
+
+ torture_comment(tctx, "Testing libnet_rpc_useradd\n");
+
+ status = libnet_rpc_useradd(tctx->ev, p->binding_handle, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to call libnet_rpc_useradd - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return ret;
+}
+
+
+static bool test_useradd_async(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char* username)
+{
+ NTSTATUS status;
+ struct composite_context *c;
+ struct libnet_rpc_useradd user;
+
+ user.in.domain_handle = *handle;
+ user.in.username = username;
+
+ torture_comment(tctx, "Testing async libnet_rpc_useradd\n");
+
+ c = libnet_rpc_useradd_send(mem_ctx, tctx->ev, p->binding_handle,
+ &user, msg_handler);
+ if (!c) {
+ torture_comment(tctx, "Failed to call async libnet_rpc_useradd\n");
+ return false;
+ }
+
+ status = libnet_rpc_useradd_recv(c, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Calling async libnet_rpc_useradd failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+
+}
+
+static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, int num_changes,
+ struct libnet_rpc_usermod *mod, char **username)
+{
+ const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
+ const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
+ const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
+ const char *homedir, *homedrive, *logonscript;
+ const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED),
+ (ACB_NORMAL | ACB_PWNOEXP),
+ (ACB_NORMAL | ACB_PW_EXPIRED) };
+
+ NTSTATUS status;
+ struct timeval now;
+ enum test_fields testfld;
+ int i;
+
+ ZERO_STRUCT(*mod);
+ srandom((unsigned)time(NULL));
+
+ mod->in.username = talloc_strdup(mem_ctx, *username);
+ mod->in.domain_handle = *handle;
+
+ torture_comment(tctx, "modifying user (%d simultaneous change(s))\n",
+ num_changes);
+
+ torture_comment(tctx, "fields to change: [");
+
+ for (i = 0; i < num_changes && i <= USER_FIELD_LAST; i++) {
+ const char *fldname;
+
+ testfld = (random() % USER_FIELD_LAST) + 1;
+
+ GetTimeOfDay(&now);
+
+ switch (testfld) {
+ case acct_name:
+ continue_if_field_set(mod->in.change.account_name);
+ mod->in.change.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
+ (int)(random() % 100));
+ mod->in.change.fields |= USERMOD_FIELD_ACCOUNT_NAME;
+ fldname = "account_name";
+ *username = talloc_strdup(mem_ctx, mod->in.change.account_name);
+ break;
+
+ case acct_full_name:
+ continue_if_field_set(mod->in.change.full_name);
+ mod->in.change.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME,
+ (int)random(), (int)random());
+ mod->in.change.fields |= USERMOD_FIELD_FULL_NAME;
+ fldname = "full_name";
+ break;
+
+ case acct_description:
+ continue_if_field_set(mod->in.change.description);
+ mod->in.change.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION,
+ random());
+ mod->in.change.fields |= USERMOD_FIELD_DESCRIPTION;
+ fldname = "description";
+ break;
+
+ case acct_home_directory:
+ continue_if_field_set(mod->in.change.home_directory);
+ homedir = home_dirs[random() % (sizeof(home_dirs)/sizeof(char*))];
+ mod->in.change.home_directory = talloc_strdup(mem_ctx, homedir);
+ mod->in.change.fields |= USERMOD_FIELD_HOME_DIRECTORY;
+ fldname = "home_directory";
+ break;
+
+ case acct_home_drive:
+ continue_if_field_set(mod->in.change.home_drive);
+ homedrive = home_drives[random() % (sizeof(home_drives)/sizeof(char*))];
+ mod->in.change.home_drive = talloc_strdup(mem_ctx, homedrive);
+ mod->in.change.fields |= USERMOD_FIELD_HOME_DRIVE;
+ fldname = "home_drive";
+ break;
+
+ case acct_comment:
+ continue_if_field_set(mod->in.change.comment);
+ mod->in.change.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT,
+ random(), random());
+ mod->in.change.fields |= USERMOD_FIELD_COMMENT;
+ fldname = "comment";
+ break;
+
+ case acct_logon_script:
+ continue_if_field_set(mod->in.change.logon_script);
+ logonscript = logon_scripts[random() % (sizeof(logon_scripts)/sizeof(char*))];
+ mod->in.change.logon_script = talloc_strdup(mem_ctx, logonscript);
+ mod->in.change.fields |= USERMOD_FIELD_LOGON_SCRIPT;
+ fldname = "logon_script";
+ break;
+
+ case acct_profile_path:
+ continue_if_field_set(mod->in.change.profile_path);
+ mod->in.change.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH,
+ (long int)random(), (unsigned int)random());
+ mod->in.change.fields |= USERMOD_FIELD_PROFILE_PATH;
+ fldname = "profile_path";
+ break;
+
+ case acct_expiry:
+ continue_if_field_set(mod->in.change.acct_expiry);
+ now = timeval_add(&now, (random() % (31*24*60*60)), 0);
+ mod->in.change.acct_expiry = (struct timeval *)talloc_memdup(mem_ctx, &now, sizeof(now));
+ mod->in.change.fields |= USERMOD_FIELD_ACCT_EXPIRY;
+ fldname = "acct_expiry";
+ break;
+
+ case acct_flags:
+ continue_if_field_set(mod->in.change.acct_flags);
+ mod->in.change.acct_flags = flags[random() % ARRAY_SIZE(flags)];
+ mod->in.change.fields |= USERMOD_FIELD_ACCT_FLAGS;
+ fldname = "acct_flags";
+ break;
+
+ default:
+ fldname = talloc_asprintf(mem_ctx, "unknown_field (%d)", testfld);
+ break;
+ }
+
+ torture_comment(tctx, ((i < num_changes - 1) ? "%s," : "%s"), fldname);
+ }
+ torture_comment(tctx, "]\n");
+
+ status = libnet_rpc_usermod(tctx->ev, p->binding_handle, mem_ctx, mod);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to call sync libnet_rpc_usermod");
+
+ return true;
+}
+
+
+static bool test_userdel(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *username)
+{
+ NTSTATUS status;
+ struct libnet_rpc_userdel user;
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *handle;
+ user.in.username = username;
+
+ status = libnet_rpc_userdel(tctx->ev, p->binding_handle, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to call sync libnet_rpc_userdel - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+#define CMP_LSA_STRING_FLD(fld, flags) \
+ if ((mod->in.change.fields & flags) && \
+ !strequal(i->fld.string, mod->in.change.fld)) { \
+ torture_comment(tctx, "'%s' field does not match\n", #fld); \
+ torture_comment(tctx, "received: '%s'\n", i->fld.string); \
+ torture_comment(tctx, "expected: '%s'\n", mod->in.change.fld); \
+ return false; \
+ }
+
+
+#define CMP_TIME_FLD(fld, flags) \
+ if (mod->in.change.fields & flags) { \
+ nttime_to_timeval(&t, i->fld); \
+ if (timeval_compare(&t, mod->in.change.fld)) { \
+ torture_comment(tctx, "'%s' field does not match\n", #fld); \
+ torture_comment(tctx, "received: '%s (+%ld us)'\n", \
+ timestring(mem_ctx, t.tv_sec), (long)t.tv_usec); \
+ torture_comment(tctx, "expected: '%s (+%ld us)'\n", \
+ timestring(mem_ctx, mod->in.change.fld->tv_sec), \
+ (long)mod->in.change.fld->tv_usec); \
+ return false; \
+ } \
+ }
+
+#define CMP_NUM_FLD(fld, flags) \
+ if ((mod->in.change.fields & flags) && \
+ (i->fld != mod->in.change.fld)) { \
+ torture_comment(tctx, "'%s' field does not match\n", #fld); \
+ torture_comment(tctx, "received: '%04x'\n", i->fld); \
+ torture_comment(tctx, "expected: '%04x'\n", mod->in.change.fld); \
+ return false; \
+ }
+
+
+static bool test_compare(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct libnet_rpc_usermod *mod,
+ const char *username)
+{
+ NTSTATUS status;
+ struct libnet_rpc_userinfo info;
+ struct samr_UserInfo21 *i;
+ struct timeval t;
+
+ ZERO_STRUCT(info);
+
+ info.in.username = username;
+ info.in.domain_handle = *handle;
+ info.in.level = 21; /* the most rich infolevel available */
+
+ status = libnet_rpc_userinfo(tctx->ev, p->binding_handle, mem_ctx, &info);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to call sync libnet_rpc_userinfo");
+
+ i = &info.out.info.info21;
+
+ CMP_LSA_STRING_FLD(account_name, USERMOD_FIELD_ACCOUNT_NAME);
+ CMP_LSA_STRING_FLD(full_name, USERMOD_FIELD_FULL_NAME);
+ CMP_LSA_STRING_FLD(description, USERMOD_FIELD_DESCRIPTION);
+ CMP_LSA_STRING_FLD(comment, USERMOD_FIELD_COMMENT);
+ CMP_LSA_STRING_FLD(logon_script, USERMOD_FIELD_LOGON_SCRIPT);
+ CMP_LSA_STRING_FLD(profile_path, USERMOD_FIELD_PROFILE_PATH);
+ CMP_LSA_STRING_FLD(home_directory, USERMOD_FIELD_HOME_DIRECTORY);
+ CMP_LSA_STRING_FLD(home_drive, USERMOD_FIELD_HOME_DRIVE);
+ CMP_TIME_FLD(acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
+ CMP_NUM_FLD(acct_flags, USERMOD_FIELD_ACCT_FLAGS)
+
+ return true;
+}
+
+
+bool torture_useradd(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ const char *name = TEST_USERNAME;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+
+ mem_ctx = talloc_init("test_useradd");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ torture_assert_ntstatus_ok(torture, status, "RPC connect failed");
+ b = p->binding_handle;
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ if (!test_domain_open(torture, b, &domain_name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_useradd(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, b, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_domain_open(torture, b, &domain_name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_useradd_async(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, b, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_userdel(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+ const char *name = TEST_USERNAME;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+
+ mem_ctx = talloc_init("test_userdel");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ if (!test_domain_open(torture, b, &domain_name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, b, mem_ctx, &h, name, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_userdel(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_usermod(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+ int i;
+ char *name;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+
+ mem_ctx = talloc_init("test_userdel");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ torture_assert_ntstatus_ok(torture, status, "RPC connect");
+ b = p->binding_handle;
+
+ domain_name.string = lpcfg_workgroup(torture->lp_ctx);
+ name = talloc_strdup(mem_ctx, TEST_USERNAME);
+
+ if (!test_domain_open(torture, b, &domain_name, mem_ctx, &h, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, b, mem_ctx, &h, name, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ for (i = USER_FIELD_FIRST; i <= USER_FIELD_LAST; i++) {
+ struct libnet_rpc_usermod m;
+
+ if (!test_usermod(torture, p, mem_ctx, &h, i, &m, &name)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (!test_compare(torture, p, mem_ctx, &h, &m, name)) {
+ ret = false;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (!test_user_cleanup(torture, b, mem_ctx, &h, TEST_USERNAME)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/usertest.h b/source4/torture/libnet/usertest.h
new file mode 100644
index 0000000..b3b2dc1
--- /dev/null
+++ b/source4/torture/libnet/usertest.h
@@ -0,0 +1,42 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Rafal Szczesniak 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define TEST_USERNAME "libnetusertest"
+
+#define continue_if_field_set(field) \
+ if (field != 0) { \
+ i--; \
+ continue; \
+ }
+
+
+#define USER_FIELD_FIRST acct_name
+#define USER_FIELD_LAST acct_flags
+
+enum test_fields { none = 0,
+ acct_name, acct_full_name, acct_description,
+ acct_home_directory, acct_home_drive, acct_comment,
+ acct_logon_script, acct_profile_path, acct_expiry, acct_flags };
+
+
+#define TEST_CHG_ACCOUNTNAME "newlibnetusertest%02d"
+#define TEST_CHG_DESCRIPTION "Sample description %ld"
+#define TEST_CHG_FULLNAME "First%04x Last%04x"
+#define TEST_CHG_COMMENT "Comment[%04lu%04lu]"
+#define TEST_CHG_PROFILEPATH "\\\\srv%04ld\\profile%02u\\prof"
diff --git a/source4/torture/libnet/utils.c b/source4/torture/libnet/utils.c
new file mode 100644
index 0000000..c0e0e65
--- /dev/null
+++ b/source4/torture/libnet/utils.c
@@ -0,0 +1,556 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * These are more general use functions shared among the tests.
+ */
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "torture/libnet/proto.h"
+#include "ldb_wrap.h"
+
+/**
+ * Opens handle on Domain using SAMR
+ *
+ * @param _domain_handle [out] Ptr to storage to store Domain handle
+ * @param _dom_sid [out] If NULL, Domain SID won't be returned
+ */
+bool test_domain_open(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct lsa_String *domname,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *_domain_handle,
+ struct dom_sid2 *_dom_sid)
+{
+ struct policy_handle connect_handle;
+ struct policy_handle domain_handle;
+ struct samr_Connect r1;
+ struct samr_LookupDomain r2;
+ struct dom_sid2 *sid = NULL;
+ struct samr_OpenDomain r3;
+
+ torture_comment(tctx, "connecting\n");
+
+ r1.in.system_name = 0;
+ r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r1.out.connect_handle = &connect_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Connect_r(b, mem_ctx, &r1),
+ "Connect failed");
+ torture_assert_ntstatus_ok(tctx, r1.out.result,
+ "Connect failed");
+
+ r2.in.connect_handle = &connect_handle;
+ r2.in.domain_name = domname;
+ r2.out.sid = &sid;
+
+ torture_comment(tctx, "domain lookup on %s\n", domname->string);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_LookupDomain_r(b, mem_ctx, &r2),
+ "LookupDomain failed");
+ torture_assert_ntstatus_ok(tctx, r2.out.result,
+ "LookupDomain failed");
+
+ r3.in.connect_handle = &connect_handle;
+ r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r3.in.sid = *r2.out.sid;
+ r3.out.domain_handle = &domain_handle;
+
+ torture_comment(tctx, "opening domain %s\n", domname->string);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenDomain_r(b, mem_ctx, &r3),
+ "OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, r3.out.result,
+ "OpenDomain failed");
+
+ *_domain_handle = domain_handle;
+
+ if (_dom_sid) {
+ *_dom_sid = **r2.out.sid;
+ }
+
+ /* Close connect_handle, we don't need it anymore */
+ test_samr_close_handle(tctx, b, mem_ctx, &connect_handle);
+
+ return true;
+}
+
+
+/**
+ * Find out user's samAccountName for given
+ * user RDN. We need samAccountName value
+ * when deleting users.
+ */
+static bool _get_account_name_for_user_rdn(struct torture_context *tctx,
+ const char *user_rdn,
+ TALLOC_CTX *mem_ctx,
+ const char **_account_name)
+{
+ const char *url;
+ struct ldb_context *ldb;
+ TALLOC_CTX *tmp_ctx;
+ bool test_res = true;
+ const char *hostname = torture_setting_string(tctx, "host", NULL);
+ int ldb_ret;
+ struct ldb_result *ldb_res;
+ const char *account_name = NULL;
+ static const char *attrs[] = {
+ "samAccountName",
+ NULL
+ };
+
+ torture_assert(tctx, hostname != NULL, "Failed to get hostname");
+
+ tmp_ctx = talloc_new(tctx);
+ torture_assert(tctx, tmp_ctx != NULL, "Failed to create temporary mem context");
+
+ url = talloc_asprintf(tmp_ctx, "ldap://%s/", hostname);
+ torture_assert_goto(tctx, url != NULL, test_res, done, "Failed to allocate URL for ldb");
+
+ ldb = ldb_wrap_connect(tmp_ctx,
+ tctx->ev, tctx->lp_ctx,
+ url, NULL, samba_cmdline_get_creds(), 0);
+ torture_assert_goto(tctx, ldb != NULL, test_res, done, "Failed to make LDB connection");
+
+ ldb_ret = ldb_search(ldb, tmp_ctx, &ldb_res,
+ ldb_get_default_basedn(ldb), LDB_SCOPE_SUBTREE,
+ attrs,
+ "(&(objectClass=user)(name=%s))", user_rdn);
+ if (LDB_SUCCESS == ldb_ret && 1 == ldb_res->count) {
+ account_name = ldb_msg_find_attr_as_string(ldb_res->msgs[0], "samAccountName", NULL);
+ }
+
+ /* return user_rdn by default */
+ if (!account_name) {
+ account_name = user_rdn;
+ }
+
+ /* duplicate memory in parent context */
+ *_account_name = talloc_strdup(mem_ctx, account_name);
+
+done:
+ talloc_free(tmp_ctx);
+ return test_res;
+}
+
+/**
+ * Removes user by RDN through SAMR interface.
+ *
+ * @param domain_handle [in] Domain handle
+ * @param user_rdn [in] User's RDN in ldap database
+ */
+bool test_user_cleanup(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *user_rdn)
+{
+ struct samr_LookupNames r1;
+ struct samr_OpenUser r2;
+ struct samr_DeleteUser r3;
+ struct lsa_String names[2];
+ uint32_t rid;
+ struct policy_handle user_handle;
+ struct samr_Ids rids, types;
+ const char *account_name;
+
+ if (!_get_account_name_for_user_rdn(tctx, user_rdn, mem_ctx, &account_name)) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__": Failed to find samAccountName for %s", user_rdn);
+ return false;
+ }
+
+ names[0].string = account_name;
+
+ r1.in.domain_handle = domain_handle;
+ r1.in.num_names = 1;
+ r1.in.names = names;
+ r1.out.rids = &rids;
+ r1.out.types = &types;
+
+ torture_comment(tctx, "user account lookup '%s'\n", account_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_LookupNames_r(b, mem_ctx, &r1),
+ "LookupNames failed");
+ torture_assert_ntstatus_ok(tctx, r1.out.result,
+ "LookupNames failed");
+
+ rid = r1.out.rids->ids[0];
+
+ r2.in.domain_handle = domain_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.rid = rid;
+ r2.out.user_handle = &user_handle;
+
+ torture_comment(tctx, "opening user account\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenUser_r(b, mem_ctx, &r2),
+ "OpenUser failed");
+ torture_assert_ntstatus_ok(tctx, r2.out.result,
+ "OpenUser failed");
+
+ r3.in.user_handle = &user_handle;
+ r3.out.user_handle = &user_handle;
+
+ torture_comment(tctx, "deleting user account\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_DeleteUser_r(b, mem_ctx, &r3),
+ "DeleteUser failed");
+ torture_assert_ntstatus_ok(tctx, r3.out.result,
+ "DeleteUser failed");
+
+ return true;
+}
+
+
+/**
+ * Creates new user using SAMR
+ *
+ * @param name [in] Username for user to create
+ * @param rid [out] If NULL, User's RID is not returned
+ */
+bool test_user_create(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name,
+ uint32_t *rid)
+{
+ struct policy_handle user_handle;
+ struct lsa_String username;
+ struct samr_CreateUser r;
+ uint32_t user_rid;
+
+ username.string = name;
+
+ r.in.domain_handle = domain_handle;
+ r.in.account_name = &username;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.user_handle = &user_handle;
+ /* return user's RID only if requested */
+ r.out.rid = rid ? rid : &user_rid;
+
+ torture_comment(tctx, "creating user '%s'\n", username.string);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_CreateUser_r(b, mem_ctx, &r),
+ "CreateUser RPC call failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "CreateUser failed - %s\n", nt_errstr(r.out.result));
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) {
+ torture_comment(tctx,
+ "User (%s) already exists - "
+ "attempting to delete and recreate account again\n",
+ username.string);
+ if (!test_user_cleanup(tctx, b, mem_ctx, domain_handle, username.string)) {
+ return false;
+ }
+
+ torture_comment(tctx, "creating user account\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_CreateUser_r(b, mem_ctx, &r),
+ "CreateUser RPC call failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "CreateUser failed");
+
+ /* be nice and close opened handles */
+ test_samr_close_handle(tctx, b, mem_ctx, &user_handle);
+
+ return true;
+ }
+ return false;
+ }
+
+ /* be nice and close opened handles */
+ test_samr_close_handle(tctx, b, mem_ctx, &user_handle);
+
+ return true;
+}
+
+
+/**
+ * Deletes a Group using SAMR interface
+ */
+bool test_group_cleanup(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ struct samr_LookupNames r1;
+ struct samr_OpenGroup r2;
+ struct samr_DeleteDomainGroup r3;
+ struct lsa_String names[2];
+ uint32_t rid;
+ struct policy_handle group_handle;
+ struct samr_Ids rids, types;
+
+ names[0].string = name;
+
+ r1.in.domain_handle = domain_handle;
+ r1.in.num_names = 1;
+ r1.in.names = names;
+ r1.out.rids = &rids;
+ r1.out.types = &types;
+
+ torture_comment(tctx, "group account lookup '%s'\n", name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_LookupNames_r(b, mem_ctx, &r1),
+ "LookupNames failed");
+ torture_assert_ntstatus_ok(tctx, r1.out.result,
+ "LookupNames failed");
+
+ rid = r1.out.rids->ids[0];
+
+ r2.in.domain_handle = domain_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.rid = rid;
+ r2.out.group_handle = &group_handle;
+
+ torture_comment(tctx, "opening group account\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenGroup_r(b, mem_ctx, &r2),
+ "OpenGroup failed");
+ torture_assert_ntstatus_ok(tctx, r2.out.result,
+ "OpenGroup failed");
+
+ r3.in.group_handle = &group_handle;
+ r3.out.group_handle = &group_handle;
+
+ torture_comment(tctx, "deleting group account\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_DeleteDomainGroup_r(b, mem_ctx, &r3),
+ "DeleteGroup failed");
+ torture_assert_ntstatus_ok(tctx, r3.out.result,
+ "DeleteGroup failed");
+
+ return true;
+}
+
+
+/**
+ * Creates a Group object using SAMR interface
+ *
+ * @param group_name [in] Name of the group to create
+ * @param rid [out] RID of group created. May be NULL in
+ * which case RID is not required by caller
+ */
+bool test_group_create(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle,
+ const char *group_name,
+ uint32_t *rid)
+{
+ uint32_t group_rid;
+ struct lsa_String groupname;
+ struct samr_CreateDomainGroup r;
+ struct policy_handle group_handle;
+
+ groupname.string = group_name;
+
+ r.in.domain_handle = handle;
+ r.in.name = &groupname;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.group_handle = &group_handle;
+ /* use local variable in case caller
+ * don't care about the group RID */
+ r.out.rid = rid ? rid : &group_rid;
+
+ torture_comment(tctx, "creating group account %s\n", group_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_CreateDomainGroup_r(b, mem_ctx, &r),
+ "CreateGroup failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "CreateGroup failed - %s\n", nt_errstr(r.out.result));
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_GROUP_EXISTS)) {
+ torture_comment(tctx,
+ "Group (%s) already exists - "
+ "attempting to delete and recreate group again\n",
+ group_name);
+ if (!test_group_cleanup(tctx, b, mem_ctx, handle, group_name)) {
+ return false;
+ }
+
+ torture_comment(tctx, "creating group account\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_CreateDomainGroup_r(b, mem_ctx, &r),
+ "CreateGroup failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "CreateGroup failed");
+
+ /* be nice and close opened handles */
+ test_samr_close_handle(tctx, b, mem_ctx, &group_handle);
+
+ return true;
+ }
+ return false;
+ }
+
+ /* be nice and close opened handles */
+ test_samr_close_handle(tctx, b, mem_ctx, &group_handle);
+
+ return true;
+}
+
+/**
+ * Closes SAMR handle obtained from Connect, Open User/Domain, etc
+ */
+bool test_samr_close_handle(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *samr_handle)
+{
+ struct samr_Close r;
+
+ r.in.handle = samr_handle;
+ r.out.handle = samr_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Close_r(b, mem_ctx, &r),
+ "Close SAMR handle RPC call failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Close SAMR handle failed");
+
+ return true;
+}
+
+/**
+ * Closes LSA handle obtained from Connect, Open Group, etc
+ */
+bool test_lsa_close_handle(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *lsa_handle)
+{
+ struct lsa_Close r;
+
+ r.in.handle = lsa_handle;
+ r.out.handle = lsa_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_Close_r(b, mem_ctx, &r),
+ "Close LSA handle RPC call failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Close LSA handle failed");
+
+ return true;
+}
+
+/**
+ * Create and initialize libnet_context Context.
+ * Use this function in cases where we need to have SAMR and LSA pipes
+ * of libnet_context to be connected before executing any other
+ * libnet call
+ *
+ * @param rpc_connect [in] Connects SAMR and LSA pipes
+ */
+bool test_libnet_context_init(struct torture_context *tctx,
+ bool rpc_connect,
+ struct libnet_context **_net_ctx)
+{
+ NTSTATUS status;
+ bool bret = true;
+ struct libnet_context *net_ctx;
+
+ net_ctx = libnet_context_init(tctx->ev, tctx->lp_ctx);
+ torture_assert(tctx, net_ctx != NULL, "Failed to create libnet_context");
+
+ /* Use command line credentials for testing */
+ net_ctx->cred = samba_cmdline_get_creds();
+
+ if (rpc_connect) {
+ /* connect SAMR pipe */
+ status = torture_rpc_connection(tctx,
+ &net_ctx->samr.pipe,
+ &ndr_table_samr);
+ torture_assert_ntstatus_ok_goto(tctx, status, bret, done,
+ "Failed to connect SAMR pipe");
+
+ net_ctx->samr.samr_handle = net_ctx->samr.pipe->binding_handle;
+
+ /* connect LSARPC pipe */
+ status = torture_rpc_connection(tctx,
+ &net_ctx->lsa.pipe,
+ &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok_goto(tctx, status, bret, done,
+ "Failed to connect LSA pipe");
+
+ net_ctx->lsa.lsa_handle = net_ctx->lsa.pipe->binding_handle;
+ }
+
+ *_net_ctx = net_ctx;
+
+done:
+ if (!bret) {
+ /* a previous call has failed,
+ * clean up memory before exit */
+ talloc_free(net_ctx);
+ }
+ return bret;
+}
+
+
+void msg_handler(struct monitor_msg *m)
+{
+ struct msg_rpc_open_user *msg_open;
+ struct msg_rpc_query_user *msg_query;
+ struct msg_rpc_close_user *msg_close;
+ struct msg_rpc_create_user *msg_create;
+
+ switch (m->type) {
+ case mon_SamrOpenUser:
+ msg_open = (struct msg_rpc_open_user*)m->data;
+ printf("monitor_msg: user opened (rid=%d, access_mask=0x%08x)\n",
+ msg_open->rid, msg_open->access_mask);
+ break;
+ case mon_SamrQueryUser:
+ msg_query = (struct msg_rpc_query_user*)m->data;
+ printf("monitor_msg: user queried (level=%d)\n", msg_query->level);
+ break;
+ case mon_SamrCloseUser:
+ msg_close = (struct msg_rpc_close_user*)m->data;
+ printf("monitor_msg: user closed (rid=%d)\n", msg_close->rid);
+ break;
+ case mon_SamrCreateUser:
+ msg_create = (struct msg_rpc_create_user*)m->data;
+ printf("monitor_msg: user created (rid=%d)\n", msg_create->rid);
+ break;
+ }
+}
diff --git a/source4/torture/libnetapi/libnetapi.c b/source4/torture/libnetapi/libnetapi.c
new file mode 100644
index 0000000..fa6dcef
--- /dev/null
+++ b/source4/torture/libnetapi/libnetapi.c
@@ -0,0 +1,94 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "source3/include/includes.h"
+#include "torture/smbtorture.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "source3/lib/netapi/netapi.h"
+#include "source3/lib/netapi/netapi_private.h"
+#include "lib/param/param.h"
+#include "torture/libnetapi/proto.h"
+
+bool torture_libnetapi_init_context(struct torture_context *tctx,
+ struct libnetapi_ctx **ctx_p)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+
+ if (!lp_load_global(lpcfg_configfile(tctx->lp_ctx))) {
+ fprintf(stderr, "error loading %s\n", lpcfg_configfile(tctx->lp_ctx));
+ talloc_free(frame);
+ return W_ERROR_V(WERR_GEN_FAILURE);
+ }
+
+ load_interfaces();
+
+ status = libnetapi_net_init(&ctx, tctx->lp_ctx, creds);
+ if (status != 0) {
+ talloc_free(frame);
+ return false;
+ }
+
+ *ctx_p = ctx;
+
+ talloc_free(frame);
+ return true;
+}
+
+static bool torture_libnetapi_initialize(struct torture_context *tctx)
+{
+ NET_API_STATUS status;
+ struct libnetapi_ctx *ctx;
+
+ /* We must do this first, as otherwise we fail if we don't
+ * have an smb.conf in the default path (we need to use the
+ * torture smb.conf */
+ torture_assert(tctx, torture_libnetapi_init_context(tctx, &ctx),
+ "failed to initialize libnetapi");
+
+ status = libnetapi_init(&ctx);
+
+ torture_assert(tctx, ctx != NULL, "Failed to get a libnetapi_ctx");
+ torture_assert_int_equal(tctx, status, 0, "libnetapi_init failed despite already being set up");
+
+ libnetapi_free(ctx);
+
+ return true;
+}
+
+NTSTATUS torture_libnetapi_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(ctx, "netapi");
+
+ torture_suite_add_simple_test(suite, "server", torture_libnetapi_server);
+ torture_suite_add_simple_test(suite, "group", torture_libnetapi_group);
+ torture_suite_add_simple_test(suite, "user", torture_libnetapi_user);
+ torture_suite_add_simple_test(suite, "initialize", torture_libnetapi_initialize);
+
+ suite->description = talloc_strdup(suite, "libnetapi convenience interface tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/libnetapi/libnetapi_group.c b/source4/torture/libnetapi/libnetapi_group.c
new file mode 100644
index 0000000..6f6d3e2
--- /dev/null
+++ b/source4/torture/libnetapi/libnetapi_group.c
@@ -0,0 +1,522 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include <netapi.h>
+#include "torture/libnetapi/proto.h"
+
+#undef strcasecmp
+
+#define TORTURE_TEST_USER "testuser"
+
+#define NETAPI_STATUS(tctx, x,y,fn) \
+ torture_warning(tctx, "FAILURE: line %d: %s failed with status: %s (%d)\n", \
+ __LINE__, fn, libnetapi_get_error_string(x,y), y);
+
+#define NETAPI_STATUS_MSG(tctx, x,y,fn,z) \
+ torture_warning(tctx, "FAILURE: line %d: %s failed with status: %s (%d), %s\n", \
+ __LINE__, fn, libnetapi_get_error_string(x,y), y, z);
+
+static NET_API_STATUS test_netgroupenum(struct torture_context *tctx,
+ const char *hostname,
+ uint32_t level,
+ const char *groupname)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int found_group = 0;
+ const char *current_name = NULL;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct GROUP_INFO_0 *info0 = NULL;
+ struct GROUP_INFO_1 *info1 = NULL;
+ struct GROUP_INFO_2 *info2 = NULL;
+ struct GROUP_INFO_3 *info3 = NULL;
+
+ torture_comment(tctx, "Testing NetGroupEnum level %d\n", level);
+
+ do {
+ status = NetGroupEnum(hostname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ info0 = (struct GROUP_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_INFO_1 *)buffer;
+ break;
+ case 2:
+ info2 = (struct GROUP_INFO_2 *)buffer;
+ break;
+ case 3:
+ info3 = (struct GROUP_INFO_3 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = info0->grpi0_name;
+ break;
+ case 1:
+ current_name = info1->grpi1_name;
+ break;
+ case 2:
+ current_name = info2->grpi2_name;
+ break;
+ case 3:
+ current_name = info3->grpi3_name;
+ break;
+ default:
+ break;
+ }
+
+ if (strcasecmp(current_name, groupname) == 0) {
+ found_group = 1;
+ }
+
+ switch (level) {
+ case 0:
+ info0++;
+ break;
+ case 1:
+ info1++;
+ break;
+ case 2:
+ info2++;
+ break;
+ case 3:
+ info3++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (!found_group) {
+ torture_comment(tctx, "failed to get group\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static NET_API_STATUS test_netgroupgetusers(struct torture_context *tctx,
+ const char *hostname,
+ uint32_t level,
+ const char *groupname,
+ const char *username)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ int found_user = 0;
+ const char *current_name = NULL;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct GROUP_USERS_INFO_0 *info0 = NULL;
+ struct GROUP_USERS_INFO_1 *info1 = NULL;
+
+ torture_comment(tctx, "Testing NetGroupGetUsers level %d\n", level);
+
+ do {
+ status = NetGroupGetUsers(hostname,
+ groupname,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+
+ switch (level) {
+ case 0:
+ info0 = (struct GROUP_USERS_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct GROUP_USERS_INFO_1 *)buffer;
+ break;
+ default:
+ break;
+ }
+ for (i=0; i<entries_read; i++) {
+ switch (level) {
+ case 0:
+ current_name = info0->grui0_name;
+ break;
+ case 1:
+ current_name = info1->grui1_name;
+ break;
+ default:
+ break;
+ }
+
+ if (username && strcasecmp(current_name, username) == 0) {
+ found_user = 1;
+ }
+
+ switch (level) {
+ case 0:
+ info0++;
+ break;
+ case 1:
+ info1++;
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (username && !found_user) {
+ torture_comment(tctx, "failed to get user\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static NET_API_STATUS test_netgroupsetusers(struct torture_context *tctx,
+ const char *hostname,
+ const char *groupname,
+ uint32_t level,
+ size_t num_entries,
+ const char **names)
+{
+ NET_API_STATUS status;
+ uint8_t *buffer = NULL;
+ int i = 0;
+ size_t buf_size = 0;
+
+ struct GROUP_USERS_INFO_0 *g0 = NULL;
+ struct GROUP_USERS_INFO_1 *g1 = NULL;
+
+ torture_comment(tctx, "Testing NetGroupSetUsers level %d\n", level);
+
+ switch (level) {
+ case 0:
+ buf_size = sizeof(struct GROUP_USERS_INFO_0) * num_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g0);
+ if (status) {
+ goto out;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ g0[i].grui0_name = names[i];
+ }
+
+ buffer = (uint8_t *)g0;
+ break;
+ case 1:
+ buf_size = sizeof(struct GROUP_USERS_INFO_1) * num_entries;
+
+ status = NetApiBufferAllocate(buf_size, (void **)&g1);
+ if (status) {
+ goto out;
+ }
+
+ for (i=0; i<num_entries; i++) {
+ g1[i].grui1_name = names[i];
+ }
+
+ buffer = (uint8_t *)g1;
+ break;
+ default:
+ break;
+ }
+
+ /* NetGroupSetUsers */
+
+ status = NetGroupSetUsers(hostname,
+ groupname,
+ level,
+ buffer,
+ num_entries);
+ if (status) {
+ goto out;
+ }
+
+ out:
+ NetApiBufferFree(buffer);
+ return status;
+}
+
+bool torture_libnetapi_group(struct torture_context *tctx)
+{
+ NET_API_STATUS status = 0;
+ const char *username, *groupname, *groupname2;
+ uint8_t *buffer = NULL;
+ struct GROUP_INFO_0 g0;
+ uint32_t parm_err = 0;
+ uint32_t levels[] = { 0, 1, 2, 3};
+ uint32_t enum_levels[] = { 0, 1, 2, 3};
+ uint32_t getmem_levels[] = { 0, 1};
+ int i;
+ const char *hostname = torture_setting_string(tctx, "host", NULL);
+ struct libnetapi_ctx *ctx;
+
+ torture_assert(tctx, torture_libnetapi_init_context(tctx, &ctx),
+ "failed to initialize libnetapi");
+
+ torture_comment(tctx, "NetGroup tests\n");
+
+ username = "torture_test_user";
+ groupname = "torture_test_group";
+ groupname2 = "torture_test_group2";
+
+ /* cleanup */
+ NetGroupDel(hostname, groupname);
+ NetGroupDel(hostname, groupname2);
+ NetUserDel(hostname, username);
+
+ /* add a group */
+
+ g0.grpi0_name = groupname;
+
+ torture_comment(tctx, "Testing NetGroupAdd\n");
+
+ status = NetGroupAdd(hostname, 0, (uint8_t *)&g0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupAdd");
+ goto out;
+ }
+
+ /* 2nd add must fail */
+
+ status = NetGroupAdd(hostname, 0, (uint8_t *)&g0, &parm_err);
+ if (status == 0) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupAdd");
+ status = -1;
+ goto out;
+ }
+
+ /* test enum */
+
+ for (i=0; i<ARRAY_SIZE(enum_levels); i++) {
+
+ status = test_netgroupenum(tctx, hostname, enum_levels[i], groupname);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupEnum");
+ goto out;
+ }
+ }
+
+ /* basic queries */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ torture_comment(tctx, "Testing NetGroupGetInfo level %d\n", levels[i]);
+
+ status = NetGroupGetInfo(hostname, groupname, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetInfo");
+ goto out;
+ }
+ }
+
+ /* group rename */
+
+ g0.grpi0_name = groupname2;
+
+ torture_comment(tctx, "Testing NetGroupSetInfo level 0\n");
+
+ status = NetGroupSetInfo(hostname, groupname, 0, (uint8_t *)&g0, &parm_err);
+ switch ((uint32_t)status) {
+ case 0:
+ break;
+ case 50: /* not supported */
+ case 124: /* not implemented */
+ groupname2 = groupname;
+ goto skip_rename;
+ default:
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupSetInfo");
+ goto out;
+ }
+
+ /* should not exist anymore */
+
+ status = NetGroupDel(hostname, groupname);
+ if (status == 0) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupDel");
+ goto out;
+ }
+
+ skip_rename:
+ /* query info */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ status = NetGroupGetInfo(hostname, groupname2, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetInfo");
+ goto out;
+ }
+ }
+
+ /* add user to group */
+
+ status = test_netuseradd(tctx, hostname, username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserAdd");
+ goto out;
+ }
+
+ /* should not be member */
+
+ for (i=0; i<ARRAY_SIZE(getmem_levels); i++) {
+
+ status = test_netgroupgetusers(tctx, hostname, getmem_levels[i], groupname2, NULL);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetUsers");
+ goto out;
+ }
+ }
+
+ torture_comment(tctx, "Testing NetGroupAddUser\n");
+
+ status = NetGroupAddUser(hostname, groupname2, username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupAddUser");
+ goto out;
+ }
+
+ /* should be member */
+
+ for (i=0; i<ARRAY_SIZE(getmem_levels); i++) {
+
+ status = test_netgroupgetusers(tctx, hostname, getmem_levels[i], groupname2, username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetUsers");
+ goto out;
+ }
+ }
+
+ torture_comment(tctx, "Testing NetGroupDelUser\n");
+
+ status = NetGroupDelUser(hostname, groupname2, username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupDelUser");
+ goto out;
+ }
+
+ /* should not be member */
+
+ status = test_netgroupgetusers(tctx, hostname, 0, groupname2, NULL);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetUsers");
+ goto out;
+ }
+
+ /* set it again via explicit member set */
+
+ status = test_netgroupsetusers(tctx, hostname, groupname2, 0, 1, &username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupSetUsers");
+ goto out;
+ }
+
+ /* should be member */
+
+ status = test_netgroupgetusers(tctx, hostname, 0, groupname2, username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetUsers");
+ goto out;
+ }
+#if 0
+ /* wipe out member list */
+
+ status = test_netgroupsetusers(hostname, groupname2, 0, 0, NULL);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupSetUsers");
+ goto out;
+ }
+
+ /* should not be member */
+
+ status = test_netgroupgetusers(hostname, 0, groupname2, NULL);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupGetUsers");
+ goto out;
+ }
+#endif
+ status = NetUserDel(hostname, username);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserDel");
+ goto out;
+ }
+
+ /* delete */
+
+ torture_comment(tctx, "Testing NetGroupDel\n");
+
+ status = NetGroupDel(hostname, groupname2);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetGroupDel");
+ goto out;
+ };
+
+ /* should not exist anymore */
+
+ status = NetGroupGetInfo(hostname, groupname2, 0, &buffer);
+ if (status == 0) {
+ NETAPI_STATUS_MSG(tctx, ctx, status, "NetGroupGetInfo", "expected failure and error code");
+ status = -1;
+ goto out;
+ };
+
+ status = 0;
+
+ torture_comment(tctx, "NetGroup tests succeeded\n");
+ out:
+ if (status != 0) {
+ torture_comment(tctx, "NetGroup testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ libnetapi_free(ctx);
+ return false;
+ }
+
+ libnetapi_free(ctx);
+ return true;
+}
diff --git a/source4/torture/libnetapi/libnetapi_server.c b/source4/torture/libnetapi/libnetapi_server.c
new file mode 100644
index 0000000..1888009
--- /dev/null
+++ b/source4/torture/libnetapi/libnetapi_server.c
@@ -0,0 +1,76 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include <netapi.h>
+#include "torture/libnetapi/proto.h"
+
+#define NETAPI_STATUS(tctx, x,y,fn) \
+ torture_warning(tctx, "FAILURE: line %d: %s failed with status: %s (%d)\n", \
+ __LINE__, fn, libnetapi_get_error_string(x,y), y);
+
+bool torture_libnetapi_server(struct torture_context *tctx)
+{
+ NET_API_STATUS status = 0;
+ uint8_t *buffer = NULL;
+ int i;
+
+ const char *hostname = torture_setting_string(tctx, "host", NULL);
+ struct libnetapi_ctx *ctx;
+
+ torture_assert(tctx, torture_libnetapi_init_context(tctx, &ctx),
+ "failed to initialize libnetapi");
+
+ torture_comment(tctx, "NetServer tests\n");
+
+ torture_comment(tctx, "Testing NetRemoteTOD\n");
+
+ status = NetRemoteTOD(hostname, &buffer);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetRemoteTOD");
+ goto out;
+ }
+ NetApiBufferFree(buffer);
+
+ torture_comment(tctx, "Testing NetRemoteTOD 10 times\n");
+
+ for (i=0; i<10; i++) {
+ status = NetRemoteTOD(hostname, &buffer);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetRemoteTOD");
+ goto out;
+ }
+ NetApiBufferFree(buffer);
+ }
+
+ status = 0;
+
+ torture_comment(tctx, "NetServer tests succeeded\n");
+ out:
+ if (status != 0) {
+ torture_comment(tctx, "NetServer testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ libnetapi_free(ctx);
+ return false;
+ }
+
+ libnetapi_free(ctx);
+ return true;
+}
diff --git a/source4/torture/libnetapi/libnetapi_user.c b/source4/torture/libnetapi/libnetapi_user.c
new file mode 100644
index 0000000..1411d7e
--- /dev/null
+++ b/source4/torture/libnetapi/libnetapi_user.c
@@ -0,0 +1,487 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include <netapi.h>
+#include "torture/libnetapi/proto.h"
+
+#undef strcasecmp
+
+#define TORTURE_TEST_USER "torture_testuser"
+#define TORTURE_TEST_USER2 "torture_testuser2"
+
+#define NETAPI_STATUS(tctx, x,y,fn) \
+ torture_warning(tctx, "FAILURE: line %d: %s failed with status: %s (%d)\n", \
+ __LINE__, fn, libnetapi_get_error_string(x,y), y);
+
+static NET_API_STATUS test_netuserenum(struct torture_context *tctx,
+ const char *hostname,
+ uint32_t level,
+ const char *username)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ uint32_t resume_handle = 0;
+ const char *current_name = NULL;
+ int found_user = 0;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct USER_INFO_0 *info0 = NULL;
+ struct USER_INFO_1 *info1 = NULL;
+ struct USER_INFO_2 *info2 = NULL;
+ struct USER_INFO_3 *info3 = NULL;
+ struct USER_INFO_4 *info4 = NULL;
+ struct USER_INFO_10 *info10 = NULL;
+ struct USER_INFO_11 *info11 = NULL;
+ struct USER_INFO_20 *info20 = NULL;
+ struct USER_INFO_23 *info23 = NULL;
+
+ torture_comment(tctx, "Testing NetUserEnum level %d\n", level);
+
+ do {
+ status = NetUserEnum(hostname,
+ level,
+ FILTER_NORMAL_ACCOUNT,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries,
+ &resume_handle);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ info0 = (struct USER_INFO_0 *)buffer;
+ break;
+ case 1:
+ info1 = (struct USER_INFO_1 *)buffer;
+ break;
+ case 2:
+ info2 = (struct USER_INFO_2 *)buffer;
+ break;
+ case 3:
+ info3 = (struct USER_INFO_3 *)buffer;
+ break;
+ case 4:
+ info4 = (struct USER_INFO_4 *)buffer;
+ break;
+ case 10:
+ info10 = (struct USER_INFO_10 *)buffer;
+ break;
+ case 11:
+ info11 = (struct USER_INFO_11 *)buffer;
+ break;
+ case 20:
+ info20 = (struct USER_INFO_20 *)buffer;
+ break;
+ case 23:
+ info23 = (struct USER_INFO_23 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = info0->usri0_name;
+ break;
+ case 1:
+ current_name = info1->usri1_name;
+ break;
+ case 2:
+ current_name = info2->usri2_name;
+ break;
+ case 3:
+ current_name = info3->usri3_name;
+ break;
+ case 4:
+ current_name = info4->usri4_name;
+ break;
+ case 10:
+ current_name = info10->usri10_name;
+ break;
+ case 11:
+ current_name = info11->usri11_name;
+ break;
+ case 20:
+ current_name = info20->usri20_name;
+ break;
+ case 23:
+ current_name = info23->usri23_name;
+ break;
+ default:
+ return -1;
+ }
+
+ if (strcasecmp(current_name, username) == 0) {
+ found_user = 1;
+ }
+
+ switch (level) {
+ case 0:
+ info0++;
+ break;
+ case 1:
+ info1++;
+ break;
+ case 2:
+ info2++;
+ break;
+ case 3:
+ info3++;
+ break;
+ case 4:
+ info4++;
+ break;
+ case 10:
+ info10++;
+ break;
+ case 11:
+ info11++;
+ break;
+ case 20:
+ info20++;
+ break;
+ case 23:
+ info23++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (!found_user) {
+ torture_comment(tctx, "failed to get user\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+NET_API_STATUS test_netuseradd(struct torture_context *tctx,
+ const char *hostname,
+ const char *username)
+{
+ struct USER_INFO_1 u1;
+ uint32_t parm_err = 0;
+
+ ZERO_STRUCT(u1);
+
+ torture_comment(tctx, "Testing NetUserAdd\n");
+
+ u1.usri1_name = username;
+ u1.usri1_password = "W297!832jD8J";
+ u1.usri1_password_age = 0;
+ u1.usri1_priv = 0;
+ u1.usri1_home_dir = NULL;
+ u1.usri1_comment = "User created using Samba NetApi Example code";
+ u1.usri1_flags = 0;
+ u1.usri1_script_path = NULL;
+
+ return NetUserAdd(hostname, 1, (uint8_t *)&u1, &parm_err);
+}
+
+static NET_API_STATUS test_netusermodals(struct torture_context *tctx,
+ struct libnetapi_ctx *ctx,
+ const char *hostname)
+{
+ NET_API_STATUS status;
+ struct USER_MODALS_INFO_0 *u0 = NULL;
+ struct USER_MODALS_INFO_0 *_u0 = NULL;
+ uint8_t *buffer = NULL;
+ uint32_t parm_err = 0;
+ uint32_t levels[] = { 0, 1, 2, 3 };
+ int i = 0;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ torture_comment(tctx, "Testing NetUserModalsGet level %d\n", levels[i]);
+
+ status = NetUserModalsGet(hostname, levels[i], &buffer);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserModalsGet");
+ return status;
+ }
+ }
+
+ status = NetUserModalsGet(hostname, 0, (uint8_t **)&u0);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserModalsGet");
+ return status;
+ }
+
+ torture_comment(tctx, "Testing NetUserModalsSet\n");
+
+ status = NetUserModalsSet(hostname, 0, (uint8_t *)u0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserModalsSet");
+ return status;
+ }
+
+ status = NetUserModalsGet(hostname, 0, (uint8_t **)&_u0);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserModalsGet");
+ return status;
+ }
+
+ if (memcmp(u0, _u0, sizeof(*u0)) != 0) {
+ torture_comment(tctx, "USER_MODALS_INFO_0 struct has changed!!!!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static NET_API_STATUS test_netusergetgroups(struct torture_context *tctx,
+ const char *hostname,
+ uint32_t level,
+ const char *username,
+ const char *groupname)
+{
+ NET_API_STATUS status;
+ uint32_t entries_read = 0;
+ uint32_t total_entries = 0;
+ const char *current_name;
+ int found_group = 0;
+ uint8_t *buffer = NULL;
+ int i;
+
+ struct GROUP_USERS_INFO_0 *i0 = NULL;
+ struct GROUP_USERS_INFO_1 *i1 = NULL;
+
+ torture_comment(tctx, "Testing NetUserGetGroups level %d\n", level);
+
+ do {
+ status = NetUserGetGroups(hostname,
+ username,
+ level,
+ &buffer,
+ (uint32_t)-1,
+ &entries_read,
+ &total_entries);
+ if (status == 0 || status == ERROR_MORE_DATA) {
+ switch (level) {
+ case 0:
+ i0 = (struct GROUP_USERS_INFO_0 *)buffer;
+ break;
+ case 1:
+ i1 = (struct GROUP_USERS_INFO_1 *)buffer;
+ break;
+ default:
+ return -1;
+ }
+
+ for (i=0; i<entries_read; i++) {
+
+ switch (level) {
+ case 0:
+ current_name = i0->grui0_name;
+ break;
+ case 1:
+ current_name = i1->grui1_name;
+ break;
+ default:
+ return -1;
+ }
+
+ if (groupname && strcasecmp(current_name, groupname) == 0) {
+ found_group = 1;
+ }
+
+ switch (level) {
+ case 0:
+ i0++;
+ break;
+ case 1:
+ i1++;
+ break;
+ default:
+ break;
+ }
+ }
+ NetApiBufferFree(buffer);
+ }
+ } while (status == ERROR_MORE_DATA);
+
+ if (status) {
+ return status;
+ }
+
+ if (groupname && !found_group) {
+ torture_comment(tctx, "failed to get membership\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+bool torture_libnetapi_user(struct torture_context *tctx)
+{
+ NET_API_STATUS status = 0;
+ uint8_t *buffer = NULL;
+ uint32_t levels[] = { 0, 1, 2, 3, 4, 10, 11, 20, 23 };
+ uint32_t enum_levels[] = { 0, 1, 2, 3, 4, 10, 11, 20, 23 };
+ uint32_t getgr_levels[] = { 0, 1 };
+ int i;
+
+ struct USER_INFO_0 u0;
+ struct USER_INFO_1007 u1007;
+ uint32_t parm_err = 0;
+
+ const char *hostname = torture_setting_string(tctx, "host", NULL);
+ struct libnetapi_ctx *ctx;
+
+ torture_assert(tctx, torture_libnetapi_init_context(tctx, &ctx),
+ "failed to initialize libnetapi");
+
+ torture_comment(tctx, "NetUser tests\n");
+
+ /* cleanup */
+
+ NetUserDel(hostname, TORTURE_TEST_USER);
+ NetUserDel(hostname, TORTURE_TEST_USER2);
+
+ /* add a user */
+
+ status = test_netuseradd(tctx, hostname, TORTURE_TEST_USER);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserAdd");
+ goto out;
+ }
+
+ /* enum the new user */
+
+ for (i=0; i<ARRAY_SIZE(enum_levels); i++) {
+
+ status = test_netuserenum(tctx, hostname, enum_levels[i], TORTURE_TEST_USER);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserEnum");
+ goto out;
+ }
+ }
+
+ /* basic queries */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ torture_comment(tctx, "Testing NetUserGetInfo level %d\n", levels[i]);
+
+ status = NetUserGetInfo(hostname, TORTURE_TEST_USER, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserGetInfo");
+ goto out;
+ }
+ }
+
+ /* testing getgroups */
+
+ for (i=0; i<ARRAY_SIZE(getgr_levels); i++) {
+
+ status = test_netusergetgroups(tctx, hostname, getgr_levels[i], TORTURE_TEST_USER, NULL);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserGetGroups");
+ goto out;
+ }
+ }
+
+ /* modify description */
+
+ torture_comment(tctx, "Testing NetUserSetInfo level %d\n", 1007);
+
+ u1007.usri1007_comment = "NetApi modified user";
+
+ status = NetUserSetInfo(hostname, TORTURE_TEST_USER, 1007, (uint8_t *)&u1007, &parm_err);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserSetInfo");
+ goto out;
+ }
+
+ /* query info */
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+ status = NetUserGetInfo(hostname, TORTURE_TEST_USER, levels[i], &buffer);
+ if (status && status != 124) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserGetInfo");
+ goto out;
+ }
+ }
+
+ torture_comment(tctx, "Testing NetUserSetInfo level 0\n");
+
+ u0.usri0_name = TORTURE_TEST_USER2;
+
+ status = NetUserSetInfo(hostname, TORTURE_TEST_USER, 0, (uint8_t *)&u0, &parm_err);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserSetInfo");
+ goto out;
+ }
+
+ /* delete */
+
+ torture_comment(tctx, "Testing NetUserDel\n");
+
+ status = NetUserDel(hostname, TORTURE_TEST_USER2);
+ if (status) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserDel");
+ goto out;
+ }
+
+ /* should not exist anymore */
+
+ status = NetUserGetInfo(hostname, TORTURE_TEST_USER2, 0, &buffer);
+ if (status == 0) {
+ NETAPI_STATUS(tctx, ctx, status, "NetUserGetInfo");
+ status = -1;
+ goto out;
+ }
+
+ status = test_netusermodals(tctx, ctx, hostname);
+ if (status) {
+ goto out;
+ }
+
+ status = 0;
+
+ torture_comment(tctx, "NetUser tests succeeded\n");
+ out:
+ /* cleanup */
+ NetUserDel(hostname, TORTURE_TEST_USER);
+ NetUserDel(hostname, TORTURE_TEST_USER2);
+
+ if (status != 0) {
+ torture_comment(tctx, "NetUser testsuite failed with: %s\n",
+ libnetapi_get_error_string(ctx, status));
+ libnetapi_free(ctx);
+ return false;
+ }
+
+ libnetapi_free(ctx);
+ return true;
+}
diff --git a/source4/torture/libnetapi/wscript_build b/source4/torture/libnetapi/wscript_build
new file mode 100644
index 0000000..988ba9b
--- /dev/null
+++ b/source4/torture/libnetapi/wscript_build
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_LIBNETAPI',
+ source='libnetapi.c libnetapi_user.c libnetapi_group.c libnetapi_server.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_libnetapi_init',
+ deps='netapi CMDLINE_S4',
+ internal_module=True,
+ )
+
diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c
new file mode 100644
index 0000000..72af8fc
--- /dev/null
+++ b/source4/torture/libsmbclient/libsmbclient.c
@@ -0,0 +1,1617 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/dir.h"
+#include "torture/smbtorture.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include <libsmbclient.h>
+#include "torture/libsmbclient/proto.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param_global.h"
+#include "libcli/smb/smb_constants.h"
+#include "dynconfig.h"
+#include "lib/util/time.h"
+
+/* test string to compare with when debug_callback is called */
+#define TEST_STRING "smbc_setLogCallback test"
+
+/* Dummy log callback function */
+static void debug_callback(void *private_ptr, int level, const char *msg)
+{
+ bool *found = private_ptr;
+ if (strstr(msg, TEST_STRING) != NULL) {
+ *found = true;
+ }
+ return;
+}
+
+static void auth_callback(const char *srv,
+ const char *shr,
+ char *wg, int wglen,
+ char *un, int unlen,
+ char *pw, int pwlen)
+{
+ const char *workgroup =
+ cli_credentials_get_domain(samba_cmdline_get_creds());
+ const char *username =
+ cli_credentials_get_username(samba_cmdline_get_creds());
+ const char *password =
+ cli_credentials_get_password(samba_cmdline_get_creds());
+ ssize_t ret;
+
+ if (workgroup != NULL) {
+ ret = strlcpy(wg, workgroup, wglen);
+ if (ret >= wglen) {
+ abort();
+ }
+ }
+
+ if (username != NULL) {
+ ret = strlcpy(un, username, unlen);
+ if (ret >= unlen) {
+ abort();
+ }
+ }
+
+ if (password != NULL) {
+ ret = strlcpy(pw, password, pwlen);
+ if (ret >= pwlen) {
+ abort();
+ }
+ }
+};
+
+bool torture_libsmbclient_init_context(struct torture_context *tctx,
+ SMBCCTX **ctx_p)
+{
+ const char *workgroup =
+ cli_credentials_get_domain(samba_cmdline_get_creds());
+ const char *username =
+ cli_credentials_get_username(samba_cmdline_get_creds());
+ const char *client_proto =
+ torture_setting_string(tctx, "clientprotocol", NULL);
+ SMBCCTX *ctx = NULL;
+ SMBCCTX *p = NULL;
+ bool ok = true;
+ int dbglevel = DEBUGLEVEL;
+
+ ctx = smbc_new_context();
+ torture_assert_not_null_goto(tctx,
+ ctx,
+ ok,
+ out,
+ "Failed to create new context");
+
+ p = smbc_init_context(ctx);
+ torture_assert_not_null_goto(tctx,
+ p,
+ ok,
+ out,
+ "Failed to initialize context");
+
+ smbc_setDebug(ctx, dbglevel);
+ smbc_setOptionDebugToStderr(ctx, 1);
+
+ if (workgroup != NULL) {
+ smbc_setWorkgroup(ctx, workgroup);
+ }
+ if (username != NULL) {
+ smbc_setUser(ctx, username);
+ }
+
+ smbc_setFunctionAuthData(ctx, auth_callback);
+
+ if (client_proto != NULL) {
+ smbc_setOptionProtocols(ctx, client_proto, client_proto);
+ }
+
+ *ctx_p = ctx;
+
+out:
+ if (!ok) {
+ smbc_free_context(ctx, 1);
+ }
+
+ return ok;
+}
+
+static bool torture_libsmbclient_version(struct torture_context *tctx)
+{
+ torture_comment(tctx, "Testing smbc_version\n");
+
+ torture_assert(tctx, smbc_version(), "failed to get version");
+
+ return true;
+}
+
+static bool torture_libsmbclient_initialize(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ bool ret = false;
+
+ torture_comment(tctx, "Testing smbc_new_context\n");
+
+ ctx = smbc_new_context();
+ torture_assert(tctx, ctx, "failed to get new context");
+
+ torture_comment(tctx, "Testing smbc_init_context\n");
+
+ torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
+
+ smbc_setLogCallback(ctx, &ret, debug_callback);
+ DEBUG(0, (TEST_STRING"\n"));
+ torture_assert(tctx, ret, "Failed debug_callback not called");
+ ret = false;
+ smbc_setLogCallback(ctx, NULL, NULL);
+ DEBUG(0, (TEST_STRING"\n"));
+ torture_assert(tctx, !ret, "Failed debug_callback called");
+
+ smbc_free_context(ctx, 1);
+
+ return true;
+}
+
+static bool torture_libsmbclient_setConfiguration(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ struct loadparm_global *global_config = NULL;
+ const char *new_smb_conf = torture_setting_string(tctx,
+ "replace_smbconf",
+ "");
+
+ ctx = smbc_new_context();
+ torture_assert_not_null(tctx, ctx, "failed to get new context");
+
+ torture_assert_not_null(
+ tctx, smbc_init_context(ctx), "failed to init context");
+
+ torture_comment(tctx, "Testing smbc_setConfiguration - new file %s\n",
+ new_smb_conf);
+
+ global_config = get_globals();
+ torture_assert(tctx, global_config, "Global Config is NULL");
+
+ /* check configuration before smbc_setConfiguration call */
+ torture_comment(tctx, "'workgroup' before setConfiguration %s\n",
+ global_config->workgroup);
+ torture_comment(tctx, "'client min protocol' before "
+ "setConfiguration %d\n",
+ global_config->client_min_protocol);
+ torture_comment(tctx, "'client max protocol' before "
+ "setConfiguration %d\n",
+ global_config->_client_max_protocol);
+ torture_comment(tctx, "'client signing' before setConfiguration %d\n",
+ global_config->client_signing);
+ torture_comment(tctx, "'deadtime' before setConfiguration %d\n",
+ global_config->deadtime);
+
+ torture_assert_int_equal(tctx, smbc_setConfiguration(ctx, new_smb_conf),
+ 0, "setConfiguration conf file not found");
+
+ /* verify configuration */
+ torture_assert_str_equal(tctx, global_config->workgroup,
+ "NEW_WORKGROUP",
+ "smbc_setConfiguration failed, "
+ "'workgroup' not updated");
+ torture_assert_int_equal(tctx, global_config->client_min_protocol, PROTOCOL_NT1,
+ "smbc_setConfiguration failed, 'client min protocol' "
+ "not updated");
+ torture_assert_int_equal(tctx, global_config->_client_max_protocol, PROTOCOL_SMB3_00,
+ "smbc_setConfiguration failed, 'client max protocol' "
+ "not updated");
+ torture_assert_int_equal(tctx, global_config->client_signing, 1,
+ "smbc_setConfiguration failed, 'client signing' "
+ "not updated");
+ torture_assert_int_equal(tctx, global_config->deadtime, 5,
+ "smbc_setConfiguration failed, 'deadtime' not updated");
+
+ /* Restore configuration to default */
+ smbc_setConfiguration(ctx, get_dyn_CONFIGFILE());
+
+ smbc_free_context(ctx, 1);
+
+ return true;
+}
+
+static bool test_opendir(struct torture_context *tctx,
+ SMBCCTX *ctx,
+ const char *fname,
+ bool expect_success)
+{
+ int handle, ret;
+
+ torture_comment(tctx, "Testing smbc_opendir(%s)\n", fname);
+
+ handle = smbc_opendir(fname);
+ if (!expect_success) {
+ return true;
+ }
+ if (handle < 0) {
+ torture_fail(tctx, talloc_asprintf(tctx, "failed to obain file handle for '%s'", fname));
+ }
+
+ ret = smbc_closedir(handle);
+ torture_assert_int_equal(tctx, ret, 0,
+ talloc_asprintf(tctx, "failed to close file handle for '%s'", fname));
+
+ return true;
+}
+
+static bool torture_libsmbclient_opendir(struct torture_context *tctx)
+{
+ size_t i;
+ SMBCCTX *ctx;
+ bool ret = true;
+ const char *bad_urls[] = {
+ "",
+ NULL,
+ "smb",
+ "smb:",
+ "smb:/",
+ "smb:///",
+ "bms://",
+ ":",
+ ":/",
+ "://",
+ ":///",
+ "/",
+ "//",
+ "///"
+ };
+ const char *good_urls[] = {
+ "smb://",
+ "smb://WORKGROUP",
+ "smb://WORKGROUP/"
+ };
+
+ torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+ smbc_set_context(ctx);
+
+ for (i=0; i < ARRAY_SIZE(bad_urls); i++) {
+ ret &= test_opendir(tctx, ctx, bad_urls[i], false);
+ }
+ for (i=0; i < ARRAY_SIZE(good_urls); i++) {
+ ret &= test_opendir(tctx, ctx, good_urls[i], true);
+ }
+
+ smbc_free_context(ctx, 1);
+
+ return ret;
+}
+
+static bool torture_libsmbclient_readdirplus(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ int ret = -1;
+ int dhandle = -1;
+ int fhandle = -1;
+ bool found = false;
+ const char *filename = NULL;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+ }
+
+ torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+ smbc_set_context(ctx);
+
+ filename = talloc_asprintf(tctx,
+ "%s/test_readdirplus.txt",
+ smburl);
+ if (filename == NULL) {
+ torture_fail(tctx,
+ "talloc fail\n");
+ }
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(filename);
+
+ /* Create it. */
+ fhandle = smbc_creat(filename, 0666);
+ if (fhandle < 0) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal(tctx,
+ ret,
+ 0,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename));
+
+ dhandle = smbc_opendir(smburl);
+ if (dhandle < 0) {
+ int saved_errno = errno;
+ smbc_unlink(filename);
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to obtain "
+ "directory handle for '%s' : %s",
+ smburl,
+ strerror(saved_errno)));
+ }
+
+ /* Readdirplus to ensure we see the new file. */
+ for (;;) {
+ const struct libsmb_file_info *exstat =
+ smbc_readdirplus(dhandle);
+ if (exstat == NULL) {
+ break;
+ }
+ if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ /* Remove it again. */
+ smbc_unlink(filename);
+ ret = smbc_closedir(dhandle);
+ torture_assert_int_equal(tctx,
+ ret,
+ 0,
+ talloc_asprintf(tctx,
+ "failed to close directory handle for '%s'",
+ smburl));
+
+ smbc_free_context(ctx, 1);
+
+ if (!found) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to find file '%s'",
+ filename));
+ }
+
+ return true;
+}
+
+static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ int ret = -1;
+ int dhandle = -1;
+ int fhandle = -1;
+ const char *dname = NULL;
+ const char *full_filename[100] = {0};
+ const char *filename[100] = {0};
+ const struct libsmb_file_info *direntries[102] = {0};
+ unsigned int i = 0;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ bool success = false;
+ off_t telldir_50 = (off_t)-1;
+ off_t telldir_20 = (off_t)-1;
+ size_t getdentries_size = 0;
+ struct smbc_dirent *getdentries = NULL;
+ struct smbc_dirent *dirent_20 = NULL;
+ const struct libsmb_file_info *direntries_20 = NULL;
+ const struct libsmb_file_info *direntriesplus_20 = NULL;
+ const char *plus2_stat_path = NULL;
+ struct stat st = {0};
+ struct stat st2 = {0};
+
+ torture_assert_not_null(
+ tctx,
+ smburl,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n"));
+
+ torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), "");
+ smbc_set_context(ctx);
+
+ dname = talloc_asprintf(tctx,
+ "%s/rd_seek",
+ smburl);
+ torture_assert_not_null_goto(
+ tctx, dname, success, done, "talloc fail\n");
+
+ /* Ensure the files don't exist. */
+ for (i = 0; i < 100; i++) {
+ filename[i] = talloc_asprintf(tctx,
+ "test_readdirplus_%u.txt",
+ i);
+ torture_assert_not_null_goto(
+ tctx, filename[i], success, done, "talloc fail");
+ full_filename[i] = talloc_asprintf(tctx,
+ "%s/%s",
+ dname,
+ filename[i]);
+ torture_assert_not_null_goto(
+ tctx, full_filename[i], success, done, "talloc fail");
+ (void)smbc_unlink(full_filename[i]);
+ }
+ /* Ensure the directory doesn't exist. */
+ (void)smbc_rmdir(dname);
+
+ /* Create containing directory. */
+ ret = smbc_mkdir(dname, 0777);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create directory '%s': %s",
+ dname,
+ strerror(errno)));
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n"));
+
+ /* Create them. */
+ for (i = 0; i < 100; i++) {
+ fhandle = smbc_creat(full_filename[i], 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ full_filename[i],
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ full_filename[i]));
+ }
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n"));
+
+ /* Now enumerate the directory. */
+ dhandle = smbc_opendir(dname);
+ torture_assert_goto(
+ tctx,
+ dhandle >= 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to obtain "
+ "directory handle for '%s' : %s",
+ dname,
+ strerror(errno)));
+
+ /* Read all the files. 100 we created plus . and .. */
+ for (i = 0; i < 102; i++) {
+ bool found = false;
+ unsigned int j;
+
+ direntries[i] = smbc_readdirplus(dhandle);
+ if (direntries[i] == NULL) {
+ break;
+ }
+
+ /* Store at offset 50. */
+ if (i == 50) {
+ telldir_50 = smbc_telldir(dhandle);
+ torture_assert_goto(
+ tctx,
+ telldir_50 != (off_t)-1,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "telldir failed file %s\n",
+ direntries[i]->name));
+ }
+
+ if (ISDOT(direntries[i]->name)) {
+ continue;
+ }
+ if (ISDOTDOT(direntries[i]->name)) {
+ continue;
+ }
+
+ /* Ensure all our files exist. */
+ for (j = 0; j < 100; j++) {
+ if (strcmp(direntries[i]->name,
+ filename[j]) == 0) {
+ found = true;
+ }
+ }
+ torture_assert_goto(
+ tctx,
+ found,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to find file %s\n",
+ direntries[i]->name));
+ }
+
+ /*
+ * We're seeking on in-memory lists here, so
+ * whilst the handle is open we really should
+ * get the same files back in the same order.
+ */
+
+ ret = smbc_lseekdir(dhandle, telldir_50);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (50) directory handle for '%s'",
+ dname));
+
+ DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n"));
+
+ for (i = 51; i < 102; i++) {
+ const struct libsmb_file_info *entry =
+ smbc_readdirplus(dhandle);
+ torture_assert_goto(
+ tctx,
+ entry == direntries[i],
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek - failed to find "
+ "file %s - got %s\n",
+ direntries[i]->name,
+ entry->name));
+ }
+
+ /* Seek back to the start. */
+ ret = smbc_lseekdir(dhandle, 0);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek directory handle to start for '%s'",
+ dname));
+
+ /*
+ * Mix getdents/readdir/readdirplus with lseek to ensure
+ * we get the same result.
+ */
+
+ /* Allocate the space for 20 entries.
+ * Tricky as we need to allocate 20 struct smbc_dirent's + space
+ * for the name lengths.
+ */
+ getdentries_size = 20 * (sizeof(struct smbc_dirent) +
+ strlen("test_readdirplus_1000.txt") + 1);
+
+ getdentries = (struct smbc_dirent *)talloc_array_size(tctx,
+ getdentries_size,
+ 1);
+ torture_assert_not_null_goto(
+ tctx,
+ getdentries,
+ success,
+ done,
+ "talloc fail");
+
+ ret = smbc_getdents(dhandle, getdentries, getdentries_size);
+ torture_assert_goto(tctx,
+ (ret != -1),
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "smbd_getdents(1) for '%s' failed\n",
+ dname));
+
+ telldir_20 = smbc_telldir(dhandle);
+ torture_assert_goto(
+ tctx,
+ telldir_20 != (off_t)-1,
+ success,
+ done,
+ "telldir (20) failed\n");
+
+ /* Read another 20. */
+ ret = smbc_getdents(dhandle, getdentries, getdentries_size);
+ torture_assert_goto(tctx,
+ (ret != -1),
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "smbd_getdents(2) for '%s' failed\n",
+ dname));
+
+ /* Seek back to 20. */
+ ret = smbc_lseekdir(dhandle, telldir_20);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (20) directory handle for '%s'",
+ dname));
+
+ /* Read with readdir. */
+ dirent_20 = smbc_readdir(dhandle);
+ torture_assert_not_null_goto(
+ tctx,
+ dirent_20,
+ success,
+ done,
+ "smbc_readdir (20) failed\n");
+
+ /* Ensure the getdents and readdir names are the same. */
+ ret = strcmp(dirent_20->name, getdentries[0].name);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek (20) readdir name mismatch "
+ "file %s - got %s\n",
+ dirent_20->name,
+ getdentries[0].name));
+
+ /* Seek back to 20. */
+ ret = smbc_lseekdir(dhandle, telldir_20);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (20) directory handle for '%s'",
+ dname));
+ /* Read with readdirplus. */
+ direntries_20 = smbc_readdirplus(dhandle);
+ torture_assert_not_null_goto(
+ tctx,
+ direntries_20,
+ success,
+ done,
+ "smbc_readdirplus (20) failed\n");
+
+ /* Ensure the readdirplus and readdir names are the same. */
+ ret = strcmp(dirent_20->name, direntries_20->name);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek (20) readdirplus name mismatch "
+ "file %s - got %s\n",
+ dirent_20->name,
+ direntries_20->name));
+
+ /* Seek back to 20. */
+ ret = smbc_lseekdir(dhandle, telldir_20);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to seek (20) directory handle for '%s'",
+ dname));
+
+ /* Read with readdirplus2. */
+ direntriesplus_20 = smbc_readdirplus2(dhandle, &st2);
+ torture_assert_not_null_goto(
+ tctx,
+ direntriesplus_20,
+ success,
+ done,
+ "smbc_readdirplus2 (20) failed\n");
+
+ /* Ensure the readdirplus2 and readdirplus names are the same. */
+ ret = strcmp(direntries_20->name, direntriesplus_20->name);
+ torture_assert_goto(
+ tctx,
+ ret == 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "after seek (20) readdirplus2 name mismatch "
+ "file %s - got %s\n",
+ dirent_20->name,
+ direntries_20->name));
+
+ /* Ensure doing stat gets the same data. */
+ plus2_stat_path = talloc_asprintf(tctx,
+ "%s/%s",
+ dname,
+ direntriesplus_20->name);
+ torture_assert_not_null_goto(
+ tctx,
+ plus2_stat_path,
+ success,
+ done,
+ "talloc fail\n");
+
+ ret = smbc_stat(plus2_stat_path, &st);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to stat file '%s'",
+ plus2_stat_path));
+
+ torture_assert_int_equal(tctx,
+ st.st_ino,
+ st2.st_ino,
+ talloc_asprintf(tctx,
+ "file %s mismatched ino value "
+ "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
+ plus2_stat_path,
+ (uint64_t)st.st_ino,
+ (uint64_t)st2.st_ino));
+
+ torture_assert_int_equal(tctx,
+ st.st_dev,
+ st2.st_dev,
+ talloc_asprintf(tctx,
+ "file %s mismatched dev value "
+ "stat got %"PRIx64" readdirplus2 got %"PRIx64"" ,
+ plus2_stat_path,
+ (uint64_t)st.st_dev,
+ (uint64_t)st2.st_dev));
+
+ ret = smbc_closedir(dhandle);
+ torture_assert_int_equal(tctx,
+ ret,
+ 0,
+ talloc_asprintf(tctx,
+ "failed to close directory handle for '%s'",
+ dname));
+
+ dhandle = -1;
+ success = true;
+
+ done:
+
+ /* Clean up. */
+ if (dhandle != -1) {
+ smbc_closedir(dhandle);
+ }
+ for (i = 0; i < 100; i++) {
+ if (full_filename[i] != NULL) {
+ smbc_unlink(full_filename[i]);
+ }
+ }
+ if (dname != NULL) {
+ smbc_rmdir(dname);
+ }
+
+ smbc_free_context(ctx, 1);
+
+ return success;
+}
+
+#ifndef SMBC_FILE_MODE
+#define SMBC_FILE_MODE (S_IFREG | 0444)
+#endif
+
+static bool torture_libsmbclient_readdirplus2(struct torture_context *tctx)
+{
+ SMBCCTX *ctx = NULL;
+ int dhandle = -1;
+ int fhandle = -1;
+ bool found = false;
+ bool success = false;
+ const char *filename = NULL;
+ struct stat st2 = {0};
+ struct stat st = {0};
+ int ret;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+ }
+
+ torture_assert_goto(tctx, torture_libsmbclient_init_context(tctx, &ctx), success, done, "");
+ smbc_set_context(ctx);
+
+ filename = talloc_asprintf(tctx,
+ "%s/test_readdirplus.txt",
+ smburl);
+ if (filename == NULL) {
+ torture_fail_goto(tctx, done, "talloc fail\n");
+ }
+
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(filename);
+
+ /* Create it. */
+ fhandle = smbc_creat(filename, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename));
+
+ dhandle = smbc_opendir(smburl);
+ if (dhandle < 0) {
+ int saved_errno = errno;
+ smbc_unlink(filename);
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to obtain "
+ "directory handle for '%s' : %s",
+ smburl,
+ strerror(saved_errno)));
+ }
+
+ /* readdirplus2 to ensure we see the new file. */
+ for (;;) {
+ const struct libsmb_file_info *exstat =
+ smbc_readdirplus2(dhandle, &st2);
+ if (exstat == NULL) {
+ break;
+ }
+
+ if (strcmp(exstat->name, "test_readdirplus.txt") == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ smbc_unlink(filename);
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to find file '%s'",
+ filename));
+ }
+
+ /* Ensure mode is as expected. */
+ /*
+ * New file gets SMBC_FILE_MODE plus
+ * archive bit -> S_IXUSR
+ * !READONLY -> S_IWUSR.
+ */
+ torture_assert_int_equal_goto(tctx,
+ st2.st_mode,
+ SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "file %s st_mode should be 0%o, got 0%o'",
+ filename,
+ SMBC_FILE_MODE|S_IXUSR|S_IWUSR,
+ (unsigned int)st2.st_mode));
+
+ /* Ensure smbc_stat() gets the same data. */
+ ret = smbc_stat(filename, &st);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to stat file '%s'",
+ filename));
+
+ torture_assert_int_equal_goto(tctx,
+ st2.st_ino,
+ st.st_ino,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "filename '%s' ino mismatch. "
+ "From smbc_readdirplus2 = %"PRIx64" "
+ "From smbc_stat = %"PRIx64"",
+ filename,
+ (uint64_t)st2.st_ino,
+ (uint64_t)st.st_ino));
+
+
+ /* Remove it again. */
+ smbc_unlink(filename);
+ ret = smbc_closedir(dhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close directory handle for '%s'",
+ filename));
+ success = true;
+
+ done:
+ smbc_free_context(ctx, 1);
+ return success;
+}
+
+bool torture_libsmbclient_configuration(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ bool ok = true;
+
+ ctx = smbc_new_context();
+ torture_assert(tctx, ctx, "failed to get new context");
+ torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
+
+ torture_comment(tctx, "Testing smbc_(set|get)Debug\n");
+ smbc_setDebug(ctx, DEBUGLEVEL);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getDebug(ctx),
+ DEBUGLEVEL,
+ ok,
+ done,
+ "failed to set DEBUGLEVEL");
+
+ torture_comment(tctx, "Testing smbc_(set|get)NetbiosName\n");
+ smbc_setNetbiosName(ctx, discard_const("torture_netbios"));
+ torture_assert_str_equal_goto(tctx,
+ smbc_getNetbiosName(ctx),
+ "torture_netbios",
+ ok,
+ done,
+ "failed to set NetbiosName");
+
+ torture_comment(tctx, "Testing smbc_(set|get)Workgroup\n");
+ smbc_setWorkgroup(ctx, discard_const("torture_workgroup"));
+ torture_assert_str_equal_goto(tctx,
+ smbc_getWorkgroup(ctx),
+ "torture_workgroup",
+ ok,
+ done,
+ "failed to set Workgroup");
+
+ torture_comment(tctx, "Testing smbc_(set|get)User\n");
+ smbc_setUser(ctx, "torture_user");
+ torture_assert_str_equal_goto(tctx,
+ smbc_getUser(ctx),
+ "torture_user",
+ ok,
+ done,
+ "failed to set User");
+
+ torture_comment(tctx, "Testing smbc_(set|get)Timeout\n");
+ smbc_setTimeout(ctx, 12345);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getTimeout(ctx),
+ 12345,
+ ok,
+ done,
+ "failed to set Timeout");
+
+done:
+ smbc_free_context(ctx, 1);
+
+ return ok;
+}
+
+bool torture_libsmbclient_options(struct torture_context *tctx)
+{
+ SMBCCTX *ctx;
+ bool ok = true;
+
+ ctx = smbc_new_context();
+ torture_assert(tctx, ctx, "failed to get new context");
+ torture_assert(tctx, smbc_init_context(ctx), "failed to init context");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionDebugToStderr\n");
+ smbc_setOptionDebugToStderr(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionDebugToStderr(ctx),
+ ok,
+ done,
+ "failed to set OptionDebugToStderr");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionFullTimeNames\n");
+ smbc_setOptionFullTimeNames(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionFullTimeNames(ctx),
+ ok,
+ done,
+ "failed to set OptionFullTimeNames");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionOpenShareMode\n");
+ smbc_setOptionOpenShareMode(ctx, SMBC_SHAREMODE_DENY_ALL);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getOptionOpenShareMode(ctx),
+ SMBC_SHAREMODE_DENY_ALL,
+ ok,
+ done,
+ "failed to set OptionOpenShareMode");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionUserData\n");
+ smbc_setOptionUserData(ctx, (void *)discard_const("torture_user_data"));
+ torture_assert_str_equal_goto(tctx,
+ (const char*)smbc_getOptionUserData(ctx),
+ "torture_user_data",
+ ok,
+ done,
+ "failed to set OptionUserData");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionSmbEncryptionLevel\n");
+ smbc_setOptionSmbEncryptionLevel(ctx, SMBC_ENCRYPTLEVEL_REQUEST);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getOptionSmbEncryptionLevel(ctx),
+ SMBC_ENCRYPTLEVEL_REQUEST,
+ ok,
+ done,
+ "failed to set OptionSmbEncryptionLevel");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionCaseSensitive\n");
+ smbc_setOptionCaseSensitive(ctx, false);
+ torture_assert_goto(tctx,
+ !smbc_getOptionCaseSensitive(ctx),
+ ok,
+ done,
+ "failed to set OptionCaseSensitive");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionBrowseMaxLmbCount\n");
+ smbc_setOptionBrowseMaxLmbCount(ctx, 2);
+ torture_assert_int_equal_goto(tctx,
+ smbc_getOptionBrowseMaxLmbCount(ctx),
+ 2,
+ ok,
+ done,
+ "failed to set OptionBrowseMaxLmbCount");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionUrlEncodeReaddirEntries\n");
+ smbc_setOptionUrlEncodeReaddirEntries(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionUrlEncodeReaddirEntries(ctx),
+ ok,
+ done,
+ "failed to set OptionUrlEncodeReaddirEntries");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionOneSharePerServer\n");
+ smbc_setOptionOneSharePerServer(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionOneSharePerServer(ctx),
+ ok,
+ done,
+ "failed to set OptionOneSharePerServer");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionUseKerberos\n");
+ smbc_setOptionUseKerberos(ctx, false);
+ torture_assert_goto(tctx,
+ !smbc_getOptionUseKerberos(ctx),
+ ok,
+ done,
+ "failed to set OptionUseKerberos");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionFallbackAfterKerberos\n");
+ smbc_setOptionFallbackAfterKerberos(ctx, false);
+ torture_assert_goto(tctx,
+ !smbc_getOptionFallbackAfterKerberos(ctx),
+ ok,
+ done,
+ "failed to set OptionFallbackAfterKerberos");
+
+ torture_comment(tctx,
+ "Testing smbc_(set|get)OptionNoAutoAnonymousLogin\n");
+ smbc_setOptionNoAutoAnonymousLogin(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionNoAutoAnonymousLogin(ctx),
+ ok,
+ done,
+ "failed to set OptionNoAutoAnonymousLogin");
+
+ torture_comment(tctx, "Testing smbc_(set|get)OptionUseCCache\n");
+ smbc_setOptionUseCCache(ctx, true);
+ torture_assert_goto(tctx,
+ smbc_getOptionUseCCache(ctx),
+ ok,
+ done,
+ "failed to set OptionUseCCache");
+
+done:
+ smbc_free_context(ctx, 1);
+
+ return ok;
+}
+
+static bool torture_libsmbclient_list_shares(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ struct smbc_dirent *dirent = NULL;
+ SMBCCTX *ctx = NULL;
+ int dhandle = -1;
+ bool ipc_share_found = false;
+ bool ok = true;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert_goto(tctx,
+ ok,
+ ok,
+ out,
+ "Failed to init context");
+ smbc_set_context(ctx);
+
+ torture_comment(tctx, "Listing: %s\n", smburl);
+ dhandle = smbc_opendir(smburl);
+ torture_assert_int_not_equal_goto(tctx,
+ dhandle,
+ -1,
+ ok,
+ out,
+ "Failed to open smburl");
+
+ while((dirent = smbc_readdir(dhandle)) != NULL) {
+ torture_comment(tctx, "DIR: %s\n", dirent->name);
+ torture_assert_not_null_goto(tctx,
+ dirent->name,
+ ok,
+ out,
+ "Failed to read name");
+
+ if (strequal(dirent->name, "IPC$")) {
+ ipc_share_found = true;
+ }
+ }
+
+ torture_assert_goto(tctx,
+ ipc_share_found,
+ ok,
+ out,
+ "Failed to list IPC$ share");
+
+out:
+ smbc_closedir(dhandle);
+ return ok;
+}
+
+static bool torture_libsmbclient_utimes(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ SMBCCTX *ctx = NULL;
+ struct stat st;
+ int fhandle, ret;
+ struct timeval tbuf[2];
+ bool ok;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert(tctx, ok, "Failed to init context");
+ smbc_set_context(ctx);
+
+ fhandle = smbc_open(smburl, O_RDWR|O_CREAT, 0644);
+ torture_assert_int_not_equal(tctx, fhandle, -1, "smbc_open failed");
+
+ ret = smbc_fstat(fhandle, &st);
+ torture_assert_int_not_equal(tctx, ret, -1, "smbc_fstat failed");
+
+ tbuf[0] = convert_timespec_to_timeval(get_atimespec(&st));
+ tbuf[1] = convert_timespec_to_timeval(get_mtimespec(&st));
+
+ tbuf[1] = timeval_add(&tbuf[1], 0, 100000); /* 100 msec */
+
+ ret = smbc_utimes(smburl, tbuf);
+ torture_assert_int_not_equal(tctx, ret, -1, "smbc_utimes failed");
+
+ ret = smbc_fstat(fhandle, &st);
+ torture_assert_int_not_equal(tctx, ret, -1, "smbc_fstat failed");
+
+ torture_assert_int_equal(
+ tctx,
+ get_mtimensec(&st) / 1000,
+ tbuf[1].tv_usec,
+ "smbc_utimes did not update msec");
+
+ smbc_close(fhandle);
+ smbc_unlink(smburl);
+ return true;
+}
+
+static bool torture_libsmbclient_noanon_list(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ struct smbc_dirent *dirent = NULL;
+ SMBCCTX *ctx = NULL;
+ int dhandle = -1;
+ bool ok = true;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert_goto(tctx,
+ ok,
+ ok,
+ out,
+ "Failed to init context");
+ torture_comment(tctx,
+ "Testing smbc_setOptionNoAutoAnonymousLogin\n");
+ smbc_setOptionNoAutoAnonymousLogin(ctx, true);
+ smbc_set_context(ctx);
+
+ torture_comment(tctx, "Listing: %s\n", smburl);
+ dhandle = smbc_opendir(smburl);
+ torture_assert_int_not_equal_goto(tctx,
+ dhandle,
+ -1,
+ ok,
+ out,
+ "Failed to open smburl");
+
+ while((dirent = smbc_readdir(dhandle)) != NULL) {
+ torture_comment(tctx, "DIR: %s\n", dirent->name);
+ torture_assert_not_null_goto(tctx,
+ dirent->name,
+ ok,
+ out,
+ "Failed to read name");
+ }
+
+out:
+ smbc_closedir(dhandle);
+ return ok;
+}
+
+static bool torture_libsmbclient_rename(struct torture_context *tctx)
+{
+ SMBCCTX *ctx = NULL;
+ int fhandle = -1;
+ bool success = false;
+ const char *filename_src = NULL;
+ const char *filename_dst = NULL;
+ int ret;
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server/share missing\n");
+ }
+
+ torture_assert_goto(tctx,
+ torture_libsmbclient_init_context(tctx, &ctx),
+ success,
+ done,
+ "");
+
+ smbc_set_context(ctx);
+
+ filename_src = talloc_asprintf(tctx,
+ "%s/src",
+ smburl);
+ if (filename_src == NULL) {
+ torture_fail_goto(tctx, done, "talloc fail\n");
+ }
+
+ filename_dst = talloc_asprintf(tctx,
+ "%s/dst",
+ smburl);
+ if (filename_dst == NULL) {
+ torture_fail_goto(tctx, done, "talloc fail\n");
+ }
+
+ /* Ensure the files don't exist. */
+ smbc_unlink(filename_src);
+ smbc_unlink(filename_dst);
+
+ /* Create them. */
+ fhandle = smbc_creat(filename_src, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename_src,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename_src));
+
+ fhandle = smbc_creat(filename_dst, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ filename_dst,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ filename_dst));
+
+ ret = smbc_rename(filename_src, filename_dst);
+
+ /*
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14938
+ * gives ret == -1, but errno = 0 for overwrite renames
+ * over SMB2.
+ */
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ success,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_rename '%s' -> '%s' failed with %s\n",
+ filename_src,
+ filename_dst,
+ strerror(errno)));
+
+ /* Remove them again. */
+ smbc_unlink(filename_src);
+ smbc_unlink(filename_dst);
+ success = true;
+
+ done:
+ smbc_free_context(ctx, 1);
+ return success;
+}
+
+static bool torture_libsmbclient_getatr(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ SMBCCTX *ctx = NULL;
+ char *getatr_name = NULL;
+ struct stat st = {0};
+ bool ok;
+ int ret = 0;
+ int err = 0;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert(tctx, ok, "Failed to init context");
+ smbc_set_context(ctx);
+
+ getatr_name = talloc_asprintf(tctx,
+ "%s/noexist",
+ smburl);
+ if (getatr_name == NULL) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__": %s",
+ "talloc fail\n");
+ return false;
+ }
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(getatr_name);
+ /*
+ * smbc_stat() internally uses SMBC_getatr().
+ * Make sure doing getatr on a non-existent file gives
+ * an error of -1, errno = ENOENT.
+ */
+
+ ret = smbc_stat(getatr_name, &st);
+ if (ret == -1) {
+ err = errno;
+ }
+ torture_assert_int_equal(tctx,
+ ret,
+ -1,
+ talloc_asprintf(tctx,
+ "smbc_stat on '%s' should "
+ "get -1, got %d\n",
+ getatr_name,
+ ret));
+ torture_assert_int_equal(tctx,
+ err,
+ ENOENT,
+ talloc_asprintf(tctx,
+ "smbc_stat on '%s' should "
+ "get errno = ENOENT, got %s\n",
+ getatr_name,
+ strerror(err)));
+ return true;
+}
+
+static bool torture_libsmbclient_getxattr(struct torture_context *tctx)
+{
+ const char *smburl = torture_setting_string(tctx, "smburl", NULL);
+ int fhandle = -1;
+ SMBCCTX *ctx = NULL;
+ char *getxattr_name = NULL;
+ char value[4096];
+ bool ok = false;
+ int ret = -1;
+
+ if (smburl == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:smburl="
+ "smb://user:password@server missing\n");
+ }
+
+ ok = torture_libsmbclient_init_context(tctx, &ctx);
+ torture_assert(tctx, ok, "Failed to init context");
+ smbc_set_context(ctx);
+
+ getxattr_name = talloc_asprintf(tctx,
+ "%s/getxattr",
+ smburl);
+ if (getxattr_name == NULL) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__": %s",
+ "talloc fail\n");
+ return false;
+ }
+ /* Ensure the file doesn't exist. */
+ smbc_unlink(getxattr_name);
+
+ /* Create testfile. */
+ fhandle = smbc_creat(getxattr_name, 0666);
+ if (fhandle < 0) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "failed to create file '%s': %s",
+ getxattr_name,
+ strerror(errno)));
+ }
+ ret = smbc_close(fhandle);
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ 0,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "failed to close handle for '%s'",
+ getxattr_name));
+
+ /*
+ * Ensure getting a non-existent attribute returns -1.
+ */
+ ret = smbc_getxattr(getxattr_name, "foobar", value, sizeof(value));
+ torture_assert_int_equal_goto(tctx,
+ ret,
+ -1,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_getxattr(foobar) on '%s' should "
+ "get -1, got %d\n",
+ getxattr_name,
+ ret));
+
+ /*
+ * Ensure getting a valid attribute computes its size.
+ */
+ ret = smbc_getxattr(getxattr_name, "system.*", NULL, 0);
+ torture_assert_goto(tctx,
+ ret >= 0,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_getxattr(foobar, NULL) on '%s' should "
+ "get >=0, got %d\n",
+ getxattr_name,
+ ret));
+
+ /*
+ * Ensure getting a valid attribute returns its size.
+ */
+ ret = smbc_getxattr(getxattr_name, "system.*", value, sizeof(value));
+ torture_assert_goto(tctx,
+ ret >= 0,
+ ok,
+ done,
+ talloc_asprintf(tctx,
+ "smbc_getxattr(foobar, value) on '%s' should "
+ "get >=0, got %d\n",
+ getxattr_name,
+ ret));
+
+ ok = true;
+
+ done:
+
+ smbc_unlink(getxattr_name);
+ smbc_free_context(ctx, 1);
+ return ok;
+}
+
+NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(ctx, "libsmbclient");
+
+ torture_suite_add_simple_test(suite, "version", torture_libsmbclient_version);
+ torture_suite_add_simple_test(suite, "initialize", torture_libsmbclient_initialize);
+ torture_suite_add_simple_test(suite, "configuration", torture_libsmbclient_configuration);
+ torture_suite_add_simple_test(suite, "setConfiguration", torture_libsmbclient_setConfiguration);
+ torture_suite_add_simple_test(suite, "options", torture_libsmbclient_options);
+ torture_suite_add_simple_test(suite, "opendir", torture_libsmbclient_opendir);
+ torture_suite_add_simple_test(suite, "list_shares", torture_libsmbclient_list_shares);
+ torture_suite_add_simple_test(suite, "readdirplus",
+ torture_libsmbclient_readdirplus);
+ torture_suite_add_simple_test(suite, "readdirplus_seek",
+ torture_libsmbclient_readdirplus_seek);
+ torture_suite_add_simple_test(suite, "readdirplus2",
+ torture_libsmbclient_readdirplus2);
+ torture_suite_add_simple_test(
+ suite, "utimes", torture_libsmbclient_utimes);
+ torture_suite_add_simple_test(
+ suite, "noanon_list", torture_libsmbclient_noanon_list);
+ torture_suite_add_simple_test(suite,
+ "rename",
+ torture_libsmbclient_rename);
+ torture_suite_add_simple_test(suite, "getatr",
+ torture_libsmbclient_getatr);
+ torture_suite_add_simple_test(suite, "getxattr",
+ torture_libsmbclient_getxattr);
+
+ suite->description = talloc_strdup(suite, "libsmbclient interface tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/libsmbclient/wscript_build b/source4/torture/libsmbclient/wscript_build
new file mode 100644
index 0000000..61d819b
--- /dev/null
+++ b/source4/torture/libsmbclient/wscript_build
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_MODULE('TORTURE_LIBSMBCLIENT',
+ source='libsmbclient.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_libsmbclient_init',
+ deps='smbclient CMDLINE_S4',
+ internal_module=True
+ )
+
+
+
diff --git a/source4/torture/local/dbspeed.c b/source4/torture/local/dbspeed.c
new file mode 100644
index 0000000..9452d6a
--- /dev/null
+++ b/source4/torture/local/dbspeed.c
@@ -0,0 +1,268 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local test for tdb/ldb speed
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include <tdb.h>
+#include <ldb.h>
+#include <ldb_errors.h>
+#include "ldb_wrap.h"
+#include "lib/tdb_wrap/tdb_wrap.h"
+#include "torture/smbtorture.h"
+#include "torture/local/proto.h"
+#include "param/param.h"
+
+float tdb_speed;
+
+static bool tdb_add_record(struct tdb_wrap *tdbw, const char *p1,
+ const char *p2, int i)
+{
+ TDB_DATA key, data;
+ int ret;
+
+ key.dptr = (uint8_t *)talloc_asprintf(tdbw, "%s%u", p1, i);
+ key.dsize = strlen((char *)key.dptr)+1;
+ data.dptr = (uint8_t *)talloc_asprintf(tdbw, "%s%u", p2, i+10000);
+ data.dsize = strlen((char *)data.dptr)+1;
+
+ ret = tdb_store(tdbw->tdb, key, data, TDB_INSERT);
+
+ talloc_free(key.dptr);
+ talloc_free(data.dptr);
+ return ret == 0;
+}
+
+/*
+ test tdb speed
+*/
+static bool test_tdb_speed(struct torture_context *torture, const void *_data)
+{
+ struct timeval tv;
+ struct tdb_wrap *tdbw;
+ int timelimit = torture_setting_int(torture, "timelimit", 10);
+ int i, count;
+ TALLOC_CTX *tmp_ctx = talloc_new(torture);
+
+ unlink("test.tdb");
+
+ torture_comment(torture, "Testing tdb speed for sidmap\n");
+
+ tdbw = tdb_wrap_open(tmp_ctx, "test.tdb", 10000,
+ lpcfg_tdb_flags(torture->lp_ctx, 0),
+ O_RDWR|O_CREAT|O_TRUNC, 0600);
+ if (!tdbw) {
+ torture_result(torture, TORTURE_FAIL, "Failed to open test.tdb");
+ goto failed;
+ }
+
+ torture_comment(torture, "Adding %d SID records\n", torture_entries);
+
+ for (i=0;i<torture_entries;i++) {
+ if (!tdb_add_record(tdbw,
+ "S-1-5-21-53173311-3623041448-2049097239-",
+ "UID ", i)) {
+ torture_result(torture, TORTURE_FAIL, "Failed to add SID %d!", i);
+ goto failed;
+ }
+ if (!tdb_add_record(tdbw,
+ "UID ",
+ "S-1-5-21-53173311-3623041448-2049097239-", i)) {
+ torture_result(torture, TORTURE_FAIL, "Failed to add UID %d!", i);
+ goto failed;
+ }
+ }
+
+ torture_comment(torture, "Testing for %d seconds\n", timelimit);
+
+ tv = timeval_current();
+
+ for (count=0;timeval_elapsed(&tv) < timelimit;count++) {
+ TDB_DATA key, data;
+ i = random() % torture_entries;
+ key.dptr = (uint8_t *)talloc_asprintf(tmp_ctx, "S-1-5-21-53173311-3623041448-2049097239-%u", i);
+ key.dsize = strlen((char *)key.dptr)+1;
+ data = tdb_fetch(tdbw->tdb, key);
+ talloc_free(key.dptr);
+ if (data.dptr == NULL) {
+ torture_result(torture, TORTURE_FAIL, "Failed to find SID %d!", i);
+ goto failed;
+ }
+ free(data.dptr);
+ key.dptr = (uint8_t *)talloc_asprintf(tmp_ctx, "UID %u", i);
+ key.dsize = strlen((char *)key.dptr)+1;
+ data = tdb_fetch(tdbw->tdb, key);
+ talloc_free(key.dptr);
+ if (data.dptr == NULL) {
+ torture_result(torture, TORTURE_FAIL, "Failed to find UID %d!", i);
+ goto failed;
+ }
+ free(data.dptr);
+ }
+
+ tdb_speed = count/timeval_elapsed(&tv);
+ torture_comment(torture, "tdb speed %.2f ops/sec\n", tdb_speed);
+
+ talloc_free(tmp_ctx);
+ unlink("test.tdb");
+ return true;
+
+failed:
+ talloc_free(tmp_ctx);
+ unlink("test.tdb");
+ return false;
+}
+
+
+static bool ldb_add_record(struct ldb_context *ldb, unsigned rid)
+{
+ struct ldb_message *msg;
+ int ret;
+
+ msg = ldb_msg_new(ldb);
+ if (msg == NULL) {
+ return false;
+ }
+
+ msg->dn = ldb_dn_new_fmt(msg, ldb, "SID=S-1-5-21-53173311-3623041448-2049097239-%u", rid);
+ if (msg->dn == NULL) {
+ talloc_free(msg);
+ return false;
+ }
+
+ ret = ldb_msg_add_fmt(msg, "UID", "%u", rid);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return false;
+ }
+
+ ret = ldb_add(ldb, msg);
+
+ talloc_free(msg);
+
+ return ret == LDB_SUCCESS;
+}
+
+
+/*
+ test ldb speed
+*/
+static bool test_ldb_speed(struct torture_context *torture, const void *_data)
+{
+ struct timeval tv;
+ struct ldb_context *ldb;
+ int timelimit = torture_setting_int(torture, "timelimit", 10);
+ int i, count;
+ TALLOC_CTX *tmp_ctx = talloc_new(torture);
+ struct ldb_ldif *ldif;
+ const char *init_ldif = "dn: @INDEXLIST\n" \
+ "@IDXATTR: UID\n";
+ float ldb_speed;
+
+ unlink("./test.ldb");
+
+ torture_comment(torture, "Testing ldb speed for sidmap\n");
+
+ ldb = ldb_wrap_connect(tmp_ctx, torture->ev, torture->lp_ctx, "tdb://test.ldb",
+ NULL, NULL, LDB_FLG_NOSYNC);
+ if (!ldb) {
+ torture_result(torture, TORTURE_FAIL, "Failed to open test.ldb");
+ goto failed;
+ }
+
+ /* add an index */
+ ldif = ldb_ldif_read_string(ldb, &init_ldif);
+ if (ldif == NULL) {
+ torture_result(torture, TORTURE_FAIL, "Didn't get LDIF data!");
+ goto failed;
+ }
+ if (ldb_add(ldb, ldif->msg) != LDB_SUCCESS) {
+ torture_result(torture, TORTURE_FAIL, "Couldn't apply LDIF data!");
+ talloc_free(ldif);
+ goto failed;
+ }
+ talloc_free(ldif);
+
+ torture_comment(torture, "Adding %d SID records\n", torture_entries);
+
+ for (i=0;i<torture_entries;i++) {
+ if (!ldb_add_record(ldb, i)) {
+ torture_result(torture, TORTURE_FAIL, "Failed to add SID %d", i);
+ goto failed;
+ }
+ }
+
+ if (talloc_total_blocks(tmp_ctx) > 100) {
+ torture_result(torture, TORTURE_FAIL, "memory leak in ldb add");
+ goto failed;
+ }
+
+ torture_comment(torture, "Testing for %d seconds\n", timelimit);
+
+ tv = timeval_current();
+
+ for (count=0;timeval_elapsed(&tv) < timelimit;count++) {
+ struct ldb_dn *dn;
+ struct ldb_result *res;
+
+ i = random() % torture_entries;
+ dn = ldb_dn_new_fmt(tmp_ctx, ldb, "SID=S-1-5-21-53173311-3623041448-2049097239-%u", i);
+ if (ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL) != LDB_SUCCESS || res->count != 1) {
+ torture_result(torture, TORTURE_FAIL, "Failed to find SID %d!", i);
+ goto failed;
+ }
+ talloc_free(res);
+ talloc_free(dn);
+ if (ldb_search(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "(UID=%u)", i) != LDB_SUCCESS || res->count != 1) {
+ torture_result(torture, TORTURE_FAIL, "Failed to find UID %d!", i);
+ goto failed;
+ }
+ talloc_free(res);
+ }
+
+ if (talloc_total_blocks(tmp_ctx) > 100) {
+ torture_result(torture, TORTURE_FAIL, "memory leak in ldb search");
+ goto failed;
+ }
+
+ ldb_speed = count/timeval_elapsed(&tv);
+ torture_comment(torture, "ldb speed %.2f ops/sec\n", ldb_speed);
+
+ torture_comment(torture, "ldb/tdb speed ratio is %.2f%%\n", (100*ldb_speed/tdb_speed));
+
+ talloc_free(tmp_ctx);
+ unlink("./test.ldb");
+ return true;
+
+failed:
+ talloc_free(tmp_ctx);
+ unlink("./test.ldb");
+ return false;
+}
+
+struct torture_suite *torture_local_dbspeed(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *s = torture_suite_create(mem_ctx, "dbspeed");
+ torture_suite_add_simple_tcase_const(s, "tdb_speed", test_tdb_speed,
+ NULL);
+ torture_suite_add_simple_tcase_const(s, "ldb_speed", test_ldb_speed,
+ NULL);
+ return s;
+}
diff --git a/source4/torture/local/fsrvp_state.c b/source4/torture/local/fsrvp_state.c
new file mode 100644
index 0000000..9b63ec1
--- /dev/null
+++ b/source4/torture/local/fsrvp_state.c
@@ -0,0 +1,492 @@
+/*
+ Test suite for FSRVP server state
+
+ Copyright (C) David Disseldorp 2012-2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <unistd.h>
+
+#include "librpc/gen_ndr/security.h"
+#include "lib/param/param.h"
+#include "lib/util/dlinklist.h"
+#include "libcli/resolve/resolve.h"
+#include "librpc/gen_ndr/ndr_fsrvp.h"
+#include "librpc/gen_ndr/ndr_fsrvp_c.h"
+#include "source3/rpc_server/fss/srv_fss_private.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+static bool test_fsrvp_state_empty(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct fss_global fss_global;
+ struct stat sbuf;
+ char db_dir[] = "fsrvp_torture_XXXXXX";
+ char *db_path = talloc_asprintf(NULL, "%s/%s",
+ mkdtemp(db_dir), FSS_DB_NAME);
+
+ memset(&fss_global, 0, sizeof(fss_global));
+ fss_global.mem_ctx = talloc_new(NULL);
+ fss_global.db_path = db_path;
+
+ status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
+ fss_global.sc_sets_count, fss_global.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to store empty fss state");
+
+ torture_assert_int_equal(tctx, stat(fss_global.db_path, &sbuf), 0,
+ "failed to stat fss state tdb");
+ talloc_free(fss_global.mem_ctx);
+
+ memset(&fss_global, 0, sizeof(fss_global));
+ fss_global.mem_ctx = talloc_new(NULL);
+ fss_global.db_path = db_path;
+
+ status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
+ &fss_global.sc_sets_count,
+ fss_global.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to retrieve empty fss state");
+ torture_assert_int_equal(tctx, fss_global.sc_sets_count, 0,
+ "sc_sets_count set when it should be zero");
+ talloc_free(fss_global.mem_ctx);
+ unlink(db_path);
+ rmdir(db_dir);
+ talloc_free(db_path);
+
+ return true;
+}
+
+static bool test_fsrvp_state_sc_set(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct fss_sc_set **sc_set_out)
+{
+ struct fss_sc_set *sc_set;
+
+ sc_set = talloc_zero(mem_ctx, struct fss_sc_set);
+ sc_set->id = GUID_random();
+ sc_set->id_str = GUID_string(sc_set, &sc_set->id);
+ sc_set->state = FSS_SC_COMMITED;
+ sc_set->context = FSRVP_CTX_FILE_SHARE_BACKUP;
+ *sc_set_out = sc_set;
+
+ return true;
+}
+
+static bool test_fsrvp_state_sc(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct fss_sc **sc_out)
+{
+ struct fss_sc *sc;
+
+ sc = talloc_zero(mem_ctx, struct fss_sc);
+ sc->id = GUID_random();
+ sc->id_str = GUID_string(sc, &sc->id);
+ sc->volume_name = talloc_strdup(sc, "/this/is/a/path");
+ /* keep snap path NULL, i.e. not yet committed */
+ sc->create_ts = time(NULL);
+ *sc_out = sc;
+
+ return true;
+}
+
+static bool test_fsrvp_state_smap(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const char *base_share_name,
+ const char *sc_share_name,
+ struct fss_sc_smap **smap_out)
+{
+ struct fss_sc_smap *smap;
+
+ smap = talloc_zero(mem_ctx, struct fss_sc_smap);
+ smap->share_name = talloc_strdup(mem_ctx, base_share_name);
+ smap->sc_share_name = talloc_strdup(mem_ctx, sc_share_name);
+ smap->sc_share_comment = talloc_strdup(mem_ctx, "test sc share comment");
+ smap->is_exposed = false;
+ *smap_out = smap;
+
+ return true;
+}
+
+static bool test_fsrvp_state_smap_compare(struct torture_context *tctx,
+ struct fss_sc_smap *smap_1,
+ struct fss_sc_smap *smap_2)
+{
+ /* already confirmed by caller */
+ torture_assert_str_equal(tctx, smap_1->sc_share_name,
+ smap_2->sc_share_name,
+ "smap sc share name strings differ");
+
+ torture_assert_str_equal(tctx, smap_1->share_name,
+ smap_2->share_name,
+ "smap share name strings differ");
+
+ torture_assert_str_equal(tctx, smap_1->sc_share_comment,
+ smap_2->sc_share_comment,
+ "smap sc share comment strings differ");
+
+ torture_assert(tctx, (smap_1->is_exposed == smap_2->is_exposed),
+ "smap exposure settings differ");
+
+ return true;
+}
+
+static bool test_fsrvp_state_sc_compare(struct torture_context *tctx,
+ struct fss_sc *sc_1,
+ struct fss_sc *sc_2)
+{
+ struct fss_sc_smap *smap_1;
+ struct fss_sc_smap *smap_2;
+ bool ok;
+
+ /* should have already been confirmed by the caller */
+ torture_assert(tctx, GUID_equal(&sc_1->id, &sc_2->id),
+ "sc guids differ");
+
+ torture_assert_str_equal(tctx, sc_1->volume_name, sc_2->volume_name,
+ "sc volume_name strings differ");
+
+ /* may be null, assert_str_eq handles null ptrs safely */
+ torture_assert_str_equal(tctx, sc_1->sc_path, sc_2->sc_path,
+ "sc path strings differ");
+
+ torture_assert(tctx, difftime(sc_1->create_ts, sc_2->create_ts) == 0,
+ "sc create timestamps differ");
+
+ torture_assert_int_equal(tctx, sc_1->smaps_count, sc_2->smaps_count,
+ "sc smaps counts differ");
+
+ for (smap_1 = sc_1->smaps; smap_1; smap_1 = smap_1->next) {
+ bool matched = false;
+ for (smap_2 = sc_2->smaps; smap_2; smap_2 = smap_2->next) {
+ if (strcmp(smap_1->sc_share_name,
+ smap_2->sc_share_name) == 0) {
+ matched = true;
+ ok = test_fsrvp_state_smap_compare(tctx,
+ smap_1,
+ smap_2);
+ torture_assert(tctx, ok, "");
+ break;
+ }
+ }
+ torture_assert(tctx, matched, "no match for smap");
+ }
+
+ return true;
+}
+
+static bool test_fsrvp_state_sc_set_compare(struct torture_context *tctx,
+ struct fss_sc_set *sc_set_1,
+ struct fss_sc_set *sc_set_2)
+{
+ struct fss_sc *sc_1;
+ struct fss_sc *sc_2;
+ bool ok;
+
+ /* should have already been confirmed by the caller */
+ torture_assert(tctx, GUID_equal(&sc_set_1->id, &sc_set_2->id),
+ "sc_set guids differ");
+
+ torture_assert_str_equal(tctx, sc_set_1->id_str, sc_set_2->id_str,
+ "sc_set guid strings differ");
+
+ torture_assert_int_equal(tctx, sc_set_1->state, sc_set_2->state,
+ "sc_set state enums differ");
+
+ torture_assert_int_equal(tctx, sc_set_1->context, sc_set_2->context,
+ "sc_set contexts differ");
+
+ torture_assert_int_equal(tctx, sc_set_1->scs_count, sc_set_2->scs_count,
+ "sc_set sc counts differ");
+
+ for (sc_1 = sc_set_1->scs; sc_1; sc_1 = sc_1->next) {
+ bool matched = false;
+ for (sc_2 = sc_set_2->scs; sc_2; sc_2 = sc_2->next) {
+ if (GUID_equal(&sc_1->id, &sc_2->id)) {
+ matched = true;
+ ok = test_fsrvp_state_sc_compare(tctx, sc_1,
+ sc_2);
+ torture_assert(tctx, ok, "");
+ break;
+ }
+ }
+ torture_assert(tctx, matched, "no match for sc");
+ }
+ return true;
+}
+
+static bool test_fsrvp_state_compare(struct torture_context *tctx,
+ struct fss_global *fss_1,
+ struct fss_global *fss_2)
+{
+ struct fss_sc_set *sc_set_1;
+ struct fss_sc_set *sc_set_2;
+ bool ok;
+
+ torture_assert_int_equal(tctx, fss_1->sc_sets_count,
+ fss_2->sc_sets_count,
+ "sc_sets_count differ");
+
+ for (sc_set_1 = fss_1->sc_sets; sc_set_1; sc_set_1 = sc_set_1->next) {
+ bool matched = false;
+ for (sc_set_2 = fss_2->sc_sets;
+ sc_set_2;
+ sc_set_2 = sc_set_2->next) {
+ if (GUID_equal(&sc_set_1->id, &sc_set_2->id)) {
+ matched = true;
+ ok = test_fsrvp_state_sc_set_compare(tctx,
+ sc_set_1,
+ sc_set_2);
+ torture_assert(tctx, ok, "");
+ break;
+ }
+ }
+ torture_assert(tctx, matched, "no match for sc_set");
+ }
+
+ return true;
+}
+
+/*
+ * test a simple hierarchy of:
+ *
+ * |
+ * sc_set
+ * |
+ * sc
+ * \
+ * smap
+ */
+static bool test_fsrvp_state_single(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ bool ok;
+ struct fss_global fss_gs;
+ struct fss_global fss_gr;
+ struct fss_sc_set *sc_set;
+ struct fss_sc *sc;
+ struct fss_sc_smap *smap;
+ char db_dir[] = "fsrvp_torture_XXXXXX";
+ char *db_path = talloc_asprintf(NULL, "%s/%s",
+ mkdtemp(db_dir), FSS_DB_NAME);
+
+ memset(&fss_gs, 0, sizeof(fss_gs));
+ fss_gs.mem_ctx = talloc_new(NULL);
+ fss_gs.db_path = db_path;
+
+ ok = test_fsrvp_state_sc_set(tctx, fss_gs.mem_ctx, &sc_set);
+ torture_assert(tctx, ok, "failed to create sc set");
+
+ /* use parent as mem ctx */
+ ok = test_fsrvp_state_sc(tctx, sc_set, &sc);
+ torture_assert(tctx, ok, "failed to create sc");
+
+ ok = test_fsrvp_state_smap(tctx, sc, "base_share", "sc_share", &smap);
+ torture_assert(tctx, ok, "failed to create smap");
+
+ DLIST_ADD_END(fss_gs.sc_sets, sc_set);
+ fss_gs.sc_sets_count++;
+ DLIST_ADD_END(sc_set->scs, sc);
+ sc_set->scs_count++;
+ sc->sc_set = sc_set;
+ DLIST_ADD_END(sc->smaps, smap);
+ sc->smaps_count++;
+
+ status = fss_state_store(fss_gs.mem_ctx, fss_gs.sc_sets,
+ fss_gs.sc_sets_count, fss_gs.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to store fss state");
+
+ memset(&fss_gr, 0, sizeof(fss_gr));
+ fss_gr.mem_ctx = talloc_new(NULL);
+ fss_gr.db_path = db_path;
+
+ status = fss_state_retrieve(fss_gr.mem_ctx, &fss_gr.sc_sets,
+ &fss_gr.sc_sets_count, fss_gr.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to retrieve fss state");
+
+ ok = test_fsrvp_state_compare(tctx, &fss_gs, &fss_gr);
+ torture_assert(tctx, ok,
+ "stored and retrieved state comparison failed");
+
+ talloc_free(fss_gs.mem_ctx);
+ talloc_free(fss_gr.mem_ctx);
+ unlink(db_path);
+ rmdir(db_dir);
+ talloc_free(db_path);
+
+ return true;
+}
+
+/*
+ * test a complex hierarchy of:
+ *
+ * /\
+ * / \
+ * sc_set_a sc_set_b
+ * / \
+ * sc_aa sc_ab
+ * | | \
+ * smap_aaa | \
+ * | \
+ * smap_aba smap_abb
+ */
+static bool test_fsrvp_state_multi(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ bool ok;
+ struct fss_global fss_gs;
+ struct fss_global fss_gr;
+ struct fss_sc_set *sc_set_a;
+ struct fss_sc_set *sc_set_b;
+ struct fss_sc *sc_aa;
+ struct fss_sc *sc_ab;
+ struct fss_sc_smap *smap_aaa;
+ struct fss_sc_smap *smap_aba;
+ struct fss_sc_smap *smap_abb;
+ char db_dir[] = "fsrvp_torture_XXXXXX";
+ char *db_path = talloc_asprintf(NULL, "%s/%s",
+ mkdtemp(db_dir), FSS_DB_NAME);
+
+ memset(&fss_gs, 0, sizeof(fss_gs));
+ fss_gs.mem_ctx = talloc_new(NULL);
+ fss_gs.db_path = db_path;
+
+ ok = test_fsrvp_state_sc_set(tctx, fss_gs.mem_ctx, &sc_set_a);
+ torture_assert(tctx, ok, "failed to create sc set");
+
+ ok = test_fsrvp_state_sc_set(tctx, fss_gs.mem_ctx, &sc_set_b);
+ torture_assert(tctx, ok, "failed to create sc set");
+
+ /* use parent as mem ctx */
+ ok = test_fsrvp_state_sc(tctx, sc_set_a, &sc_aa);
+ torture_assert(tctx, ok, "failed to create sc");
+
+ ok = test_fsrvp_state_sc(tctx, sc_set_a, &sc_ab);
+ torture_assert(tctx, ok, "failed to create sc");
+
+ ok = test_fsrvp_state_smap(tctx, sc_ab, "share_aa", "sc_share_aaa",
+ &smap_aaa);
+ torture_assert(tctx, ok, "failed to create smap");
+
+ ok = test_fsrvp_state_smap(tctx, sc_ab, "share_ab", "sc_share_aba",
+ &smap_aba);
+ torture_assert(tctx, ok, "failed to create smap");
+
+ ok = test_fsrvp_state_smap(tctx, sc_ab, "share_ab", "sc_share_abb",
+ &smap_abb);
+ torture_assert(tctx, ok, "failed to create smap");
+
+ DLIST_ADD_END(fss_gs.sc_sets, sc_set_a);
+ fss_gs.sc_sets_count++;
+ DLIST_ADD_END(fss_gs.sc_sets, sc_set_b);
+ fss_gs.sc_sets_count++;
+
+ DLIST_ADD_END(sc_set_a->scs, sc_aa);
+ sc_set_a->scs_count++;
+ sc_aa->sc_set = sc_set_a;
+ DLIST_ADD_END(sc_set_a->scs, sc_ab);
+ sc_set_a->scs_count++;
+ sc_ab->sc_set = sc_set_a;
+
+ DLIST_ADD_END(sc_aa->smaps, smap_aaa);
+ sc_aa->smaps_count++;
+ DLIST_ADD_END(sc_ab->smaps, smap_aba);
+ sc_ab->smaps_count++;
+ DLIST_ADD_END(sc_ab->smaps, smap_abb);
+ sc_ab->smaps_count++;
+
+ status = fss_state_store(fss_gs.mem_ctx, fss_gs.sc_sets,
+ fss_gs.sc_sets_count, fss_gs.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to store fss state");
+
+ memset(&fss_gr, 0, sizeof(fss_gr));
+ fss_gr.mem_ctx = talloc_new(NULL);
+ fss_gr.db_path = db_path;
+ status = fss_state_retrieve(fss_gr.mem_ctx, &fss_gr.sc_sets,
+ &fss_gr.sc_sets_count, fss_gr.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to retrieve fss state");
+
+ ok = test_fsrvp_state_compare(tctx, &fss_gs, &fss_gr);
+ torture_assert(tctx, ok,
+ "stored and retrieved state comparison failed");
+
+ talloc_free(fss_gs.mem_ctx);
+ talloc_free(fss_gr.mem_ctx);
+ unlink(db_path);
+ rmdir(db_dir);
+ talloc_free(db_path);
+
+ return true;
+}
+
+static bool test_fsrvp_state_none(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct fss_global fss_global;
+ char db_dir[] = "fsrvp_torture_XXXXXX";
+ char *db_path = talloc_asprintf(NULL, "%s/%s",
+ mkdtemp(db_dir), FSS_DB_NAME);
+
+ memset(&fss_global, 0, sizeof(fss_global));
+ fss_global.mem_ctx = talloc_new(NULL);
+ fss_global.db_path = db_path;
+
+ status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
+ &fss_global.sc_sets_count,
+ fss_global.db_path);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to retrieve fss state");
+ torture_assert_int_equal(tctx, fss_global.sc_sets_count, 0,
+ "sc_sets_count set when it should be zero");
+ talloc_free(fss_global.mem_ctx);
+ unlink(db_path);
+ rmdir(db_dir);
+ talloc_free(db_path);
+
+ return true;
+}
+
+struct torture_suite *torture_local_fsrvp(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "fsrvp_state");
+
+ /* dbwrap uses talloc_tos(), hence we need a stackframe :( */
+ talloc_stackframe();
+
+ torture_suite_add_simple_test(suite,
+ "state_empty",
+ test_fsrvp_state_empty);
+
+ torture_suite_add_simple_test(suite,
+ "state_single",
+ test_fsrvp_state_single);
+
+ torture_suite_add_simple_test(suite,
+ "state_multi",
+ test_fsrvp_state_multi);
+
+ torture_suite_add_simple_test(suite,
+ "state_none",
+ test_fsrvp_state_none);
+
+ return suite;
+}
diff --git a/source4/torture/local/local.c b/source4/torture/local/local.c
new file mode 100644
index 0000000..95417ef
--- /dev/null
+++ b/source4/torture/local/local.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/local/proto.h"
+#include "torture/ndr/proto.h"
+#include "torture/auth/proto.h"
+#include "../lib/crypto/test_proto.h"
+#include "lib/registry/tests/proto.h"
+#include "lib/replace/replace-testsuite.h"
+
+/* ignore me */ static struct torture_suite *
+ (*suite_generators[]) (TALLOC_CTX *mem_ctx) =
+{
+ torture_local_binding_string,
+ torture_ntlmssp,
+ torture_smbencrypt,
+ torture_local_messaging,
+ torture_local_irpc,
+ torture_local_util_strlist,
+ torture_local_util_file,
+ torture_local_util_str,
+ torture_local_util_time,
+ torture_local_util_data_blob,
+ torture_local_util_binsearch,
+ torture_local_util_asn1,
+ torture_local_util_anonymous_shared,
+ torture_local_util_strv,
+ torture_local_util_strv_util,
+ torture_local_util,
+ torture_local_idtree,
+ torture_local_dlinklist,
+ torture_local_genrand,
+ torture_local_iconv,
+ torture_local_socket,
+ torture_pac,
+ torture_local_resolve,
+ torture_local_ndr,
+ torture_local_tdr,
+ torture_local_share,
+ torture_local_loadparm,
+ torture_local_charset,
+ torture_local_convert_string_handle,
+ torture_local_convert_string,
+ torture_local_string_case_handle,
+ torture_local_string_case,
+ torture_local_util_unistr,
+ torture_local_event,
+ torture_local_tevent_req,
+ torture_local_torture,
+ torture_local_dbspeed,
+ torture_ldb,
+ torture_dsdb_dn,
+ torture_dsdb_syntax,
+ torture_registry,
+ torture_local_verif_trailer,
+ torture_local_nss,
+ torture_local_fsrvp,
+ torture_local_util_str_escape,
+ torture_local_tfork,
+ torture_local_mdspkt,
+ torture_local_smbtorture,
+ NULL
+};
+
+NTSTATUS torture_local_init(TALLOC_CTX *ctx)
+{
+ int i;
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "local");
+
+ torture_suite_add_simple_test(suite, "talloc", torture_local_talloc);
+ torture_suite_add_simple_test(suite, "replace", torture_local_replace);
+
+ torture_suite_add_simple_test(suite,
+ "crypto.md4", torture_local_crypto_md4);
+
+ for (i = 0; suite_generators[i]; i++)
+ torture_suite_add_suite(suite,
+ suite_generators[i](ctx));
+
+ suite->description = talloc_strdup(suite,
+ "Local, Samba-specific tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/local/mdspkt.c b/source4/torture/local/mdspkt.c
new file mode 100644
index 0000000..dd9c391
--- /dev/null
+++ b/source4/torture/local/mdspkt.c
@@ -0,0 +1,104 @@
+/*
+ * Tests for mdssvc packets (un)marshalling
+ *
+ * Copyright Ralph Boehme <slow@samba.org> 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+#include "lib/util/samba_util.h"
+#include "lib/torture/torture.h"
+#include "lib/util/data_blob.h"
+#include "torture/local/proto.h"
+#include "mdssvc/marshalling.h"
+
+static const unsigned char mdspkt_empty_cnid_fm[] = {
+ 0x34, 0x33, 0x32, 0x31, 0x33, 0x30, 0x64, 0x6d,
+ 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x00,
+ 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x87, 0x08, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const char *mdspkt_empty_cnid_fm_dump =
+"DALLOC_CTX(#1): {\n"
+" sl_array_t(#3): {\n"
+" uint64_t: 0x0023\n"
+" CNIDs: unkn1: 0x0, unkn2: 0x0\n"
+" DALLOC_CTX(#0): {\n"
+" }\n"
+" sl_filemeta_t(#0): {\n"
+" }\n"
+" }\n"
+"}\n";
+
+static bool test_mdspkt_empty_cnid_fm(struct torture_context *tctx)
+{
+ DALLOC_CTX *d = NULL;
+ sl_cnids_t *cnids = NULL;
+ char *dstr = NULL;
+ size_t ncnids;
+ bool ret = true;
+
+ d = dalloc_new(tctx);
+ torture_assert_not_null_goto(tctx, d, ret, done,
+ "dalloc_new failed\n");
+
+ ret = sl_unpack(d,
+ (const char *)mdspkt_empty_cnid_fm,
+ sizeof(mdspkt_empty_cnid_fm));
+ torture_assert_goto(tctx, ret, ret, done, "sl_unpack failed\n");
+
+ cnids = dalloc_get(d, "DALLOC_CTX", 0, "sl_cnids_t", 1);
+ torture_assert_not_null_goto(tctx, cnids, ret, done,
+ "dalloc_get cnids failed\n");
+
+ ncnids = dalloc_size(cnids->ca_cnids);
+ torture_assert_int_equal_goto(tctx, ncnids, 0, ret, done,
+ "Wrong number of CNIDs\n");
+
+ dstr = dalloc_dump(d, 0);
+ torture_assert_not_null_goto(tctx, dstr, ret, done,
+ "dalloc_dump failed\n");
+
+ torture_assert_str_equal_goto(tctx, dstr, mdspkt_empty_cnid_fm_dump,
+ ret, done, "Bad dump\n");
+
+done:
+ TALLOC_FREE(d);
+ return ret;
+}
+
+struct torture_suite *torture_local_mdspkt(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(mem_ctx, "mdspkt");
+
+ torture_suite_add_simple_test(suite,
+ "empty_cnid_fm",
+ test_mdspkt_empty_cnid_fm);
+
+ return suite;
+}
diff --git a/source4/torture/local/nss_tests.c b/source4/torture/local/nss_tests.c
new file mode 100644
index 0000000..e911aa2
--- /dev/null
+++ b/source4/torture/local/nss_tests.c
@@ -0,0 +1,1061 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of the nss wrapper
+
+ Copyright (C) Guenther Deschner 2009-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/replace/system/passwd.h"
+
+static bool copy_passwd(struct torture_context *tctx,
+ const struct passwd *pwd,
+ struct passwd *p)
+{
+ p->pw_name = talloc_strdup(tctx, pwd->pw_name);
+ torture_assert(tctx, (p->pw_name != NULL || pwd->pw_name == NULL), __location__);
+ p->pw_passwd = talloc_strdup(tctx, pwd->pw_passwd);
+ torture_assert(tctx, (p->pw_passwd != NULL || pwd->pw_passwd == NULL), __location__);
+ p->pw_uid = pwd->pw_uid;
+ p->pw_gid = pwd->pw_gid;
+ p->pw_gecos = talloc_strdup(tctx, pwd->pw_gecos);
+ torture_assert(tctx, (p->pw_gecos != NULL || pwd->pw_gecos == NULL), __location__);
+ p->pw_dir = talloc_strdup(tctx, pwd->pw_dir);
+ torture_assert(tctx, (p->pw_dir != NULL || pwd->pw_dir == NULL), __location__);
+ p->pw_shell = talloc_strdup(tctx, pwd->pw_shell);
+ torture_assert(tctx, (p->pw_shell != NULL || pwd->pw_shell == NULL), __location__);
+
+ return true;
+}
+
+static void print_passwd(struct passwd *pwd)
+{
+ printf("%s:%s:%lu:%lu:%s:%s:%s\n",
+ pwd->pw_name,
+ pwd->pw_passwd,
+ (unsigned long)pwd->pw_uid,
+ (unsigned long)pwd->pw_gid,
+ pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell);
+}
+
+
+static bool test_getpwnam(struct torture_context *tctx,
+ const char *name,
+ struct passwd *pwd_p)
+{
+ struct passwd *pwd;
+ int ret;
+
+ torture_comment(tctx, "Testing getpwnam: %s\n", name);
+
+ errno = 0;
+ pwd = getpwnam(name);
+ ret = errno;
+ torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
+ "getpwnam(%s) failed - %d - %s",
+ name, ret, strerror(ret)));
+
+ if (pwd_p != NULL) {
+ torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
+ }
+
+ return true;
+}
+
+static bool test_getpwnam_r(struct torture_context *tctx,
+ const char *name,
+ struct passwd *pwd_p)
+{
+ struct passwd pwd, *pwdp;
+ char buffer[4096];
+ int ret;
+
+ torture_comment(tctx, "Testing getpwnam_r: %s\n", name);
+
+ ret = getpwnam_r(name, &pwd, buffer, sizeof(buffer), &pwdp);
+ torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
+ "getpwnam_r(%s) failed - %d - %s",
+ name, ret, strerror(ret)));
+
+ print_passwd(&pwd);
+
+ if (pwd_p != NULL) {
+ torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
+ }
+
+ return true;
+}
+
+static bool test_getpwuid(struct torture_context *tctx,
+ uid_t uid,
+ struct passwd *pwd_p)
+{
+ struct passwd *pwd;
+ int ret;
+
+ torture_comment(tctx, "Testing getpwuid: %lu\n", (unsigned long)uid);
+
+ errno = 0;
+ pwd = getpwuid(uid);
+ ret = errno;
+ torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
+ "getpwuid(%lu) failed - %d - %s",
+ (unsigned long)uid, ret, strerror(ret)));
+
+ print_passwd(pwd);
+
+ if (pwd_p != NULL) {
+ torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
+ }
+
+ return true;
+}
+
+static bool test_getpwuid_r(struct torture_context *tctx,
+ uid_t uid,
+ struct passwd *pwd_p)
+{
+ struct passwd pwd, *pwdp;
+ char buffer[4096];
+ int ret;
+
+ torture_comment(tctx, "Testing getpwuid_r: %lu\n", (unsigned long)uid);
+
+ ret = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &pwdp);
+ torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
+ "getpwuid_r(%lu) failed - %d - %s",
+ (unsigned long)uid, ret, strerror(ret)));
+
+ print_passwd(&pwd);
+
+ if (pwd_p != NULL) {
+ torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
+ }
+
+ return true;
+}
+
+
+static bool copy_group(struct torture_context *tctx,
+ const struct group *grp,
+ struct group *g)
+{
+ int i;
+
+ g->gr_name = talloc_strdup(tctx, grp->gr_name);
+ torture_assert(tctx, (g->gr_name != NULL || grp->gr_name == NULL), __location__);
+ g->gr_passwd = talloc_strdup(tctx, grp->gr_passwd);
+ torture_assert(tctx, (g->gr_passwd != NULL || grp->gr_passwd == NULL), __location__);
+ g->gr_gid = grp->gr_gid;
+ g->gr_mem = NULL;
+
+ for (i=0; grp->gr_mem && grp->gr_mem[i]; i++) {
+ g->gr_mem = talloc_realloc(tctx, g->gr_mem, char *, i + 2);
+ torture_assert(tctx, (g->gr_mem != NULL), __location__);
+ g->gr_mem[i] = talloc_strdup(g->gr_mem, grp->gr_mem[i]);
+ torture_assert(tctx, (g->gr_mem[i] != NULL), __location__);
+ g->gr_mem[i+1] = NULL;
+ }
+
+ return true;
+}
+
+static void print_group(struct group *grp)
+{
+ int i;
+ printf("%s:%s:%lu:",
+ grp->gr_name,
+ grp->gr_passwd,
+ (unsigned long)grp->gr_gid);
+
+ if ((grp->gr_mem == NULL) || !grp->gr_mem[0]) {
+ printf("\n");
+ return;
+ }
+
+ for (i=0; grp->gr_mem[i+1]; i++) {
+ printf("%s,", grp->gr_mem[i]);
+ }
+ printf("%s\n", grp->gr_mem[i]);
+}
+
+static bool test_getgrnam(struct torture_context *tctx,
+ const char *name,
+ struct group *grp_p)
+{
+ struct group *grp;
+ int ret;
+
+ torture_comment(tctx, "Testing getgrnam: %s\n", name);
+
+ errno = 0;
+ grp = getgrnam(name);
+ ret = errno;
+ torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
+ "getgrnam(%s) failed - %d - %s",
+ name, ret, strerror(ret)));
+
+ print_group(grp);
+
+ if (grp_p != NULL) {
+ torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
+ }
+
+ return true;
+}
+
+static bool test_getgrnam_r(struct torture_context *tctx,
+ const char *name,
+ struct group *grp_p)
+{
+ struct group grp, *grpp;
+ char buffer[4096];
+ int ret;
+
+ torture_comment(tctx, "Testing getgrnam_r: %s\n", name);
+
+ ret = getgrnam_r(name, &grp, buffer, sizeof(buffer), &grpp);
+ torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
+ "getgrnam_r(%s) failed - %d - %s",
+ name, ret, strerror(ret)));
+
+ print_group(&grp);
+
+ if (grp_p != NULL) {
+ torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
+ }
+
+ return true;
+}
+
+
+static bool test_getgrgid(struct torture_context *tctx,
+ gid_t gid,
+ struct group *grp_p)
+{
+ struct group *grp;
+ int ret;
+
+ torture_comment(tctx, "Testing getgrgid: %lu\n", (unsigned long)gid);
+
+ errno = 0;
+ grp = getgrgid(gid);
+ ret = errno;
+ torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
+ "getgrgid(%lu) failed - %d - %s",
+ (unsigned long)gid, ret, strerror(ret)));
+
+ print_group(grp);
+
+ if (grp_p != NULL) {
+ torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
+ }
+
+ return true;
+}
+
+static bool test_getgrgid_r(struct torture_context *tctx,
+ gid_t gid,
+ struct group *grp_p)
+{
+ struct group grp, *grpp;
+ char buffer[4096];
+ int ret;
+
+ torture_comment(tctx, "Testing getgrgid_r: %lu\n", (unsigned long)gid);
+
+ ret = getgrgid_r(gid, &grp, buffer, sizeof(buffer), &grpp);
+ torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
+ "getgrgid_r(%lu) failed - %d - %s",
+ (unsigned long)gid, ret, strerror(ret)));
+
+ print_group(&grp);
+
+ if (grp_p != NULL) {
+ torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
+ }
+
+ return true;
+}
+
+static bool test_enum_passwd(struct torture_context *tctx,
+ struct passwd **pwd_array_p,
+ size_t *num_pwd_p)
+{
+ struct passwd *pwd;
+ struct passwd *pwd_array = NULL;
+ size_t num_pwd = 0;
+
+ torture_comment(tctx, "Testing setpwent\n");
+ setpwent();
+
+ while ((pwd = getpwent()) != NULL) {
+ torture_comment(tctx, "Testing getpwent\n");
+
+ print_passwd(pwd);
+ if (pwd_array_p && num_pwd_p) {
+ pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
+ torture_assert(tctx, pwd_array, "out of memory");
+ copy_passwd(tctx, pwd, &pwd_array[num_pwd]);
+ num_pwd++;
+ }
+ }
+
+ torture_comment(tctx, "Testing endpwent\n");
+ endpwent();
+
+ if (pwd_array_p) {
+ *pwd_array_p = pwd_array;
+ }
+ if (num_pwd_p) {
+ *num_pwd_p = num_pwd;
+ }
+
+ return true;
+}
+
+static bool test_enum_r_passwd(struct torture_context *tctx,
+ struct passwd **pwd_array_p,
+ size_t *num_pwd_p)
+{
+ struct passwd pwd, *pwdp;
+ struct passwd *pwd_array = NULL;
+ size_t num_pwd = 0;
+ char buffer[4096];
+ int ret;
+
+ torture_comment(tctx, "Testing setpwent\n");
+ setpwent();
+
+#ifdef HAVE_GETPWENT_R /* getpwent_r not supported on macOS */
+ while (1) {
+ torture_comment(tctx, "Testing getpwent_r\n");
+
+#ifdef SOLARIS_GETPWENT_R
+ ret = getpwent_r(&pwd, buffer, sizeof(buffer));
+#else /* SOLARIS_GETPWENT_R */
+ ret = getpwent_r(&pwd, buffer, sizeof(buffer), &pwdp);
+#endif /* SOLARIS_GETPWENT_R */
+ if (ret != 0) {
+ if (ret != ENOENT) {
+ torture_comment(tctx, "got %d return code\n", ret);
+ }
+ break;
+ }
+ print_passwd(&pwd);
+ if (pwd_array_p && num_pwd_p) {
+ pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
+ torture_assert(tctx, pwd_array, "out of memory");
+ copy_passwd(tctx, &pwd, &pwd_array[num_pwd]);
+ num_pwd++;
+ }
+ }
+#endif /* getpwent_r not supported on macOS */
+
+ torture_comment(tctx, "Testing endpwent\n");
+ endpwent();
+
+ if (pwd_array_p) {
+ *pwd_array_p = pwd_array;
+ }
+ if (num_pwd_p) {
+ *num_pwd_p = num_pwd;
+ }
+
+ return true;
+}
+
+static bool torture_assert_passwd_equal(struct torture_context *tctx,
+ const struct passwd *p1,
+ const struct passwd *p2,
+ const char *comment)
+{
+ torture_assert_str_equal(tctx, p1->pw_name, p2->pw_name, comment);
+ torture_assert_str_equal(tctx, p1->pw_passwd, p2->pw_passwd, comment);
+ torture_assert_int_equal(tctx, p1->pw_uid, p2->pw_uid, comment);
+ torture_assert_int_equal(tctx, p1->pw_gid, p2->pw_gid, comment);
+ torture_assert_str_equal(tctx, p1->pw_gecos, p2->pw_gecos, comment);
+ torture_assert_str_equal(tctx, p1->pw_dir, p2->pw_dir, comment);
+ torture_assert_str_equal(tctx, p1->pw_shell, p2->pw_shell, comment);
+
+ return true;
+}
+
+static bool test_passwd(struct torture_context *tctx)
+{
+ int i;
+ struct passwd *pwd, pwd1, pwd2;
+ size_t num_pwd;
+
+ torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
+ "failed to enumerate passwd");
+
+ for (i=0; i < num_pwd; i++) {
+ torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd1),
+ "failed to call getpwnam for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
+ "getpwent and getpwnam gave different results"),
+ __location__);
+ torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd2),
+ "failed to call getpwuid for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
+ "getpwent and getpwuid gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
+ "getpwnam and getpwuid gave different results"),
+ __location__);
+ }
+
+ return true;
+}
+
+static bool test_passwd_r(struct torture_context *tctx)
+{
+ int i;
+ struct passwd *pwd, pwd1, pwd2;
+ size_t num_pwd;
+
+ torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
+ "failed to enumerate passwd");
+
+ for (i=0; i < num_pwd; i++) {
+ torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
+ "failed to call getpwnam_r for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
+ "getpwent_r and getpwnam_r gave different results"),
+ __location__);
+ torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
+ "failed to call getpwuid_r for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
+ "getpwent_r and getpwuid_r gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
+ "getpwnam_r and getpwuid_r gave different results"),
+ __location__);
+ }
+
+ return true;
+}
+
+static bool test_passwd_r_cross(struct torture_context *tctx)
+{
+ int i;
+ struct passwd *pwd, pwd1, pwd2, pwd3, pwd4;
+ size_t num_pwd;
+
+ torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
+ "failed to enumerate passwd");
+
+ for (i=0; i < num_pwd; i++) {
+ torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
+ "failed to call getpwnam_r for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
+ "getpwent_r and getpwnam_r gave different results"),
+ __location__);
+ torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
+ "failed to call getpwuid_r for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
+ "getpwent_r and getpwuid_r gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
+ "getpwnam_r and getpwuid_r gave different results"),
+ __location__);
+ torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd3),
+ "failed to call getpwnam for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd3,
+ "getpwent_r and getpwnam gave different results"),
+ __location__);
+ torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd4),
+ "failed to call getpwuid for enumerated user");
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd4,
+ "getpwent_r and getpwuid gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd3, &pwd4,
+ "getpwnam and getpwuid gave different results"),
+ __location__);
+ }
+
+ return true;
+}
+
+static bool test_enum_group(struct torture_context *tctx,
+ struct group **grp_array_p,
+ size_t *num_grp_p)
+{
+ struct group *grp;
+ struct group *grp_array = NULL;
+ size_t num_grp = 0;
+
+ torture_comment(tctx, "Testing setgrent\n");
+ setgrent();
+
+ while ((grp = getgrent()) != NULL) {
+ torture_comment(tctx, "Testing getgrent\n");
+
+ print_group(grp);
+ if (grp_array_p && num_grp_p) {
+ grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
+ torture_assert(tctx, grp_array, "out of memory");
+ copy_group(tctx, grp, &grp_array[num_grp]);
+ num_grp++;
+ }
+ }
+
+ torture_comment(tctx, "Testing endgrent\n");
+ endgrent();
+
+ if (grp_array_p) {
+ *grp_array_p = grp_array;
+ }
+ if (num_grp_p) {
+ *num_grp_p = num_grp;
+ }
+
+ return true;
+}
+
+static bool test_enum_r_group(struct torture_context *tctx,
+ struct group **grp_array_p,
+ size_t *num_grp_p)
+{
+ struct group grp, *grpp;
+ struct group *grp_array = NULL;
+ size_t num_grp = 0;
+ char buffer[4096];
+ int ret;
+
+ torture_comment(tctx, "Testing setgrent\n");
+ setgrent();
+
+#ifdef HAVE_GETGRENT_R /* getgrent_r not supported on macOS */
+ while (1) {
+ torture_comment(tctx, "Testing getgrent_r\n");
+
+#ifdef SOLARIS_GETGRENT_R
+ ret = getgrent_r(&grp, buffer, sizeof(buffer));
+#else /* SOLARIS_GETGRENT_R */
+ ret = getgrent_r(&grp, buffer, sizeof(buffer), &grpp);
+#endif /* SOLARIS_GETGRENT_R */
+ if (ret != 0) {
+ if (ret != ENOENT) {
+ torture_comment(tctx, "got %d return code\n", ret);
+ }
+ break;
+ }
+ print_group(&grp);
+ if (grp_array_p && num_grp_p) {
+ grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
+ torture_assert(tctx, grp_array, "out of memory");
+ copy_group(tctx, &grp, &grp_array[num_grp]);
+ num_grp++;
+ }
+ }
+#endif /* getgrent_r not supported on macOS */
+
+ torture_comment(tctx, "Testing endgrent\n");
+ endgrent();
+
+ if (grp_array_p) {
+ *grp_array_p = grp_array;
+ }
+ if (num_grp_p) {
+ *num_grp_p = num_grp;
+ }
+
+ return true;
+}
+
+static bool torture_assert_group_equal(struct torture_context *tctx,
+ const struct group *g1,
+ const struct group *g2,
+ const char *comment)
+{
+ int i;
+ torture_assert_str_equal(tctx, g1->gr_name, g2->gr_name, comment);
+ torture_assert_str_equal(tctx, g1->gr_passwd, g2->gr_passwd, comment);
+ torture_assert_int_equal(tctx, g1->gr_gid, g2->gr_gid, comment);
+ torture_assert(tctx, !(g1->gr_mem && !g2->gr_mem), __location__);
+ torture_assert(tctx, !(!g1->gr_mem && g2->gr_mem), __location__);
+ if (!g1->gr_mem && !g2->gr_mem) {
+ return true;
+ }
+ for (i=0; g1->gr_mem[i] && g2->gr_mem[i]; i++) {
+ torture_assert_str_equal(tctx, g1->gr_mem[i], g2->gr_mem[i], comment);
+ }
+
+ return true;
+}
+
+static bool test_group(struct torture_context *tctx)
+{
+ int i;
+ struct group *grp, grp1, grp2;
+ size_t num_grp;
+
+ torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
+ "failed to enumerate group");
+
+ for (i=0; i < num_grp; i++) {
+ torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp1),
+ "failed to call getgrnam for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
+ "getgrent and getgrnam gave different results"),
+ __location__);
+ torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp2),
+ "failed to call getgrgid for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
+ "getgrent and getgrgid gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
+ "getgrnam and getgrgid gave different results"),
+ __location__);
+ }
+
+ return true;
+}
+
+static bool test_group_r(struct torture_context *tctx)
+{
+ int i;
+ struct group *grp, grp1, grp2;
+ size_t num_grp;
+
+ torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
+ "failed to enumerate group");
+
+ for (i=0; i < num_grp; i++) {
+ torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
+ "failed to call getgrnam_r for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
+ "getgrent_r and getgrnam_r gave different results"),
+ __location__);
+ torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
+ "failed to call getgrgid_r for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
+ "getgrent_r and getgrgid_r gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
+ "getgrnam_r and getgrgid_r gave different results"),
+ __location__);
+ }
+
+ return true;
+}
+
+static bool test_group_r_cross(struct torture_context *tctx)
+{
+ int i;
+ struct group *grp, grp1, grp2, grp3, grp4;
+ size_t num_grp;
+
+ torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
+ "failed to enumerate group");
+
+ for (i=0; i < num_grp; i++) {
+ torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
+ "failed to call getgrnam_r for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
+ "getgrent_r and getgrnam_r gave different results"),
+ __location__);
+ torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
+ "failed to call getgrgid_r for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
+ "getgrent_r and getgrgid_r gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
+ "getgrnam_r and getgrgid_r gave different results"),
+ __location__);
+ torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp3),
+ "failed to call getgrnam for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp3,
+ "getgrent_r and getgrnam gave different results"),
+ __location__);
+ torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp4),
+ "failed to call getgrgid for enumerated user");
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp4,
+ "getgrent_r and getgrgid gave different results"),
+ __location__);
+ torture_assert(tctx, torture_assert_group_equal(tctx, &grp3, &grp4,
+ "getgrnam and getgrgid gave different results"),
+ __location__);
+ }
+
+ return true;
+}
+
+#ifdef HAVE_GETGROUPLIST
+static bool test_getgrouplist(struct torture_context *tctx,
+ const char *user,
+ gid_t gid,
+ gid_t **gids_p,
+ int *num_gids_p)
+{
+ int ret;
+ int num_groups = 0;
+ gid_t *groups = NULL;
+
+ torture_comment(tctx, "Testing getgrouplist: %s\n", user);
+
+ ret = getgrouplist(user, gid, NULL, &num_groups);
+ if (ret == -1 || num_groups != 0) {
+
+ groups = talloc_array(tctx, gid_t, num_groups);
+ torture_assert(tctx, groups, "out of memory\n");
+
+ ret = getgrouplist(user, gid, groups, &num_groups);
+ }
+
+ torture_assert(tctx, (ret != -1), "failed to call getgrouplist");
+
+ torture_comment(tctx, "%s is member in %d groups\n", user, num_groups);
+
+ if (gids_p) {
+ *gids_p = groups;
+ }
+ if (num_gids_p) {
+ *num_gids_p = num_groups;
+ }
+
+ return true;
+}
+#endif /* HAVE_GETGROUPLIST */
+
+static bool test_user_in_group(struct torture_context *tctx,
+ const struct passwd *pwd,
+ const struct group *grp)
+{
+ int i;
+
+ for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
+ if (strequal(grp->gr_mem[i], pwd->pw_name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool test_membership_user(struct torture_context *tctx,
+ const struct passwd *pwd,
+ struct group *grp_array,
+ size_t num_grp)
+{
+ int num_user_groups = 0;
+ int num_user_groups_from_enum = 0;
+ gid_t *user_groups = NULL;
+ int g, i;
+ bool primary_group_had_user_member = false;
+
+ /*
+ * For the local users ('LOCALADMEMBER') below, the test fails.
+ * wb_queryuser() wrongly defaults the group sid to RID 513 i.e.
+ * 'LOCALADMEMBER/domusers', but those users have a different group sid.
+ *
+ * The fix for wb_queryuser() is not part of this MR. It is a complex
+ * task that needs to fill samlogon cache using S4USelf and will come
+ * sometime later. Once wb_queryuser() gets fixed, this can be removed.
+ */
+ if (strcmp(pwd->pw_name, "user1") == 0 ||
+ strcmp(pwd->pw_name, "user2") == 0 ||
+ strcmp(pwd->pw_name, "force_user") == 0 || pwd->pw_uid == 1000) {
+ return true;
+ }
+
+#ifdef HAVE_GETGROUPLIST
+ torture_assert(tctx, test_getgrouplist(tctx,
+ pwd->pw_name,
+ pwd->pw_gid,
+ &user_groups,
+ &num_user_groups),
+ "failed to test getgrouplist");
+#endif /* HAVE_GETGROUPLIST */
+
+ for (g=0; g < num_user_groups; g++) {
+ torture_assert(tctx, test_getgrgid(tctx, user_groups[g], NULL),
+ "failed to find the group the user is a member of");
+ }
+
+
+ for (i=0; i < num_grp; i++) {
+
+ struct group grp = grp_array[i];
+
+ if (test_user_in_group(tctx, pwd, &grp)) {
+
+ struct group current_grp;
+ num_user_groups_from_enum++;
+
+ torture_assert(tctx, test_getgrnam(tctx, grp.gr_name, &current_grp),
+ "failed to find the group the user is a member of");
+
+ if (current_grp.gr_gid == pwd->pw_gid) {
+ torture_comment(tctx, "primary group %s of user %s lists user as member\n",
+ current_grp.gr_name,
+ pwd->pw_name);
+ primary_group_had_user_member = true;
+ }
+
+ continue;
+ }
+ }
+
+ if (!primary_group_had_user_member) {
+ num_user_groups_from_enum++;
+ }
+
+ torture_assert_int_equal(tctx, num_user_groups, num_user_groups_from_enum,
+ "getgrouplist and real inspection of grouplist gave different results\n");
+
+ return true;
+}
+
+static bool test_membership(struct torture_context *tctx)
+{
+ const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
+ const char *old_group = getenv("NSS_WRAPPER_GROUP");
+ struct passwd *pwd;
+ size_t num_pwd;
+ struct group *grp;
+ size_t num_grp;
+ int i;
+ const char *env = getenv("ENVNAME");
+
+ if (!old_pwd || !old_group) {
+ torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
+ torture_skip(tctx, "nothing to test\n");
+ }
+
+ /*
+ * test_membership_user() fails for ad_dc with error like this:
+ *
+ * WARNING!: ../../source4/torture/local/nss_tests.c:823:
+ * num_user_groups was 3 (0x3), expected 2 (0x2): getgrouplist
+ * and real inspection of grouplist gave different results
+
+ * There are at least 3 reasons:
+
+ * 1. For each ADDOMAIN user, there is also a group with the same name:
+
+$ bin/wbinfo --user-info ADDOMAIN/alice
+ADDOMAIN/alice:*:3000015:65531::/home/ADDOMAIN/alice:/bin/false
+
+$ bin/wbinfo --group-info ADDOMAIN/alice
+ADDOMAIN/alice:x:3000015:ADDOMAIN/alice
+
+ * 2. ADDOMAIN/joe is the only user of "ADDOMAIN/Domain Users"
+ * e.g. alice is not there:
+
+$ bin/wbinfo --group-info "ADDOMAIN/Domain users"
+ADDOMAIN/domain users:x:65531:ADDOMAIN/joe
+
+ * 3. getgrouplist() for joe returns also "ADDOMAIN/samba users"
+ * but "ADDOMAIN/samba users" is an empty group:
+
+$ bin/wbinfo --group-info "ADDOMAIN/samba users"
+ADDOMAIN/samba users:x:3000051:
+
+ */
+
+ /* Only ad_member_idmap_rid sets 'winbind expand groups' */
+ if (strcmp(env, "ad_member_idmap_rid:local") != 0) {
+ torture_comment(tctx,
+ "Testing in env '%s' is not supported.\n",
+ env);
+ torture_skip(tctx, "nothing to test\n");
+ return true;
+ }
+
+ torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
+ "failed to enumerate passwd");
+ torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
+ "failed to enumerate group");
+
+ for (i=0; i < num_pwd; i++) {
+
+ torture_assert(tctx, test_membership_user(tctx, &pwd[i], grp, num_grp),
+ "failed to test membership for user");
+
+ }
+
+ return true;
+}
+
+static bool test_enumeration(struct torture_context *tctx)
+{
+ const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
+ const char *old_group = getenv("NSS_WRAPPER_GROUP");
+
+ if (!old_pwd || !old_group) {
+ torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
+ torture_skip(tctx, "nothing to test\n");
+ }
+
+ torture_assert(tctx, test_passwd(tctx),
+ "failed to test users");
+ torture_assert(tctx, test_group(tctx),
+ "failed to test groups");
+
+ return true;
+}
+
+static bool test_reentrant_enumeration(struct torture_context *tctx)
+{
+ const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
+ const char *old_group = getenv("NSS_WRAPPER_GROUP");
+
+ if (!old_pwd || !old_group) {
+ torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
+ torture_skip(tctx, "nothing to test\n");
+ }
+
+ torture_comment(tctx, "Testing re-entrant calls\n");
+
+ torture_assert(tctx, test_passwd_r(tctx),
+ "failed to test users");
+ torture_assert(tctx, test_group_r(tctx),
+ "failed to test groups");
+
+ return true;
+}
+
+static bool test_reentrant_enumeration_crosschecks(struct torture_context *tctx)
+{
+ const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
+ const char *old_group = getenv("NSS_WRAPPER_GROUP");
+
+ if (!old_pwd || !old_group) {
+ torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
+ torture_skip(tctx, "nothing to test\n");
+ }
+
+ torture_comment(tctx, "Testing re-entrant calls with cross checks\n");
+
+ torture_assert(tctx, test_passwd_r_cross(tctx),
+ "failed to test users");
+ torture_assert(tctx, test_group_r_cross(tctx),
+ "failed to test groups");
+
+ return true;
+}
+
+static bool test_passwd_duplicates(struct torture_context *tctx)
+{
+ size_t i, d;
+ struct passwd *pwd;
+ size_t num_pwd;
+ int duplicates = 0;
+
+ torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
+ "failed to enumerate passwd");
+
+ for (i=0; i < num_pwd; i++) {
+ const char *current_name = pwd[i].pw_name;
+ for (d=0; d < num_pwd; d++) {
+ const char *dup_name = pwd[d].pw_name;
+ if (d == i) {
+ continue;
+ }
+ if (!strequal(current_name, dup_name)) {
+ continue;
+ }
+
+ torture_warning(tctx, "found duplicate names:");
+ print_passwd(&pwd[d]);
+ print_passwd(&pwd[i]);
+ duplicates++;
+ }
+ }
+
+ if (duplicates) {
+ torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
+ }
+
+ return true;
+}
+
+static bool test_group_duplicates(struct torture_context *tctx)
+{
+ size_t i, d;
+ struct group *grp;
+ size_t num_grp;
+ int duplicates = 0;
+
+ torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
+ "failed to enumerate group");
+
+ for (i=0; i < num_grp; i++) {
+ const char *current_name = grp[i].gr_name;
+ for (d=0; d < num_grp; d++) {
+ const char *dup_name = grp[d].gr_name;
+ if (d == i) {
+ continue;
+ }
+ if (!strequal(current_name, dup_name)) {
+ continue;
+ }
+
+ torture_warning(tctx, "found duplicate names:");
+ print_group(&grp[d]);
+ print_group(&grp[i]);
+ duplicates++;
+ }
+ }
+
+ if (duplicates) {
+ torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
+ }
+
+ return true;
+}
+
+
+static bool test_duplicates(struct torture_context *tctx)
+{
+ const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
+ const char *old_group = getenv("NSS_WRAPPER_GROUP");
+
+ if (!old_pwd || !old_group) {
+ torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
+ torture_skip(tctx, "nothing to test\n");
+ }
+
+ torture_assert(tctx, test_passwd_duplicates(tctx),
+ "failed to test users");
+ torture_assert(tctx, test_group_duplicates(tctx),
+ "failed to test groups");
+
+ return true;
+}
+
+
+struct torture_suite *torture_local_nss(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "nss");
+
+ torture_suite_add_simple_test(suite, "enumeration", test_enumeration);
+ torture_suite_add_simple_test(suite, "reentrant enumeration", test_reentrant_enumeration);
+ torture_suite_add_simple_test(suite, "reentrant enumeration crosschecks", test_reentrant_enumeration_crosschecks);
+ torture_suite_add_simple_test(suite, "membership", test_membership);
+ torture_suite_add_simple_test(suite, "duplicates", test_duplicates);
+
+ return suite;
+}
diff --git a/source4/torture/local/smbtorture_fullname.c b/source4/torture/local/smbtorture_fullname.c
new file mode 100644
index 0000000..875b3cf
--- /dev/null
+++ b/source4/torture/local/smbtorture_fullname.c
@@ -0,0 +1,31 @@
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/local/proto.h"
+
+static bool test_smbtorture_always_pass(struct torture_context *tctx)
+{
+ return true;
+}
+
+struct torture_suite *torture_local_smbtorture(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "smbtorture");
+ struct torture_suite *suite_level1 = torture_suite_create(ctx,
+ "level1");
+ struct torture_suite *suite_level2 = torture_suite_create(ctx,
+ "level2");
+ struct torture_suite *suite_level3 = torture_suite_create(ctx,
+ "level3");
+
+ torture_suite_add_suite(suite_level2, suite_level3);
+ torture_suite_add_suite(suite_level1, suite_level2);
+ torture_suite_add_suite(suite, suite_level1);
+
+ torture_suite_add_simple_test(suite_level3, "always_pass",
+ test_smbtorture_always_pass);
+
+ suite->description = talloc_strdup(suite,
+ "smbtorture multilevel always pass test.");
+
+ return suite;
+}
diff --git a/source4/torture/local/torture.c b/source4/torture/local/torture.c
new file mode 100644
index 0000000..ca59ebf
--- /dev/null
+++ b/source4/torture/local/torture.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ local testing of torture
+
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/wait.h"
+#include "libcli/raw/libcliraw.h"
+#include "torture/util.h"
+#include "torture/local/proto.h"
+#include "param/provision.h"
+
+static bool test_tempdir(struct torture_context *tctx)
+{
+ char *location = NULL;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ torture_assert_ntstatus_ok(tctx, torture_temp_dir(mem_ctx, "tempdir", &location),
+ "torture_temp_dir should return NT_STATUS_OK" );
+
+ torture_assert(tctx, directory_exist(location),
+ "created dir doesn't exist");
+ return true;
+}
+
+static bool test_provision(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct provision_settings *settings = talloc_zero(tctx, struct provision_settings);
+ struct provision_result result;
+ char *targetdir = NULL;
+
+ torture_assert_ntstatus_ok(tctx, torture_temp_dir(tctx, "torture_provision", &targetdir),
+ "torture_temp_dir should return NT_STATUS_OK" );
+ settings->targetdir = talloc_steal(settings, targetdir);
+
+ settings->site_name = "SOME-SITE-NAME";
+ settings->root_dn_str = "DC=EXAMPLE,DC=COM";
+ settings->domain_dn_str = "DC=EXAMPLE,DC=COM";
+ settings->config_dn_str = NULL;
+ settings->schema_dn_str = NULL;
+ settings->invocation_id = NULL;
+ settings->netbios_name = "FOO";
+ settings->realm = "EXAMPLE.COM";
+ settings->domain = "EXAMPLE";
+ settings->netbios_name = "torture";
+ settings->ntds_dn_str = NULL;
+ settings->machine_password = "geheim";
+ settings->use_ntvfs = true;
+
+ status = provision_bare(settings, tctx->lp_ctx, settings, &result);
+
+ torture_assert_ntstatus_ok(tctx, status, "provision");
+
+ torture_assert_str_equal(tctx, result.domaindn, "DC=EXAMPLE,DC=COM",
+ "domaindn incorrect");
+
+ return true;
+}
+
+struct torture_suite *torture_local_torture(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "torture");
+
+ torture_suite_add_simple_test(suite, "tempdir", test_tempdir);
+ torture_suite_add_simple_test(suite, "provision", test_provision);
+
+ return suite;
+}
diff --git a/source4/torture/local/verif_trailer.c b/source4/torture/local/verif_trailer.c
new file mode 100644
index 0000000..acbd69b
--- /dev/null
+++ b/source4/torture/local/verif_trailer.c
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for DCE/RPC verification trailer parsing
+
+ Copyright (C) David Disseldorp 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <unistd.h>
+
+#include "librpc/gen_ndr/security.h"
+#include "lib/param/param.h"
+#include "lib/util/dlinklist.h"
+#include "libcli/resolve/resolve.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "librpc/rpc/rpc_common.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+/* VT blob obtained from an FSRVP request */
+uint8_t test_vt[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71,
+ 0x02, 0x40, 0x28, 0x00, 0x3c, 0x65, 0xe0, 0xa8,
+ 0x44, 0x27, 0x89, 0x43, 0xa6, 0x1d, 0x73, 0x73,
+ 0xdf, 0x8b, 0x22, 0x92, 0x01, 0x00, 0x00, 0x00,
+ 0x33, 0x05, 0x71, 0x71, 0xba, 0xbe, 0x37, 0x49,
+ 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36,
+ 0x01, 0x00, 0x00, 0x00};
+
+const char *vt_abstr_syntax = "a8e0653c-2744-4389-a61d-7373df8b2292/0x00000001";
+const char *vt_trans_syntax = "71710533-beba-4937-8319-b5dbef9ccc36/0x00000001";
+
+static bool test_verif_trailer_pctx(struct torture_context *tctx)
+{
+ DATA_BLOB blob;
+ bool ok;
+ struct dcerpc_sec_vt_pcontext pctx;
+ struct dcerpc_sec_verification_trailer *vt = NULL;
+ struct ndr_pull *ndr;
+ enum ndr_err_code ndr_err;
+ struct ndr_print *ndr_print;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ torture_assert(tctx, mem_ctx != NULL, "mem");
+
+ blob.data = test_vt;
+ blob.length = ARRAY_SIZE(test_vt);
+
+ ndr = ndr_pull_init_blob(&blob, mem_ctx);
+ torture_assert(tctx, ndr != NULL, "ndr");
+
+ ndr_err = ndr_pop_dcerpc_sec_verification_trailer(ndr, mem_ctx, &vt);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr");
+
+ ndr_print = talloc_zero(mem_ctx, struct ndr_print);
+ torture_assert(tctx, ndr_print != NULL, "mem");
+ ndr_print->print = ndr_print_printf_helper;
+ ndr_print->depth = 1;
+
+ ndr_print_dcerpc_sec_verification_trailer(ndr_print,
+ "Verification Trailer", vt);
+
+ ZERO_STRUCT(pctx);
+ ok = ndr_syntax_id_from_string(vt_abstr_syntax, &pctx.abstract_syntax);
+ torture_assert(tctx, ok, "vt_abstr_syntax");
+ ok = ndr_syntax_id_from_string(vt_trans_syntax, &pctx.transfer_syntax);
+ torture_assert(tctx, ok, "vt_trans_syntax");
+
+ ok = dcerpc_sec_verification_trailer_check(vt, NULL, &pctx, NULL);
+ torture_assert(tctx, ok, "VT check");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+struct torture_suite *torture_local_verif_trailer(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "verif_trailer");
+
+ torture_suite_add_simple_test(suite,
+ "pctx",
+ test_verif_trailer_pctx);
+
+ return suite;
+}
diff --git a/source4/torture/local/wscript_build b/source4/torture/local/wscript_build
new file mode 100644
index 0000000..741f667
--- /dev/null
+++ b/source4/torture/local/wscript_build
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+provision = bld.pyembed_libname('PROVISION')
+
+TORTURE_LOCAL_SOURCE = '''../../../lib/util/charset/tests/iconv.c
+ ../../../lib/talloc/testsuite.c ../../lib/messaging/tests/messaging.c
+ ../../lib/messaging/tests/irpc.c ../../librpc/tests/binding_string.c
+ ../../../lib/util/tests/idtree.c ../../../lib/util/tests/dlinklist.c
+ ../../lib/socket/testsuite.c ../../libcli/resolve/testsuite.c
+ ../../../lib/util/tests/strlist.c ../../../lib/util/tests/binsearch.c
+ ../../../lib/util/tests/str.c ../../../lib/util/tests/time.c
+ ../../../lib/util/tests/asn1_tests.c ../../../lib/util/tests/data_blob.c
+ ../../../lib/util/tests/file.c ../../../lib/util/tests/genrand.c
+ ../../../lib/util/charset/tests/charset.c
+ ../../../lib/util/charset/tests/convert_string.c
+ ../../../lib/util/charset/tests/util_unistr.c
+ ../../../lib/tdr/testsuite.c
+ ../../../lib/tevent/testsuite.c ../../param/tests/share.c
+ ../../../lib/tevent/test_req.c
+ ../../param/tests/loadparm.c local.c
+ dbspeed.c torture.c ../ldb/ldb.c ../../dsdb/common/tests/dsdb_dn.c
+ ../../dsdb/schema/tests/schema_syntax.c
+ ../../../lib/util/tests/anonymous_shared.c
+ ../../../lib/util/tests/strv.c
+ ../../../lib/util/tests/strv_util.c
+ ../../../lib/util/tests/util.c
+ ../../../lib/util/tests/util_str_escape.c
+ ../../../lib/util/tests/tfork.c
+ verif_trailer.c
+ nss_tests.c
+ mdspkt.c
+ fsrvp_state.c
+ smbtorture_fullname.c'''
+
+TORTURE_LOCAL_DEPS = 'RPC_NDR_ECHO TDR LIBCLI_SMB MESSAGING iconv TORTURE_AUTH TORTURE_UTIL TORTURE_NDR TORTURE_LIBCRYPTO share torture_registry %s ldb samdb replace-test RPC_FSS_STATE util_str_escape' % provision
+
+bld.SAMBA_MODULE('TORTURE_LOCAL',
+ source=TORTURE_LOCAL_SOURCE,
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_local_init',
+ deps=TORTURE_LOCAL_DEPS,
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
diff --git a/source4/torture/locktest.c b/source4/torture/locktest.c
new file mode 100644
index 0000000..11701a9
--- /dev/null
+++ b/source4/torture/locktest.c
@@ -0,0 +1,700 @@
+/*
+ Unix SMB/CIFS implementation.
+ randomised byte range lock tester
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "lib/events/events.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "libcli/libcli.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+
+static int numops = 1000;
+static int showall;
+static int analyze;
+static int hide_unlock_fails;
+static int use_oplocks;
+static unsigned int lock_range = 100;
+static unsigned int lock_base = 0;
+static unsigned int min_length = 0;
+static int exact_error_codes;
+static int zero_zero;
+
+#define FILENAME "\\locktest.dat"
+
+#define READ_PCT 50
+#define LOCK_PCT 45
+#define UNLOCK_PCT 70
+#define RANGE_MULTIPLE 1
+#define NSERVERS 2
+#define NCONNECTIONS 2
+#define NFILES 2
+#define LOCK_TIMEOUT 0
+
+static struct cli_credentials *servers[NSERVERS];
+
+enum lock_op {OP_LOCK, OP_UNLOCK, OP_REOPEN};
+
+struct record {
+ enum lock_op lock_op;
+ enum brl_type lock_type;
+ char conn, f;
+ uint64_t start, len;
+ char needed;
+ uint16_t pid;
+};
+
+#define PRESETS 0
+
+#if PRESETS
+static struct record preset[] = {
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 0, 1},
+{OP_UNLOCK, 0 , 0, 0, 2, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+};
+#endif
+
+static struct record *recorded;
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct smbcli_state *connect_one(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
+ char *share, int snum, int conn)
+{
+ struct smbcli_state *c;
+ char *server, *myname;
+ NTSTATUS status;
+ int retries = 10;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(lp_ctx, &options);
+ lpcfg_smbcli_session_options(lp_ctx, &session_options);
+
+ printf("connect_one(%s, %d, %d)\n", share, snum, conn);
+
+ server = talloc_strdup(mem_ctx, share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ if (snum == 0) {
+ char **unc_list = NULL;
+ int num_unc_names;
+ const char *p;
+ p = lpcfg_parm_string(lp_ctx, NULL, "torture", "unclist");
+ if (p) {
+ char *h, *s;
+ unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
+ if (!unc_list || num_unc_names <= 0) {
+ printf("Failed to load unc names list from '%s'\n", p);
+ exit(1);
+ }
+
+ if (!smbcli_parse_unc(unc_list[conn % num_unc_names],
+ NULL, &h, &s)) {
+ printf("Failed to parse UNC name %s\n",
+ unc_list[conn % num_unc_names]);
+ exit(1);
+ }
+ server = talloc_strdup(mem_ctx, h);
+ share = talloc_strdup(mem_ctx, s);
+ }
+ }
+
+
+ myname = talloc_asprintf(mem_ctx, "lock-%d-%d", (int) getpid(), snum);
+ cli_credentials_set_workstation(servers[snum], myname, CRED_SPECIFIED);
+
+ do {
+ printf("\\\\%s\\%s\n", server, share);
+ status = smbcli_full_connection(NULL, &c,
+ server,
+ lpcfg_smb_ports(lp_ctx),
+ share, NULL,
+ lpcfg_socket_options(lp_ctx),
+ servers[snum],
+ lpcfg_resolve_context(lp_ctx),
+ ev, &options, &session_options,
+ lpcfg_gensec_settings(mem_ctx, lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ sleep(2);
+ }
+ } while (!NT_STATUS_IS_OK(status) && retries--);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return c;
+}
+
+
+static void reconnect(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ char *share[NSERVERS])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++) {
+ if (cli[server][conn]) {
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][conn][f] != -1) {
+ smbcli_close(cli[server][conn]->tree, fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ }
+ talloc_free(cli[server][conn]);
+ }
+ cli[server][conn] = connect_one(ev, lp_ctx, mem_ctx, share[server],
+ server, conn);
+ if (!cli[server][conn]) {
+ DEBUG(0,("Failed to connect to %s\n", share[server]));
+ exit(1);
+ }
+ }
+}
+
+
+
+static bool test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ struct record *rec)
+{
+ unsigned int conn = rec->conn;
+ unsigned int f = rec->f;
+ uint64_t start = rec->start;
+ uint64_t len = rec->len;
+ enum brl_type op = rec->lock_type;
+ int server;
+ /* bool ret[NSERVERS]; */
+ NTSTATUS status[NSERVERS];
+
+ switch (rec->lock_op) {
+ case OP_LOCK:
+ /* set a lock */
+ for (server=0;server<NSERVERS;server++) {
+ NTSTATUS res;
+ struct smbcli_tree *tree=cli[server][conn]->tree;
+ int fn=fnum[server][conn][f];
+
+ if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ res=smbcli_lock(tree, fn, start, len, LOCK_TIMEOUT, (enum brl_type) rec->lock_op);
+ } else {
+ union smb_lock parms;
+ int ltype;
+ struct smb_lock_entry lock[1];
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.file.fnum = fn;
+
+ ltype = (rec->lock_type == READ_LOCK? 1 : 0);
+ ltype |= LOCKING_ANDX_LARGE_FILES;
+ parms.lockx.in.mode = ltype;
+ parms.lockx.in.timeout = LOCK_TIMEOUT;
+ parms.lockx.in.ulock_cnt = 0;
+ parms.lockx.in.lock_cnt = 1;
+ lock[0].pid = rec->pid;
+ lock[0].offset = start;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ res = smb_raw_lock(tree, &parms);
+ }
+
+ /* ret[server] = NT_STATUS_IS_OK(res); */
+ status[server] = res;
+ if (!exact_error_codes &&
+ NT_STATUS_EQUAL(status[server],
+ NT_STATUS_FILE_LOCK_CONFLICT)) {
+ status[server] = NT_STATUS_LOCK_NOT_GRANTED;
+ }
+ }
+ if (showall || !NT_STATUS_EQUAL(status[0],status[1])) {
+ printf("lock conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s\n",
+ conn, f,
+ (double)start, (double)len,
+ op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
+ nt_errstr(status[0]), nt_errstr(status[1]));
+ }
+ if (!NT_STATUS_EQUAL(status[0],status[1])) return false;
+ break;
+
+ case OP_UNLOCK:
+ /* unset a lock */
+ for (server=0;server<NSERVERS;server++) {
+ NTSTATUS res;
+ struct smbcli_tree *tree=cli[server][conn]->tree;
+ int fn=fnum[server][conn][f];
+
+
+ if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ res=smbcli_unlock(tree, fn, start, len);
+ } else {
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.file.fnum = fn;
+ parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ parms.lockx.in.timeout = 0;
+ parms.lockx.in.ulock_cnt = 1;
+ parms.lockx.in.lock_cnt = 0;
+ lock[0].pid = rec->pid;
+ lock[0].count = len;
+ lock[0].offset = start;
+ parms.lockx.in.locks = &lock[0];
+
+ res = smb_raw_lock(tree, &parms);
+ }
+
+ /* ret[server] = NT_STATUS_IS_OK(res); */
+ status[server] = res;
+ }
+ if (showall ||
+ (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))) {
+ printf("unlock conn=%u f=%u range=%.0f(%.0f) -> %s:%s\n",
+ conn, f,
+ (double)start, (double)len,
+ nt_errstr(status[0]), nt_errstr(status[1]));
+ }
+ if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))
+ return false;
+ break;
+
+ case OP_REOPEN:
+ /* reopen the file */
+ for (server=0;server<NSERVERS;server++) {
+ smbcli_close(cli[server][conn]->tree, fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ for (server=0;server<NSERVERS;server++) {
+ fnum[server][conn][f] = smbcli_open(cli[server][conn]->tree, FILENAME,
+ O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum[server][conn][f] == -1) {
+ printf("failed to reopen on share%d\n", server);
+ return false;
+ }
+ }
+ if (showall) {
+ printf("reopen conn=%u f=%u\n",
+ conn, f);
+ }
+ break;
+ }
+
+ return true;
+}
+
+static void close_files(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ if (fnum[server][conn][f] != -1) {
+ smbcli_close(cli[server][conn]->tree, fnum[server][conn][f]);
+ fnum[server][conn][f] = -1;
+ }
+ }
+ for (server=0;server<NSERVERS;server++) {
+ smbcli_unlink(cli[server][0]->tree, FILENAME);
+ }
+}
+
+static void open_files(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES])
+{
+ int server, conn, f;
+
+ for (server=0;server<NSERVERS;server++)
+ for (conn=0;conn<NCONNECTIONS;conn++)
+ for (f=0;f<NFILES;f++) {
+ fnum[server][conn][f] = smbcli_open(cli[server][conn]->tree, FILENAME,
+ O_RDWR|O_CREAT,
+ DENY_NONE);
+ if (fnum[server][conn][f] == -1) {
+ fprintf(stderr,"Failed to open fnum[%u][%u][%u]\n",
+ server, conn, f);
+ exit(1);
+ }
+ }
+}
+
+
+static int retest(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
+ int fnum[NSERVERS][NCONNECTIONS][NFILES],
+ int n)
+{
+ int i;
+ printf("Testing %u ...\n", n);
+ for (i=0; i<n; i++) {
+ if (i && i % 100 == 0) {
+ printf("%u\n", i);
+ }
+
+ if (recorded[i].needed &&
+ !test_one(cli, fnum, &recorded[i])) return i;
+ }
+ return n;
+}
+
+
+/* each server has two connections open to it. Each connection has two file
+ descriptors open on the file - 8 file descriptors in total
+
+ we then do random locking ops in tamdem on the 4 fnums from each
+ server and ensure that the results match
+ */
+static int test_locks(struct tevent_context *ev,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
+ char *share[NSERVERS])
+{
+ struct smbcli_state *cli[NSERVERS][NCONNECTIONS];
+ int fnum[NSERVERS][NCONNECTIONS][NFILES];
+ int n, i, n1, skip, r1, r2;
+
+ ZERO_STRUCT(fnum);
+ ZERO_STRUCT(cli);
+
+ recorded = malloc_array_p(struct record, numops);
+
+ for (n=0; n<numops; n++) {
+#if PRESETS
+ if (n < sizeof(preset) / sizeof(preset[0])) {
+ recorded[n] = preset[n];
+ } else {
+#endif
+ recorded[n].conn = random() % NCONNECTIONS;
+ recorded[n].f = random() % NFILES;
+ recorded[n].start = lock_base + ((unsigned int)random() % (lock_range-1));
+ recorded[n].len = min_length +
+ random() % (lock_range-(recorded[n].start-lock_base));
+ recorded[n].start *= RANGE_MULTIPLE;
+ recorded[n].len *= RANGE_MULTIPLE;
+ recorded[n].pid = random()%3;
+ if (recorded[n].pid == 2) {
+ recorded[n].pid = 0xFFFF; /* see if its magic */
+ }
+ r1 = random() % 100;
+ r2 = random() % 100;
+ if (r1 < READ_PCT) {
+ recorded[n].lock_type = READ_LOCK;
+ } else {
+ recorded[n].lock_type = WRITE_LOCK;
+ }
+ if (r2 < LOCK_PCT) {
+ recorded[n].lock_op = OP_LOCK;
+ } else if (r2 < UNLOCK_PCT) {
+ recorded[n].lock_op = OP_UNLOCK;
+ } else {
+ recorded[n].lock_op = OP_REOPEN;
+ }
+ recorded[n].needed = true;
+ if (!zero_zero && recorded[n].start==0 && recorded[n].len==0) {
+ recorded[n].len = 1;
+ }
+#if PRESETS
+ }
+#endif
+ }
+
+ reconnect(ev, lp_ctx, mem_ctx, cli, fnum, share);
+ open_files(cli, fnum);
+ n = retest(cli, fnum, numops);
+
+ if (n == numops || !analyze) {
+ if (n != numops) {
+ return 1;
+ }
+ return 0;
+ }
+ n++;
+
+ skip = n/2;
+
+ while (1) {
+ n1 = n;
+
+ close_files(cli, fnum);
+ reconnect(ev, lp_ctx, mem_ctx, cli, fnum, share);
+ open_files(cli, fnum);
+
+ for (i=0;i<n-skip;i+=skip) {
+ int m, j;
+ printf("excluding %d-%d\n", i, i+skip-1);
+ for (j=i;j<i+skip;j++) {
+ recorded[j].needed = false;
+ }
+
+ close_files(cli, fnum);
+ open_files(cli, fnum);
+
+ m = retest(cli, fnum, n);
+ if (m == n) {
+ for (j=i;j<i+skip;j++) {
+ recorded[j].needed = true;
+ }
+ } else {
+ if (i+(skip-1) < m) {
+ memmove(&recorded[i], &recorded[i+skip],
+ (m-(i+skip-1))*sizeof(recorded[0]));
+ }
+ n = m-(skip-1);
+ i--;
+ }
+ }
+
+ if (skip > 1) {
+ skip = skip/2;
+ printf("skip=%d\n", skip);
+ continue;
+ }
+
+ if (n1 == n) break;
+ }
+
+ close_files(cli, fnum);
+ reconnect(ev, lp_ctx, mem_ctx, cli, fnum, share);
+ open_files(cli, fnum);
+ showall = true;
+ n1 = retest(cli, fnum, n);
+ if (n1 != n-1) {
+ printf("ERROR - inconsistent result (%u %u)\n", n1, n);
+ }
+ close_files(cli, fnum);
+
+ for (i=0;i<n;i++) {
+ printf("{%d, %d, %u, %u, %.0f, %.0f, %u},\n",
+ recorded[i].lock_op,
+ recorded[i].lock_type,
+ recorded[i].conn,
+ recorded[i].f,
+ (double)recorded[i].start,
+ (double)recorded[i].len,
+ recorded[i].needed);
+ }
+
+ return 1;
+}
+
+
+
+static void usage(poptContext pc)
+{
+ printf("Usage:\n\tlocktest //server1/share1 //server2/share2 [options..]\n");
+ poptPrintUsage(pc, stdout, 0);
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+int main(int argc, const char *argv[])
+{
+ char *share[NSERVERS];
+ int opt;
+ int seed, server;
+ int username_count=0;
+ struct tevent_context *ev;
+ struct loadparm_context *lp_ctx;
+ poptContext pc;
+ int argc_new, i;
+ char **argv_new;
+ enum {
+ OPT_UNCLIST=1000,
+ OPT_USER1,
+ OPT_USER2,
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"seed", 0, POPT_ARG_INT, &seed, 0, "Seed to use for randomizer", NULL},
+ {"num-ops", 0, POPT_ARG_INT, &numops, 0, "num ops", NULL},
+ {"lockrange", 0, POPT_ARG_INT, &lock_range,0, "locking range", NULL},
+ {"lockbase", 0, POPT_ARG_INT, &lock_base, 0, "locking base", NULL},
+ {"minlength", 0, POPT_ARG_INT, &min_length,0, "min lock length", NULL},
+ {"hidefails", 0, POPT_ARG_NONE, &hide_unlock_fails,0,"hide unlock fails", NULL},
+ {"oplocks", 0, POPT_ARG_NONE, &use_oplocks,0, "use oplocks", NULL},
+ {"showall", 0, POPT_ARG_NONE, &showall, 0, "display all operations", NULL},
+ {"analyse", 0, POPT_ARG_NONE, &analyze, 0, "do backtrack analysis", NULL},
+ {"zerozero", 0, POPT_ARG_NONE, &zero_zero, 0, "do zero/zero lock", NULL},
+ {"exacterrors", 0, POPT_ARG_NONE, &exact_error_codes,0,"use exact error codes", NULL},
+ {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
+ {"user1", 0, POPT_ARG_STRING, NULL, OPT_USER1, "Set first network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
+ {"user2", 0, POPT_ARG_STRING, NULL, OPT_USER2, "Set second network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+ POPT_LEGACY_S4
+ POPT_TABLEEND
+ };
+ TALLOC_CTX *mem_ctx = NULL;
+ int ret = -1;
+ bool ok;
+
+ setlinebuf(stdout);
+ seed = time(NULL);
+
+ mem_ctx = talloc_named_const(NULL, 0, "locktest_ctx");
+ if (mem_ctx == NULL) {
+ printf("Unable to allocate locktest_ctx\n");
+ exit(1);
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+
+ pc = samba_popt_get_context("locktest",
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+
+ servers[0] = cli_credentials_init(mem_ctx);
+ servers[1] = cli_credentials_init(mem_ctx);
+ cli_credentials_guess(servers[0], lp_ctx);
+ cli_credentials_guess(servers[1], lp_ctx);
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_UNCLIST:
+ lpcfg_set_cmdline(lp_ctx, "torture:unclist", poptGetOptArg(pc));
+ break;
+ case OPT_USER1:
+ cli_credentials_parse_string(servers[0],
+ poptGetOptArg(pc),
+ CRED_SPECIFIED);
+ username_count++;
+ break;
+ case OPT_USER2:
+ cli_credentials_parse_string(servers[1],
+ poptGetOptArg(pc),
+ CRED_SPECIFIED);
+ username_count++;
+ break;
+ case POPT_ERROR_BADOPT:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ argv_new = discard_const_p(char *, poptGetArgs(pc));
+ argc_new = argc;
+ for (i=0; i<argc; i++) {
+ if (argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (!(argc_new >= 3)) {
+ usage(pc);
+ exit(1);
+ }
+
+ setup_logging("locktest", DEBUG_STDOUT);
+
+ for (server=0;server<NSERVERS;server++) {
+ share[server] = argv_new[1+server];
+ all_string_sub(share[server],"/","\\",0);
+ }
+
+ if (username_count == 0) {
+ usage(pc);
+ poptFreeContext(pc);
+ return -1;
+ }
+ if (username_count == 1) {
+ servers[1] = servers[0];
+ }
+
+ ev = s4_event_context_init(mem_ctx);
+
+ gensec_init();
+
+ DEBUG(0,("seed=%u base=%d range=%d min_length=%d\n",
+ seed, lock_base, lock_range, min_length));
+ srandom(seed);
+
+ ret = test_locks(ev, lp_ctx, NULL, share);
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
diff --git a/source4/torture/man/gentest.1.xml b/source4/torture/man/gentest.1.xml
new file mode 100644
index 0000000..65523f6
--- /dev/null
+++ b/source4/torture/man/gentest.1.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="gentest.1">
+
+<refmeta>
+ <refentrytitle>gentest</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">Test Suite</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>gentest</refname>
+ <refpurpose>Run random generic SMB operations against two SMB servers
+ and show the differences in behavior</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>gentest</command>
+ <arg choice="req">//server1/share1</arg>
+ <arg choice="req">//server2/share2</arg>
+ <arg choice="req">-U user%pass</arg>
+ <arg choice="req">-U user%pass</arg>
+ <arg choice="opt">-s seed</arg>
+ <arg choice="opt">-o numops</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-A</arg>
+ <arg choice="opt">-i FILE</arg>
+ <arg choice="opt">-O</arg>
+ <arg choice="opt">-S FILE</arg>
+ <arg choice="opt">-L</arg>
+ <arg choice="opt">-F</arg>
+ <arg choice="opt">-C</arg>
+ <arg choice="opt">-X</arg>
+ </cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><application>gentest</application> is a utility for
+ detecting differences in behaviour between SMB servers.
+ It will run a random set of generic operations against
+ <parameter>//server1/share1</parameter> and then the same
+ random set against <parameter>//server2/share2</parameter>
+ and display the differences in the responses it gets.
+ </para>
+
+ <para>
+ This utility is used by the Samba team to find differences in
+ behaviour between Samba and Windows servers.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-U user%pass</term>
+ <listitem><para>
+ Specify the user and password to use when logging on
+ on the shares. This parameter is mandatory and has to
+ be specified twice.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s seed</term>
+ <listitem><para>
+ Seed the random number generator with the specified value.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o numops</term>
+ <listitem><para>Set the number of operations to perform.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>Print the operations that are performed. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-A</term>
+ <listitem><para>Backtrack to find minimal number of operations
+ required to make the response to a certain call differ.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i FILE</term>
+ <listitem><para>
+ Specify a file containing the names of fields that
+ have to be ignored (such as time fields). See
+ below for a description of the file format.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O</term>
+ <listitem><para>Enable oplocks.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-S FILE</term>
+ <listitem><para>Set preset seeds file. The default is <filename>gentest_seeds.dat</filename>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-L</term>
+ <listitem><para>Use preset seeds</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-F</term>
+ <listitem><para>Fast reconnect (just close files)</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-C</term>
+ <listitem><para>Continuous analysis mode</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-X</term>
+ <listitem><para>Analyse even when the test succeeded.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>Samba</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
+
+ <para>gentest was written by Andrew Tridgell.</para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source4/torture/man/locktest.1.xml b/source4/torture/man/locktest.1.xml
new file mode 100644
index 0000000..3265823
--- /dev/null
+++ b/source4/torture/man/locktest.1.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="locktest.1">
+
+<refmeta>
+ <refentrytitle>locktest</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">Test Suite</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>locktest</refname>
+ <refpurpose>Find differences in locking between two SMB servers</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>locktest</command>
+ <arg choice="req">//server1/share1</arg>
+ <arg choice="req">//server2/share2</arg>
+ <arg choice="opt">-U user%pass</arg>
+ <arg choice="opt">-U user%pass</arg>
+ <arg choice="opt">-s seed</arg>
+ <arg choice="opt">-o numops</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-O</arg>
+ <arg choice="opt">-E</arg>
+ <arg choice="opt">-Z</arg>
+ <arg choice="opt">-R range</arg>
+ <arg choice="opt">-B base</arg>
+ <arg choice="opt">-M min</arg>
+ </cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><application>locktest</application> is a utility for
+ detecting differences in behaviour in locking between SMB servers.
+ It will run a random set of locking operations against
+ <parameter>//server1/share1</parameter> and then the same
+ random set against <parameter>//server2/share2</parameter>
+ and display the differences in the responses it gets.
+ </para>
+
+ <para>
+ This utility is used by the Samba team to find differences in
+ behaviour between Samba and Windows servers.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-U user%pass</term>
+ <listitem><para>
+ Specify the user and password to use when logging on
+ on the shares. This parameter can be specified twice
+ (once for the first server, once for the second).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s seed</term>
+ <listitem><para>
+ Seed the random number generator with the specified value.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-o numops</term>
+ <listitem><para>Set the number of operations to perform.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>Print the operations that are performed. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-A</term>
+ <listitem><para>Backtrack to find minimal number of operations
+ required to make the response to a certain call differ.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-O</term>
+ <listitem><para>Enable oplocks.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-u</term>
+ <listitem><para>Hide unlock fails.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-E</term>
+ <listitem><para>enable exact error code checking</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-Z</term>
+ <listitem><para>enable the zero/zero lock</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-R range</term>
+ <listitem><para>set lock range</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-B base</term>
+ <listitem><para>set lock base</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-M min</term>
+ <listitem><para>set min lock length</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-k</term>
+ <listitem><para>Use kerberos</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>Samba</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
+
+ <para>locktest was written by Andrew Tridgell.</para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source4/torture/man/masktest.1.xml b/source4/torture/man/masktest.1.xml
new file mode 100644
index 0000000..9cd46e3
--- /dev/null
+++ b/source4/torture/man/masktest.1.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="masktest.1">
+
+<refmeta>
+ <refentrytitle>masktest</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">Test Suite</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>masktest</refname>
+ <refpurpose>Find differences in wildcard matching between
+ Samba's implementation and that of a remote server.</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>masktest</command>
+ <arg choice="req">//server/share</arg>
+ <arg choice="opt">-U user%pass</arg>
+ <arg choice="opt">-d debuglevel</arg>
+ <arg choice="opt">-W workgroup</arg>
+ <arg choice="opt">-n numloops</arg>
+ <arg choice="opt">-s seed</arg>
+ <arg choice="opt">-a</arg>
+ <arg choice="opt">-E</arg>
+ <arg choice="opt">-M max protocol</arg>
+ <arg choice="opt">-f filechars</arg>
+ <arg choice="opt">-m maskchars</arg>
+ <arg choice="opt">-v</arg>
+ </cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para><application>masktest</application> is a utility for
+ detecting differences in behaviour between Samba's
+ own implementation and that of a remote server.
+ It will run generate random filenames/masks and
+ check if these match the same files they do on the remote file as
+ they do on the local server. It will display any differences it finds.
+ </para>
+
+ <para>
+ This utility is used by the Samba team to find differences in
+ behaviour between Samba and Windows servers.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-U user%pass</term>
+ <listitem><para>
+ Specify the user and password to use when logging on
+ on the shares. This parameter can be specified twice
+ (once for the first server, once for the second).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-s seed</term>
+ <listitem><para>
+ Seed the random number generator with the specified value.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-n numops</term>
+ <listitem><para>Set the number of operations to perform.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a</term>
+ <listitem><para>Print the operations that are performed. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-M max_protocol</term>
+ <listitem><para>
+ Maximum protocol to use.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-f</term>
+ <listitem><para>Specify characters that can be used
+ when generating file names. Default: abcdefghijklm.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-E</term>
+ <listitem><para>Abort when difference in behaviour is found.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-m maskchars</term>
+ <listitem><para>Specify characters used for wildcards.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>Be verbose</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>Samba</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
+
+ <para>masktest was written by Andrew Tridgell.</para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source4/torture/man/smbtorture.1.xml b/source4/torture/man/smbtorture.1.xml
new file mode 100644
index 0000000..9d2f9c9
--- /dev/null
+++ b/source4/torture/man/smbtorture.1.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="smbtorture.1">
+
+<refmeta>
+ <refentrytitle>smbtorture</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">Test Suite</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>smbtorture</refname>
+ <refpurpose>Run a series of tests against a SMB server</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>smbtorture</command>
+ <arg choice="req">//server/share</arg>
+ <arg choice="opt">-d debuglevel</arg>
+ <arg choice="opt">-U user%pass</arg>
+ <arg choice="opt">-k</arg>
+ <arg choice="opt">-N numprocs</arg>
+ <arg choice="opt">-n netbios_name</arg>
+ <arg choice="opt">-W workgroup</arg>
+ <arg choice="opt">-e num files(entries)</arg>
+ <arg choice="opt">-O socket_options</arg>
+ <arg choice="opt">-m maximum_protocol</arg>
+ <arg choice="opt">-L</arg>
+ <arg choice="opt">-c CLIENT.TXT</arg>
+ <arg choice="opt">-t timelimit</arg>
+ <arg choice="opt">-C filename</arg>
+ <arg choice="opt">-A</arg>
+ <arg choice="opt">-p port</arg>
+ <arg choice="opt">-s seed</arg>
+ <arg choice="opt">-f max_failures</arg>
+ <arg choice="opt">-X</arg>
+ <arg choice="req">BINDING-STRING|UNC</arg>
+ <arg choice="req">TEST1</arg>
+ <arg choice="opt">TEST2</arg>
+ <arg choice="opt">...</arg>
+ </cmdsynopsis>
+
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>smbtorture is a testsuite that runs several tests
+ against a SMB server. All tests are known to succeed
+ against a Windows 2003 server (?). Smbtorture's primary
+ goal is finding differences in implementations of the SMB protocol
+ and testing SMB servers.
+ </para>
+
+ <para>Any number of tests can be specified
+ on the command-line. If no tests are specified, all tests
+ are run. </para>
+
+ <para>If no arguments are specified at all, all available options
+ and tests are listed.</para>
+
+ <refsect2>
+ <title>Binding string format</title>
+
+ <para>The binding string format is:</para>
+
+ <para>TRANSPORT:host[flags]</para>
+
+ <para>Where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP or ncalrpc for local connections.
+ </para>
+
+ <para>
+ 'host' is an IP or hostname or netbios name. If the binding string
+ identifies the server side of an endpoint, 'host' may be an empty
+ string.
+ </para>
+
+ <para>
+ 'flags' can include a SMB pipe name if using the ncacn_np transport or
+ a TCP port number if using the ncacn_ip_tcp transport, otherwise they
+ will be auto-determined.
+ </para>
+
+ <para>
+ other recognised flags are:
+ </para>
+
+ <variablelist>
+ <varlistentry><term>sign</term>
+ <listitem><para>enable ntlmssp signing</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>seal</term>
+ <listitem><para>enable ntlmssp sealing</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>connect</term>
+ <listitem><para>enable rpc connect level auth (auth, but no sign or seal)</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>validate</term>
+ <listitem><para>enable the NDR validator</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>print</term>
+ <listitem><para>enable debugging of the packets</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>bigendian</term>
+ <listitem><para>use bigendian RPC</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>padcheck</term>
+ <listitem><para>check reply data for non-zero pad bytes</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>For example, these all connect to the samr pipe:</para>
+
+ <itemizedlist>
+ <listitem><para>ncacn_np:myserver</para></listitem>
+ <listitem><para>ncacn_np:myserver[samr]</para></listitem>
+ <listitem><para>ncacn_np:myserver[\\pipe\\samr]</para></listitem>
+ <listitem><para>ncacn_np:myserver[/pipe/samr]</para></listitem>
+ <listitem><para>ncacn_np:myserver[samr,sign,print]</para></listitem>
+ <listitem><para>ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]</para></listitem>
+ <listitem><para>ncacn_np:myserver[/pipe/samr,seal,validate]</para></listitem>
+ <listitem><para>ncacn_np:</para></listitem>
+ <listitem><para>ncacn_np:[/pipe/samr]</para></listitem>
+ <listitem><para>ncacn_ip_tcp:myserver</para></listitem>
+ <listitem><para>ncacn_ip_tcp:myserver[1024]</para></listitem>
+ <listitem><para>ncacn_ip_tcp:myserver[1024,sign,seal]</para></listitem>
+ <listitem><para>ncalrpc:</para></listitem>
+ </itemizedlist>
+
+ </refsect2>
+
+ <refsect2>
+ <title>UNC Format</title>
+
+ <para>The UNC format is:</para>
+
+ <para>//server/share</para>
+ </refsect2>
+
+</refsect1>
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry><term>-d debuglevel</term>
+ <listitem><para>Use the specified Samba debug level. A higher debug level
+ means more output.</para></listitem>
+ </varlistentry>
+ <varlistentry><term>-U user%pass</term>
+ <listitem><para>Use the specified username/password combination when logging in to a remote server.</para></listitem>
+ </varlistentry>
+ <varlistentry><term>-k</term>
+ <listitem><para>Use kerberos when authenticating.</para></listitem>
+ </varlistentry>
+ <varlistentry><term>-W workgroup</term>
+ <listitem><para>Use specified name as our workgroup name.</para></listitem>
+ </varlistentry>
+ <varlistentry><term>-n netbios_name</term>
+ <listitem><para>Use specified name as our NetBIOS name.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-O socket_options</term>
+ <listitem><para>Use specified socket options, equivalent of the smb.conf option <quote>socket options</quote>. See the smb.conf(5) manpage for details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-m max_protocol</term>
+ <listitem><para>Specify the maximum SMB dialect that should be used. Possible values are: CORE, COREPLUS, LANMAN1, LANMAN2, NT1</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-s seed</term>
+ <listitem><para>Initialize the randomizer using <replaceable>seed</replaceable> as seed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-L</term>
+ <listitem><para>Use oplocks.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-X</term>
+ <listitem><para>Enable dangerous tests. Use with care! This might crash your server...</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-t timelimit</term>
+ <listitem><para>Specify the NBENCH time limit in seconds. Defaults to 600.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-p ports</term>
+ <listitem><para>Specify ports to connect to.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-c file</term>
+ <listitem><para>Read NBENCH commands from <replaceable>file</replaceable> instead of from CLIENT.TXT.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-A</term>
+ <listitem><para>Show not just OK or FAILED but more detailed
+ output. Used only by DENY test at the moment.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-C filename</term>
+ <listitem><para>Load a list of UNC names from the specified filename. Smbtorture instances will connect to a random host from this list.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-N numprocs</term>
+ <listitem><para>Specify number of smbtorture processes to launch.</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-e num_files</term>
+ <listitem><para>Number of entries to use in certain tests (such as creating X files) (default: 1000).</para></listitem>
+ </varlistentry>
+
+ <varlistentry><term>-f max_failures</term>
+ <listitem><para>Number of failures before aborting a test (default: 1).</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>Samba</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
+
+ <para>smbtorture was written by Andrew Tridgell.</para>
+
+ <para>This manpage was written by Jelmer Vernooij.</para>
+
+</refsect1>
+
+</refentry>
diff --git a/source4/torture/masktest.c b/source4/torture/masktest.c
new file mode 100644
index 0000000..e311769
--- /dev/null
+++ b/source4/torture/masktest.c
@@ -0,0 +1,418 @@
+/*
+ Unix SMB/CIFS implementation.
+ mask_match tester
+ Copyright (C) Andrew Tridgell 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include "libcli/libcli.h"
+#include "system/time.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/events/events.h"
+
+static bool showall = false;
+static bool old_list = false;
+static const char *maskchars = "<>\"?*abc.";
+static const char *filechars = "abcdefghijklm.";
+static int die_on_error;
+static int NumLoops = 0;
+static int max_length = 20;
+struct masktest_state {
+ TALLOC_CTX *mem_ctx;
+};
+
+static bool reg_match_one(struct smbcli_state *cli, const char *pattern, const char *file)
+{
+ /* oh what a weird world this is */
+ if (old_list && strcmp(pattern, "*.*") == 0) return true;
+
+ if (ISDOT(pattern)) return false;
+
+ if (ISDOTDOT(file)) file = ".";
+
+ return ms_fnmatch_protocol(
+ pattern, file, cli->transport->negotiate.protocol, false)==0;
+}
+
+static char *reg_test(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *pattern, const char *long_name, const char *short_name)
+{
+ char *ret;
+ ret = talloc_strdup(mem_ctx, "---");
+
+ pattern = 1+strrchr_m(pattern,'\\');
+
+ if (reg_match_one(cli, pattern, ".")) ret[0] = '+';
+ if (reg_match_one(cli, pattern, "..")) ret[1] = '+';
+ if (reg_match_one(cli, pattern, long_name) ||
+ (*short_name && reg_match_one(cli, pattern, short_name))) ret[2] = '+';
+ return ret;
+}
+
+
+/*****************************************************
+return a connection to a server
+*******************************************************/
+static struct smbcli_state *connect_one(struct resolve_context *resolve_ctx,
+ struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ char *share, const char **ports,
+ const char *socket_options,
+ struct smbcli_options *options,
+ struct smbcli_session_options *session_options,
+ struct gensec_settings *gensec_settings)
+{
+ struct smbcli_state *c;
+ char *server;
+ NTSTATUS status;
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+
+ server = talloc_strdup(mem_ctx, share+2);
+ share = strchr_m(server,'\\');
+ if (!share) return NULL;
+ *share = 0;
+ share++;
+
+ cli_credentials_set_workstation(creds,
+ "masktest", CRED_SPECIFIED);
+
+ status = smbcli_full_connection(NULL, &c,
+ server,
+ ports,
+ share, NULL,
+ socket_options,
+ creds,
+ resolve_ctx, ev,
+ options, session_options,
+ gensec_settings);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return c;
+}
+
+static char *resultp;
+static struct {
+ char *long_name;
+ char *short_name;
+} last_hit;
+static bool f_info_hit;
+
+static void listfn(struct clilist_file_info *f, const char *s, void *state)
+{
+ struct masktest_state *m = (struct masktest_state *)state;
+
+ if (ISDOT(f->name)) {
+ resultp[0] = '+';
+ } else if (ISDOTDOT(f->name)) {
+ resultp[1] = '+';
+ } else {
+ resultp[2] = '+';
+ }
+
+ last_hit.long_name = talloc_strdup(m->mem_ctx, f->name);
+ last_hit.short_name = talloc_strdup(m->mem_ctx, f->short_name);
+ f_info_hit = true;
+}
+
+static void get_real_name(TALLOC_CTX *mem_ctx, struct smbcli_state *cli,
+ char **long_name, char **short_name)
+{
+ const char *mask;
+ struct masktest_state state;
+
+ if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1) {
+ mask = "\\masktest\\*.*";
+ } else {
+ mask = "\\masktest\\*";
+ }
+
+ f_info_hit = false;
+
+ state.mem_ctx = mem_ctx;
+
+ smbcli_list_new(cli->tree, mask,
+ FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,
+ RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
+ listfn, &state);
+
+ if (f_info_hit) {
+ *short_name = strlower_talloc(mem_ctx, last_hit.short_name);
+ *long_name = strlower_talloc(mem_ctx, last_hit.long_name);
+ }
+
+ if (*short_name[0] == '\0') {
+ *short_name = talloc_strdup(mem_ctx, *long_name);
+ }
+}
+
+static void testpair(TALLOC_CTX *mem_ctx, struct smbcli_state *cli, char *mask,
+ char *file)
+{
+ int fnum;
+ char res1[256];
+ char *res2;
+ static int count;
+ char *short_name = NULL;
+ char *long_name = NULL;
+ struct masktest_state state;
+
+ count++;
+
+ strlcpy(res1, "---", sizeof(res1));
+
+ state.mem_ctx = mem_ctx;
+
+ fnum = smbcli_open(cli->tree, file, O_CREAT|O_TRUNC|O_RDWR, 0);
+ if (fnum == -1) {
+ DEBUG(0,("Can't create %s\n", file));
+ return;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ resultp = res1;
+ short_name = talloc_strdup(mem_ctx, "");
+ get_real_name(mem_ctx, cli, &long_name, &short_name);
+ strlcpy(res1, "---", sizeof(res1));
+ smbcli_list_new(cli->tree, mask,
+ FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,
+ RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
+ listfn, &state);
+
+ res2 = reg_test(cli, mem_ctx, mask, long_name, short_name);
+
+ if (showall || strcmp(res1, res2)) {
+ d_printf("%s %s %d mask=[%s] file=[%s] rfile=[%s/%s]\n",
+ res1, res2, count, mask, file, long_name, short_name);
+ if (die_on_error) exit(1);
+ }
+
+ smbcli_unlink(cli->tree, file);
+
+ if (count % 100 == 0) DEBUG(0,("%d\n", count));
+
+ resultp = NULL;
+}
+
+static void test_mask(int argc, char *argv[],
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_state *cli)
+{
+ char *mask, *file;
+ int l1, l2, i, l;
+ int mc_len = strlen(maskchars);
+ int fc_len = strlen(filechars);
+
+ smbcli_mkdir(cli->tree, "\\masktest");
+
+ smbcli_unlink_wcard(cli->tree, "\\masktest\\*");
+
+ if (argc >= 2) {
+ while (argc >= 2) {
+ mask = talloc_strdup(mem_ctx, "\\masktest\\");
+ file = talloc_strdup(mem_ctx, "\\masktest\\");
+ mask = talloc_strdup_append(mask, argv[0]);
+ file = talloc_strdup_append(file, argv[1]);
+ testpair(mem_ctx, cli, mask, file);
+ argv += 2;
+ argc -= 2;
+ }
+ goto finished;
+ }
+
+ while (1) {
+ l1 = 1 + random() % max_length;
+ l2 = 1 + random() % max_length;
+ mask = talloc_strdup(mem_ctx, "\\masktest\\");
+ file = talloc_strdup(mem_ctx, "\\masktest\\");
+ mask = talloc_realloc_size(mem_ctx, mask, strlen(mask)+l1+1);
+ file = talloc_realloc_size(mem_ctx, file, strlen(file)+l2+1);
+ l = strlen(mask);
+ for (i=0;i<l1;i++) {
+ mask[i+l] = maskchars[random() % mc_len];
+ }
+ mask[l+l1] = 0;
+
+ for (i=0;i<l2;i++) {
+ file[i+l] = filechars[random() % fc_len];
+ }
+ file[l+l2] = 0;
+
+ if (ISDOT(file+l) || ISDOTDOT(file+l) || ISDOTDOT(mask+l)) {
+ continue;
+ }
+
+ if (strspn(file+l, ".") == strlen(file+l)) continue;
+
+ testpair(mem_ctx, cli, mask, file);
+ if (NumLoops && (--NumLoops == 0))
+ break;
+ }
+
+ finished:
+ smbcli_rmdir(cli->tree, "\\masktest");
+}
+
+
+static void usage(poptContext pc)
+{
+ printf(
+"Usage:\n\
+ masktest //server/share [options..]\n\
+\n\
+ This program tests wildcard matching between two servers. It generates\n\
+ random pairs of filenames/masks and tests that they match in the same\n\
+ way on the servers and internally\n");
+ poptPrintUsage(pc, stdout, 0);
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+int main(int argc, const char *argv[])
+{
+ char *share;
+ struct smbcli_state *cli;
+ int opt;
+ int seed;
+ struct tevent_context *ev;
+ struct loadparm_context *lp_ctx;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+ poptContext pc;
+ int argc_new, i;
+ char **argv_new;
+ TALLOC_CTX *mem_ctx = NULL;
+ enum {OPT_UNCLIST=1000};
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"seed", 0, POPT_ARG_INT, &seed, 0, "Seed to use for randomizer", NULL},
+ {"num-ops", 0, POPT_ARG_INT, &NumLoops, 0, "num ops", NULL},
+ {"maxlength", 0, POPT_ARG_INT, &max_length,0, "maximum length", NULL},
+ {"dieonerror", 0, POPT_ARG_NONE, &die_on_error, 0, "die on errors", NULL},
+ {"showall", 0, POPT_ARG_NONE, &showall, 0, "display all operations", NULL},
+ {"oldlist", 0, POPT_ARG_NONE, &old_list, 0, "use old list call", NULL},
+ {"maskchars", 0, POPT_ARG_STRING, &maskchars, 0,"mask characters", NULL},
+ {"filechars", 0, POPT_ARG_STRING, &filechars, 0,"file characters", NULL},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+ POPT_LEGACY_S4
+ POPT_TABLEEND
+ };
+ bool ok;
+
+ setlinebuf(stdout);
+ seed = time(NULL);
+
+ mem_ctx = talloc_named_const(NULL, 0, "masktest_ctx");
+ if (mem_ctx == NULL) {
+ exit(1);
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "<unc>");
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_UNCLIST:
+ lpcfg_set_cmdline(lp_ctx,
+ "torture:unclist",
+ poptGetOptArg(pc));
+ break;
+ case POPT_ERROR_BADOPT:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ argv_new = discard_const_p(char *, poptGetArgs(pc));
+ argc_new = argc;
+ for (i=0; i<argc; i++) {
+ if (argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (!(argc_new >= 2)) {
+ usage(pc);
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+
+ setup_logging("masktest", DEBUG_STDOUT);
+
+ share = argv_new[1];
+
+ all_string_sub(share,"/","\\",0);
+
+ ev = s4_event_context_init(mem_ctx);
+
+ gensec_init();
+
+ lpcfg_smbcli_options(lp_ctx, &options);
+ lpcfg_smbcli_session_options(lp_ctx, &session_options);
+
+ cli = connect_one(lpcfg_resolve_context(lp_ctx), ev, mem_ctx, share,
+ lpcfg_smb_ports(lp_ctx), lpcfg_socket_options(lp_ctx),
+ &options, &session_options,
+ lpcfg_gensec_settings(mem_ctx, lp_ctx));
+ if (!cli) {
+ DEBUG(0,("Failed to connect to %s\n", share));
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+
+ /* need to init seed after connect as clientgen uses random numbers */
+ DEBUG(0,("seed=%d format --- --- (server, correct)\n", seed));
+ srandom(seed);
+
+ test_mask(argc_new-1, argv_new+1, mem_ctx, cli);
+
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return(0);
+}
diff --git a/source4/torture/nbench/nbench.c b/source4/torture/nbench/nbench.c
new file mode 100644
index 0000000..05ff3ab
--- /dev/null
+++ b/source4/torture/nbench/nbench.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - NBENCH test
+ Copyright (C) Andrew Tridgell 1997-2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/smbtorture.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "lib/util/smb_strtox.h"
+
+#include "torture/nbench/proto.h"
+
+int nbench_line_count = 0;
+static int timelimit = 600;
+static int warmup;
+static const char *loadfile;
+static int read_only;
+
+#define ival(s) strtoll(s, NULL, 0)
+
+static unsigned long nb_max_retries;
+
+#define NB_RETRY(op) \
+ for (n=0;n<=nb_max_retries && !op;n++) do_reconnect(&cli, tctx, client)
+
+static void do_reconnect(struct smbcli_state **cli, struct torture_context *tctx, int client)
+{
+ int n;
+ printf("[%d] Reconnecting client %d\n", nbench_line_count, client);
+ for (n=0;n<nb_max_retries;n++) {
+ if (nb_reconnect(cli, tctx, client)) {
+ printf("[%d] Reconnected client %d\n", nbench_line_count, client);
+ return;
+ }
+ }
+ printf("[%d] Failed to reconnect client %d\n", nbench_line_count, client);
+ nb_exit(1);
+}
+
+/* run a test that simulates an approximate netbench client load */
+static bool run_netbench(struct torture_context *tctx, struct smbcli_state *cli, int client)
+{
+ int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+ int i;
+ char line[1024];
+ char *cname;
+ FILE *f;
+ bool correct = true;
+ double target_rate = torture_setting_double(tctx, "targetrate", 0);
+ int n = 0;
+ int ret;
+
+ if (target_rate != 0 && client == 0) {
+ printf("Targeting %.4f MByte/sec\n", target_rate);
+ }
+
+ nb_setup(cli, client);
+
+ if (torture_nprocs == 1) {
+ if (!read_only) {
+ NB_RETRY(torture_setup_dir(cli, "\\clients"));
+ }
+ }
+
+ ret = asprintf(&cname, "client%d", client+1);
+ if (ret == -1) {
+ return false;
+ }
+
+ f = fopen(loadfile, "r");
+
+ if (!f) {
+ perror(loadfile);
+ return false;
+ }
+
+again:
+ nbio_time_reset();
+
+ while (fgets(line, sizeof(line)-1, f)) {
+ NTSTATUS status;
+ const char **params0, **params;
+ unsigned long int tmp;
+ int error = 0;
+
+ nbench_line_count++;
+
+ if ((strlen(line) > 0) && line[strlen(line)-1] == '\n') {
+ line[strlen(line)-1] = 0;
+ }
+
+ all_string_sub(line, "client1", cname, sizeof(line));
+
+ params = params0 = const_str_list(
+ str_list_make_shell(NULL, line, " "));
+ i = str_list_length(params);
+
+ if (i > 0 && isdigit(params[0][0])) {
+ double targett = strtod(params[0], NULL);
+ if (target_rate != 0) {
+ nbio_target_rate(target_rate);
+ } else {
+ nbio_time_delay(targett);
+ }
+ params++;
+ i--;
+ } else if (target_rate != 0) {
+ nbio_target_rate(target_rate);
+ }
+
+ if (i < 2 || params[0][0] == '#') continue;
+
+ if (!strncmp(params[0],"SMB", 3)) {
+ printf("ERROR: You are using a dbench 1 load file\n");
+ nb_exit(1);
+ }
+
+ if (strncmp(params[i-1], "NT_STATUS_", 10) != 0 &&
+ strncmp(params[i-1], "0x", 2) != 0) {
+ printf("Badly formed status at line %d\n", nbench_line_count);
+ talloc_free(params);
+ continue;
+ }
+
+ /* accept numeric or string status codes */
+ if (strncmp(params[i-1], "0x", 2) == 0) {
+ tmp = smb_strtoul(params[i-1],
+ NULL,
+ 16,
+ &error,
+ SMB_STR_STANDARD);
+ if (error != 0) {
+ tmp = error;
+ }
+ status = NT_STATUS(tmp);
+ } else {
+ status = nt_status_string_to_code(params[i-1]);
+ }
+
+ DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1]));
+
+ if (!strcmp(params[0],"NTCreateX")) {
+ NB_RETRY(nb_createx(params[1], ival(params[2]), ival(params[3]),
+ ival(params[4]), status));
+ } else if (!strcmp(params[0],"Close")) {
+ NB_RETRY(nb_close(ival(params[1]), status));
+ } else if (!read_only && !strcmp(params[0],"Rename")) {
+ NB_RETRY(nb_rename(params[1], params[2], status, n>0));
+ } else if (!read_only && !strcmp(params[0],"Unlink")) {
+ NB_RETRY(nb_unlink(params[1], ival(params[2]), status, n>0));
+ } else if (!read_only && !strcmp(params[0],"Deltree")) {
+ NB_RETRY(nb_deltree(params[1], n>0));
+ } else if (!read_only && !strcmp(params[0],"Rmdir")) {
+ NB_RETRY(nb_rmdir(params[1], status, n>0));
+ } else if (!read_only && !strcmp(params[0],"Mkdir")) {
+ NB_RETRY(nb_mkdir(params[1], status, n>0));
+ } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) {
+ NB_RETRY(nb_qpathinfo(params[1], ival(params[2]), status));
+ } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) {
+ NB_RETRY(nb_qfileinfo(ival(params[1]), ival(params[2]), status));
+ } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) {
+ NB_RETRY(nb_qfsinfo(ival(params[1]), status));
+ } else if (!read_only && !strcmp(params[0],"SET_FILE_INFORMATION")) {
+ NB_RETRY(nb_sfileinfo(ival(params[1]), ival(params[2]), status));
+ } else if (!strcmp(params[0],"FIND_FIRST")) {
+ NB_RETRY(nb_findfirst(params[1], ival(params[2]),
+ ival(params[3]), ival(params[4]), status));
+ } else if (!read_only && !strcmp(params[0],"WriteX")) {
+ NB_RETRY(nb_writex(ival(params[1]),
+ ival(params[2]), ival(params[3]), ival(params[4]),
+ status));
+ } else if (!read_only && !strcmp(params[0],"Write")) {
+ NB_RETRY(nb_write(ival(params[1]),
+ ival(params[2]), ival(params[3]), ival(params[4]),
+ status));
+ } else if (!strcmp(params[0],"LockX")) {
+ NB_RETRY(nb_lockx(ival(params[1]),
+ ival(params[2]), ival(params[3]), status));
+ } else if (!strcmp(params[0],"UnlockX")) {
+ NB_RETRY(nb_unlockx(ival(params[1]),
+ ival(params[2]), ival(params[3]), status));
+ } else if (!strcmp(params[0],"ReadX")) {
+ NB_RETRY(nb_readx(ival(params[1]),
+ ival(params[2]), ival(params[3]), ival(params[4]),
+ status));
+ } else if (!strcmp(params[0],"Flush")) {
+ NB_RETRY(nb_flush(ival(params[1]), status));
+ } else if (!strcmp(params[0],"Sleep")) {
+ nb_sleep(ival(params[1]), status);
+ } else {
+ printf("[%d] Unknown operation %s\n", nbench_line_count, params[0]);
+ }
+
+ if (n > nb_max_retries) {
+ printf("Maximum reconnect retries reached for op '%s'\n", params[0]);
+ nb_exit(1);
+ }
+
+ talloc_free(params0);
+
+ if (nb_tick()) goto done;
+ }
+
+ rewind(f);
+ goto again;
+
+done:
+ fclose(f);
+
+ if (!read_only && torture_nprocs == 1) {
+ smbcli_deltree(cli->tree, "\\clients");
+ }
+ if (!torture_close_connection(cli)) {
+ correct = false;
+ }
+
+ return correct;
+}
+
+
+/* run a test that simulates an approximate netbench client load */
+bool torture_nbench(struct torture_context *torture)
+{
+ bool correct = true;
+ int torture_nprocs = torture_setting_int(torture, "nprocs", 4);
+ struct smbcli_state *cli;
+ const char *p;
+
+ read_only = torture_setting_bool(torture, "readonly", false);
+
+ nb_max_retries = torture_setting_int(torture, "nretries", 1);
+
+ p = torture_setting_string(torture, "timelimit", NULL);
+ if (p && *p) {
+ timelimit = atoi(p);
+ }
+
+ warmup = timelimit / 20;
+
+ loadfile = torture_setting_string(torture, "loadfile", NULL);
+ if (!loadfile || !*loadfile) {
+ loadfile = "client.txt";
+ }
+
+ if (torture_nprocs > 1) {
+ if (!torture_open_connection(&cli, torture, 0)) {
+ return false;
+ }
+
+ if (!read_only && !torture_setup_dir(cli, "\\clients")) {
+ return false;
+ }
+ }
+
+ nbio_shmem(torture_nprocs, timelimit, warmup);
+
+ printf("Running for %d seconds with load '%s' and warmup %d secs\n",
+ timelimit, loadfile, warmup);
+
+ /* we need to reset SIGCHLD here as the name resolution
+ library may have changed it. We rely on correct signals
+ from children in the main torture code which reaps
+ children. This is why smbtorture BENCH-NBENCH was sometimes
+ failing */
+ signal(SIGCHLD, SIG_DFL);
+
+
+ signal(SIGALRM, nb_alarm);
+ alarm(1);
+ torture_create_procs(torture, run_netbench, &correct);
+ alarm(0);
+
+ if (!read_only && torture_nprocs > 1) {
+ smbcli_deltree(cli->tree, "\\clients");
+ }
+
+ printf("\nThroughput %g MB/sec\n", nbio_result());
+ return correct;
+}
+
+NTSTATUS torture_nbench_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "bench");
+
+ torture_suite_add_simple_test(suite, "nbench", torture_nbench);
+
+ suite->description = talloc_strdup(suite, "Benchmarks");
+
+ torture_register_suite(ctx, suite);
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/nbench/nbio.c b/source4/torture/nbench/nbio.c
new file mode 100644
index 0000000..1de988e
--- /dev/null
+++ b/source4/torture/nbench/nbio.c
@@ -0,0 +1,994 @@
+/*
+ TODO: add splitting of writes for servers with signing
+*/
+
+
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "../lib/util/dlinklist.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/nbench/proto.h"
+
+extern int nbench_line_count;
+static int nbio_id = -1;
+static int nprocs;
+static bool bypass_io;
+static struct timeval tv_start, tv_end;
+static int warmup, timelimit;
+static int in_cleanup;
+
+struct lock_info {
+ struct lock_info *next, *prev;
+ off_t offset;
+ int size;
+};
+
+struct createx_params {
+ char *fname;
+ unsigned int create_options;
+ unsigned int create_disposition;
+ int handle;
+};
+
+struct ftable {
+ struct ftable *next, *prev;
+ int fd; /* the fd that we got back from the server */
+ int handle; /* the handle in the load file */
+ struct createx_params cp;
+ struct lock_info *locks;
+};
+
+static struct ftable *ftable;
+
+static struct {
+ double bytes, warmup_bytes;
+ int line;
+ int done;
+ bool connected;
+ double max_latency;
+ struct timeval starttime;
+} *children;
+
+static bool nb_do_createx(struct ftable *f,
+ const char *fname,
+ unsigned int create_options,
+ unsigned int create_disposition,
+ int handle,
+ NTSTATUS status,
+ bool retry);
+
+static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status);
+
+static void nb_set_createx_params(struct ftable *f,
+ const char *fname,
+ unsigned int create_options,
+ unsigned int create_disposition,
+ int handle)
+{
+ struct createx_params *cp = &f->cp;
+
+ if (fname != NULL) {
+ cp->fname = talloc_strdup(f, fname);
+ if (cp->fname == NULL) {
+ perror("nb_set_createx_params: strdup");
+ nb_exit(1);
+ }
+ } else {
+ cp->fname = NULL;
+ }
+
+ cp->create_options = create_options;
+ cp->create_disposition = create_disposition;
+ cp->handle = handle;
+}
+
+static bool nb_reestablish_locks(struct ftable *f)
+{
+ struct lock_info *linfo = f->locks;
+
+ while (linfo != NULL) {
+ DEBUG(1,("nb_reestablish_locks: lock for file %d at %lu\n",
+ f->handle, (unsigned long) linfo->offset));
+
+ if (!nb_do_lockx(true, f->handle, linfo->offset, linfo->size, NT_STATUS_OK)) {
+ printf("nb_reestablish_locks: failed to get lock for file %s at %lu\n",
+ f->cp.fname, (unsigned long) linfo->offset);
+ return false;
+ }
+
+ linfo = linfo->next;
+ }
+
+ return true;
+}
+
+static bool nb_reopen_all_files(void)
+{
+ struct ftable *f = ftable;
+
+ while (f != NULL) {
+ DEBUG(1,("-- nb_reopen_all_files: opening %s (handle %d)\n",
+ f->cp.fname, f->cp.handle));
+
+ if (!nb_do_createx(f,
+ f->cp.fname,
+ f->cp.create_options,
+ f->cp.create_disposition,
+ f->cp.handle,
+ NT_STATUS_OK,
+ true))
+ {
+ printf("-- nb_reopen_all_files: failed to open file %s\n", f->cp.fname);
+ return false;
+ }
+
+ if (!nb_reestablish_locks(f)) {
+ printf("--nb_reopen_all_files: failed to reestablish locks\n");
+ return false;
+ }
+
+ f = f->next;
+ }
+
+ return true;
+}
+
+bool nb_reconnect(struct smbcli_state **cli, struct torture_context *tctx, int client)
+{
+ children[client].connected = false;
+
+ if (*cli != NULL) {
+ talloc_free(*cli);
+ }
+
+ if (!torture_open_connection(cli, tctx, client)) {
+ printf("nb_reconnect: failed to connect\n");
+ *cli = NULL;
+ return false;
+ }
+
+ nb_setup(*cli, client);
+
+ if (!nb_reopen_all_files()) {
+ printf("nb_reconnect: failed to reopen files in client %d\n", client);
+ return false;
+ }
+
+ return true;
+}
+
+void nbio_target_rate(double rate)
+{
+ static double last_bytes;
+ static struct timeval last_time;
+ double tdelay;
+
+ if (last_bytes == 0) {
+ last_bytes = children[nbio_id].bytes;
+ last_time = timeval_current();
+ return;
+ }
+
+ tdelay = (children[nbio_id].bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
+ if (tdelay > 0) {
+ smb_msleep(tdelay*1000);
+ } else {
+ children[nbio_id].max_latency = MAX(children[nbio_id].max_latency, -tdelay);
+ }
+
+ last_time = timeval_current();
+ last_bytes = children[nbio_id].bytes;
+}
+
+void nbio_time_reset(void)
+{
+ children[nbio_id].starttime = timeval_current();
+}
+
+void nbio_time_delay(double targett)
+{
+ double elapsed = timeval_elapsed(&children[nbio_id].starttime);
+ if (targett > elapsed) {
+ smb_msleep(1000*(targett - elapsed));
+ } else if (elapsed - targett > children[nbio_id].max_latency) {
+ children[nbio_id].max_latency = MAX(elapsed - targett, children[nbio_id].max_latency);
+ }
+}
+
+double nbio_result(void)
+{
+ int i;
+ double total = 0;
+ for (i=0;i<nprocs;i++) {
+ total += children[i].bytes - children[i].warmup_bytes;
+ }
+ return 1.0e-6 * total / timeval_elapsed2(&tv_start, &tv_end);
+}
+
+double nbio_latency(void)
+{
+ int i;
+ double max_latency = 0;
+ for (i=0;i<nprocs;i++) {
+ if (children[i].max_latency > max_latency) {
+ max_latency = children[i].max_latency;
+ children[i].max_latency = 0;
+ }
+ }
+ return max_latency;
+}
+
+bool nb_tick(void)
+{
+ return children[nbio_id].done;
+}
+
+
+void nb_alarm(int sig)
+{
+ int i;
+ int lines=0;
+ double t;
+ int in_warmup = 0;
+ int num_connected = 0;
+
+ if (nbio_id != -1) return;
+
+ for (i=0;i<nprocs;i++) {
+ if (children[i].connected) {
+ num_connected++;
+ }
+ if (children[i].bytes == 0) {
+ in_warmup = 1;
+ }
+ lines += children[i].line;
+ }
+
+ t = timeval_elapsed(&tv_start);
+
+ if (!in_warmup && warmup>0 && t > warmup) {
+ tv_start = timeval_current();
+ warmup = 0;
+ for (i=0;i<nprocs;i++) {
+ children[i].warmup_bytes = children[i].bytes;
+ }
+ goto next;
+ }
+ if (t < warmup) {
+ in_warmup = 1;
+ } else if (!in_warmup && !in_cleanup && t > timelimit) {
+ for (i=0;i<nprocs;i++) {
+ children[i].done = 1;
+ }
+ tv_end = timeval_current();
+ in_cleanup = 1;
+ }
+ if (t < 1) {
+ goto next;
+ }
+ if (!in_cleanup) {
+ tv_end = timeval_current();
+ }
+
+ if (in_warmup) {
+ printf("%4d %8d %.2f MB/sec warmup %.0f sec \n",
+ num_connected, lines/nprocs,
+ nbio_result(), t);
+ } else if (in_cleanup) {
+ printf("%4d %8d %.2f MB/sec cleanup %.0f sec \n",
+ num_connected, lines/nprocs,
+ nbio_result(), t);
+ } else {
+ printf("%4d %8d %.2f MB/sec execute %.0f sec latency %.2f msec \n",
+ num_connected, lines/nprocs,
+ nbio_result(), t, nbio_latency() * 1.0e3);
+ }
+
+ fflush(stdout);
+next:
+ signal(SIGALRM, nb_alarm);
+ alarm(1);
+}
+
+void nbio_shmem(int n, int t_timelimit, int t_warmup)
+{
+ nprocs = n;
+ children = anonymous_shared_allocate(sizeof(*children) * nprocs);
+ if (!children) {
+ printf("Failed to setup shared memory!\n");
+ nb_exit(1);
+ }
+ memset(children, 0, sizeof(*children) * nprocs);
+ timelimit = t_timelimit;
+ warmup = t_warmup;
+ in_cleanup = 0;
+ tv_start = timeval_current();
+}
+
+static struct lock_info* find_lock(struct lock_info *linfo, off_t offset, int size)
+{
+ while (linfo != NULL) {
+ if (linfo->offset == offset &&
+ linfo->size == size)
+ {
+ return linfo;
+ }
+
+ linfo = linfo->next;
+ }
+
+ return NULL;
+}
+
+static struct ftable *find_ftable(int handle)
+{
+ struct ftable *f;
+
+ for (f=ftable;f;f=f->next) {
+ if (f->handle == handle) return f;
+ }
+ return NULL;
+}
+
+static int find_handle(int handle, struct ftable **f_ret)
+{
+ struct ftable *f;
+
+ if (f_ret != NULL)
+ *f_ret = NULL;
+
+ children[nbio_id].line = nbench_line_count;
+
+ f = find_ftable(handle);
+ if (f) {
+ if (f_ret != NULL)
+ *f_ret = f;
+ return f->fd;
+ }
+ printf("(%d) ERROR: handle %d was not found\n",
+ nbench_line_count, handle);
+ nb_exit(1);
+
+ return -1; /* Not reached */
+}
+
+
+
+static struct smbcli_state *c;
+
+/*
+ a handler function for oplock break requests
+*/
+static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid,
+ uint16_t fnum, uint8_t level, void *private_data)
+{
+ struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
+ return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
+}
+
+void nb_setup(struct smbcli_state *cli, int id)
+{
+ nbio_id = id;
+ c = cli;
+ if (bypass_io)
+ printf("skipping I/O\n");
+
+ if (cli) {
+ smbcli_oplock_handler(cli->transport, oplock_handler, cli->tree);
+ }
+
+ children[id].connected = true;
+}
+
+
+static bool check_status(const char *op, NTSTATUS status, NTSTATUS ret)
+{
+ if ((NT_STATUS_EQUAL(ret, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(ret, NT_STATUS_NET_WRITE_FAULT) ||
+ NT_STATUS_EQUAL(ret, NT_STATUS_CONNECTION_RESET))
+ && !NT_STATUS_EQUAL (status, ret))
+ {
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) {
+ printf("[%d] Error: %s should have failed with %s\n",
+ nbench_line_count, op, nt_errstr(status));
+ nb_exit(1);
+ }
+
+ if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) {
+ printf("[%d] Error: %s should have succeeded - %s\n",
+ nbench_line_count, op, nt_errstr(ret));
+ nb_exit(1);
+ }
+
+ if (!NT_STATUS_EQUAL(status, ret)) {
+ printf("[%d] Warning: got status %s but expected %s\n",
+ nbench_line_count, nt_errstr(ret), nt_errstr(status));
+ }
+
+ return true;
+}
+
+
+bool nb_unlink(const char *fname, int attr, NTSTATUS status, bool retry)
+{
+ union smb_unlink io;
+ NTSTATUS ret;
+
+ io.unlink.in.pattern = fname;
+
+ io.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ if (strchr(fname, '*') == 0) {
+ io.unlink.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ ret = smb_raw_unlink(c->tree, &io);
+
+ if (!retry)
+ return check_status("Unlink", status, ret);
+
+ return true;
+}
+
+static bool nb_do_createx(struct ftable *f,
+ const char *fname,
+ unsigned int create_options,
+ unsigned int create_disposition,
+ int handle,
+ NTSTATUS status,
+ bool retry)
+{
+ union smb_open io;
+ uint32_t desired_access;
+ NTSTATUS ret;
+ TALLOC_CTX *mem_ctx;
+ unsigned int flags = 0;
+
+ mem_ctx = talloc_init("raw_open");
+
+ if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
+ desired_access = SEC_FILE_READ_DATA;
+ } else {
+ desired_access =
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ }
+
+ io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = flags;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = desired_access;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = create_disposition;
+ io.ntcreatex.in.create_options = create_options;
+ io.ntcreatex.in.impersonation = 0;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ if (retry) {
+ /* Reopening after a disconnect. */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ } else
+ if (f != NULL &&
+ f->cp.create_disposition == NTCREATEX_DISP_CREATE &&
+ NT_STATUS_IS_OK(status))
+ {
+ /* Reopening after nb_createx() error. */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ }
+
+ ret = smb_raw_open(c->tree, mem_ctx, &io);
+
+ talloc_free(mem_ctx);
+
+ if (!check_status("NTCreateX", status, ret))
+ return false;
+
+ if (!NT_STATUS_IS_OK(ret))
+ return true;
+
+ if (f == NULL) {
+ f = talloc (NULL, struct ftable);
+ f->locks = NULL;
+ nb_set_createx_params(f, fname, create_options, create_disposition, handle);
+ DLIST_ADD_END(ftable, f);
+ }
+
+ f->handle = handle;
+ f->fd = io.ntcreatex.out.file.fnum;
+
+ return true;
+}
+
+bool nb_createx(const char *fname,
+ unsigned int create_options, unsigned int create_disposition, int handle,
+ NTSTATUS status)
+{
+ return nb_do_createx(NULL, fname, create_options, create_disposition, handle, status, false);
+}
+
+bool nb_writex(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
+{
+ union smb_write io;
+ int i;
+ NTSTATUS ret;
+ uint8_t *buf;
+
+ i = find_handle(handle, NULL);
+
+ if (bypass_io)
+ return true;
+
+ buf = malloc(size);
+ memset(buf, 0xab, size);
+
+ io.writex.level = RAW_WRITE_WRITEX;
+ io.writex.in.file.fnum = i;
+ io.writex.in.wmode = 0;
+ io.writex.in.remaining = 0;
+ io.writex.in.offset = offset;
+ io.writex.in.count = size;
+ io.writex.in.data = buf;
+
+ ret = smb_raw_write(c->tree, &io);
+
+ free(buf);
+
+ if (!check_status("WriteX", status, ret))
+ return false;
+
+ if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
+ printf("[%d] Warning: WriteX got count %d expected %d\n",
+ nbench_line_count,
+ io.writex.out.nwritten, ret_size);
+ }
+
+ children[nbio_id].bytes += ret_size;
+
+ return true;
+}
+
+bool nb_write(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
+{
+ union smb_write io;
+ int i;
+ NTSTATUS ret;
+ uint8_t *buf;
+
+ i = find_handle(handle, NULL);
+
+ if (bypass_io)
+ return true;
+
+ buf = malloc(size);
+
+ memset(buf, 0x12, size);
+
+ io.write.level = RAW_WRITE_WRITE;
+ io.write.in.file.fnum = i;
+ io.write.in.remaining = 0;
+ io.write.in.offset = offset;
+ io.write.in.count = size;
+ io.write.in.data = buf;
+
+ ret = smb_raw_write(c->tree, &io);
+
+ free(buf);
+
+ if (!check_status("Write", status, ret))
+ return false;
+
+ if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
+ printf("[%d] Warning: Write got count %d expected %d\n",
+ nbench_line_count,
+ io.write.out.nwritten, ret_size);
+ }
+
+ children[nbio_id].bytes += ret_size;
+
+ return true;
+}
+
+static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status)
+{
+ union smb_lock io;
+ int i;
+ NTSTATUS ret;
+ struct smb_lock_entry lck;
+ struct ftable *f;
+
+ i = find_handle(handle, &f);
+
+ lck.pid = getpid();
+ lck.offset = offset;
+ lck.count = size;
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = i;
+ io.lockx.in.mode = 0;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lck;
+
+ ret = smb_raw_lock(c->tree, &io);
+
+ if (!check_status("LockX", status, ret))
+ return false;
+
+ if (f != NULL &&
+ !relock)
+ {
+ struct lock_info *linfo;
+ linfo = talloc (f, struct lock_info);
+ linfo->offset = offset;
+ linfo->size = size;
+ DLIST_ADD_END(f->locks, linfo);
+ }
+
+ return true;
+}
+
+bool nb_lockx(int handle, off_t offset, int size, NTSTATUS status)
+{
+ return nb_do_lockx(false, handle, offset, size, status);
+}
+
+bool nb_unlockx(int handle, unsigned int offset, int size, NTSTATUS status)
+{
+ union smb_lock io;
+ int i;
+ NTSTATUS ret;
+ struct smb_lock_entry lck;
+ struct ftable *f;
+
+ i = find_handle(handle, &f);
+
+ lck.pid = getpid();
+ lck.offset = offset;
+ lck.count = size;
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = i;
+ io.lockx.in.mode = 0;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lck;
+
+ ret = smb_raw_lock(c->tree, &io);
+
+ if (!check_status("UnlockX", status, ret))
+ return false;
+
+ if (f != NULL) {
+ struct lock_info *linfo;
+ linfo = find_lock(f->locks, offset, size);
+ if (linfo != NULL)
+ DLIST_REMOVE(f->locks, linfo);
+ else
+ printf("nb_unlockx: unknown lock (%d)\n", handle);
+ }
+
+ return true;
+}
+
+bool nb_readx(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
+{
+ union smb_read io;
+ int i;
+ NTSTATUS ret;
+ uint8_t *buf;
+
+ i = find_handle(handle, NULL);
+
+ if (bypass_io)
+ return true;
+
+ buf = malloc(size);
+
+ io.readx.level = RAW_READ_READX;
+ io.readx.in.file.fnum = i;
+ io.readx.in.offset = offset;
+ io.readx.in.mincnt = size;
+ io.readx.in.maxcnt = size;
+ io.readx.in.remaining = 0;
+ io.readx.in.read_for_execute = false;
+ io.readx.out.data = buf;
+
+ ret = smb_raw_read(c->tree, &io);
+
+ free(buf);
+
+ if (!check_status("ReadX", status, ret))
+ return false;
+
+ if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
+ printf("[%d] ERROR: ReadX got count %d expected %d\n",
+ nbench_line_count,
+ io.readx.out.nread, ret_size);
+ nb_exit(1);
+ }
+
+ children[nbio_id].bytes += ret_size;
+
+ return true;
+}
+
+bool nb_close(int handle, NTSTATUS status)
+{
+ NTSTATUS ret;
+ union smb_close io;
+ int i;
+
+ i = find_handle(handle, NULL);
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.file.fnum = i;
+ io.close.in.write_time = 0;
+
+ ret = smb_raw_close(c->tree, &io);
+
+ if (!check_status("Close", status, ret))
+ return false;
+
+ if (NT_STATUS_IS_OK(ret)) {
+ struct ftable *f = find_ftable(handle);
+ DLIST_REMOVE(ftable, f);
+ talloc_free(f);
+ }
+
+ return true;
+}
+
+bool nb_rmdir(const char *dname, NTSTATUS status, bool retry)
+{
+ NTSTATUS ret;
+ struct smb_rmdir io;
+
+ io.in.path = dname;
+
+ ret = smb_raw_rmdir(c->tree, &io);
+
+ if (!retry)
+ return check_status("Rmdir", status, ret);
+
+ return true;
+}
+
+bool nb_mkdir(const char *dname, NTSTATUS status, bool retry)
+{
+ union smb_mkdir io;
+
+ io.mkdir.level = RAW_MKDIR_MKDIR;
+ io.mkdir.in.path = dname;
+
+ /* NOTE! no error checking. Used for base fileset creation */
+ smb_raw_mkdir(c->tree, &io);
+
+ return true;
+}
+
+bool nb_rename(const char *o, const char *n, NTSTATUS status, bool retry)
+{
+ NTSTATUS ret;
+ union smb_rename io;
+
+ io.generic.level = RAW_RENAME_RENAME;
+ io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+ io.rename.in.pattern1 = o;
+ io.rename.in.pattern2 = n;
+
+ ret = smb_raw_rename(c->tree, &io);
+
+ if (!retry)
+ return check_status("Rename", status, ret);
+
+ return true;
+}
+
+
+bool nb_qpathinfo(const char *fname, int level, NTSTATUS status)
+{
+ union smb_fileinfo io;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS ret;
+
+ mem_ctx = talloc_init("nb_qpathinfo");
+
+ io.generic.level = level;
+ io.generic.in.file.path = fname;
+
+ ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
+
+ talloc_free(mem_ctx);
+
+ return check_status("Pathinfo", status, ret);
+}
+
+
+bool nb_qfileinfo(int fnum, int level, NTSTATUS status)
+{
+ union smb_fileinfo io;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS ret;
+ int i;
+
+ i = find_handle(fnum, NULL);
+
+ mem_ctx = talloc_init("nb_qfileinfo");
+
+ io.generic.level = level;
+ io.generic.in.file.fnum = i;
+
+ ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
+
+ talloc_free(mem_ctx);
+
+ return check_status("Fileinfo", status, ret);
+}
+
+bool nb_sfileinfo(int fnum, int level, NTSTATUS status)
+{
+ union smb_setfileinfo io;
+ NTSTATUS ret;
+ int i;
+
+ if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
+ printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
+ return true;
+ }
+
+ ZERO_STRUCT(io);
+
+ i = find_handle(fnum, NULL);
+
+ io.generic.level = level;
+ io.generic.in.file.fnum = i;
+ unix_to_nt_time(&io.basic_info.in.create_time, time(NULL));
+ unix_to_nt_time(&io.basic_info.in.access_time, 0);
+ unix_to_nt_time(&io.basic_info.in.write_time, 0);
+ unix_to_nt_time(&io.basic_info.in.change_time, 0);
+ io.basic_info.in.attrib = 0;
+
+ ret = smb_raw_setfileinfo(c->tree, &io);
+
+ return check_status("Setfileinfo", status, ret);
+}
+
+bool nb_qfsinfo(int level, NTSTATUS status)
+{
+ union smb_fsinfo io;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS ret;
+
+ mem_ctx = talloc_init("smbcli_dskattr");
+
+ io.generic.level = level;
+ ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
+
+ talloc_free(mem_ctx);
+
+ return check_status("Fsinfo", status, ret);
+}
+
+/* callback function used for trans2 search */
+static bool findfirst_callback(void *private_data, const union smb_search_data *file)
+{
+ return true;
+}
+
+bool nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
+{
+ union smb_search_first io;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS ret;
+
+ mem_ctx = talloc_init("smbcli_dskattr");
+
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = level;
+ io.t2ffirst.in.max_count = maxcnt;
+ io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
+ io.t2ffirst.in.pattern = mask;
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
+ io.t2ffirst.in.storage_type = 0;
+
+ ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
+
+ talloc_free(mem_ctx);
+
+ if (!check_status("Search", status, ret))
+ return false;
+
+ if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
+ printf("[%d] Warning: got count %d expected %d\n",
+ nbench_line_count,
+ io.t2ffirst.out.count, count);
+ }
+
+ return true;
+}
+
+bool nb_flush(int fnum, NTSTATUS status)
+{
+ union smb_flush io;
+ NTSTATUS ret;
+ int i;
+ i = find_handle(fnum, NULL);
+
+ io.flush.level = RAW_FLUSH_FLUSH;
+ io.flush.in.file.fnum = i;
+
+ ret = smb_raw_flush(c->tree, &io);
+
+ return check_status("Flush", status, ret);
+}
+
+void nb_sleep(int usec, NTSTATUS status)
+{
+ usleep(usec);
+}
+
+bool nb_deltree(const char *dname, bool retry)
+{
+ int total_deleted;
+
+ smb_raw_exit(c->session);
+
+ while (ftable) {
+ struct ftable *f = ftable;
+ DLIST_REMOVE(ftable, f);
+ talloc_free (f);
+ }
+
+ total_deleted = smbcli_deltree(c->tree, dname);
+
+ if (total_deleted == -1) {
+ printf("Failed to cleanup tree %s - exiting\n", dname);
+ nb_exit(1);
+ }
+
+ smbcli_rmdir(c->tree, dname);
+
+ return true;
+}
+
+
+void nb_exit(int status)
+{
+ children[nbio_id].connected = false;
+ printf("[%d] client %d exiting with status %d\n",
+ nbench_line_count, nbio_id, status);
+ exit(status);
+}
diff --git a/source4/torture/nbt/dgram.c b/source4/torture/nbt/dgram.c
new file mode 100644
index 0000000..2f7ea19
--- /dev/null
+++ b/source4/torture/nbt/dgram.c
@@ -0,0 +1,699 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NBT dgram testing
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/dgram/libdgram.h"
+#include "lib/socket/socket.h"
+#include "lib/events/events.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/nbt/proto.h"
+#include "libcli/resolve/resolve.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "param/param.h"
+
+#define TEST_NAME "TORTURE_TEST"
+
+/*
+ reply handler for netlogon request
+*/
+static void netlogon_handler(struct dgram_mailslot_handler *dgmslot,
+ struct nbt_dgram_packet *packet,
+ struct socket_address *src)
+{
+ NTSTATUS status;
+ struct nbt_netlogon_response *netlogon = dgmslot->private_data;
+
+ dgmslot->private_data = netlogon = talloc(dgmslot, struct nbt_netlogon_response);
+
+ if (!dgmslot->private_data) {
+ return;
+ }
+
+ printf("netlogon reply from %s:%d\n", src->addr, src->port);
+
+ /* Fills in the netlogon pointer */
+ status = dgram_mailslot_netlogon_parse_response(netlogon, packet,
+ netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to parse netlogon packet from %s:%d\n",
+ src->addr, src->port);
+ return;
+ }
+
+}
+
+
+/* test UDP/138 netlogon requests */
+static bool nbt_test_netlogon(struct torture_context *tctx)
+{
+ struct dgram_mailslot_handler *dgmslot;
+ struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(tctx, tctx->ev);
+ struct socket_address *dest;
+ const char *myaddress;
+ struct nbt_netlogon_packet logon;
+ struct nbt_netlogon_response *response;
+ struct nbt_name myname;
+ NTSTATUS status;
+ struct timeval tv = timeval_current();
+
+ struct socket_address *socket_address;
+
+ const char *address;
+ struct nbt_name name;
+
+ struct interface *ifaces;
+
+ name.name = lpcfg_workgroup(tctx->lp_ctx);
+ name.type = NBT_NAME_LOGON;
+ name.scope = NULL;
+
+ /* do an initial name resolution to find its IP */
+ torture_assert_ntstatus_ok(tctx,
+ resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0,
+ &name, tctx, &address, tctx->ev),
+ talloc_asprintf(tctx, "Failed to resolve %s", name.name));
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+ myaddress = talloc_strdup(dgmsock, iface_list_best_ip(ifaces, address));
+
+
+ socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ myaddress, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, socket_address != NULL, "Error getting address");
+
+ /* try receiving replies on port 138 first, which will only
+ work if we are root and smbd/nmbd are not running - fall
+ back to listening on any port, which means replies from
+ most windows versions won't be seen */
+ status = socket_listen(dgmsock->sock, socket_address, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(socket_address);
+ socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ myaddress, 0);
+ torture_assert(tctx, socket_address != NULL, "Error getting address");
+
+ socket_listen(dgmsock->sock, socket_address, 0, 0);
+ }
+
+ /* setup a temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_PRIMARY_QUERY;
+ logon.req.pdc.computer_name = TEST_NAME;
+ logon.req.pdc.mailslot_name = dgmslot->mailslot_name;
+ logon.req.pdc.unicode_name = TEST_NAME;
+ logon.req.pdc.nt_version = 1;
+ logon.req.pdc.lmnt_token = 0xFFFF;
+ logon.req.pdc.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, dest != NULL, "Error getting address");
+
+ status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
+ NBT_MAILSLOT_NETLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && !dgmslot->private_data) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert(tctx, response->response_type == NETLOGON_GET_PDC, "Got incorrect type of netlogon response");
+ torture_assert(tctx, response->data.get_pdc.command == NETLOGON_RESPONSE_FROM_PDC, "Got incorrect netlogon response command");
+
+ return true;
+}
+
+
+/* test UDP/138 netlogon requests */
+static bool nbt_test_netlogon2(struct torture_context *tctx)
+{
+ struct dgram_mailslot_handler *dgmslot;
+ struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(tctx, tctx->ev);
+ struct socket_address *dest;
+ const char *myaddress;
+ struct nbt_netlogon_packet logon;
+ struct nbt_netlogon_response *response;
+ struct nbt_name myname;
+ NTSTATUS status;
+ struct timeval tv = timeval_current();
+
+ struct socket_address *socket_address;
+
+ const char *address;
+ struct nbt_name name;
+
+ struct interface *ifaces;
+ struct test_join *join_ctx;
+ struct cli_credentials *machine_credentials;
+ const struct dom_sid *dom_sid;
+
+ name.name = lpcfg_workgroup(tctx->lp_ctx);
+ name.type = NBT_NAME_LOGON;
+ name.scope = NULL;
+
+ /* do an initial name resolution to find its IP */
+ torture_assert_ntstatus_ok(tctx,
+ resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0,
+ &name, tctx, &address, tctx->ev),
+ talloc_asprintf(tctx, "Failed to resolve %s", name.name));
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+ myaddress = talloc_strdup(dgmsock, iface_list_best_ip(ifaces, address));
+
+ socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ myaddress, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, socket_address != NULL, "Error getting address");
+
+ /* try receiving replies on port 138 first, which will only
+ work if we are root and smbd/nmbd are not running - fall
+ back to listening on any port, which means replies from
+ some windows versions won't be seen */
+ status = socket_listen(dgmsock->sock, socket_address, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(socket_address);
+ socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ myaddress, 0);
+ torture_assert(tctx, socket_address != NULL, "Error getting address");
+
+ socket_listen(dgmsock->sock, socket_address, 0, 0);
+ }
+
+ /* setup a temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = "";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.nt_version = NETLOGON_NT_VERSION_5EX_WITH_IP|NETLOGON_NT_VERSION_5|NETLOGON_NT_VERSION_1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
+ NBT_MAILSLOT_NETLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX, "Got incorrect netlogon response command");
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.nt_version, NETLOGON_NT_VERSION_5EX_WITH_IP|NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_1, "Got incorrect netlogon response command");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") == NULL,
+ "PDC name should not be in UNC form");
+
+ /* setup (another) temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = TEST_NAME"$";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.nt_version = 1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
+ NBT_MAILSLOT_NETLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN, "Got incorrect netlogon response command");
+
+ torture_assert_str_equal(tctx, response->data.samlogon.data.nt5_ex.user_name, TEST_NAME"$", "Got incorrect user in netlogon response");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ join_ctx = torture_join_domain(tctx, TEST_NAME,
+ ACB_WSTRUST, &machine_credentials);
+
+ torture_assert(tctx, join_ctx != NULL,
+ talloc_asprintf(tctx, "Failed to join domain %s as %s\n",
+ lpcfg_workgroup(tctx->lp_ctx), TEST_NAME));
+
+ dom_sid = torture_join_sid(join_ctx);
+
+ /* setup (another) temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = TEST_NAME"$";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.sid = *dom_sid;
+ logon.req.logon.nt_version = 1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
+ NBT_MAILSLOT_NETLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
+
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN, "Got incorrect netlogon response command");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ /* setup (another) temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error getting a Mailslot for GetDC reply");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = TEST_NAME"$";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.sid = *dom_sid;
+ logon.req.logon.acct_control = ACB_WSTRUST;
+ logon.req.logon.nt_version = 1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
+ NBT_MAILSLOT_NETLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
+
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE, "Got incorrect netlogon response command");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ dgmslot->private_data = NULL;
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = TEST_NAME"$";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.sid = *dom_sid;
+ logon.req.logon.acct_control = ACB_NORMAL;
+ logon.req.logon.nt_version = 1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
+ NBT_MAILSLOT_NETLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
+
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_USER_UNKNOWN, "Got incorrect netlogon response command");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ torture_leave_domain(tctx, join_ctx);
+ return true;
+}
+
+
+/* test UDP/138 ntlogon requests */
+static bool nbt_test_ntlogon(struct torture_context *tctx)
+{
+ struct dgram_mailslot_handler *dgmslot;
+ struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(tctx, tctx->ev);
+ struct socket_address *dest;
+ struct test_join *join_ctx;
+ const struct dom_sid *dom_sid;
+ struct cli_credentials *machine_credentials;
+
+ const char *myaddress;
+ struct nbt_netlogon_packet logon;
+ struct nbt_netlogon_response *response;
+ struct nbt_name myname;
+ NTSTATUS status;
+ struct timeval tv = timeval_current();
+
+ struct socket_address *socket_address;
+ const char *address;
+ struct nbt_name name;
+
+ struct interface *ifaces;
+
+ name.name = lpcfg_workgroup(tctx->lp_ctx);
+ name.type = NBT_NAME_LOGON;
+ name.scope = NULL;
+
+ /* do an initial name resolution to find its IP */
+ torture_assert_ntstatus_ok(tctx,
+ resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0, &name, tctx, &address, tctx->ev),
+ talloc_asprintf(tctx, "Failed to resolve %s", name.name));
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+ myaddress = talloc_strdup(dgmsock, iface_list_best_ip(ifaces, address));
+
+ socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ myaddress, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, socket_address != NULL, "Error getting address");
+
+ /* try receiving replies on port 138 first, which will only
+ work if we are root and smbd/nmbd are not running - fall
+ back to listening on any port, which means replies from
+ most windows versions won't be seen */
+ status = socket_listen(dgmsock->sock, socket_address, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(socket_address);
+ socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ myaddress, 0);
+ torture_assert(tctx, socket_address != NULL, "Error getting address");
+
+ socket_listen(dgmsock->sock, socket_address, 0, 0);
+ }
+
+ join_ctx = torture_join_domain(tctx, TEST_NAME,
+ ACB_WSTRUST, &machine_credentials);
+
+ torture_assert(tctx, join_ctx != NULL,
+ talloc_asprintf(tctx, "Failed to join domain %s as %s\n",
+ lpcfg_workgroup(tctx->lp_ctx), TEST_NAME));
+ dom_sid = torture_join_sid(join_ctx);
+
+ /* setup a temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = TEST_NAME"$";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.acct_control = ACB_WSTRUST;
+ /* Try with a SID this time */
+ logon.req.logon.sid = *dom_sid;
+ logon.req.logon.nt_version = 1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock,
+ &name, dest,
+ NBT_MAILSLOT_NTLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send ntlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE, "Got incorrect netlogon response command");
+
+ torture_assert_str_equal(tctx, response->data.samlogon.data.nt5_ex.user_name, TEST_NAME"$", "Got incorrect user in netlogon response");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ /* setup a temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_SAM_LOGON_REQUEST;
+ logon.req.logon.request_count = 0;
+ logon.req.logon.computer_name = TEST_NAME;
+ logon.req.logon.user_name = TEST_NAME"$";
+ logon.req.logon.mailslot_name = dgmslot->mailslot_name;
+ logon.req.logon.acct_control = ACB_WSTRUST;
+ /* Leave sid as all zero */
+ logon.req.logon.nt_version = 1;
+ logon.req.logon.lmnt_token = 0xFFFF;
+ logon.req.logon.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock,
+ &name, dest,
+ NBT_MAILSLOT_NTLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send ntlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && dgmslot->private_data == NULL) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_SAMLOGON, "Got incorrect type of netlogon response");
+ map_netlogon_samlogon_response(&response->data.samlogon);
+
+ torture_assert_int_equal(tctx, response->data.samlogon.data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE, "Got incorrect netlogon response command");
+
+ torture_assert_str_equal(tctx, response->data.samlogon.data.nt5_ex.user_name, TEST_NAME"$", "Got incorrect user in netlogon response");
+
+ torture_assert(tctx,
+ strstr(response->data.samlogon.data.nt5_ex.pdc_name, "\\\\") != NULL,
+ "PDC name should be in UNC form");
+
+ /* setup (another) temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_PRIMARY_QUERY;
+ logon.req.pdc.computer_name = TEST_NAME;
+ logon.req.pdc.mailslot_name = dgmslot->mailslot_name;
+ logon.req.pdc.unicode_name = TEST_NAME;
+ logon.req.pdc.nt_version = 1;
+ logon.req.pdc.lmnt_token = 0xFFFF;
+ logon.req.pdc.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock,
+ &name, dest,
+ NBT_MAILSLOT_NTLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send ntlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && !dgmslot->private_data) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_GET_PDC, "Got incorrect type of ntlogon response");
+ torture_assert_int_equal(tctx, response->data.get_pdc.command, NETLOGON_RESPONSE_FROM_PDC, "Got incorrect ntlogon response command");
+
+ torture_leave_domain(tctx, join_ctx);
+
+ /* setup (another) temporary mailslot listener for replies */
+ dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
+ netlogon_handler, NULL);
+ torture_assert(tctx, dgmslot != NULL, "Error temporary mailslot for GetDC");
+
+ ZERO_STRUCT(logon);
+ logon.command = LOGON_PRIMARY_QUERY;
+ logon.req.pdc.computer_name = TEST_NAME;
+ logon.req.pdc.mailslot_name = dgmslot->mailslot_name;
+ logon.req.pdc.unicode_name = TEST_NAME;
+ logon.req.pdc.nt_version = 1;
+ logon.req.pdc.lmnt_token = 0xFFFF;
+ logon.req.pdc.lm20_token = 0xFFFF;
+
+ make_nbt_name_client(&myname, TEST_NAME);
+
+ dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
+ address, lpcfg_dgram_port(tctx->lp_ctx));
+ torture_assert(tctx, dest != NULL, "Error getting address");
+ status = dgram_mailslot_netlogon_send(dgmsock,
+ &name, dest,
+ NBT_MAILSLOT_NTLOGON,
+ &myname, &logon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to send ntlogon request");
+
+ while (timeval_elapsed(&tv) < 5 && !dgmslot->private_data) {
+ tevent_loop_once(dgmsock->event_ctx);
+ }
+
+ response = talloc_get_type(dgmslot->private_data, struct nbt_netlogon_response);
+
+ torture_assert(tctx, response != NULL, "Failed to receive a netlogon reply packet");
+
+ torture_assert_int_equal(tctx, response->response_type, NETLOGON_GET_PDC, "Got incorrect type of ntlogon response");
+ torture_assert_int_equal(tctx, response->data.get_pdc.command, NETLOGON_RESPONSE_FROM_PDC, "Got incorrect ntlogon response command");
+
+
+ return true;
+}
+
+
+/*
+ test nbt dgram operations
+*/
+struct torture_suite *torture_nbt_dgram(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "dgram");
+
+ torture_suite_add_simple_test(suite, "netlogon", nbt_test_netlogon);
+ torture_suite_add_simple_test(suite, "netlogon2", nbt_test_netlogon2);
+ torture_suite_add_simple_test(suite, "ntlogon", nbt_test_ntlogon);
+
+ return suite;
+}
diff --git a/source4/torture/nbt/nbt.c b/source4/torture/nbt/nbt.c
new file mode 100644
index 0000000..f350885
--- /dev/null
+++ b/source4/torture/nbt/nbt.c
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../libcli/nbt/libnbt.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "torture/smbtorture.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+
+struct nbt_name_socket *torture_init_nbt_socket(struct torture_context *tctx)
+{
+ return nbt_name_socket_init(tctx, tctx->ev);
+}
+
+bool torture_nbt_get_name(struct torture_context *tctx,
+ struct nbt_name *name,
+ const char **address)
+{
+ make_nbt_name_server(name, strupper_talloc(tctx,
+ torture_setting_string(tctx, "host", NULL)));
+
+ /* do an initial name resolution to find its IP */
+ torture_assert_ntstatus_ok(tctx,
+ resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0,
+ name, tctx, address, tctx->ev),
+ talloc_asprintf(tctx,
+ "Failed to resolve %s", name->name));
+
+ return true;
+}
+
+NTSTATUS torture_nbt_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "nbt");
+ /* nbt tests */
+ torture_suite_add_suite(suite, torture_nbt_register(suite));
+ torture_suite_add_suite(suite, torture_nbt_wins(suite));
+ torture_suite_add_suite(suite, torture_nbt_dgram(suite));
+ torture_suite_add_suite(suite, torture_nbt_winsreplication(suite));
+ torture_suite_add_suite(suite, torture_bench_nbt(suite));
+ torture_suite_add_suite(suite, torture_bench_wins(suite));
+
+ suite->description = talloc_strdup(suite,
+ "NetBIOS over TCP/IP and WINS tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/nbt/query.c b/source4/torture/nbt/query.c
new file mode 100644
index 0000000..001ff19
--- /dev/null
+++ b/source4/torture/nbt/query.c
@@ -0,0 +1,115 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NBT name query testing
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "param/param.h"
+
+struct result_struct {
+ int num_pass;
+ int num_fail;
+};
+
+static void increment_handler(struct nbt_name_request *req)
+{
+ struct result_struct *v = talloc_get_type(req->async.private_data, struct result_struct);
+ if (req->state != NBT_REQUEST_DONE) {
+ v->num_fail++;
+ } else {
+ v->num_pass++;
+ }
+ talloc_free(req);
+}
+
+/*
+ benchmark simple name queries
+*/
+static bool bench_namequery(struct torture_context *tctx)
+{
+ struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
+ int num_sent=0;
+ struct result_struct *result;
+ struct nbt_name_query io;
+ struct timeval tv = timeval_current();
+ int timelimit = torture_setting_int(tctx, "timelimit", 5);
+
+ const char *address;
+ struct nbt_name name;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ io.in.name = name;
+ io.in.dest_addr = address;
+ io.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ io.in.broadcast = false;
+ io.in.wins_lookup = false;
+ io.in.timeout = 1;
+
+ result = talloc_zero(tctx, struct result_struct);
+
+ torture_comment(tctx, "Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ while (num_sent - (result->num_pass+result->num_fail) < 10) {
+ struct nbt_name_request *req;
+ req = nbt_name_query_send(nbtsock, &io);
+ torture_assert(tctx, req != NULL, "Failed to setup request!");
+ req->async.fn = increment_handler;
+ req->async.private_data = result;
+ num_sent++;
+ if (num_sent % 1000 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%.1f queries per second (%d failures) \r",
+ result->num_pass / timeval_elapsed(&tv),
+ result->num_fail);
+ fflush(stdout);
+ }
+ }
+ }
+
+ tevent_loop_once(nbtsock->event_ctx);
+ }
+
+ while (num_sent != (result->num_pass + result->num_fail)) {
+ tevent_loop_once(nbtsock->event_ctx);
+ }
+
+ torture_comment(tctx, "%.1f queries per second (%d failures) \n",
+ result->num_pass / timeval_elapsed(&tv),
+ result->num_fail);
+
+ return true;
+}
+
+
+/*
+ benchmark how fast a server can respond to name queries
+*/
+struct torture_suite *torture_bench_nbt(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "bench");
+ torture_suite_add_simple_test(suite, "namequery", bench_namequery);
+
+ return suite;
+}
diff --git a/source4/torture/nbt/register.c b/source4/torture/nbt/register.c
new file mode 100644
index 0000000..24ca328
--- /dev/null
+++ b/source4/torture/nbt/register.c
@@ -0,0 +1,176 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NBT name registration testing
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "param/param.h"
+
+#define CHECK_VALUE(tctx, v, correct) \
+ torture_assert_int_equal(tctx, v, correct, "Incorrect value")
+
+#define CHECK_STRING(tctx, v, correct) \
+ torture_assert_casestr_equal(tctx, v, correct, "Incorrect value")
+
+
+
+
+/*
+ test that a server responds correctly to attempted registrations of its name
+*/
+static bool nbt_register_own(struct torture_context *tctx)
+{
+ struct nbt_name_register io;
+ NTSTATUS status;
+ struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
+ struct socket_address *socket_address;
+ struct nbt_name name;
+ const char *address;
+ const char *myaddress;
+ struct interface *ifaces;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+
+ myaddress = iface_list_best_ip(ifaces, address);
+
+ socket_address = socket_address_from_strings(tctx, nbtsock->sock->backend_name,
+ myaddress, 0);
+ torture_assert(tctx, socket_address != NULL, "Unable to get address");
+
+ status = socket_listen(nbtsock->sock, socket_address, 0, 0);
+ torture_assert_ntstatus_ok(tctx, status,
+ "socket_listen for nbt_register_own failed");
+
+ torture_comment(tctx, "Testing name defense to name registration\n");
+
+ io.in.name = name;
+ io.in.dest_addr = address;
+ io.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ io.in.address = myaddress;
+ io.in.nb_flags = NBT_NODE_B | NBT_NM_ACTIVE;
+ io.in.register_demand = false;
+ io.in.broadcast = true;
+ io.in.multi_homed = false;
+ io.in.ttl = 1234;
+ io.in.timeout = 3;
+ io.in.retries = 0;
+
+ status = nbt_name_register(nbtsock, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name register",
+ address));
+
+ CHECK_STRING(tctx, io.out.name.name, name.name);
+ CHECK_VALUE(tctx, io.out.name.type, name.type);
+ CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
+
+ /* check a register demand */
+ io.in.address = myaddress;
+ io.in.register_demand = true;
+
+ status = nbt_name_register(nbtsock, tctx, &io);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name register demand", address));
+
+ CHECK_STRING(tctx, io.out.name.name, name.name);
+ CHECK_VALUE(tctx, io.out.name.type, name.type);
+ CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
+
+ return true;
+}
+
+
+/*
+ test that a server responds correctly to attempted name refresh requests
+*/
+static bool nbt_refresh_own(struct torture_context *tctx)
+{
+ struct nbt_name_refresh io;
+ NTSTATUS status;
+ struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
+ const char *myaddress;
+ struct socket_address *socket_address;
+ struct nbt_name name;
+ const char *address;
+ struct interface *ifaces;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+
+ myaddress = iface_list_best_ip(ifaces, address);
+
+ socket_address = socket_address_from_strings(tctx, nbtsock->sock->backend_name,
+ myaddress, 0);
+ torture_assert(tctx, socket_address != NULL,
+ "Can't parse socket address");
+
+ status = socket_listen(nbtsock->sock, socket_address, 0, 0);
+ torture_assert_ntstatus_ok(tctx, status,
+ "socket_listen for nbt_referesh_own failed");
+
+ torture_comment(tctx, "Testing name defense to name refresh\n");
+
+ io.in.name = name;
+ io.in.dest_addr = address;
+ io.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ io.in.address = myaddress;
+ io.in.nb_flags = NBT_NODE_B | NBT_NM_ACTIVE;
+ io.in.broadcast = false;
+ io.in.ttl = 1234;
+ io.in.timeout = 3;
+ io.in.retries = 0;
+
+ status = nbt_name_refresh(nbtsock, tctx, &io);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name refresh", address));
+
+ CHECK_STRING(tctx, io.out.name.name, name.name);
+ CHECK_VALUE(tctx, io.out.name.type, name.type);
+ CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
+
+ return true;
+}
+
+
+/*
+ test name registration to a server
+*/
+struct torture_suite *torture_nbt_register(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(mem_ctx, "register");
+ torture_suite_add_simple_test(suite, "register_own", nbt_register_own);
+ torture_suite_add_simple_test(suite, "refresh_own", nbt_refresh_own);
+
+ return suite;
+}
diff --git a/source4/torture/nbt/wins.c b/source4/torture/nbt/wins.c
new file mode 100644
index 0000000..8c847b5
--- /dev/null
+++ b/source4/torture/nbt/wins.c
@@ -0,0 +1,545 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NBT WINS server testing
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/dlinklist.h"
+#include "lib/events/events.h"
+#include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "param/param.h"
+
+#define CHECK_VALUE(tctx, v, correct) \
+ torture_assert_int_equal(tctx, v, correct, "Incorrect value")
+
+#define CHECK_STRING(tctx, v, correct) \
+ torture_assert_casestr_equal(tctx, v, correct, "Incorrect value")
+
+#define CHECK_NAME(tctx, _name, correct) do { \
+ CHECK_STRING(tctx, (_name).name, (correct).name); \
+ CHECK_VALUE(tctx, (uint8_t)(_name).type, (uint8_t)(correct).type); \
+ CHECK_STRING(tctx, (_name).scope, (correct).scope); \
+} while (0)
+
+
+/*
+ test operations against a WINS server
+*/
+static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
+ struct nbt_name *name, uint16_t nb_flags,
+ bool try_low_port,
+ uint8_t register_rcode)
+{
+ struct nbt_name_register_wins io;
+ struct nbt_name_register name_register;
+ struct nbt_name_query query;
+ struct nbt_name_refresh_wins refresh;
+ struct nbt_name_release release;
+ struct nbt_name_request *req;
+ NTSTATUS status;
+ struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
+ const char *myaddress;
+ struct socket_address *socket_address;
+ struct interface *ifaces;
+ bool low_port = try_low_port;
+ char **l;
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+
+ myaddress = talloc_strdup(tctx, iface_list_best_ip(ifaces, address));
+
+ socket_address = socket_address_from_strings(tctx,
+ nbtsock->sock->backend_name,
+ myaddress, lpcfg_nbt_port(tctx->lp_ctx));
+ torture_assert(tctx, socket_address != NULL,
+ "Error getting address");
+
+ /* we do the listen here to ensure the WINS server receives the packets from
+ the right IP */
+ status = socket_listen(nbtsock->sock, socket_address, 0, 0);
+ talloc_free(socket_address);
+ if (!NT_STATUS_IS_OK(status)) {
+ low_port = false;
+ socket_address = socket_address_from_strings(tctx,
+ nbtsock->sock->backend_name,
+ myaddress, 0);
+ torture_assert(tctx, socket_address != NULL,
+ "Error getting address");
+
+ status = socket_listen(nbtsock->sock, socket_address, 0, 0);
+ talloc_free(socket_address);
+ torture_assert_ntstatus_ok(tctx, status,
+ "socket_listen for WINS failed");
+ }
+
+ torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n",
+ nbt_name_string(tctx, name), myaddress, nb_flags);
+
+ torture_comment(tctx, "release the name\n");
+ release.in.name = *name;
+ release.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ release.in.dest_addr = address;
+ release.in.address = myaddress;
+ release.in.nb_flags = nb_flags;
+ release.in.broadcast = false;
+ release.in.timeout = 3;
+ release.in.retries = 0;
+
+ status = nbt_name_release(nbtsock, tctx, &release);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+ CHECK_VALUE(tctx, release.out.rcode, 0);
+
+ if (nb_flags & NBT_NM_GROUP) {
+ /* ignore this for group names */
+ } else if (!low_port) {
+ torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
+ } else {
+ torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
+ io.in.name = *name;
+ io.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
+ io.in.wins_servers = const_str_list(
+ str_list_make_single(tctx, address));
+ io.in.addresses = const_str_list(
+ str_list_make_single(tctx, "127.64.64.1"));
+ io.in.nb_flags = nb_flags;
+ io.in.ttl = 300000;
+
+ status = nbt_name_register_wins(nbtsock, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "No response from %s for name register\n",
+ address));
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name register\n",
+ address));
+
+ CHECK_STRING(tctx, io.out.wins_server, address);
+ CHECK_VALUE(tctx, io.out.rcode, 0);
+
+ torture_comment(tctx, "register the name correct address\n");
+ name_register.in.name = *name;
+ name_register.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ name_register.in.dest_addr = address;
+ name_register.in.address = myaddress;
+ name_register.in.nb_flags = nb_flags;
+ name_register.in.register_demand= false;
+ name_register.in.broadcast = false;
+ name_register.in.multi_homed = true;
+ name_register.in.ttl = 300000;
+ name_register.in.timeout = 3;
+ name_register.in.retries = 2;
+
+ /*
+ * test if the server ignores resent requests
+ */
+ req = nbt_name_register_send(nbtsock, &name_register);
+ while (true) {
+ tevent_loop_once(nbtsock->event_ctx);
+ if (req->state != NBT_REQUEST_WAIT) {
+ break;
+ }
+ if (req->received_wack) {
+ /*
+ * if we received the wack response
+ * we resend the request and the
+ * server should ignore that
+ * and not handle it as new request
+ */
+ req->state = NBT_REQUEST_SEND;
+ DLIST_ADD_END(nbtsock->send_queue, req);
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+ break;
+ }
+ }
+
+ status = nbt_name_register_recv(req, tctx, &name_register);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "No response from %s for name register\n",
+ address));
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name register\n",
+ address));
+
+ CHECK_VALUE(tctx, name_register.out.rcode, 0);
+ CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
+ }
+
+ torture_comment(tctx, "register the name correct address\n");
+ io.in.name = *name;
+ io.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
+ l = str_list_make_single(tctx, address);
+ io.in.wins_servers = discard_const_p(const char *, l);
+ l = str_list_make_single(tctx, myaddress);
+ io.in.addresses = discard_const_p(const char *, l);
+ io.in.nb_flags = nb_flags;
+ io.in.ttl = 300000;
+
+ status = nbt_name_register_wins(nbtsock, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
+
+ CHECK_STRING(tctx, io.out.wins_server, address);
+ CHECK_VALUE(tctx, io.out.rcode, register_rcode);
+
+ if (register_rcode != NBT_RCODE_OK) {
+ return true;
+ }
+
+ if (name->type != NBT_NAME_MASTER &&
+ name->type != NBT_NAME_LOGON &&
+ name->type != NBT_NAME_BROWSER &&
+ (nb_flags & NBT_NM_GROUP)) {
+ torture_comment(tctx, "Try to register as non-group\n");
+ io.in.nb_flags &= ~NBT_NM_GROUP;
+ status = nbt_name_register_wins(nbtsock, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register\n",
+ address));
+ CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
+ }
+
+ torture_comment(tctx, "query the name to make sure its there\n");
+ query.in.name = *name;
+ query.in.dest_addr = address;
+ query.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ query.in.broadcast = false;
+ query.in.wins_lookup = true;
+ query.in.timeout = 3;
+ query.in.retries = 0;
+
+ status = nbt_name_query(nbtsock, tctx, &query);
+ if (name->type == NBT_NAME_MASTER) {
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ talloc_asprintf(tctx, "Bad response from %s for name query", address));
+ return true;
+ }
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+
+ CHECK_NAME(tctx, query.out.name, *name);
+ CHECK_VALUE(tctx, query.out.num_addrs, 1);
+ if (name->type != NBT_NAME_LOGON &&
+ (nb_flags & NBT_NM_GROUP)) {
+ CHECK_STRING(tctx, query.out.reply_addrs[0], "255.255.255.255");
+ } else {
+ CHECK_STRING(tctx, query.out.reply_addrs[0], myaddress);
+ }
+
+
+ query.in.name.name = strupper_talloc(tctx, name->name);
+ if (query.in.name.name &&
+ strcmp(query.in.name.name, name->name) != 0) {
+ torture_comment(tctx, "check case sensitivity\n");
+ status = nbt_name_query(nbtsock, tctx, &query);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+ }
+
+ query.in.name = *name;
+ if (name->scope) {
+ query.in.name.scope = strupper_talloc(tctx, name->scope);
+ }
+ if (query.in.name.scope &&
+ strcmp(query.in.name.scope, name->scope) != 0) {
+ torture_comment(tctx, "check case sensitivity on scope\n");
+ status = nbt_name_query(nbtsock, tctx, &query);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+ }
+
+ torture_comment(tctx, "refresh the name\n");
+ refresh.in.name = *name;
+ refresh.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
+ l = str_list_make_single(tctx, address);
+ refresh.in.wins_servers = discard_const_p(const char *, l);
+ l = str_list_make_single(tctx, myaddress);
+ refresh.in.addresses = discard_const_p(const char *, l);
+ refresh.in.nb_flags = nb_flags;
+ refresh.in.ttl = 12345;
+
+ status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "No response from %s for name refresh",
+ address));
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name refresh",
+ address));
+
+ CHECK_STRING(tctx, refresh.out.wins_server, address);
+ CHECK_VALUE(tctx, refresh.out.rcode, 0);
+
+ printf("release the name\n");
+ release.in.name = *name;
+ release.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ release.in.dest_addr = address;
+ release.in.address = myaddress;
+ release.in.nb_flags = nb_flags;
+ release.in.broadcast = false;
+ release.in.timeout = 3;
+ release.in.retries = 0;
+
+ status = nbt_name_release(nbtsock, tctx, &release);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "No response from %s for name release",
+ address));
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name release",
+ address));
+
+ CHECK_NAME(tctx, release.out.name, *name);
+ CHECK_VALUE(tctx, release.out.rcode, 0);
+
+ if (nb_flags & NBT_NM_GROUP) {
+ /* ignore this for group names */
+ } else if (!low_port) {
+ torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
+ } else {
+ torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
+ io.in.name = *name;
+ io.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
+ io.in.wins_servers = const_str_list(
+ str_list_make_single(tctx, address));
+ io.in.addresses = const_str_list(
+ str_list_make_single(tctx, "127.64.64.1"));
+ io.in.nb_flags = nb_flags;
+ io.in.ttl = 300000;
+
+ status = nbt_name_register_wins(nbtsock, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "No response from %s for name register\n",
+ address));
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name register\n",
+ address));
+
+ CHECK_STRING(tctx, io.out.wins_server, address);
+ CHECK_VALUE(tctx, io.out.rcode, 0);
+ }
+
+ torture_comment(tctx, "refresh the name with the correct address\n");
+ refresh.in.name = *name;
+ refresh.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
+ refresh.in.wins_servers = const_str_list(
+ str_list_make_single(tctx, address));
+ refresh.in.addresses = const_str_list(
+ str_list_make_single(tctx, myaddress));
+ refresh.in.nb_flags = nb_flags;
+ refresh.in.ttl = 12345;
+
+ status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "No response from %s for name refresh",
+ address));
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name refresh",
+ address));
+
+ CHECK_STRING(tctx, refresh.out.wins_server, address);
+ CHECK_VALUE(tctx, refresh.out.rcode, 0);
+
+ torture_comment(tctx, "release the name\n");
+ release.in.name = *name;
+ release.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ release.in.dest_addr = address;
+ release.in.address = myaddress;
+ release.in.nb_flags = nb_flags;
+ release.in.broadcast = false;
+ release.in.timeout = 3;
+ release.in.retries = 0;
+
+ status = nbt_name_release(nbtsock, tctx, &release);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
+
+ CHECK_NAME(tctx, release.out.name, *name);
+ CHECK_VALUE(tctx, release.out.rcode, 0);
+
+ torture_comment(tctx, "release again\n");
+ status = nbt_name_release(nbtsock, tctx, &release);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "Bad response from %s for name query",
+ address));
+
+ CHECK_NAME(tctx, release.out.name, *name);
+ CHECK_VALUE(tctx, release.out.rcode, 0);
+
+
+ torture_comment(tctx, "query the name to make sure its gone\n");
+ query.in.name = *name;
+ status = nbt_name_query(nbtsock, tctx, &query);
+ if (name->type != NBT_NAME_LOGON &&
+ (nb_flags & NBT_NM_GROUP)) {
+ torture_assert_ntstatus_ok(tctx, status,
+ "ERROR: Name query failed after group release");
+ } else {
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "Incorrect response to name query");
+ }
+
+ return true;
+}
+
+
+static char *test_nbt_wins_scope_string(TALLOC_CTX *mem_ctx, uint8_t count)
+{
+ char *res;
+ uint8_t i;
+
+ res = talloc_array(mem_ctx, char, count+1);
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (i=0; i < count; i++) {
+ switch (i) {
+ case 63:
+ case 63 + 1 + 63:
+ case 63 + 1 + 63 + 1 + 63:
+ res[i] = '.';
+ break;
+ default:
+ res[i] = '0' + (i%10);
+ break;
+ }
+ }
+
+ res[count] = '\0';
+
+ talloc_set_name_const(res, res);
+
+ return res;
+}
+
+/*
+ test operations against a WINS server
+*/
+static bool nbt_test_wins(struct torture_context *tctx)
+{
+ struct nbt_name name;
+ uint32_t r = (uint32_t)(random() % (100000));
+ const char *address;
+ bool ret = true;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ name.name = talloc_asprintf(tctx, "_TORTURE-%5u", r);
+
+ name.type = NBT_NAME_CLIENT;
+ name.scope = NULL;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, true, NBT_RCODE_OK);
+
+ name.type = NBT_NAME_MASTER;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
+
+ name.type = NBT_NAME_SERVER;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, true, NBT_RCODE_OK);
+
+ name.type = NBT_NAME_LOGON;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
+
+ name.type = NBT_NAME_BROWSER;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
+
+ name.type = NBT_NAME_PDC;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, true, NBT_RCODE_OK);
+
+ name.type = 0xBF;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, true, NBT_RCODE_OK);
+
+ name.type = 0xBE;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.scope = "example";
+ name.type = 0x72;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, true, NBT_RCODE_OK);
+
+ name.scope = "example";
+ name.type = 0x71;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
+
+ name.scope = "foo.example.com";
+ name.type = 0x72;
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.name = talloc_asprintf(tctx, "_T\01-%5u.foo", r);
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.name = "";
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.name = talloc_asprintf(tctx, ".");
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.name = talloc_asprintf(tctx, "%5u-\377\200\300FOO", r);
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.scope = test_nbt_wins_scope_string(tctx, 237);
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_OK);
+
+ name.scope = test_nbt_wins_scope_string(tctx, 238);
+ ret &= nbt_test_wins_name(tctx, address, &name,
+ NBT_NODE_H, false, NBT_RCODE_SVR);
+
+ return ret;
+}
+
+/*
+ test WINS operations
+*/
+struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "wins");
+
+ torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
+
+ return suite;
+}
diff --git a/source4/torture/nbt/winsbench.c b/source4/torture/nbt/winsbench.c
new file mode 100644
index 0000000..3722202
--- /dev/null
+++ b/source4/torture/nbt/winsbench.c
@@ -0,0 +1,300 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ WINS benchmark test
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "lib/socket/socket.h"
+#include "libcli/resolve/resolve.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "param/param.h"
+
+struct wins_state {
+ int num_names;
+ bool *registered;
+ int pass_count;
+ int fail_count;
+ const char *wins_server;
+ uint16_t wins_port;
+ const char *my_ip;
+ uint32_t ttl;
+};
+
+struct idx_state {
+ int idx;
+ struct wins_state *state;
+};
+
+static struct nbt_name generate_name(TALLOC_CTX *tctx, int idx)
+{
+ struct nbt_name name;
+ name.name = talloc_asprintf(tctx, "WINSBench%6u", idx);
+ name.type = 0x4;
+ name.scope = NULL;
+ return name;
+}
+
+static void register_handler(struct nbt_name_request *req)
+{
+ struct idx_state *istate = talloc_get_type(req->async.private_data, struct idx_state);
+ struct wins_state *state = istate->state;
+ struct nbt_name_register io;
+ NTSTATUS status;
+
+ status = nbt_name_register_recv(req, istate, &io);
+ if (!NT_STATUS_IS_OK(status) || io.out.rcode != NBT_RCODE_OK) {
+ state->fail_count++;
+ } else {
+ state->pass_count++;
+ state->registered[istate->idx] = true;
+ }
+ talloc_free(istate);
+}
+
+/*
+ generate a registration
+*/
+static void generate_register(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
+{
+ struct nbt_name_register io;
+ TALLOC_CTX *tmp_ctx = talloc_new(state);
+ struct nbt_name_request *req;
+ struct idx_state *istate;
+
+ istate = talloc(nbtsock, struct idx_state);
+ istate->idx = idx;
+ istate->state = state;
+
+ io.in.name = generate_name(tmp_ctx, idx);
+ io.in.dest_addr = state->wins_server;
+ io.in.dest_port = state->wins_port;
+ io.in.address = state->my_ip;
+ io.in.nb_flags = NBT_NODE_H;
+ io.in.register_demand = false;
+ io.in.broadcast = false;
+ io.in.multi_homed = false;
+ io.in.ttl = state->ttl;
+ io.in.timeout = 2;
+ io.in.retries = 1;
+
+ req = nbt_name_register_send(nbtsock, &io);
+
+ req->async.fn = register_handler;
+ req->async.private_data = istate;
+
+ talloc_free(tmp_ctx);
+}
+
+
+static void release_handler(struct nbt_name_request *req)
+{
+ struct idx_state *istate = talloc_get_type(req->async.private_data, struct idx_state);
+ struct wins_state *state = istate->state;
+ struct nbt_name_release io;
+ NTSTATUS status;
+
+ status = nbt_name_release_recv(req, istate, &io);
+ if (state->registered[istate->idx] &&
+ (!NT_STATUS_IS_OK(status) || io.out.rcode != NBT_RCODE_OK)) {
+ state->fail_count++;
+ } else {
+ state->pass_count++;
+ state->registered[istate->idx] = false;
+ }
+ talloc_free(istate);
+}
+
+/*
+ generate a name release
+*/
+static void generate_release(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
+{
+ struct nbt_name_release io;
+ TALLOC_CTX *tmp_ctx = talloc_new(state);
+ struct nbt_name_request *req;
+ struct idx_state *istate;
+
+ istate = talloc(nbtsock, struct idx_state);
+ istate->idx = idx;
+ istate->state = state;
+
+ io.in.name = generate_name(tmp_ctx, idx);
+ io.in.dest_port = state->wins_port;
+ io.in.dest_addr = state->wins_server;
+ io.in.address = state->my_ip;
+ io.in.nb_flags = NBT_NODE_H;
+ io.in.broadcast = false;
+ io.in.timeout = 2;
+ io.in.retries = 1;
+
+ req = nbt_name_release_send(nbtsock, &io);
+
+ req->async.fn = release_handler;
+ req->async.private_data = istate;
+
+ talloc_free(tmp_ctx);
+}
+
+
+static void query_handler(struct nbt_name_request *req)
+{
+ struct idx_state *istate = talloc_get_type(req->async.private_data, struct idx_state);
+ struct wins_state *state = istate->state;
+ struct nbt_name_query io;
+ NTSTATUS status;
+
+ status = nbt_name_query_recv(req, istate, &io);
+ if (!NT_STATUS_IS_OK(status) && state->registered[istate->idx]) {
+ state->fail_count++;
+ } else {
+ state->pass_count++;
+ }
+ talloc_free(istate);
+}
+
+/*
+ generate a name query
+*/
+static void generate_query(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
+{
+ struct nbt_name_query io;
+ TALLOC_CTX *tmp_ctx = talloc_new(state);
+ struct nbt_name_request *req;
+ struct idx_state *istate;
+
+ istate = talloc(nbtsock, struct idx_state);
+ istate->idx = idx;
+ istate->state = state;
+
+ io.in.name = generate_name(tmp_ctx, idx);
+ io.in.dest_addr = state->wins_server;
+ io.in.dest_port = state->wins_port;
+ io.in.broadcast = false;
+ io.in.wins_lookup = true;
+ io.in.timeout = 2;
+ io.in.retries = 1;
+
+ req = nbt_name_query_send(nbtsock, &io);
+
+ req->async.fn = query_handler;
+ req->async.private_data = istate;
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ generate one WINS request
+*/
+static void generate_request(struct nbt_name_socket *nbtsock, struct wins_state *state, int idx)
+{
+ if (random() % 5 == 0) {
+ generate_register(nbtsock, state, idx);
+ return;
+ }
+
+ if (random() % 20 == 0) {
+ generate_release(nbtsock, state, idx);
+ return;
+ }
+
+ generate_query(nbtsock, state, idx);
+}
+
+/*
+ benchmark simple name queries
+*/
+static bool bench_wins(struct torture_context *tctx)
+{
+ struct nbt_name_socket *nbtsock = nbt_name_socket_init(tctx, tctx->ev);
+ int num_sent=0;
+ struct timeval tv = timeval_current();
+ bool ret = true;
+ int timelimit = torture_setting_int(tctx, "timelimit", 5);
+ struct wins_state *state;
+ extern int torture_entries;
+ struct socket_address *my_ip;
+ struct nbt_name name;
+ const char *address;
+ struct interface *ifaces;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ state = talloc_zero(nbtsock, struct wins_state);
+
+ state->num_names = torture_entries;
+ state->registered = talloc_zero_array(state, bool, state->num_names);
+ state->wins_server = address;
+ state->wins_port = lpcfg_nbt_port(tctx->lp_ctx);
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+ state->my_ip = talloc_strdup(tctx, iface_list_best_ip(ifaces, address));
+ state->ttl = timelimit;
+
+ my_ip = socket_address_from_strings(nbtsock, nbtsock->sock->backend_name,
+ state->my_ip, 0);
+
+ socket_listen(nbtsock->sock, my_ip, 0, 0);
+
+ torture_comment(tctx, "Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ while (num_sent - (state->pass_count+state->fail_count) < 10) {
+ generate_request(nbtsock, state, num_sent % state->num_names);
+ num_sent++;
+ if (num_sent % 50 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%.1f queries per second (%d failures) \r",
+ state->pass_count / timeval_elapsed(&tv),
+ state->fail_count);
+ fflush(stdout);
+ }
+ }
+ }
+
+ tevent_loop_once(nbtsock->event_ctx);
+ }
+
+ while (num_sent != (state->pass_count + state->fail_count)) {
+ tevent_loop_once(nbtsock->event_ctx);
+ }
+
+ torture_comment(tctx, "%.1f queries per second (%d failures) \n",
+ state->pass_count / timeval_elapsed(&tv),
+ state->fail_count);
+
+ talloc_free(nbtsock);
+ return ret;
+}
+
+
+/*
+ benchmark how fast a WINS server can respond to a mixture of
+ registration/refresh/release and name query requests
+*/
+struct torture_suite *torture_bench_wins(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "bench-wins");
+
+ torture_suite_add_simple_test(suite, "wins", bench_wins);
+
+ return suite;
+}
diff --git a/source4/torture/nbt/winsreplication.c b/source4/torture/nbt/winsreplication.c
new file mode 100644
index 0000000..e1c9a4d
--- /dev/null
+++ b/source4/torture/nbt/winsreplication.c
@@ -0,0 +1,9884 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ WINS replication testing
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/wrepl/winsrepl.h"
+#include "lib/events/events.h"
+#include "lib/socket/socket.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "libcli/nbt/libnbt.h"
+#include "torture/torture.h"
+#include "torture/nbt/proto.h"
+#include "param/param.h"
+
+#define CHECK_STATUS(tctx, status, correct) \
+ torture_assert_ntstatus_equal(tctx, status, correct, \
+ "Incorrect status")
+
+#define CHECK_VALUE(tctx, v, correct) \
+ torture_assert(tctx, (v) == (correct), \
+ talloc_asprintf(tctx, "Incorrect value %s=%d - should be %d\n", \
+ #v, v, correct))
+
+#define CHECK_VALUE_UINT64(tctx, v, correct) \
+ torture_assert(tctx, (v) == (correct), \
+ talloc_asprintf(tctx, "Incorrect value %s=%llu - should be %llu\n", \
+ #v, (long long)v, (long long)correct))
+
+#define CHECK_VALUE_STRING(tctx, v, correct) \
+ torture_assert_str_equal(tctx, v, correct, "Invalid value")
+
+#define _NBT_NAME(n,t,s) {\
+ .name = n,\
+ .type = t,\
+ .scope = s\
+}
+
+static const char *wrepl_name_type_string(enum wrepl_name_type type)
+{
+ switch (type) {
+ case WREPL_TYPE_UNIQUE: return "UNIQUE";
+ case WREPL_TYPE_GROUP: return "GROUP";
+ case WREPL_TYPE_SGROUP: return "SGROUP";
+ case WREPL_TYPE_MHOMED: return "MHOMED";
+ }
+ return "UNKNOWN_TYPE";
+}
+
+static const char *wrepl_name_state_string(enum wrepl_name_state state)
+{
+ switch (state) {
+ case WREPL_STATE_ACTIVE: return "ACTIVE";
+ case WREPL_STATE_RELEASED: return "RELEASED";
+ case WREPL_STATE_TOMBSTONE: return "TOMBSTONE";
+ case WREPL_STATE_RESERVED: return "RESERVED";
+ }
+ return "UNKNOWN_STATE";
+}
+
+/*
+ test how assoc_ctx's are only usable on the connection
+ they are created on.
+*/
+static bool test_assoc_ctx1(struct torture_context *tctx)
+{
+ bool ret = true;
+ struct tevent_req *subreq;
+ struct wrepl_socket *wrepl_socket1;
+ struct wrepl_associate associate1;
+ struct wrepl_socket *wrepl_socket2;
+ struct wrepl_associate associate2;
+ struct wrepl_packet packet;
+ struct wrepl_send_ctrl ctrl;
+ struct wrepl_packet *rep_packet;
+ struct wrepl_associate_stop assoc_stop;
+ NTSTATUS status;
+ struct nbt_name name;
+ const char *address;
+ bool ok;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ torture_comment(tctx, "Test if assoc_ctx is only valid on the connection it was created on\n");
+
+ wrepl_socket1 = wrepl_socket_init(tctx, tctx->ev);
+ wrepl_socket2 = wrepl_socket_init(tctx, tctx->ev);
+
+ torture_comment(tctx, "Setup 2 wrepl connections\n");
+ status = wrepl_connect(wrepl_socket1, wrepl_best_ip(tctx->lp_ctx, address), address);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ status = wrepl_connect(wrepl_socket2, wrepl_best_ip(tctx->lp_ctx, address), address);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Send a start association request (conn1)\n");
+ status = wrepl_associate(wrepl_socket1, &associate1);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
+
+ torture_comment(tctx, "Send a start association request (conn2)\n");
+ status = wrepl_associate(wrepl_socket2, &associate2);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
+
+ torture_comment(tctx, "Send a replication table query, with assoc 1 (conn2), the answer should be on conn1\n");
+ ZERO_STRUCT(packet);
+ packet.opcode = WREPL_OPCODE_BITS;
+ packet.assoc_ctx = associate1.out.assoc_ctx;
+ packet.mess_type = WREPL_REPLICATION;
+ packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
+ ZERO_STRUCT(ctrl);
+ ctrl.send_only = true;
+ subreq = wrepl_request_send(tctx, tctx->ev, wrepl_socket2, &packet, &ctrl);
+ ok = tevent_req_poll(subreq, tctx->ev);
+ if (!ok) {
+ CHECK_STATUS(tctx, NT_STATUS_INTERNAL_ERROR, NT_STATUS_OK);
+ }
+ status = wrepl_request_recv(subreq, tctx, &rep_packet);
+ TALLOC_FREE(subreq);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Send a association request (conn2), to make sure the last request was ignored\n");
+ status = wrepl_associate(wrepl_socket2, &associate2);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
+ ZERO_STRUCT(packet);
+ packet.opcode = WREPL_OPCODE_BITS;
+ packet.assoc_ctx = 0;
+ packet.mess_type = WREPL_REPLICATION;
+ packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
+ status = wrepl_request(wrepl_socket1, tctx, &packet, &rep_packet);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Send a association request (conn1), to make sure the last request was handled correct\n");
+ status = wrepl_associate(wrepl_socket1, &associate2);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
+ assoc_stop.in.reason = 4;
+ torture_comment(tctx, "Send a association stop request (conn1), reason: %u\n", assoc_stop.in.reason);
+ status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
+ CHECK_STATUS(tctx, status, NT_STATUS_END_OF_FILE);
+
+ assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
+ assoc_stop.in.reason = 0;
+ torture_comment(tctx, "Send a association stop request (conn2), reason: %u\n", assoc_stop.in.reason);
+ status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Close 2 wrepl connections\n");
+ talloc_free(wrepl_socket1);
+ talloc_free(wrepl_socket2);
+ return ret;
+}
+
+/*
+ test if we always get back the same assoc_ctx
+*/
+static bool test_assoc_ctx2(struct torture_context *tctx)
+{
+ struct wrepl_socket *wrepl_socket;
+ struct wrepl_associate associate;
+ uint32_t assoc_ctx1;
+ struct nbt_name name;
+ NTSTATUS status;
+ const char *address;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ torture_comment(tctx, "Test if we always get back the same assoc_ctx\n");
+
+ wrepl_socket = wrepl_socket_init(tctx, tctx->ev);
+
+ torture_comment(tctx, "Setup wrepl connections\n");
+ status = wrepl_connect(wrepl_socket, wrepl_best_ip(tctx->lp_ctx, address), address);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Send 1st start association request\n");
+ status = wrepl_associate(wrepl_socket, &associate);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ assoc_ctx1 = associate.out.assoc_ctx;
+ torture_comment(tctx, "1st association context: 0x%x\n", associate.out.assoc_ctx);
+
+ torture_comment(tctx, "Send 2nd start association request\n");
+ status = wrepl_associate(wrepl_socket, &associate);
+ torture_assert_ntstatus_ok(tctx, status, "2nd start association failed");
+ torture_assert(tctx, associate.out.assoc_ctx == assoc_ctx1,
+ "Different context returned");
+ torture_comment(tctx, "2nd association context: 0x%x\n", associate.out.assoc_ctx);
+
+ torture_comment(tctx, "Send 3rd start association request\n");
+ status = wrepl_associate(wrepl_socket, &associate);
+ torture_assert(tctx, associate.out.assoc_ctx == assoc_ctx1,
+ "Different context returned");
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ torture_comment(tctx, "3rd association context: 0x%x\n", associate.out.assoc_ctx);
+
+ torture_comment(tctx, "Close wrepl connections\n");
+ talloc_free(wrepl_socket);
+ return true;
+}
+
+
+/*
+ display a replication entry
+*/
+static void display_entry(struct torture_context *tctx, struct wrepl_name *name)
+{
+ int i;
+
+ torture_comment(tctx, "%s\n", nbt_name_string(tctx, &name->name));
+ torture_comment(tctx, "\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
+ name->type, name->state, name->node, name->is_static, (long long)name->version_id);
+ torture_comment(tctx, "\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
+ name->raw_flags, name->owner);
+ for (i=0;i<name->num_addresses;i++) {
+ torture_comment(tctx, "\tADDR: %-15s OWNER: %-15s\n",
+ name->addresses[i].address, name->addresses[i].owner);
+ }
+}
+
+/*
+ test a full replication dump from a WINS server
+*/
+static bool test_wins_replication(struct torture_context *tctx)
+{
+ struct wrepl_socket *wrepl_socket;
+ NTSTATUS status;
+ int i, j;
+ struct wrepl_associate associate;
+ struct wrepl_pull_table pull_table;
+ struct wrepl_pull_names pull_names;
+ struct nbt_name name;
+ const char *address;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ torture_comment(tctx, "Test one pull replication cycle\n");
+
+ wrepl_socket = wrepl_socket_init(tctx, tctx->ev);
+
+ torture_comment(tctx, "Setup wrepl connections\n");
+ status = wrepl_connect(wrepl_socket, wrepl_best_ip(tctx->lp_ctx, address), address);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Send a start association request\n");
+
+ status = wrepl_associate(wrepl_socket, &associate);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "association context: 0x%x\n", associate.out.assoc_ctx);
+
+ torture_comment(tctx, "Send a replication table query\n");
+ pull_table.in.assoc_ctx = associate.out.assoc_ctx;
+
+ status = wrepl_pull_table(wrepl_socket, tctx, &pull_table);
+ if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
+ struct wrepl_associate_stop assoc_stop;
+
+ assoc_stop.in.assoc_ctx = associate.out.assoc_ctx;
+ assoc_stop.in.reason = 0;
+
+ wrepl_associate_stop(wrepl_socket, &assoc_stop);
+
+ torture_fail(tctx, "We are not a valid pull partner for the server");
+ }
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Found %d replication partners\n", pull_table.out.num_partners);
+
+ for (i=0;i<pull_table.out.num_partners;i++) {
+ struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
+ torture_comment(tctx, "%s max_version=%6llu min_version=%6llu type=%d\n",
+ partner->address,
+ (long long)partner->max_version,
+ (long long)partner->min_version,
+ partner->type);
+
+ pull_names.in.assoc_ctx = associate.out.assoc_ctx;
+ pull_names.in.partner = *partner;
+
+ status = wrepl_pull_names(wrepl_socket, tctx, &pull_names);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Received %d names\n", pull_names.out.num_names);
+
+ for (j=0;j<pull_names.out.num_names;j++) {
+ display_entry(tctx, &pull_names.out.names[j]);
+ }
+ }
+
+ torture_comment(tctx, "Close wrepl connections\n");
+ talloc_free(wrepl_socket);
+ return true;
+}
+
+struct test_wrepl_conflict_conn {
+ const char *address;
+ struct wrepl_socket *pull;
+ uint32_t pull_assoc;
+
+#define TEST_OWNER_A_ADDRESS "127.65.65.1"
+#define TEST_ADDRESS_A_PREFIX "127.0.65"
+#define TEST_OWNER_B_ADDRESS "127.66.66.1"
+#define TEST_ADDRESS_B_PREFIX "127.0.66"
+#define TEST_OWNER_X_ADDRESS "127.88.88.1"
+#define TEST_ADDRESS_X_PREFIX "127.0.88"
+
+ struct wrepl_wins_owner a, b, c, x;
+
+ struct socket_address *myaddr;
+ struct socket_address *myaddr2;
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_socket *nbtsock2;
+
+ struct nbt_name_socket *nbtsock_srv;
+ struct nbt_name_socket *nbtsock_srv2;
+
+ uint32_t addresses_best_num;
+ struct wrepl_ip *addresses_best;
+
+ uint32_t addresses_best2_num;
+ struct wrepl_ip *addresses_best2;
+
+ uint32_t addresses_all_num;
+ struct wrepl_ip *addresses_all;
+
+ uint32_t addresses_mhomed_num;
+ struct wrepl_ip *addresses_mhomed;
+};
+
+static const struct wrepl_ip addresses_A_1[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".1"
+ }
+};
+static const struct wrepl_ip addresses_A_2[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".2"
+ }
+};
+static const struct wrepl_ip addresses_A_3_4[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".4"
+ }
+};
+static const struct wrepl_ip addresses_A_3_4_X_3_4[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".4"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".4"
+ }
+};
+static const struct wrepl_ip addresses_A_3_4_B_3_4[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".4"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".4"
+ }
+};
+static const struct wrepl_ip addresses_A_3_4_OWNER_B[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".4"
+ }
+};
+static const struct wrepl_ip addresses_A_3_4_X_3_4_OWNER_B[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".4"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".4"
+ }
+};
+/*
+static const struct wrepl_ip addresses_A_3_4_X_1_2[] = {
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_A_ADDRESS,
+ .ip = TEST_ADDRESS_A_PREFIX".4"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".1"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".2"
+ }
+};
+*/
+static const struct wrepl_ip addresses_B_1[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".1"
+ }
+};
+/*
+static const struct wrepl_ip addresses_B_2[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".2"
+ }
+};
+*/
+static const struct wrepl_ip addresses_B_3_4[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".4"
+ }
+};
+static const struct wrepl_ip addresses_B_3_4_X_3_4[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".4"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".4"
+ }
+};
+static const struct wrepl_ip addresses_B_3_4_X_1_2[] = {
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_B_ADDRESS,
+ .ip = TEST_ADDRESS_B_PREFIX".4"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".1"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".2"
+ }
+};
+
+/*
+static const struct wrepl_ip addresses_X_1_2[] = {
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".1"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".2"
+ }
+};
+*/
+
+static const struct wrepl_ip addresses_X_3_4[] = {
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".3"
+ },
+ {
+ .owner = TEST_OWNER_X_ADDRESS,
+ .ip = TEST_ADDRESS_X_PREFIX".4"
+ }
+};
+
+static struct test_wrepl_conflict_conn *test_create_conflict_ctx(
+ struct torture_context *tctx, const char *address)
+{
+ struct test_wrepl_conflict_conn *ctx;
+ struct wrepl_associate associate;
+ struct wrepl_pull_table pull_table;
+ struct socket_address *nbt_srv_addr;
+ NTSTATUS status;
+ uint32_t i;
+ uint32_t num_ifaces;
+ struct interface *ifaces;
+
+ ctx = talloc_zero(tctx, struct test_wrepl_conflict_conn);
+ if (!ctx) return NULL;
+
+ ctx->address = address;
+ ctx->pull = wrepl_socket_init(ctx, tctx->ev);
+ if (!ctx->pull) return NULL;
+
+ torture_comment(tctx, "Setup wrepl conflict pull connection\n");
+ status = wrepl_connect(ctx->pull, wrepl_best_ip(tctx->lp_ctx, ctx->address), ctx->address);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ status = wrepl_associate(ctx->pull, &associate);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ ctx->pull_assoc = associate.out.assoc_ctx;
+
+ ctx->a.address = TEST_OWNER_A_ADDRESS;
+ ctx->a.max_version = 0;
+ ctx->a.min_version = 0;
+ ctx->a.type = 1;
+
+ ctx->b.address = TEST_OWNER_B_ADDRESS;
+ ctx->b.max_version = 0;
+ ctx->b.min_version = 0;
+ ctx->b.type = 1;
+
+ ctx->x.address = TEST_OWNER_X_ADDRESS;
+ ctx->x.max_version = 0;
+ ctx->x.min_version = 0;
+ ctx->x.type = 1;
+
+ ctx->c.address = address;
+ ctx->c.max_version = 0;
+ ctx->c.min_version = 0;
+ ctx->c.type = 1;
+
+ pull_table.in.assoc_ctx = ctx->pull_assoc;
+ status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ for (i=0; i < pull_table.out.num_partners; i++) {
+ if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
+ ctx->a.max_version = pull_table.out.partners[i].max_version;
+ ctx->a.min_version = pull_table.out.partners[i].min_version;
+ }
+ if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
+ ctx->b.max_version = pull_table.out.partners[i].max_version;
+ ctx->b.min_version = pull_table.out.partners[i].min_version;
+ }
+ if (strcmp(TEST_OWNER_X_ADDRESS,pull_table.out.partners[i].address)==0) {
+ ctx->x.max_version = pull_table.out.partners[i].max_version;
+ ctx->x.min_version = pull_table.out.partners[i].min_version;
+ }
+ if (strcmp(address,pull_table.out.partners[i].address)==0) {
+ ctx->c.max_version = pull_table.out.partners[i].max_version;
+ ctx->c.min_version = pull_table.out.partners[i].min_version;
+ }
+ }
+
+ talloc_free(pull_table.out.partners);
+
+ ctx->nbtsock = nbt_name_socket_init(ctx, tctx->ev);
+ if (!ctx->nbtsock) return NULL;
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+
+ ctx->myaddr = socket_address_from_strings(tctx, ctx->nbtsock->sock->backend_name, iface_list_best_ip(ifaces, address), 0);
+ if (!ctx->myaddr) return NULL;
+
+ for (i = 0; i < iface_list_count(ifaces); i++) {
+ if (!iface_list_n_is_v4(ifaces, i)) continue;
+ if (strcmp(ctx->myaddr->addr, iface_list_n_ip(ifaces, i)) == 0) continue;
+ ctx->myaddr2 = socket_address_from_strings(tctx, ctx->nbtsock->sock->backend_name, iface_list_n_ip(ifaces, i), 0);
+ if (!ctx->myaddr2) return NULL;
+ break;
+ }
+
+ status = socket_listen(ctx->nbtsock->sock, ctx->myaddr, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ ctx->nbtsock_srv = nbt_name_socket_init(ctx, tctx->ev);
+ if (!ctx->nbtsock_srv) return NULL;
+
+ /* Make a port 137 version of ctx->myaddr */
+ nbt_srv_addr = socket_address_from_strings(tctx, ctx->nbtsock_srv->sock->backend_name, ctx->myaddr->addr, lpcfg_nbt_port(tctx->lp_ctx));
+ if (!nbt_srv_addr) return NULL;
+
+ /* And if possible, bind to it. This won't work unless we are root or in socketwrapper */
+ status = socket_listen(ctx->nbtsock_srv->sock, nbt_srv_addr, 0, 0);
+ talloc_free(nbt_srv_addr);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* this isn't fatal */
+ talloc_free(ctx->nbtsock_srv);
+ ctx->nbtsock_srv = NULL;
+ }
+
+ if (ctx->myaddr2 && ctx->nbtsock_srv) {
+ ctx->nbtsock2 = nbt_name_socket_init(ctx, tctx->ev);
+ if (!ctx->nbtsock2) return NULL;
+
+ status = socket_listen(ctx->nbtsock2->sock, ctx->myaddr2, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) return NULL;
+
+ ctx->nbtsock_srv2 = nbt_name_socket_init(ctx, ctx->nbtsock_srv->event_ctx);
+ if (!ctx->nbtsock_srv2) return NULL;
+
+ /* Make a port 137 version of ctx->myaddr2 */
+ nbt_srv_addr = socket_address_from_strings(tctx,
+ ctx->nbtsock_srv->sock->backend_name,
+ ctx->myaddr2->addr,
+ lpcfg_nbt_port(tctx->lp_ctx));
+ if (!nbt_srv_addr) return NULL;
+
+ /* And if possible, bind to it. This won't work unless we are root or in socketwrapper */
+ status = socket_listen(ctx->nbtsock_srv2->sock, ctx->myaddr2, 0, 0);
+ talloc_free(nbt_srv_addr);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* this isn't fatal */
+ talloc_free(ctx->nbtsock_srv2);
+ ctx->nbtsock_srv2 = NULL;
+ }
+ }
+
+ ctx->addresses_best_num = 1;
+ ctx->addresses_best = talloc_array(ctx, struct wrepl_ip, ctx->addresses_best_num);
+ if (!ctx->addresses_best) return NULL;
+ ctx->addresses_best[0].owner = ctx->b.address;
+ ctx->addresses_best[0].ip = ctx->myaddr->addr;
+
+
+ num_ifaces = iface_list_count(ifaces);
+ ctx->addresses_all = talloc_array(ctx, struct wrepl_ip, num_ifaces);
+ ctx->addresses_all_num = 0;
+ if (!ctx->addresses_all) return NULL;
+ for (i=0; i < num_ifaces; i++) {
+ if (!iface_list_n_is_v4(ifaces, i)) continue;
+ ctx->addresses_all[i].owner = ctx->b.address;
+ ctx->addresses_all[i].ip = talloc_strdup(ctx->addresses_all, iface_list_n_ip(ifaces, i));
+ ctx->addresses_all_num++;
+ if (!ctx->addresses_all[i].ip) return NULL;
+ }
+
+ if (ctx->nbtsock_srv2) {
+ ctx->addresses_best2_num = 1;
+ ctx->addresses_best2 = talloc_array(ctx, struct wrepl_ip, ctx->addresses_best2_num);
+ if (!ctx->addresses_best2) return NULL;
+ ctx->addresses_best2[0].owner = ctx->b.address;
+ ctx->addresses_best2[0].ip = ctx->myaddr2->addr;
+
+ ctx->addresses_mhomed_num = 2;
+ ctx->addresses_mhomed = talloc_array(ctx, struct wrepl_ip, ctx->addresses_mhomed_num);
+ if (!ctx->addresses_mhomed) return NULL;
+ ctx->addresses_mhomed[0].owner = ctx->b.address;
+ ctx->addresses_mhomed[0].ip = ctx->myaddr->addr;
+ ctx->addresses_mhomed[1].owner = ctx->b.address;
+ ctx->addresses_mhomed[1].ip = ctx->myaddr2->addr;
+ }
+
+ return ctx;
+}
+
+static bool test_wrepl_update_one(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx,
+ const struct wrepl_wins_owner *owner,
+ const struct wrepl_wins_name *name)
+{
+ struct wrepl_socket *wrepl_socket;
+ struct wrepl_associate associate;
+ struct wrepl_packet update_packet, repl_send;
+ struct wrepl_table *update;
+ struct wrepl_wins_owner wrepl_wins_owners[1];
+ struct wrepl_packet *repl_recv;
+ struct wrepl_send_reply *send_reply;
+ struct wrepl_wins_name wrepl_wins_names[1];
+ uint32_t assoc_ctx;
+ NTSTATUS status;
+
+ wrepl_socket = wrepl_socket_init(ctx, tctx->ev);
+
+ status = wrepl_connect(wrepl_socket, wrepl_best_ip(tctx->lp_ctx, ctx->address), ctx->address);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ status = wrepl_associate(wrepl_socket, &associate);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ assoc_ctx = associate.out.assoc_ctx;
+
+ /* now send a WREPL_REPL_UPDATE message */
+ ZERO_STRUCT(update_packet);
+ update_packet.opcode = WREPL_OPCODE_BITS;
+ update_packet.assoc_ctx = assoc_ctx;
+ update_packet.mess_type = WREPL_REPLICATION;
+ update_packet.message.replication.command = WREPL_REPL_UPDATE;
+ update = &update_packet.message.replication.info.table;
+
+ update->partner_count = ARRAY_SIZE(wrepl_wins_owners);
+ update->partners = wrepl_wins_owners;
+ update->initiator = "0.0.0.0";
+
+ wrepl_wins_owners[0] = *owner;
+
+ status = wrepl_request(wrepl_socket, wrepl_socket,
+ &update_packet, &repl_recv);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VALUE(tctx, repl_recv->mess_type, WREPL_REPLICATION);
+ CHECK_VALUE(tctx, repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
+
+ ZERO_STRUCT(repl_send);
+ repl_send.opcode = WREPL_OPCODE_BITS;
+ repl_send.assoc_ctx = assoc_ctx;
+ repl_send.mess_type = WREPL_REPLICATION;
+ repl_send.message.replication.command = WREPL_REPL_SEND_REPLY;
+ send_reply = &repl_send.message.replication.info.reply;
+
+ send_reply->num_names = ARRAY_SIZE(wrepl_wins_names);
+ send_reply->names = wrepl_wins_names;
+
+ wrepl_wins_names[0] = *name;
+
+ status = wrepl_request(wrepl_socket, wrepl_socket,
+ &repl_send, &repl_recv);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VALUE(tctx, repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
+ CHECK_VALUE(tctx, repl_recv->message.stop.reason, 0);
+
+ talloc_free(wrepl_socket);
+ return true;
+}
+
+static bool test_wrepl_is_applied(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx,
+ const struct wrepl_wins_owner *owner,
+ const struct wrepl_wins_name *name,
+ bool expected)
+{
+ NTSTATUS status;
+ struct wrepl_pull_names pull_names;
+ struct wrepl_name *names;
+
+ pull_names.in.assoc_ctx = ctx->pull_assoc;
+ pull_names.in.partner = *owner;
+ pull_names.in.partner.min_version = pull_names.in.partner.max_version;
+
+ status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ torture_assert(tctx, pull_names.out.num_names == (expected?1:0),
+ talloc_asprintf(tctx, "Invalid number of records returned - expected %d got %d", expected, pull_names.out.num_names));
+
+ names = pull_names.out.names;
+
+ if (expected) {
+ uint32_t flags = WREPL_NAME_FLAGS(names[0].type,
+ names[0].state,
+ names[0].node,
+ names[0].is_static);
+ char *expected_scope = NULL;
+ CHECK_VALUE(tctx, names[0].name.type, name->name->type);
+ CHECK_VALUE_STRING(tctx, names[0].name.name, name->name->name);
+
+ if (names[0].name.scope) {
+ expected_scope = talloc_strndup(tctx,
+ name->name->scope,
+ 237);
+ }
+ CHECK_VALUE_STRING(tctx, names[0].name.scope, expected_scope);
+ CHECK_VALUE(tctx, flags, name->flags);
+ CHECK_VALUE_UINT64(tctx, names[0].version_id, name->id);
+
+ if (flags & 2) {
+ CHECK_VALUE(tctx, names[0].num_addresses,
+ name->addresses.addresses.num_ips);
+ } else {
+ CHECK_VALUE(tctx, names[0].num_addresses, 1);
+ CHECK_VALUE_STRING(tctx, names[0].addresses[0].address,
+ name->addresses.ip);
+ }
+ }
+ talloc_free(pull_names.out.names);
+ return true;
+}
+
+static bool test_wrepl_mhomed_merged(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx,
+ const struct wrepl_wins_owner *owner1,
+ uint32_t num_ips1, const struct wrepl_ip *ips1,
+ const struct wrepl_wins_owner *owner2,
+ uint32_t num_ips2, const struct wrepl_ip *ips2,
+ const struct wrepl_wins_name *name2)
+{
+ NTSTATUS status;
+ struct wrepl_pull_names pull_names;
+ struct wrepl_name *names;
+ uint32_t flags;
+ uint32_t i, j;
+ uint32_t num_ips = num_ips1 + num_ips2;
+
+ for (i = 0; i < num_ips2; i++) {
+ for (j = 0; j < num_ips1; j++) {
+ if (strcmp(ips2[i].ip,ips1[j].ip) == 0) {
+ num_ips--;
+ break;
+ }
+ }
+ }
+
+ pull_names.in.assoc_ctx = ctx->pull_assoc;
+ pull_names.in.partner = *owner2;
+ pull_names.in.partner.min_version = pull_names.in.partner.max_version;
+
+ status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VALUE(tctx, pull_names.out.num_names, 1);
+
+ names = pull_names.out.names;
+
+ flags = WREPL_NAME_FLAGS(names[0].type,
+ names[0].state,
+ names[0].node,
+ names[0].is_static);
+ CHECK_VALUE(tctx, names[0].name.type, name2->name->type);
+ CHECK_VALUE_STRING(tctx, names[0].name.name, name2->name->name);
+ CHECK_VALUE_STRING(tctx, names[0].name.scope, name2->name->scope);
+ CHECK_VALUE(tctx, flags, name2->flags | WREPL_TYPE_MHOMED);
+ CHECK_VALUE_UINT64(tctx, names[0].version_id, name2->id);
+
+ CHECK_VALUE(tctx, names[0].num_addresses, num_ips);
+
+ for (i = 0; i < names[0].num_addresses; i++) {
+ const char *addr = names[0].addresses[i].address;
+ const char *owner = names[0].addresses[i].owner;
+ bool found = false;
+
+ for (j = 0; j < num_ips2; j++) {
+ if (strcmp(addr, ips2[j].ip) == 0) {
+ found = true;
+ CHECK_VALUE_STRING(tctx, owner, owner2->address);
+ break;
+ }
+ }
+
+ if (found) continue;
+
+ for (j = 0; j < num_ips1; j++) {
+ if (strcmp(addr, ips1[j].ip) == 0) {
+ found = true;
+ CHECK_VALUE_STRING(tctx, owner, owner1->address);
+ break;
+ }
+ }
+
+ if (found) continue;
+
+ CHECK_VALUE_STRING(tctx, addr, "not found in address list");
+ }
+ talloc_free(pull_names.out.names);
+ return true;
+}
+
+static bool test_wrepl_sgroup_merged(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx,
+ struct wrepl_wins_owner *merge_owner,
+ struct wrepl_wins_owner *owner1,
+ uint32_t num_ips1, const struct wrepl_ip *ips1,
+ struct wrepl_wins_owner *owner2,
+ uint32_t num_ips2, const struct wrepl_ip *ips2,
+ const struct wrepl_wins_name *name2)
+{
+ NTSTATUS status;
+ struct wrepl_pull_names pull_names;
+ struct wrepl_name *names;
+ struct wrepl_name *name = NULL;
+ uint32_t flags;
+ uint32_t i, j;
+ uint32_t num_ips = num_ips1 + num_ips2;
+
+ if (!merge_owner) {
+ merge_owner = &ctx->c;
+ }
+
+ for (i = 0; i < num_ips1; i++) {
+ if (owner1 != &ctx->c && strcmp(ips1[i].owner,owner2->address) == 0) {
+ num_ips--;
+ continue;
+ }
+ for (j = 0; j < num_ips2; j++) {
+ if (strcmp(ips1[i].ip,ips2[j].ip) == 0) {
+ num_ips--;
+ break;
+ }
+ }
+ }
+
+
+ pull_names.in.assoc_ctx = ctx->pull_assoc;
+ pull_names.in.partner = *merge_owner;
+ pull_names.in.partner.min_version = pull_names.in.partner.max_version;
+ pull_names.in.partner.max_version = 0;
+
+ status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ names = pull_names.out.names;
+
+ for (i = 0; i < pull_names.out.num_names; i++) {
+ if (names[i].name.type != name2->name->type) continue;
+ if (!names[i].name.name) continue;
+ if (strcmp(names[i].name.name, name2->name->name) != 0) continue;
+ if (names[i].name.scope) continue;
+
+ name = &names[i];
+ }
+
+ if (pull_names.out.num_names > 0) {
+ merge_owner->max_version = names[pull_names.out.num_names-1].version_id;
+ }
+
+ if (!name) {
+ torture_comment(tctx, "%s: Name '%s' not found\n", __location__, nbt_name_string(ctx, name2->name));
+ return false;
+ }
+
+ flags = WREPL_NAME_FLAGS(name->type,
+ name->state,
+ name->node,
+ name->is_static);
+ CHECK_VALUE(tctx, name->name.type, name2->name->type);
+ CHECK_VALUE_STRING(tctx, name->name.name, name2->name->name);
+ CHECK_VALUE_STRING(tctx, name->name.scope, name2->name->scope);
+ CHECK_VALUE(tctx, flags, name2->flags);
+
+ CHECK_VALUE(tctx, name->num_addresses, num_ips);
+
+ for (i = 0; i < name->num_addresses; i++) {
+ const char *addr = name->addresses[i].address;
+ const char *owner = name->addresses[i].owner;
+ bool found = false;
+
+ for (j = 0; j < num_ips2; j++) {
+ if (strcmp(addr, ips2[j].ip) == 0) {
+ found = true;
+ CHECK_VALUE_STRING(tctx, owner, ips2[j].owner);
+ break;
+ }
+ }
+
+ if (found) continue;
+
+ for (j = 0; j < num_ips1; j++) {
+ if (strcmp(addr, ips1[j].ip) == 0) {
+ found = true;
+ if (owner1 == &ctx->c) {
+ CHECK_VALUE_STRING(tctx, owner, owner1->address);
+ } else {
+ CHECK_VALUE_STRING(tctx, owner, ips1[j].owner);
+ }
+ break;
+ }
+ }
+
+ if (found) continue;
+
+ CHECK_VALUE_STRING(tctx, addr, "not found in address list");
+ }
+ talloc_free(pull_names.out.names);
+ return true;
+}
+
+static char *test_nbt_winsrepl_scope_string(TALLOC_CTX *mem_ctx, uint8_t count)
+{
+ char *res;
+ uint8_t i;
+
+ res = talloc_array(mem_ctx, char, count+1);
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (i=0; i < count; i++) {
+ res[i] = '0' + (i%10);
+ }
+
+ res[count] = '\0';
+
+ talloc_set_name_const(res, res);
+
+ return res;
+}
+
+static bool test_conflict_same_owner(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx)
+{
+ bool ret = true;
+ struct wrepl_wins_name wins_name1;
+ struct wrepl_wins_name wins_name2;
+ struct wrepl_wins_name *wins_name_tmp;
+ struct wrepl_wins_name *wins_name_last;
+ struct wrepl_wins_name *wins_name_cur;
+ uint32_t i,j;
+ struct nbt_name names[] = {
+ _NBT_NAME("_SAME_OWNER_A", 0x00, NULL),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 1)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 2)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 3)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 4)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 5)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 6)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 7)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 8)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 9)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 237)),
+ _NBT_NAME("_SAME_OWNER_A", 0x00,
+ test_nbt_winsrepl_scope_string(tctx, 238)),
+ _NBT_NAME("_SAME_OWNER_A", 0x1C, NULL),
+ };
+ struct {
+ enum wrepl_name_type type;
+ enum wrepl_name_state state;
+ enum wrepl_name_node node;
+ bool is_static;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ } records[] = {
+ {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_2),
+ .ips = addresses_A_2,
+ },{
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = true,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_2),
+ .ips = addresses_A_2,
+ },{
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_2),
+ .ips = addresses_A_2,
+ },{
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_2),
+ .ips = addresses_A_2,
+ },{
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ },{
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ },{
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ },{
+ /* the last one should always be a unique,tombstone record! */
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ }
+ };
+
+ wins_name_tmp = NULL;
+ wins_name_last = &wins_name2;
+ wins_name_cur = &wins_name1;
+
+ for (j=0; ret && j < ARRAY_SIZE(names); j++) {
+ torture_comment(tctx, "Test Replica Conflicts with same owner[%s] for %s\n",
+ nbt_name_string(ctx, &names[j]), ctx->a.address);
+
+ for(i=0; ret && i < ARRAY_SIZE(records); i++) {
+ wins_name_tmp = wins_name_last;
+ wins_name_last = wins_name_cur;
+ wins_name_cur = wins_name_tmp;
+
+ if (i > 0) {
+ torture_comment(tctx, "%s,%s%s vs. %s,%s%s with %s ip(s) => %s\n",
+ wrepl_name_type_string(records[i-1].type),
+ wrepl_name_state_string(records[i-1].state),
+ (records[i-1].is_static?",static":""),
+ wrepl_name_type_string(records[i].type),
+ wrepl_name_state_string(records[i].state),
+ (records[i].is_static?",static":""),
+ (records[i-1].ips==records[i].ips?"same":"different"),
+ "REPLACE");
+ }
+
+ wins_name_cur->name = &names[j];
+ wins_name_cur->flags = WREPL_NAME_FLAGS(records[i].type,
+ records[i].state,
+ records[i].node,
+ records[i].is_static);
+ wins_name_cur->id = ++ctx->a.max_version;
+ if (wins_name_cur->flags & 2) {
+ wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
+ wins_name_cur->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ records[i].ips);
+ } else {
+ wins_name_cur->addresses.ip = records[i].ips[0].ip;
+ }
+ wins_name_cur->unknown = "255.255.255.255";
+
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->a,wins_name_cur);
+ if (records[i].state == WREPL_STATE_RELEASED) {
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->a, wins_name_last, false);
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->a, wins_name_cur, false);
+ } else {
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->a, wins_name_cur, true);
+ }
+
+ /* the first one is a cleanup run */
+ if (!ret && i == 0) ret = true;
+
+ if (!ret) {
+ torture_comment(tctx, "conflict handled wrong or record[%u]: %s\n", i, __location__);
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+static bool test_conflict_different_owner(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx)
+{
+ bool ret = true;
+ struct wrepl_wins_name wins_name1;
+ struct wrepl_wins_name wins_name2;
+ struct wrepl_wins_name *wins_name_r1;
+ struct wrepl_wins_name *wins_name_r2;
+ uint32_t i;
+ struct {
+ const char *line; /* just better debugging */
+ struct nbt_name name;
+ const char *comment;
+ bool extra; /* not the worst case, this is an extra test */
+ bool cleanup;
+ struct {
+ struct wrepl_wins_owner *owner;
+ enum wrepl_name_type type;
+ enum wrepl_name_state state;
+ enum wrepl_name_node node;
+ bool is_static;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ bool apply_expected;
+ bool sgroup_merge;
+ struct wrepl_wins_owner *merge_owner;
+ bool sgroup_cleanup;
+ } r1, r2;
+ } records[] = {
+ /*
+ * NOTE: the first record and the last applied one
+ * needs to be from the same owner,
+ * to not conflict in the next smbtorture run!!!
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true /* ignored */
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true /* ignored */
+ }
+ },
+
+/*
+ * unique vs unique section
+ */
+ /*
+ * unique,active vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,active vs. unique,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * unique,released vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,released vs. unique,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. unique,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+
+/*
+ * unique vs normal groups section,
+ */
+ /*
+ * unique,active vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,active vs. group,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * unique,released vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,released vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * unique vs special groups section,
+ */
+ /*
+ * unique,active vs. sgroup,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * unique,active vs. sgroup,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * unique,released vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,released vs. sgroup,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. sgroup,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * unique vs multi homed section,
+ */
+ /*
+ * unique,active vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,active vs. mhomed,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * unique,released vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,released vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * unique,tombstone vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * normal groups vs unique section,
+ */
+ /*
+ * group,active vs. unique,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,active vs. unique,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,released vs. unique,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,released vs. unique,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,tombstone vs. unique,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,tombstone vs. unique,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+/*
+ * normal groups vs normal groups section,
+ */
+ /*
+ * group,active vs. group,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,active vs. group,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,released vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * group,released vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * group,tombstone vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * group,tombstone vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * normal groups vs special groups section,
+ */
+ /*
+ * group,active vs. sgroup,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,active vs. sgroup,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,released vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * group,released vs. sgroup,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,tombstone vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * group,tombstone vs. sgroup,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * normal groups vs multi homed section,
+ */
+ /*
+ * group,active vs. mhomed,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,active vs. mhomed,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,released vs. mhomed,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,released vs. mhomed,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * group,tombstone vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * group,tombstone vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * special groups vs unique section,
+ */
+ /*
+ * sgroup,active vs. unique,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * sgroup,active vs. unique,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * sgroup,released vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,released vs. unique,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. unique,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * special groups vs normal group section,
+ */
+ /*
+ * sgroup,active vs. group,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * sgroup,active vs. group,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * sgroup,released vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,released vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. group,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. group,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * special groups (not active) vs special group section,
+ */
+ /*
+ * sgroup,released vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,released vs. sgroup,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. sgroup,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. sgroup,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * special groups vs multi homed section,
+ */
+ /*
+ * sgroup,active vs. mhomed,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * sgroup,active vs. mhomed,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * sgroup,released vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,released vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * sgroup,tombstone vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * multi homed vs. unique section,
+ */
+ /*
+ * mhomed,active vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,active vs. unique,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * mhomed,released vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,released vs. uinique,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. unique,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. uinique,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * multi homed vs. normal group section,
+ */
+ /*
+ * mhomed,active vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,active vs. group,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * mhomed,released vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,released vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. group,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. group,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * multi homed vs. special group section,
+ */
+ /*
+ * mhomed,active vs. sgroup,active
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * mhomed,active vs. sgroup,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * mhomed,released vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,released vs. sgroup,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. sgroup,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. sgroup,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ },
+
+/*
+ * multi homed vs. mlti homed section,
+ */
+ /*
+ * mhomed,active vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,active vs. mhomed,tombstone
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ }
+ },
+
+ /*
+ * mhomed,released vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,released vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_RELEASED,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = false
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. mhomed,active
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ }
+ },
+
+ /*
+ * mhomed,tombstone vs. mhomed,tombstone
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true,
+ }
+ },
+/*
+ * special group vs special group section,
+ */
+ /*
+ * sgroup,active vs. sgroup,active same addresses
+ * => should be NOT replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4 vs. B:A_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = false,
+ .sgroup_cleanup = true
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active same addresses
+ * => should be NOT replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4 vs. B:NULL",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ .sgroup_cleanup = true
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active subset addresses, special case...
+ * => should NOT be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4_X_3_4 vs. B:A_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_X_3_4),
+ .ips = addresses_A_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = false,
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ },
+ .r2 = {
+ .owner = &ctx->x,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, but owner changed
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4 vs. B:A_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true,
+ .sgroup_cleanup = true
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, but owner changed
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4 vs. B:A_3_4_OWNER_B",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_OWNER_B),
+ .ips = addresses_A_3_4_OWNER_B,
+ .apply_expected = true,
+ .sgroup_cleanup = true
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, but owner changed
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4_OWNER_B vs. B:A_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_OWNER_B),
+ .ips = addresses_A_3_4_OWNER_B,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true,
+ .sgroup_cleanup = true
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .sgroup_merge = true,
+ .sgroup_cleanup = true,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, special case...
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .sgroup_merge = true,
+ .merge_owner = &ctx->b,
+ .sgroup_cleanup = false
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_X_3_4_OWNER_B),
+ .ips = addresses_A_3_4_X_3_4_OWNER_B,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, special case...
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_X_3_4),
+ .ips = addresses_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .sgroup_merge = true,
+ .sgroup_cleanup = false
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ },
+ .r2 = {
+ .owner = &ctx->x,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, special case...
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4_X_3_4 vs. B:A_3_4_OWNER_B => B:A_3_4_OWNER_B_X_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_X_3_4),
+ .ips = addresses_A_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_OWNER_B),
+ .ips = addresses_A_3_4_OWNER_B,
+ .sgroup_merge = true,
+ .merge_owner = &ctx->b,
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ },
+ .r2 = {
+ .owner = &ctx->x,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active partly different addresses, special case...
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:B_3_4_X_1_2 => C:B_3_4_X_1_2_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_1_2),
+ .ips = addresses_B_3_4_X_1_2,
+ .sgroup_merge = true,
+ .sgroup_cleanup = false
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ },
+ .r2 = {
+ .owner = &ctx->x,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, special case...
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:A_3_4_B_3_4 vs. B:NULL => B:A_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4_B_3_4),
+ .ips = addresses_A_3_4_B_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .sgroup_merge = true,
+ .merge_owner = &ctx->b,
+ .sgroup_cleanup = true
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active different addresses, special case...
+ * => should be merged
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .sgroup_merge = true,
+ .merge_owner = &ctx->b,
+ .sgroup_cleanup = true
+ }
+ },
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->x,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = false,
+ },
+ .r2 = {
+ .owner = &ctx->x,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true,
+ }
+ },
+
+ /*
+ * sgroup,active vs. sgroup,tombstone different no addresses, special
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:NULL => B:NULL",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = 0,
+ .ips = NULL,
+ .apply_expected = true,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,tombstone different addresses
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ .apply_expected = true,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,tombstone subset addresses
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:B_3_4 => B:B_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true,
+ }
+ },
+ /*
+ * sgroup,active vs. sgroup,active same addresses
+ * => should be replaced
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .comment= "A:B_3_4_X_3_4 vs. B:B_3_4_X_3_4 => B:B_3_4_X_3_4",
+ .extra = true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ },
+ .r2 = {
+ .owner = &ctx->b,
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4_X_3_4),
+ .ips = addresses_B_3_4_X_3_4,
+ .apply_expected = true,
+ }
+ },
+
+ /*
+ * This should be the last record in this array,
+ * we need to make sure the we leave a tombstoned unique entry
+ * owned by OWNER_A
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
+ .cleanup= true,
+ .r1 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ },
+ .r2 = {
+ .owner = &ctx->a,
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_A_1),
+ .ips = addresses_A_1,
+ .apply_expected = true
+ }
+ }}; /* do not add entries here, this should be the last record! */
+
+ wins_name_r1 = &wins_name1;
+ wins_name_r2 = &wins_name2;
+
+ torture_comment(tctx, "Test Replica Conflicts with different owners\n");
+
+ for(i=0; ret && i < ARRAY_SIZE(records); i++) {
+
+ if (!records[i].extra && !records[i].cleanup) {
+ /* we should test the worst cases */
+ if (records[i].r2.apply_expected && records[i].r1.ips==records[i].r2.ips) {
+ torture_comment(tctx, "(%s) Programmer error, invalid record[%u]: %s\n",
+ __location__, i, records[i].line);
+ return false;
+ } else if (!records[i].r2.apply_expected && records[i].r1.ips!=records[i].r2.ips) {
+ torture_comment(tctx, "(%s) Programmer error, invalid record[%u]: %s\n",
+ __location__, i, records[i].line);
+ return false;
+ }
+ }
+
+ if (!records[i].cleanup) {
+ const char *expected;
+ const char *ips;
+
+ if (records[i].r2.sgroup_merge) {
+ expected = "SGROUP_MERGE";
+ } else if (records[i].r2.apply_expected) {
+ expected = "REPLACE";
+ } else {
+ expected = "NOT REPLACE";
+ }
+
+ if (!records[i].r1.ips && !records[i].r2.ips) {
+ ips = "with no ip(s)";
+ } else if (records[i].r1.ips==records[i].r2.ips) {
+ ips = "with same ip(s)";
+ } else {
+ ips = "with different ip(s)";
+ }
+
+ torture_comment(tctx, "%s,%s%s vs. %s,%s%s %s => %s\n",
+ wrepl_name_type_string(records[i].r1.type),
+ wrepl_name_state_string(records[i].r1.state),
+ (records[i].r1.is_static?",static":""),
+ wrepl_name_type_string(records[i].r2.type),
+ wrepl_name_state_string(records[i].r2.state),
+ (records[i].r2.is_static?",static":""),
+ (records[i].comment?records[i].comment:ips),
+ expected);
+ }
+
+ /*
+ * Setup R1
+ */
+ wins_name_r1->name = &records[i].name;
+ wins_name_r1->flags = WREPL_NAME_FLAGS(records[i].r1.type,
+ records[i].r1.state,
+ records[i].r1.node,
+ records[i].r1.is_static);
+ wins_name_r1->id = ++records[i].r1.owner->max_version;
+ if (wins_name_r1->flags & 2) {
+ wins_name_r1->addresses.addresses.num_ips = records[i].r1.num_ips;
+ wins_name_r1->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ records[i].r1.ips);
+ } else {
+ wins_name_r1->addresses.ip = records[i].r1.ips[0].ip;
+ }
+ wins_name_r1->unknown = "255.255.255.255";
+
+ /* now apply R1 */
+ ret &= test_wrepl_update_one(tctx, ctx, records[i].r1.owner, wins_name_r1);
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r1.owner,
+ wins_name_r1, records[i].r1.apply_expected);
+
+ /*
+ * Setup R2
+ */
+ wins_name_r2->name = &records[i].name;
+ wins_name_r2->flags = WREPL_NAME_FLAGS(records[i].r2.type,
+ records[i].r2.state,
+ records[i].r2.node,
+ records[i].r2.is_static);
+ wins_name_r2->id = ++records[i].r2.owner->max_version;
+ if (wins_name_r2->flags & 2) {
+ wins_name_r2->addresses.addresses.num_ips = records[i].r2.num_ips;
+ wins_name_r2->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ records[i].r2.ips);
+ } else {
+ wins_name_r2->addresses.ip = records[i].r2.ips[0].ip;
+ }
+ wins_name_r2->unknown = "255.255.255.255";
+
+ /* now apply R2 */
+ ret &= test_wrepl_update_one(tctx, ctx, records[i].r2.owner, wins_name_r2);
+ if (records[i].r1.state == WREPL_STATE_RELEASED) {
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r1.owner,
+ wins_name_r1, false);
+ } else if (records[i].r2.sgroup_merge) {
+ ret &= test_wrepl_sgroup_merged(tctx, ctx, records[i].r2.merge_owner,
+ records[i].r1.owner,
+ records[i].r1.num_ips, records[i].r1.ips,
+ records[i].r2.owner,
+ records[i].r2.num_ips, records[i].r2.ips,
+ wins_name_r2);
+ } else if (records[i].r1.owner != records[i].r2.owner) {
+ bool _expected;
+ _expected = (records[i].r1.apply_expected && !records[i].r2.apply_expected);
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r1.owner,
+ wins_name_r1, _expected);
+ }
+ if (records[i].r2.state == WREPL_STATE_RELEASED) {
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r2.owner,
+ wins_name_r2, false);
+ } else if (!records[i].r2.sgroup_merge) {
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r2.owner,
+ wins_name_r2, records[i].r2.apply_expected);
+ }
+
+ if (records[i].r2.sgroup_cleanup) {
+ if (!ret) {
+ torture_comment(tctx, "failed before sgroup_cleanup record[%u]: %s\n", i, records[i].line);
+ return ret;
+ }
+
+ /* clean up the SGROUP record */
+ wins_name_r1->name = &records[i].name;
+ wins_name_r1->flags = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+ WREPL_STATE_ACTIVE,
+ WREPL_NODE_B, false);
+ wins_name_r1->id = ++records[i].r1.owner->max_version;
+ wins_name_r1->addresses.addresses.num_ips = 0;
+ wins_name_r1->addresses.addresses.ips = NULL;
+ wins_name_r1->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, records[i].r1.owner, wins_name_r1);
+
+ /* here we test how names from an owner are deleted */
+ if (records[i].r2.sgroup_merge && records[i].r2.num_ips) {
+ ret &= test_wrepl_sgroup_merged(tctx, ctx, NULL,
+ records[i].r2.owner,
+ records[i].r2.num_ips, records[i].r2.ips,
+ records[i].r1.owner,
+ 0, NULL,
+ wins_name_r2);
+ }
+
+ /* clean up the SGROUP record */
+ wins_name_r2->name = &records[i].name;
+ wins_name_r2->flags = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+ WREPL_STATE_ACTIVE,
+ WREPL_NODE_B, false);
+ wins_name_r2->id = ++records[i].r2.owner->max_version;
+ wins_name_r2->addresses.addresses.num_ips = 0;
+ wins_name_r2->addresses.addresses.ips = NULL;
+ wins_name_r2->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, records[i].r2.owner, wins_name_r2);
+
+ /* take ownership of the SGROUP record */
+ wins_name_r2->name = &records[i].name;
+ wins_name_r2->flags = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+ WREPL_STATE_ACTIVE,
+ WREPL_NODE_B, false);
+ wins_name_r2->id = ++records[i].r2.owner->max_version;
+ wins_name_r2->addresses.addresses.num_ips = ARRAY_SIZE(addresses_B_1);
+ wins_name_r2->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ addresses_B_1);
+ wins_name_r2->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, records[i].r2.owner, wins_name_r2);
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r2.owner, wins_name_r2, true);
+
+ /* overwrite the SGROUP record with unique,tombstone */
+ wins_name_r2->name = &records[i].name;
+ wins_name_r2->flags = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+ WREPL_STATE_TOMBSTONE,
+ WREPL_NODE_B, false);
+ wins_name_r2->id = ++records[i].r2.owner->max_version;
+ wins_name_r2->addresses.addresses.num_ips = ARRAY_SIZE(addresses_B_1);
+ wins_name_r2->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ addresses_B_1);
+ wins_name_r2->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, records[i].r2.owner, wins_name_r2);
+ ret &= test_wrepl_is_applied(tctx, ctx, records[i].r2.owner, wins_name_r2, true);
+
+ if (!ret) {
+ torture_comment(tctx, "failed in sgroup_cleanup record[%u]: %s\n", i, records[i].line);
+ return ret;
+ }
+ }
+
+ /* the first one is a cleanup run */
+ if (!ret && i == 0) ret = true;
+
+ if (!ret) {
+ torture_comment(tctx, "conflict handled wrong or record[%u]: %s\n", i, records[i].line);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_conflict_owned_released_vs_replica(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct wrepl_wins_name wins_name_;
+ struct wrepl_wins_name *wins_name = &wins_name_;
+ struct nbt_name_register name_register_;
+ struct nbt_name_register *name_register = &name_register_;
+ struct nbt_name_release release_;
+ struct nbt_name_release *release = &release_;
+ uint32_t i;
+ struct {
+ const char *line; /* just better debugging */
+ struct nbt_name name;
+ struct {
+ uint32_t nb_flags;
+ bool mhomed;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ bool apply_expected;
+ } wins;
+ struct {
+ enum wrepl_name_type type;
+ enum wrepl_name_state state;
+ enum wrepl_name_node node;
+ bool is_static;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ bool apply_expected;
+ } replica;
+ } records[] = {
+/*
+ * unique vs. unique section
+ */
+ /*
+ * unique,released vs. unique,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_UA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. unique,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_UA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. unique,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_UT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. unique,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_UT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * unique vs. group section
+ */
+ /*
+ * unique,released vs. group,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_GA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. group,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_GA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. group,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_GT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. group,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_GT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * unique vs. special group section
+ */
+ /*
+ * unique,released vs. sgroup,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_SA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. sgroup,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_SA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. sgroup,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_ST_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. sgroup,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_ST_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * unique vs. multi homed section
+ */
+ /*
+ * unique,released vs. mhomed,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_MA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. mhomed,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_MA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. mhomed,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_MT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,released vs. mhomed,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_UR_MT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * group vs. unique section
+ */
+ /*
+ * group,released vs. unique,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_UA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. unique,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_UA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. unique,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_UT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. unique,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_UT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * group vs. group section
+ */
+ /*
+ * group,released vs. group,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_GA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * group,released vs. group,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_GA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * group,released vs. group,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_GT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * group,released vs. group,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_GT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * group vs. special group section
+ */
+ /*
+ * group,released vs. sgroup,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_SA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. sgroup,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_SA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. sgroup,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_ST_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. sgroup,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_ST_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * group vs. multi homed section
+ */
+ /*
+ * group,released vs. mhomed,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_MA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. mhomed,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_MA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. mhomed,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_MT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,released vs. mhomed,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_GR_MT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * special group vs. unique section
+ */
+ /*
+ * sgroup,released vs. unique,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_UA_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. unique,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_UA_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. unique,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_UT_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. unique,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_UT_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * special group vs. group section
+ */
+ /*
+ * sgroup,released vs. group,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_GA_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. group,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_GA_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. group,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_GT_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. group,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_GT_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * special group vs. special group section
+ */
+ /*
+ * sgroup,released vs. sgroup,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_SA_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. sgroup,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_SA_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. sgroup,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_ST_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. sgroup,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_ST_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * special group vs. multi homed section
+ */
+ /*
+ * sgroup,released vs. mhomed,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_MA_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. mhomed,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_MA_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. mhomed,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_MT_SI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * sgroup,released vs. mhomed,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_SR_MT_DI", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * multi homed vs. unique section
+ */
+ /*
+ * mhomed,released vs. unique,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_UA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. unique,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_UA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. unique,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_UT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. unique,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_UT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * multi homed vs. group section
+ */
+ /*
+ * mhomed,released vs. group,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_GA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. group,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_GA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. group,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_GT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. group,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_GT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * multi homed vs. special group section
+ */
+ /*
+ * mhomed,released vs. sgroup,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_SA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. sgroup,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_SA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. sgroup,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_ST_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. sgroup,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_ST_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+/*
+ * multi homed vs. multi homed section
+ */
+ /*
+ * mhomed,released vs. mhomed,active with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_MA_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. mhomed,active with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_MA_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. mhomed,tombstone with same ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_MT_SI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,released vs. mhomed,tombstone with different ip(s)
+ */
+ {
+ .line = __location__,
+ .name = _NBT_NAME("_MR_MT_DI", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ };
+
+ torture_comment(tctx, "Test Replica records vs. owned released records\n");
+
+ for(i=0; ret && i < ARRAY_SIZE(records); i++) {
+ torture_comment(tctx, "%s => %s\n", nbt_name_string(ctx, &records[i].name),
+ (records[i].replica.apply_expected?"REPLACE":"NOT REPLACE"));
+
+ /*
+ * Setup Register
+ */
+ name_register->in.name = records[i].name;
+ name_register->in.dest_addr = ctx->address;
+ name_register->in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ name_register->in.address = records[i].wins.ips[0].ip;
+ name_register->in.nb_flags = records[i].wins.nb_flags;
+ name_register->in.register_demand= false;
+ name_register->in.broadcast = false;
+ name_register->in.multi_homed = records[i].wins.mhomed;
+ name_register->in.ttl = 300000;
+ name_register->in.timeout = 70;
+ name_register->in.retries = 0;
+
+ status = nbt_name_register(ctx->nbtsock, ctx, name_register);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_comment(tctx, "No response from %s for name register\n", ctx->address);
+ ret = false;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Bad response from %s for name register - %s\n",
+ ctx->address, nt_errstr(status));
+ ret = false;
+ }
+ CHECK_VALUE(tctx, name_register->out.rcode, 0);
+ CHECK_VALUE_STRING(tctx, name_register->out.reply_from, ctx->address);
+ CHECK_VALUE(tctx, name_register->out.name.type, records[i].name.type);
+ CHECK_VALUE_STRING(tctx, name_register->out.name.name, records[i].name.name);
+ CHECK_VALUE_STRING(tctx, name_register->out.name.scope, records[i].name.scope);
+ CHECK_VALUE_STRING(tctx, name_register->out.reply_addr, records[i].wins.ips[0].ip);
+
+ /* release the record */
+ release->in.name = records[i].name;
+ release->in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ release->in.dest_addr = ctx->address;
+ release->in.address = records[i].wins.ips[0].ip;
+ release->in.nb_flags = records[i].wins.nb_flags;
+ release->in.broadcast = false;
+ release->in.timeout = 30;
+ release->in.retries = 0;
+
+ status = nbt_name_release(ctx->nbtsock, ctx, release);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_comment(tctx, "No response from %s for name release\n", ctx->address);
+ return false;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Bad response from %s for name query - %s\n",
+ ctx->address, nt_errstr(status));
+ return false;
+ }
+ CHECK_VALUE(tctx, release->out.rcode, 0);
+
+ /*
+ * Setup Replica
+ */
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(records[i].replica.type,
+ records[i].replica.state,
+ records[i].replica.node,
+ records[i].replica.is_static);
+ wins_name->id = ++ctx->b.max_version;
+ if (wins_name->flags & 2) {
+ wins_name->addresses.addresses.num_ips = records[i].replica.num_ips;
+ wins_name->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ records[i].replica.ips);
+ } else {
+ wins_name->addresses.ip = records[i].replica.ips[0].ip;
+ }
+ wins_name->unknown = "255.255.255.255";
+
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->b, wins_name,
+ records[i].replica.apply_expected);
+
+ if (records[i].replica.apply_expected) {
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(WREPL_TYPE_UNIQUE,
+ WREPL_STATE_TOMBSTONE,
+ WREPL_NODE_B, false);
+ wins_name->id = ++ctx->b.max_version;
+ wins_name->addresses.ip = addresses_B_1[0].ip;
+ wins_name->unknown = "255.255.255.255";
+
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->b, wins_name, true);
+ } else {
+ release->in.name = records[i].name;
+ release->in.dest_addr = ctx->address;
+ release->in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ release->in.address = records[i].wins.ips[0].ip;
+ release->in.nb_flags = records[i].wins.nb_flags;
+ release->in.broadcast = false;
+ release->in.timeout = 30;
+ release->in.retries = 0;
+
+ status = nbt_name_release(ctx->nbtsock, ctx, release);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_comment(tctx, "No response from %s for name release\n", ctx->address);
+ return false;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Bad response from %s for name query - %s\n",
+ ctx->address, nt_errstr(status));
+ return false;
+ }
+ CHECK_VALUE(tctx, release->out.rcode, 0);
+ }
+ if (!ret) {
+ torture_comment(tctx, "conflict handled wrong or record[%u]: %s\n", i, records[i].line);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+struct test_conflict_owned_active_vs_replica_struct {
+ struct torture_context *tctx;
+ const char *line; /* just better debugging */
+ const char *section; /* just better debugging */
+ struct nbt_name name;
+ const char *comment;
+ bool skip;
+ struct {
+ uint32_t nb_flags;
+ bool mhomed;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ bool apply_expected;
+ } wins;
+ struct {
+ uint32_t timeout;
+ bool positive;
+ bool expect_release;
+ bool late_release;
+ bool ret;
+ /* when num_ips == 0, then .wins.ips are used */
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ } defend;
+ struct {
+ enum wrepl_name_type type;
+ enum wrepl_name_state state;
+ enum wrepl_name_node node;
+ bool is_static;
+ uint32_t num_ips;
+ const struct wrepl_ip *ips;
+ bool apply_expected;
+ bool mhomed_merge;
+ bool sgroup_merge;
+ } replica;
+};
+
+static void test_conflict_owned_active_vs_replica_handler(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *req_packet,
+ struct socket_address *src);
+
+static bool test_conflict_owned_active_vs_replica(struct torture_context *tctx,
+ struct test_wrepl_conflict_conn *ctx)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct wrepl_wins_name wins_name_;
+ struct wrepl_wins_name *wins_name = &wins_name_;
+ struct nbt_name_register name_register_;
+ struct nbt_name_register *name_register = &name_register_;
+ struct nbt_name_release release_;
+ struct nbt_name_release *release = &release_;
+ uint32_t i;
+ struct test_conflict_owned_active_vs_replica_struct records[] = {
+/*
+ * unique vs. unique section
+ */
+ /*
+ * unique,active vs. unique,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. unique,active with different ip(s), positive response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UA_DI_P", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. unique,active with different ip(s), positive response other ips
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UA_DI_O", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. unique,active with different ip(s), negative response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UA_DI_N", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = false,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. unique,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. unique,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * unique vs. group section
+ */
+ /*
+ * unique,active vs. group,active with same ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_GA_SI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. group,active with different ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_GA_DI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. group,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_GT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. group,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_GT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * unique vs. special group section
+ */
+ /*
+ * unique,active vs. sgroup,active with same ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_SA_SI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. group,active with different ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_SA_DI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. sgroup,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_ST_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. sgroup,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_ST_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * unique vs. multi homed section
+ */
+ /*
+ * unique,active vs. mhomed,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. mhomed,active with superset ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MA_SP_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. mhomed,active with different ip(s), positive response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MA_DI_P", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. mhomed,active with different ip(s), positive response other ips
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MA_DI_O", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. mhomed,active with different ip(s), negative response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MA_DI_N", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = false,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ },
+ },
+ /*
+ * unique,active vs. mhomed,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * unique,active vs. mhomed,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+/*
+ * normal group vs. unique section
+ */
+ /*
+ * group,active vs. unique,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_UA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. unique,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_UA_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. unique,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_UT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. unique,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_UT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * normal group vs. normal group section
+ */
+ /*
+ * group,active vs. group,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_GA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * group,active vs. group,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_GA_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * group,active vs. group,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_GT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. group,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_GT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * normal group vs. special group section
+ */
+ /*
+ * group,active vs. sgroup,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_SA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. sgroup,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_SA_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. sgroup,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_ST_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. sgroup,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_ST_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+/*
+ * normal group vs. multi homed section
+ */
+ /*
+ * group,active vs. mhomed,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_MA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. mhomed,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_MA_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. mhomed,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_MT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * group,active vs. mhomed,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_GA_MT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+/*
+ * special group vs. unique section
+ */
+ /*
+ * sgroup,active vs. unique,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_UA_SI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. unique,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_UA_DI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. unique,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_UT_SI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. unique,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_UT_DI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * special group vs. normal group section
+ */
+ /*
+ * sgroup,active vs. group,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_GA_SI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. group,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_GA_DI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. group,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_GT_SI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. group,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_GT_DI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * special group vs. multi homed section
+ */
+ /*
+ * sgroup,active vs. mhomed,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_MA_SI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. mhomed,active with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_MA_DI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. mhomed,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_MT_SI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. mhomed,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_MT_DI_U", 0x1C, NULL),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * multi homed vs. unique section
+ */
+ /*
+ * mhomed,active vs. unique,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_UA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. unique,active with different ip(s), positive response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_UA_DI_P", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. unique,active with different ip(s), positive response other ips
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_UA_DI_O", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. unique,active with different ip(s), negative response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_UA_DI_N", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = false,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. unique,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_UT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. unique,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_UT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * multi homed vs. normal group section
+ */
+ /*
+ * mhomed,active vs. group,active with same ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_GA_SI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. group,active with different ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_GA_DI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. group,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_GT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. group,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_GT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_GROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * multi homed vs. special group section
+ */
+ /*
+ * mhomed,active vs. sgroup,active with same ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_SA_SI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. group,active with different ip(s), release expected
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_SA_DI_R", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .expect_release = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. sgroup,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_ST_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. sgroup,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_ST_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_1),
+ .ips = addresses_B_1,
+ .apply_expected = false
+ },
+ },
+/*
+ * multi homed vs. multi homed section
+ */
+ /*
+ * mhomed,active vs. mhomed,active with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with superset ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SP_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with different ip(s), positive response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_DI_P", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with different ip(s), positive response other ips
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_DI_O", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ARRAY_SIZE(addresses_A_3_4),
+ .ips = addresses_A_3_4,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with different ip(s), negative response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_DI_N", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = false,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,tombstone with same ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MT_SI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,tombstone with different ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MT_DI_U", 0x00, NULL),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+/*
+ * some more multi homed test, including merging
+ */
+ /*
+ * mhomed,active vs. mhomed,active with superset ip(s), unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .section= "Test Replica vs. owned active: some more MHOMED combinations",
+ .name = _NBT_NAME("_MA_MA_SP_U", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:ALL => B:ALL",
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with same ips, unchecked
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SM_U", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:MHOMED => B:MHOMED",
+ .skip = (ctx->addresses_mhomed_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with subset ip(s), positive response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SB_P", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:BEST (C:MHOMED) => B:MHOMED",
+ .skip = (ctx->addresses_mhomed_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .mhomed_merge = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with subset ip(s), positive response, with all addresses
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SB_A", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:BEST (C:ALL) => B:MHOMED",
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .mhomed_merge = true
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with subset ip(s), positive response, with replicas addresses
+ * TODO: check why the server sends a name release demand for one address?
+ * the release demand has no effect to the database record...
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SB_PRA", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:BEST (C:BEST) => C:MHOMED",
+ .skip = (ctx->addresses_all_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .late_release = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with subset ip(s), positive response, with other addresses
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SB_O", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:BEST (B:B_3_4) =>C:MHOMED",
+ .skip = (ctx->addresses_all_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ /*
+ * mhomed,active vs. mhomed,active with subset ip(s), negative response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_MA_MA_SB_N", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:BEST (NEGATIVE) => B:BEST",
+ .skip = (ctx->addresses_mhomed_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = false
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ },
+/*
+ * some more multi homed and unique test, including merging
+ */
+ /*
+ * mhomed,active vs. unique,active with subset ip(s), positive response
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .section= "Test Replica vs. owned active: some more UNIQUE,MHOMED combinations",
+ .name = _NBT_NAME("_MA_UA_SB_P", 0x00, NULL),
+ .comment= "C:MHOMED vs. B:UNIQUE,BEST (C:MHOMED) => B:MHOMED",
+ .skip = (ctx->addresses_all_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = true,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .mhomed_merge = true
+ },
+ },
+ /*
+ * unique,active vs. unique,active with different ip(s), positive response, with replicas address
+ * TODO: check why the server sends a name release demand for one address?
+ * the release demand has no effect to the database record...
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UA_DI_PRA", 0x00, NULL),
+ .comment= "C:BEST vs. B:BEST2 (C:BEST2,LR:BEST2) => C:BEST",
+ .skip = (ctx->addresses_all_num < 2),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ctx->addresses_best2_num,
+ .ips = ctx->addresses_best2,
+ .late_release = true
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best2_num,
+ .ips = ctx->addresses_best2,
+ .apply_expected = false,
+ },
+ },
+ /*
+ * unique,active vs. unique,active with different ip(s), positive response, with all addresses
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_UA_DI_A", 0x00, NULL),
+ .comment= "C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED",
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ },
+ .replica= {
+ .type = WREPL_TYPE_UNIQUE,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best2_num,
+ .ips = ctx->addresses_best2,
+ .mhomed_merge = true,
+ },
+ },
+ /*
+ * unique,active vs. mhomed,active with different ip(s), positive response, with all addresses
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_UA_MA_DI_A", 0x00, NULL),
+ .comment= "C:BEST vs. B:BEST2 (C:ALL) => B:MHOMED",
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = 0,
+ .mhomed = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 10,
+ .positive = true,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ },
+ .replica= {
+ .type = WREPL_TYPE_MHOMED,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best2_num,
+ .ips = ctx->addresses_best2,
+ .mhomed_merge = true,
+ },
+ },
+/*
+ * special group vs. special group merging section
+ */
+ /*
+ * sgroup,active vs. sgroup,active with different ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .section= "Test Replica vs. owned active: SGROUP vs. SGROUP tests",
+ .name = _NBT_NAME("_SA_SA_DI_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .sgroup_merge = true
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,active with same ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_SA_SI_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .sgroup_merge = true
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,active with superset ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_SA_SP_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ .sgroup_merge = true
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,active with subset ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_SA_SB_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_ACTIVE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .sgroup_merge = true
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,tombstone with different ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_ST_DI_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ARRAY_SIZE(addresses_B_3_4),
+ .ips = addresses_B_3_4,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,tombstone with same ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_ST_SI_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,tombstone with superset ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_ST_SP_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_all_num,
+ .ips = ctx->addresses_all,
+ .apply_expected = false
+ },
+ },
+ /*
+ * sgroup,active vs. sgroup,tombstone with subset ip(s)
+ */
+ {
+ .tctx = tctx,
+ .line = __location__,
+ .name = _NBT_NAME("_SA_ST_SB_U", 0x1C, NULL),
+ .skip = (ctx->addresses_all_num < 3),
+ .wins = {
+ .nb_flags = NBT_NM_GROUP,
+ .mhomed = false,
+ .num_ips = ctx->addresses_mhomed_num,
+ .ips = ctx->addresses_mhomed,
+ .apply_expected = true
+ },
+ .defend = {
+ .timeout = 0,
+ },
+ .replica= {
+ .type = WREPL_TYPE_SGROUP,
+ .state = WREPL_STATE_TOMBSTONE,
+ .node = WREPL_NODE_B,
+ .is_static = false,
+ .num_ips = ctx->addresses_best_num,
+ .ips = ctx->addresses_best,
+ .apply_expected = false
+ },
+ },
+ };
+
+ if (!ctx->nbtsock_srv) {
+ torture_comment(tctx, "SKIP: Test Replica records vs. owned active records: not bound to port[%d]\n",
+ lpcfg_nbt_port(tctx->lp_ctx));
+ return true;
+ }
+
+ torture_comment(tctx, "Test Replica records vs. owned active records\n");
+
+ for(i=0; ret && i < ARRAY_SIZE(records); i++) {
+ struct timeval end;
+ struct test_conflict_owned_active_vs_replica_struct record = records[i];
+ uint32_t j, count = 1;
+ const char *action;
+
+ if (records[i].wins.mhomed || records[i].name.type == 0x1C) {
+ count = records[i].wins.num_ips;
+ }
+
+ if (records[i].section) {
+ torture_comment(tctx, "%s\n", records[i].section);
+ }
+
+ if (records[i].skip) {
+ torture_comment(tctx, "%s => SKIPPED\n", nbt_name_string(ctx, &records[i].name));
+ continue;
+ }
+
+ if (records[i].replica.mhomed_merge) {
+ action = "MHOMED_MERGE";
+ } else if (records[i].replica.sgroup_merge) {
+ action = "SGROUP_MERGE";
+ } else if (records[i].replica.apply_expected) {
+ action = "REPLACE";
+ } else {
+ action = "NOT REPLACE";
+ }
+
+ torture_comment(tctx, "%s%s%s => %s\n",
+ nbt_name_string(ctx, &records[i].name),
+ (records[i].comment?": ":""),
+ (records[i].comment?records[i].comment:""),
+ action);
+
+ /* Prepare for multi homed registration */
+ ZERO_STRUCT(records[i].defend);
+ records[i].defend.timeout = 10;
+ records[i].defend.positive = true;
+ nbt_set_incoming_handler(ctx->nbtsock_srv,
+ test_conflict_owned_active_vs_replica_handler,
+ &records[i]);
+ if (ctx->nbtsock_srv2) {
+ nbt_set_incoming_handler(ctx->nbtsock_srv2,
+ test_conflict_owned_active_vs_replica_handler,
+ &records[i]);
+ }
+
+ /*
+ * Setup Register
+ */
+ for (j=0; j < count; j++) {
+ struct nbt_name_request *req;
+
+ name_register->in.name = records[i].name;
+ name_register->in.dest_addr = ctx->address;
+ name_register->in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ name_register->in.address = records[i].wins.ips[j].ip;
+ name_register->in.nb_flags = records[i].wins.nb_flags;
+ name_register->in.register_demand= false;
+ name_register->in.broadcast = false;
+ name_register->in.multi_homed = records[i].wins.mhomed;
+ name_register->in.ttl = 300000;
+ name_register->in.timeout = 70;
+ name_register->in.retries = 0;
+
+ req = nbt_name_register_send(ctx->nbtsock, name_register);
+
+ /* push the request on the wire */
+ tevent_loop_once(ctx->nbtsock->event_ctx);
+
+ /*
+ * if we register multiple addresses,
+ * the server will do name queries to see if the old addresses
+ * are still alive
+ */
+ if (records[i].wins.mhomed && j > 0) {
+ end = timeval_current_ofs(records[i].defend.timeout,0);
+ records[i].defend.ret = true;
+ while (records[i].defend.timeout > 0) {
+ tevent_loop_once(ctx->nbtsock_srv->event_ctx);
+ if (timeval_expired(&end)) break;
+ }
+ ret &= records[i].defend.ret;
+ }
+
+ status = nbt_name_register_recv(req, ctx, name_register);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_comment(tctx, "No response from %s for name register\n", ctx->address);
+ ret = false;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Bad response from %s for name register - %s\n",
+ ctx->address, nt_errstr(status));
+ ret = false;
+ }
+ CHECK_VALUE(tctx, name_register->out.rcode, 0);
+ CHECK_VALUE_STRING(tctx, name_register->out.reply_from, ctx->address);
+ CHECK_VALUE(tctx, name_register->out.name.type, records[i].name.type);
+ CHECK_VALUE_STRING(tctx, name_register->out.name.name, records[i].name.name);
+ CHECK_VALUE_STRING(tctx, name_register->out.name.scope, records[i].name.scope);
+ CHECK_VALUE_STRING(tctx, name_register->out.reply_addr, records[i].wins.ips[j].ip);
+ }
+
+ /* Prepare for the current test */
+ records[i].defend = record.defend;
+ nbt_set_incoming_handler(ctx->nbtsock_srv,
+ test_conflict_owned_active_vs_replica_handler,
+ &records[i]);
+ if (ctx->nbtsock_srv2) {
+ nbt_set_incoming_handler(ctx->nbtsock_srv2,
+ test_conflict_owned_active_vs_replica_handler,
+ &records[i]);
+ }
+
+ /*
+ * Setup Replica
+ */
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(records[i].replica.type,
+ records[i].replica.state,
+ records[i].replica.node,
+ records[i].replica.is_static);
+ wins_name->id = ++ctx->b.max_version;
+ if (wins_name->flags & 2) {
+ wins_name->addresses.addresses.num_ips = records[i].replica.num_ips;
+ wins_name->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ records[i].replica.ips);
+ } else {
+ wins_name->addresses.ip = records[i].replica.ips[0].ip;
+ }
+ wins_name->unknown = "255.255.255.255";
+
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+
+ /*
+ * wait for the name query, which is handled in
+ * test_conflict_owned_active_vs_replica_handler()
+ */
+ end = timeval_current_ofs(records[i].defend.timeout,0);
+ records[i].defend.ret = true;
+ while (records[i].defend.timeout > 0) {
+ tevent_loop_once(ctx->nbtsock_srv->event_ctx);
+ if (timeval_expired(&end)) break;
+ }
+ ret &= records[i].defend.ret;
+
+ if (records[i].defend.late_release) {
+ records[i].defend = record.defend;
+ records[i].defend.expect_release = true;
+ /*
+ * wait for the name release demand, which is handled in
+ * test_conflict_owned_active_vs_replica_handler()
+ */
+ end = timeval_current_ofs(records[i].defend.timeout,0);
+ records[i].defend.ret = true;
+ while (records[i].defend.timeout > 0) {
+ tevent_loop_once(ctx->nbtsock_srv->event_ctx);
+ if (timeval_expired(&end)) break;
+ }
+ ret &= records[i].defend.ret;
+ }
+
+ if (records[i].replica.mhomed_merge) {
+ ret &= test_wrepl_mhomed_merged(tctx, ctx, &ctx->c,
+ records[i].wins.num_ips, records[i].wins.ips,
+ &ctx->b,
+ records[i].replica.num_ips, records[i].replica.ips,
+ wins_name);
+ } else if (records[i].replica.sgroup_merge) {
+ ret &= test_wrepl_sgroup_merged(tctx, ctx, NULL,
+ &ctx->c,
+ records[i].wins.num_ips, records[i].wins.ips,
+ &ctx->b,
+ records[i].replica.num_ips, records[i].replica.ips,
+ wins_name);
+ } else {
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->b, wins_name,
+ records[i].replica.apply_expected);
+ }
+
+ if (records[i].replica.apply_expected ||
+ records[i].replica.mhomed_merge) {
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(WREPL_TYPE_UNIQUE,
+ WREPL_STATE_TOMBSTONE,
+ WREPL_NODE_B, false);
+ wins_name->id = ++ctx->b.max_version;
+ wins_name->addresses.ip = addresses_B_1[0].ip;
+ wins_name->unknown = "255.255.255.255";
+
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->b, wins_name, true);
+ } else {
+ for (j=0; j < count; j++) {
+ struct nbt_name_socket *nbtsock = ctx->nbtsock;
+
+ if (ctx->myaddr2 && strcmp(records[i].wins.ips[j].ip, ctx->myaddr2->addr) == 0) {
+ nbtsock = ctx->nbtsock2;
+ }
+
+ release->in.name = records[i].name;
+ release->in.dest_addr = ctx->address;
+ release->in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
+ release->in.address = records[i].wins.ips[j].ip;
+ release->in.nb_flags = records[i].wins.nb_flags;
+ release->in.broadcast = false;
+ release->in.timeout = 30;
+ release->in.retries = 0;
+
+ status = nbt_name_release(nbtsock, ctx, release);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ torture_comment(tctx, "No response from %s for name release\n", ctx->address);
+ return false;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Bad response from %s for name query - %s\n",
+ ctx->address, nt_errstr(status));
+ return false;
+ }
+ CHECK_VALUE(tctx, release->out.rcode, 0);
+ }
+
+ if (records[i].replica.sgroup_merge) {
+ /* clean up the SGROUP record */
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+ WREPL_STATE_ACTIVE,
+ WREPL_NODE_B, false);
+ wins_name->id = ++ctx->b.max_version;
+ wins_name->addresses.addresses.num_ips = 0;
+ wins_name->addresses.addresses.ips = NULL;
+ wins_name->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+
+ /* take ownership of the SGROUP record */
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(WREPL_TYPE_SGROUP,
+ WREPL_STATE_ACTIVE,
+ WREPL_NODE_B, false);
+ wins_name->id = ++ctx->b.max_version;
+ wins_name->addresses.addresses.num_ips = ARRAY_SIZE(addresses_B_1);
+ wins_name->addresses.addresses.ips = discard_const_p(struct wrepl_ip,
+ addresses_B_1);
+ wins_name->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->b, wins_name, true);
+
+ /* overwrite the SGROUP record with unique,tombstone */
+ wins_name->name = &records[i].name;
+ wins_name->flags = WREPL_NAME_FLAGS(WREPL_TYPE_UNIQUE,
+ WREPL_STATE_TOMBSTONE,
+ WREPL_NODE_B, false);
+ wins_name->id = ++ctx->b.max_version;
+ wins_name->addresses.ip = addresses_A_1[0].ip;
+ wins_name->unknown = "255.255.255.255";
+ ret &= test_wrepl_update_one(tctx, ctx, &ctx->b, wins_name);
+ ret &= test_wrepl_is_applied(tctx, ctx, &ctx->b, wins_name, true);
+ }
+ }
+
+ if (!ret) {
+ torture_comment(tctx, "conflict handled wrong or record[%u]: %s\n", i, records[i].line);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+#define __NBT_LABEL_CAT1__(a,b) a##b
+#define __NBT_LABEL_CAT2__(a,b) __NBT_LABEL_CAT1__(a,b)
+#define _NBT_LABEL __NBT_LABEL_CAT2__(_label_, __LINE__)
+
+#define _NBT_ASSERT(v, correct) do { \
+ bool _ret = true; \
+ torture_assert_int_equal_goto(rec->tctx, v, correct, \
+ _ret, _NBT_LABEL, "Invalid int value"); \
+_NBT_LABEL: \
+ if (!_ret) { \
+ return; \
+ } \
+} while (0)
+
+#define _NBT_ASSERT_STRING(v, correct) do { \
+ bool _ret = true; \
+ torture_assert_str_equal_goto(rec->tctx, v, correct, \
+ _ret, _NBT_LABEL, "Invalid string value"); \
+_NBT_LABEL: \
+ if (!_ret) { \
+ return; \
+ } \
+} while (0)
+
+static void test_conflict_owned_active_vs_replica_handler_query(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *req_packet,
+ struct socket_address *src)
+{
+ struct nbt_name *name;
+ struct nbt_name_packet *rep_packet;
+ struct test_conflict_owned_active_vs_replica_struct *rec =
+ (struct test_conflict_owned_active_vs_replica_struct *)nbtsock->incoming.private_data;
+
+ _NBT_ASSERT(req_packet->qdcount, 1);
+ _NBT_ASSERT(req_packet->questions[0].question_type, NBT_QTYPE_NETBIOS);
+ _NBT_ASSERT(req_packet->questions[0].question_class, NBT_QCLASS_IP);
+
+ name = &req_packet->questions[0].name;
+
+ _NBT_ASSERT_STRING(name->name, rec->name.name);
+ _NBT_ASSERT(name->type, rec->name.type);
+ _NBT_ASSERT_STRING(name->scope, rec->name.scope);
+
+ _NBT_ASSERT(rec->defend.expect_release, false);
+
+ rep_packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (rep_packet == NULL) return;
+
+ rep_packet->name_trn_id = req_packet->name_trn_id;
+ rep_packet->ancount = 1;
+
+ rep_packet->answers = talloc_array(rep_packet, struct nbt_res_rec, 1);
+ if (rep_packet->answers == NULL) return;
+
+ rep_packet->answers[0].name = *name;
+ rep_packet->answers[0].rr_class = NBT_QCLASS_IP;
+ rep_packet->answers[0].ttl = 0;
+
+ if (rec->defend.positive) {
+ uint32_t i, num_ips;
+ const struct wrepl_ip *ips;
+
+ if (rec->defend.num_ips > 0) {
+ num_ips = rec->defend.num_ips;
+ ips = rec->defend.ips;
+ } else {
+ num_ips = rec->wins.num_ips;
+ ips = rec->wins.ips;
+ }
+
+ /* send a positive reply */
+ rep_packet->operation =
+ NBT_FLAG_REPLY |
+ NBT_OPCODE_QUERY |
+ NBT_FLAG_AUTHORITATIVE |
+ NBT_FLAG_RECURSION_DESIRED |
+ NBT_FLAG_RECURSION_AVAIL;
+
+ rep_packet->answers[0].rr_type = NBT_QTYPE_NETBIOS;
+
+ rep_packet->answers[0].rdata.netbios.length = num_ips*6;
+ rep_packet->answers[0].rdata.netbios.addresses =
+ talloc_array(rep_packet->answers, struct nbt_rdata_address, num_ips);
+ if (rep_packet->answers[0].rdata.netbios.addresses == NULL) return;
+
+ for (i=0; i < num_ips; i++) {
+ struct nbt_rdata_address *addr =
+ &rep_packet->answers[0].rdata.netbios.addresses[i];
+ addr->nb_flags = rec->wins.nb_flags;
+ addr->ipaddr = ips[i].ip;
+ }
+ DEBUG(2,("Sending positive name query reply for %s to %s:%d\n",
+ nbt_name_string(rep_packet, name), src->addr, src->port));
+ } else {
+ /* send a negative reply */
+ rep_packet->operation =
+ NBT_FLAG_REPLY |
+ NBT_OPCODE_QUERY |
+ NBT_FLAG_AUTHORITATIVE |
+ NBT_RCODE_NAM;
+
+ rep_packet->answers[0].rr_type = NBT_QTYPE_NULL;
+
+ ZERO_STRUCT(rep_packet->answers[0].rdata);
+
+ DEBUG(2,("Sending negative name query reply for %s to %s:%d\n",
+ nbt_name_string(rep_packet, name), src->addr, src->port));
+ }
+
+ nbt_name_reply_send(nbtsock, src, rep_packet);
+ talloc_free(rep_packet);
+
+ /* make sure we push the reply to the wire */
+ while (nbtsock->send_queue) {
+ tevent_loop_once(nbtsock->event_ctx);
+ }
+ smb_msleep(1000);
+
+ rec->defend.timeout = 0;
+ rec->defend.ret = true;
+}
+
+static void test_conflict_owned_active_vs_replica_handler_release(
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *req_packet,
+ struct socket_address *src)
+{
+ struct nbt_name *name;
+ struct nbt_name_packet *rep_packet;
+ struct test_conflict_owned_active_vs_replica_struct *rec =
+ (struct test_conflict_owned_active_vs_replica_struct *)nbtsock->incoming.private_data;
+
+ _NBT_ASSERT(req_packet->qdcount, 1);
+ _NBT_ASSERT(req_packet->questions[0].question_type, NBT_QTYPE_NETBIOS);
+ _NBT_ASSERT(req_packet->questions[0].question_class, NBT_QCLASS_IP);
+
+ name = &req_packet->questions[0].name;
+
+ _NBT_ASSERT_STRING(name->name, rec->name.name);
+ _NBT_ASSERT(name->type, rec->name.type);
+ _NBT_ASSERT_STRING(name->scope, rec->name.scope);
+
+ _NBT_ASSERT(rec->defend.expect_release, true);
+
+ rep_packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (rep_packet == NULL) return;
+
+ rep_packet->name_trn_id = req_packet->name_trn_id;
+ rep_packet->ancount = 1;
+ rep_packet->operation =
+ NBT_FLAG_REPLY |
+ NBT_OPCODE_RELEASE |
+ NBT_FLAG_AUTHORITATIVE;
+
+ rep_packet->answers = talloc_array(rep_packet, struct nbt_res_rec, 1);
+ if (rep_packet->answers == NULL) return;
+
+ rep_packet->answers[0].name = *name;
+ rep_packet->answers[0].rr_type = NBT_QTYPE_NETBIOS;
+ rep_packet->answers[0].rr_class = NBT_QCLASS_IP;
+ rep_packet->answers[0].ttl = req_packet->additional[0].ttl;
+ rep_packet->answers[0].rdata = req_packet->additional[0].rdata;
+
+ DEBUG(2,("Sending name release reply for %s to %s:%d\n",
+ nbt_name_string(rep_packet, name), src->addr, src->port));
+
+ nbt_name_reply_send(nbtsock, src, rep_packet);
+ talloc_free(rep_packet);
+
+ /* make sure we push the reply to the wire */
+ while (nbtsock->send_queue) {
+ tevent_loop_once(nbtsock->event_ctx);
+ }
+ smb_msleep(1000);
+
+ rec->defend.timeout = 0;
+ rec->defend.ret = true;
+}
+
+static void test_conflict_owned_active_vs_replica_handler(struct nbt_name_socket *nbtsock,
+ struct nbt_name_packet *req_packet,
+ struct socket_address *src)
+{
+ struct test_conflict_owned_active_vs_replica_struct *rec =
+ (struct test_conflict_owned_active_vs_replica_struct *)nbtsock->incoming.private_data;
+ struct nbt_name *name = &req_packet->questions[0].name;
+
+ if (req_packet->operation & NBT_FLAG_BROADCAST) {
+ torture_comment(rec->tctx,
+ "%s: incoming packet name[%s] flags[0x%08X] from[%s]\n",
+ __location__,
+ nbt_name_string(rec->tctx, name),
+ req_packet->operation,
+ src->addr);
+ return;
+ }
+
+ rec->defend.ret = false;
+
+ switch (req_packet->operation & NBT_OPCODE) {
+ case NBT_OPCODE_QUERY:
+ test_conflict_owned_active_vs_replica_handler_query(nbtsock, req_packet, src);
+ break;
+ case NBT_OPCODE_RELEASE:
+ test_conflict_owned_active_vs_replica_handler_release(nbtsock, req_packet, src);
+ break;
+ default:
+ torture_comment(rec->tctx,
+ "%s: unexpected packet name[%s] flags[0x%08X] from[%s]\n",
+ __location__,
+ nbt_name_string(rec->tctx, name),
+ req_packet->operation,
+ src->addr);
+ _NBT_ASSERT((req_packet->operation & NBT_OPCODE), NBT_OPCODE_QUERY);
+ break;
+ }
+}
+
+/*
+ test WINS replication replica conflicts operations
+*/
+static bool torture_nbt_winsreplication_replica(struct torture_context *tctx)
+{
+ bool ret = true;
+ struct test_wrepl_conflict_conn *ctx;
+
+ const char *address;
+ struct nbt_name name;
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ ctx = test_create_conflict_ctx(tctx, address);
+ if (!ctx) return false;
+
+ ret &= test_conflict_same_owner(tctx, ctx);
+ ret &= test_conflict_different_owner(tctx, ctx);
+
+ return ret;
+}
+
+/*
+ test WINS replication owned conflicts operations
+*/
+static bool torture_nbt_winsreplication_owned(struct torture_context *tctx)
+{
+ const char *address;
+ struct nbt_name name;
+ bool ret = true;
+ struct test_wrepl_conflict_conn *ctx;
+
+ if (torture_setting_bool(tctx, "quick", false))
+ torture_skip(tctx,
+ "skip NBT-WINSREPLICATION-OWNED test in quick test mode\n");
+
+ if (!torture_nbt_get_name(tctx, &name, &address))
+ return false;
+
+ ctx = test_create_conflict_ctx(tctx, address);
+ torture_assert(tctx, ctx != NULL, "Creating context failed");
+
+ ret &= test_conflict_owned_released_vs_replica(tctx, ctx);
+ ret &= test_conflict_owned_active_vs_replica(tctx, ctx);
+
+ return ret;
+}
+
+/*
+ test simple WINS replication operations
+*/
+struct torture_suite *torture_nbt_winsreplication(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ mem_ctx, "winsreplication");
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_simple_test(suite, "assoc_ctx1",
+ test_assoc_ctx1);
+ tcase->tests->dangerous = true;
+
+ torture_suite_add_simple_test(suite, "assoc_ctx2", test_assoc_ctx2);
+
+ torture_suite_add_simple_test(suite, "wins_replication",
+ test_wins_replication);
+
+ torture_suite_add_simple_test(suite, "replica",
+ torture_nbt_winsreplication_replica);
+
+ torture_suite_add_simple_test(suite, "owned",
+ torture_nbt_winsreplication_owned);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/README b/source4/torture/ndr/README
new file mode 100644
index 0000000..c7c127d
--- /dev/null
+++ b/source4/torture/ndr/README
@@ -0,0 +1,21 @@
+use
+ hexdump -v -e '12/1 "0x%02x, " "\n"' infile|outfile
+
+to import ndr dumps
+
+
+Or use gdb:
+
+(gdb) b dump_printer
+Breakpoint 1 at 0x49c92f: file ../source3/utils/net_printing.c, line 158.
+(gdb) cond 1 strcmp(key_name, "s0bc") == 0
+(gdb) run
+Breakpoint 1, dump_printer (mem_ctx=0x700a20, key_name=0x11fb8f9 "s0bc", data=0x18f93d0 "H\032", length=1284, do_string_conversion=true) at ../source3/utils/net_printing.c:158
+158 printf("found printer: %s\n", key_name);
+
+-> Now use x/<length in byte>bx
+
+(gdb) x/1284bx data
+
+This prints data as hex values. 1284 is the length in byte (see the length
+argument of the function). The b indicates byte.
diff --git a/source4/torture/ndr/atsvc.c b/source4/torture/ndr/atsvc.c
new file mode 100644
index 0000000..0fdbe49
--- /dev/null
+++ b/source4/torture/ndr/atsvc.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for atsvc ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_atsvc.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t jobenum_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x44, 0x00, 0x43, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool jobenum_in_check(struct torture_context *tctx,
+ struct atsvc_JobEnum *r)
+{
+ torture_assert(tctx, r->in.servername != NULL, "servername ptr");
+ torture_assert_str_equal(tctx, r->in.servername, "WIN2KDC1", "servername");
+ torture_assert_int_equal(tctx, r->in.ctr->entries_read, 0, "ctr entries read");
+ torture_assert(tctx, r->in.ctr->first_entry == NULL, "ctr entries first_entry");
+ torture_assert_int_equal(tctx, r->in.preferred_max_len, -1, "preferred max len");
+ torture_assert(tctx, r->in.resume_handle != NULL, "resume handle ptr");
+ torture_assert_int_equal(tctx, *r->in.resume_handle, 0, "resume handle");
+ return true;
+}
+
+static const uint8_t jobenum_out_data[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x28, 0x14, 0x0a, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x13, 0x00, 0x00, 0x40, 0x18, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x00, 0x00,
+ 0x30, 0x18, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0xc0, 0xe4, 0x0a, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x00, 0x00, 0x20, 0x18, 0x0a, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x13, 0x00, 0x00, 0x10, 0x18, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x00, 0x00,
+ 0x00, 0x18, 0x0a, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc0, 0xe4, 0x0a, 0x05,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x00, 0x00, 0xf0, 0x17, 0x0a, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x13, 0x00, 0x00, 0xe0, 0x17, 0x0a, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00,
+ 0x6f, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x62, 0x00, 0x61, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x2e, 0x00,
+ 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00,
+ 0x6f, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x2e, 0x00,
+ 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00,
+ 0x6f, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0xac, 0x34, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool jobenum_out_check(struct torture_context *tctx,
+ struct atsvc_JobEnum *r)
+{
+ torture_assert_int_equal(tctx, r->out.ctr->entries_read, 7, "entries read");
+ torture_assert(tctx, r->out.ctr->first_entry != NULL, "first entry");
+ torture_assert_int_equal(tctx, r->out.ctr->first_entry[0].job_id, 1, "job id");
+ torture_assert_int_equal(tctx, r->out.ctr->first_entry[0].job_time, 84600000, "job time");
+ torture_assert_int_equal(tctx, r->out.ctr->first_entry[0].days_of_week, 0x2, "days of week");
+ torture_assert_int_equal(tctx, r->out.ctr->first_entry[0].flags, 0x13, "flags");
+ torture_assert_str_equal(tctx, r->out.ctr->first_entry[0].command, "foo.exe", "command");
+ torture_assert(tctx, r->out.total_entries != NULL, "total entries ptr");
+ torture_assert_int_equal(tctx, *r->out.total_entries, 7, "total entries");
+ torture_assert(tctx, r->out.resume_handle, "resume handle ptr");
+ torture_assert_int_equal(tctx, *r->out.resume_handle, 0, "resume handle");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+static const uint8_t jobadd_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x44, 0x00, 0x43, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x2e, 0x00,
+ 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00
+};
+
+static bool jobadd_in_check(struct torture_context *tctx,
+ struct atsvc_JobAdd *r)
+{
+ torture_assert_str_equal(tctx, r->in.servername, "WIN2KDC1", "servername");
+ torture_assert_int_equal(tctx, r->in.job_info->job_time, 84600000, "time");
+ torture_assert_int_equal(tctx, r->in.job_info->days_of_month, 0, "days of month");
+ torture_assert_int_equal(tctx, r->in.job_info->days_of_week, 0x2, "days of week");
+ torture_assert_int_equal(tctx, r->in.job_info->flags, 17, "flags");
+ torture_assert_str_equal(tctx, r->in.job_info->command, "foo.exe", "command");
+
+ return true;
+}
+
+static const uint8_t jobadd_out_data[] = {
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool jobadd_out_check(struct torture_context *tctx,
+ struct atsvc_JobAdd *r)
+{
+ torture_assert_int_equal(tctx, *r->out.job_id, 14, "job id");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t jobdel_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x44, 0x00, 0x43, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00
+};
+
+static bool jobdel_in_check(struct torture_context *tctx,
+ struct atsvc_JobDel *r)
+{
+ torture_assert_str_equal(tctx, r->in.servername, "WIN2KDC1", "servername");
+ torture_assert_int_equal(tctx, r->in.min_job_id, 14, "min job id");
+ torture_assert_int_equal(tctx, r->in.max_job_id, 14, "max job id");
+ return true;
+}
+
+static const uint8_t jobdel_out_data[] = {
+ 0xde, 0x0e, 0x00, 0x00
+};
+
+static bool jobdel_out_check(struct torture_context *tctx,
+ struct atsvc_JobDel *r)
+{
+ /* FIXME: Check for unknown code 0x00000ede */
+ return true;
+}
+
+static const uint8_t jobgetinfo_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x44, 0x00, 0x43, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+static bool jobgetinfo_in_check(struct torture_context *tctx,
+ struct atsvc_JobGetInfo *r)
+{
+ torture_assert_str_equal(tctx, r->in.servername, "WIN2KDC1", "servername");
+ torture_assert_int_equal(tctx, r->in.job_id, 1, "job id");
+ return true;
+}
+
+static const uint8_t jobgetinfo_out_data[] = {
+ 0x88, 0xe2, 0x09, 0x00, 0xc0, 0xe4, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x13, 0x09, 0x00, 0x98, 0xe2, 0x09, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x6f, 0x00,
+ 0x6f, 0x00, 0x2e, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool jobgetinfo_out_check(struct torture_context *tctx,
+ struct atsvc_JobGetInfo *r)
+{
+ torture_assert(tctx, *r->out.job_info != NULL, "job info");
+ torture_assert_int_equal(tctx, (*r->out.job_info)->job_time, 84600000, "time");
+ torture_assert_int_equal(tctx, (*r->out.job_info)->days_of_month, 0, "days of month");
+ torture_assert_int_equal(tctx, (*r->out.job_info)->days_of_week, 0x2, "days of week");
+ torture_assert_int_equal(tctx, (*r->out.job_info)->flags, 0x13, "flags");
+ torture_assert_str_equal(tctx, (*r->out.job_info)->command, "foo.exe", "command");
+ return true;
+}
+
+struct torture_suite *ndr_atsvc_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "atsvc");
+
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobEnum, jobenum_in_data, NDR_IN, jobenum_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobEnum, jobenum_out_data, NDR_OUT, jobenum_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobAdd, jobadd_in_data, NDR_IN, jobadd_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobAdd, jobadd_out_data, NDR_OUT, jobadd_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobDel, jobdel_in_data, NDR_IN, jobdel_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobDel, jobdel_out_data, NDR_OUT, jobdel_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobGetInfo, jobgetinfo_in_data, NDR_IN, jobgetinfo_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, atsvc_JobGetInfo, jobgetinfo_out_data, NDR_OUT, jobgetinfo_out_check );
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/backupkey.c b/source4/torture/ndr/backupkey.c
new file mode 100644
index 0000000..1be9229
--- /dev/null
+++ b/source4/torture/ndr/backupkey.c
@@ -0,0 +1,163 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for ndr on backupkey
+
+ Copyright (C) Matthieu Patou 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_backupkey.h"
+#include "torture/ndr/proto.h"
+
+
+static const uint8_t exported_rsa_ndr[] = {
+0x02, 0x00, 0x00, 0x00, 0x94, 0x04, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00,
+0x00, 0xa4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+0x21, 0x5d, 0x57, 0xa5, 0x84, 0xfc, 0xf4, 0x89, 0x47, 0x27, 0xfe, 0x71, 0xc1, 0x7b, 0x27, 0xb1,
+0xfd, 0xe4, 0x1d, 0x7d, 0x0f, 0xe8, 0xdd, 0xc1, 0xe2, 0x95, 0x4e, 0x4a, 0xdb, 0xc7, 0x27, 0x31,
+0xbd, 0x22, 0xd7, 0xfe, 0x42, 0x12, 0x94, 0x17, 0x5e, 0x94, 0x0e, 0xc6, 0xa5, 0xef, 0xf8, 0x20,
+0x0a, 0x0f, 0xc7, 0xbf, 0x79, 0x1d, 0x12, 0x98, 0x7a, 0x21, 0xfc, 0x37, 0x9a, 0xe6, 0xec, 0x02,
+0xf6, 0xdf, 0x08, 0x49, 0x62, 0xd2, 0xee, 0x37, 0xe4, 0x1c, 0x95, 0x05, 0xd2, 0xdf, 0x8b, 0x85,
+0x80, 0x5f, 0xcb, 0x3f, 0x70, 0xb9, 0xf1, 0xf3, 0x4f, 0x8f, 0x6d, 0x73, 0xc9, 0x15, 0x2c, 0x97,
+0xb2, 0x2c, 0x17, 0x6d, 0x8b, 0xe7, 0x9a, 0x58, 0x2c, 0xcb, 0xd0, 0x06, 0x5f, 0x48, 0x49, 0xf8,
+0x80, 0x13, 0x25, 0x05, 0x2a, 0x5a, 0x71, 0x01, 0x39, 0x36, 0x89, 0x80, 0x70, 0xdb, 0x57, 0x1a,
+0xe3, 0xd7, 0xcc, 0xbd, 0x9d, 0x1f, 0x1d, 0x92, 0x60, 0x63, 0x78, 0x57, 0xd0, 0x36, 0x42, 0x07,
+0x7c, 0xdc, 0x58, 0x32, 0x6c, 0xa6, 0xfd, 0xc0, 0x85, 0x19, 0x5f, 0x32, 0x7b, 0xd6, 0x40, 0xa9,
+0xf5, 0x1a, 0x9f, 0xec, 0x7a, 0x59, 0x10, 0x71, 0xaa, 0x22, 0x39, 0x34, 0xe1, 0xd3, 0x5b, 0x0f,
+0x39, 0xd8, 0x57, 0xba, 0x59, 0x5f, 0xf3, 0xdd, 0x4d, 0x36, 0xde, 0xdc, 0x2c, 0xd3, 0x30, 0x6b,
+0x55, 0xaa, 0x5a, 0x51, 0xf6, 0xef, 0x42, 0x5c, 0x01, 0x26, 0x2b, 0x42, 0xd3, 0xf4, 0x9c, 0x6b,
+0x56, 0xb0, 0xd3, 0x80, 0x77, 0xb5, 0x80, 0xf3, 0x89, 0xbf, 0xc3, 0xd7, 0x71, 0x2e, 0x47, 0x3e,
+0x86, 0x84, 0xec, 0x9f, 0xa0, 0x38, 0xbb, 0xe9, 0xce, 0x34, 0x7d, 0x9e, 0xf7, 0xf5, 0xe8, 0xfd,
+0x90, 0x5b, 0xc1, 0x97, 0x2b, 0x08, 0x55, 0x4a, 0x57, 0x69, 0xfc, 0xd7, 0x26, 0x32, 0xd7, 0xaa,
+0x7d, 0x66, 0x4f, 0x4d, 0x46, 0xcb, 0xc9, 0x83, 0x92, 0xd9, 0x56, 0xac, 0xb0, 0x5c, 0x0a, 0xd9,
+0xeb, 0x38, 0xae, 0x24, 0x9a, 0xb0, 0x7d, 0x3c, 0x56, 0x0b, 0xbf, 0xca, 0xa9, 0xbc, 0x75, 0xad,
+0x27, 0x2f, 0x9d, 0x16, 0xb5, 0xe5, 0xf3, 0xac, 0x5e, 0x0d, 0xe1, 0x9f, 0x67, 0xb9, 0x8d, 0xeb,
+0x8a, 0xea, 0x2a, 0x00, 0xa5, 0x09, 0x35, 0x7b, 0xcc, 0xeb, 0x00, 0xdb, 0x46, 0x49, 0xac, 0x3c,
+0x00, 0x7a, 0x1e, 0x31, 0x21, 0x66, 0x7b, 0xe6, 0x10, 0x04, 0x2b, 0x39, 0x21, 0xa9, 0xe3, 0xa0,
+0x81, 0x9e, 0xeb, 0xbe, 0x04, 0xe6, 0xd4, 0x23, 0xdc, 0xca, 0x01, 0xd3, 0xfa, 0x73, 0xba, 0x75,
+0x67, 0x61, 0x7d, 0x95, 0x12, 0x14, 0x4d, 0x1e, 0x08, 0x60, 0x0f, 0xbb, 0x06, 0xcf, 0xdc, 0x1c,
+0x07, 0x3c, 0x61, 0xd9, 0x54, 0xc8, 0xca, 0x31, 0x1c, 0x5d, 0xc4, 0xf1, 0x01, 0x59, 0xfd, 0xdb,
+0x75, 0x7e, 0xcc, 0xd0, 0xe7, 0x0a, 0x9a, 0x36, 0x1e, 0xc5, 0xf9, 0x95, 0x83, 0x4d, 0x3e, 0x47,
+0x2e, 0x70, 0x12, 0x4e, 0x0e, 0x07, 0xe4, 0x56, 0x6f, 0xe7, 0xed, 0xbd, 0xe4, 0x48, 0x50, 0x0b,
+0xa6, 0x49, 0x80, 0x1c, 0x85, 0xe7, 0x92, 0x02, 0x4d, 0xfa, 0xe3, 0x6d, 0x1f, 0xc1, 0xf7, 0xf9,
+0xd0, 0x37, 0x68, 0x33, 0x85, 0x20, 0x71, 0x9c, 0xc2, 0xaa, 0x58, 0x47, 0xae, 0x39, 0x1b, 0x20,
+0x3f, 0xc1, 0x90, 0x7c, 0x3d, 0xee, 0xc9, 0x9e, 0x1b, 0x07, 0xd3, 0x0a, 0x13, 0xd1, 0xca, 0x53,
+0xd0, 0x2a, 0xf6, 0x2c, 0xa9, 0xd8, 0xef, 0xe3, 0xe0, 0x24, 0x3f, 0xf9, 0x13, 0xe3, 0xf1, 0xff,
+0x7b, 0x47, 0x59, 0x09, 0xd5, 0x6d, 0x52, 0x95, 0x87, 0xcb, 0x44, 0x6e, 0xe8, 0xaa, 0x0c, 0xe4,
+0xd1, 0xb3, 0xc9, 0xd8, 0xc0, 0xcf, 0x2b, 0x53, 0xf7, 0x8e, 0x93, 0xe9, 0xd8, 0x42, 0xce, 0xc6,
+0x01, 0x67, 0x73, 0x44, 0x5a, 0x65, 0x36, 0x96, 0x9f, 0xd1, 0xfc, 0x03, 0x9b, 0xd1, 0x0d, 0x02,
+0xc7, 0x1e, 0xe4, 0x93, 0xa6, 0x00, 0x6e, 0xfe, 0x6f, 0x8e, 0xf1, 0x93, 0x97, 0xdf, 0x28, 0xee,
+0x3e, 0x07, 0xa1, 0x38, 0xe1, 0x1b, 0xa8, 0x77, 0x78, 0x0d, 0x86, 0x39, 0x20, 0xcb, 0x71, 0xd8,
+0x2a, 0x63, 0x63, 0x00, 0xdf, 0x6e, 0xea, 0x44, 0xf1, 0xdc, 0x2e, 0xf0, 0x81, 0x41, 0x92, 0x55,
+0xce, 0x2d, 0x7c, 0xc4, 0x7f, 0x94, 0xef, 0xc9, 0xe4, 0x26, 0x15, 0x7e, 0x59, 0x9b, 0xd0, 0x10,
+0x64, 0xa6, 0x2e, 0xf7, 0x71, 0xcc, 0x5b, 0xcd, 0xa2, 0xf3, 0xe7, 0xe5, 0x56, 0xd0, 0x9d, 0xd0,
+0xaf, 0x31, 0xfc, 0x08, 0xd6, 0xff, 0x87, 0xca, 0x27, 0xa9, 0xf0, 0xf1, 0xf8, 0x2d, 0x8d, 0x1c,
+0xce, 0x48, 0xc9, 0x60, 0x50, 0x58, 0x56, 0x31, 0x6f, 0xa0, 0xbf, 0x8d, 0xf5, 0xcd, 0x3e, 0x0c,
+0x11, 0xfc, 0x5c, 0x0b, 0xe3, 0x77, 0x9e, 0x44, 0x1e, 0x1d, 0xda, 0x67, 0x8a, 0x40, 0xf2, 0x89,
+0x94, 0xd5, 0xec, 0xc9, 0xf6, 0xe8, 0xc5, 0x81, 0xd9, 0x28, 0x8b, 0x3f, 0x13, 0xc5, 0x0e, 0x3d,
+0x7f, 0x81, 0x97, 0xac, 0x52, 0xee, 0xbb, 0xcb, 0xbb, 0x3d, 0x86, 0x35, 0x1f, 0x31, 0x1a, 0x97,
+0x54, 0xf5, 0x04, 0xb4, 0x24, 0x21, 0x4e, 0xea, 0x05, 0xf3, 0x6d, 0x08, 0x20, 0xb5, 0xf7, 0x37,
+0xf6, 0xd3, 0xff, 0x57, 0x7e, 0x85, 0xf1, 0x66, 0xba, 0xed, 0xf1, 0xe9, 0xbd, 0x5b, 0x91, 0xb2,
+0x89, 0xe8, 0xdb, 0xac, 0x5b, 0x58, 0xa9, 0x0f, 0x03, 0x18, 0x38, 0x55, 0x80, 0x19, 0x04, 0x0d,
+0xa8, 0x91, 0x8b, 0x3c, 0x65, 0x23, 0x78, 0xbc, 0x0e, 0x5b, 0xc5, 0x80, 0x6e, 0xad, 0x1f, 0x97,
+0x28, 0xe5, 0x57, 0xff, 0xc9, 0x06, 0x7d, 0xa8, 0xbe, 0x65, 0xfc, 0xcd, 0x99, 0x04, 0x3a, 0x36,
+0xe3, 0xe8, 0x41, 0xd5, 0x9b, 0x13, 0x98, 0xf6, 0x76, 0xfb, 0x23, 0x6b, 0x9f, 0x2b, 0xdb, 0x06,
+0x25, 0xf3, 0x72, 0x33, 0x35, 0x92, 0x51, 0xb6, 0x49, 0x98, 0xee, 0x48, 0xc8, 0xad, 0x7b, 0x87,
+0x4a, 0x3d, 0x86, 0x69, 0x1b, 0xd3, 0x15, 0xe3, 0x6c, 0xe9, 0x83, 0x73, 0x3b, 0x0f, 0x0d, 0x0e,
+0xe2, 0x9c, 0xfe, 0xe6, 0xc0, 0x4d, 0xb9, 0xe4, 0x89, 0x56, 0x9d, 0xc0, 0x7a, 0x0c, 0xed, 0x1a,
+0x70, 0x1f, 0x2c, 0x73, 0x05, 0x22, 0x19, 0x2c, 0x70, 0x94, 0x73, 0x3d, 0x91, 0xee, 0x2d, 0xff,
+0x9c, 0x50, 0x94, 0x7b, 0x85, 0xaa, 0x42, 0xc0, 0xc9, 0xbf, 0xdc, 0xc5, 0x29, 0xaf, 0xca, 0x93,
+0x43, 0xcc, 0xc8, 0x0c, 0x3e, 0x91, 0xce, 0xcd, 0x93, 0xe6, 0x0f, 0x76, 0xcc, 0x56, 0x7a, 0x44,
+0x7c, 0x9d, 0x6b, 0xb6, 0x2d, 0xf7, 0x01, 0x3a, 0x72, 0xfb, 0x85, 0x2a, 0x37, 0xf2, 0x33, 0x0c,
+0xc1, 0x2a, 0xb4, 0x6b, 0x4f, 0xdf, 0xcd, 0x78, 0xf8, 0x18, 0xd6, 0x1e, 0xb9, 0x2e, 0x17, 0xf5,
+0xcb, 0x0e, 0xca, 0xc3, 0xf0, 0x5b, 0x2d, 0x61, 0x7b, 0xef, 0x37, 0xd7, 0x35, 0xf7, 0x90, 0x30,
+0x64, 0x46, 0x43, 0x94, 0x56, 0x5b, 0xd1, 0x10, 0x10, 0xae, 0xa4, 0x20, 0xce, 0xb3, 0x91, 0x31,
+0xbc, 0x06, 0xf2, 0xbc, 0xa0, 0x66, 0x52, 0xb5, 0xd3, 0x51, 0x6e, 0x24, 0x63, 0x3d, 0xaa, 0xa9,
+0xa9, 0x8c, 0x74, 0xf3, 0x09, 0xbf, 0x01, 0x3f, 0x48, 0x0e, 0x4a, 0x87, 0x3d, 0x91, 0x96, 0x33,
+0x17, 0x4d, 0x43, 0xe5, 0x71, 0x2c, 0x94, 0x64, 0x39, 0xe9, 0xdb, 0xdb, 0x05, 0x5f, 0x07, 0x38,
+0xa3, 0x36, 0x7b, 0x79, 0x9a, 0x74, 0xf7, 0x0e, 0x15, 0x9f, 0x49, 0x65, 0x2d, 0xf5, 0x85, 0x6c,
+0xc8, 0xbc, 0x42, 0x88, 0x93, 0xd9, 0x40, 0xfa, 0xbf, 0x14, 0x66, 0x68, 0x9e, 0x05, 0x64, 0x38,
+0x4b, 0xb5, 0x97, 0x2c, 0x48, 0x90, 0x09, 0x8e, 0x60, 0xc0, 0x56, 0xd6, 0x44, 0x2f, 0x60, 0xe8,
+0x0f, 0xa5, 0xf3, 0x95, 0xca, 0x9a, 0x09, 0x05, 0x8a, 0x3d, 0xaf, 0x01, 0x71, 0x66, 0x68, 0xa5,
+0x06, 0x6e, 0x95, 0x33, 0x46, 0x9d, 0x45, 0xcb, 0x2c, 0xdd, 0x05, 0x8d, 0xbb, 0x8f, 0xa7, 0x5b,
+0xec, 0x0b, 0x17, 0x54, 0xe3, 0xd0, 0x7d, 0xb9, 0x23, 0x77, 0xf3, 0xc6, 0x3e, 0x69, 0x2a, 0xf9,
+0xe9, 0xcf, 0x83, 0xc4, 0x09, 0xa5, 0x2a, 0xd9, 0xb3, 0x4e, 0x3f, 0x16, 0x7d, 0xf7, 0x8f, 0xb3,
+0xd0, 0x64, 0x2b, 0xc3, 0x0e, 0xb1, 0xf3, 0xdb, 0xe6, 0x4a, 0x7e, 0xf9, 0x3b, 0xc9, 0xca, 0x14,
+0x9d, 0xf2, 0x61, 0xc3, 0x59, 0x05, 0xcf, 0x0d, 0x13, 0xcf, 0x2e, 0xa9, 0xa6, 0x59, 0x30, 0xa6,
+0xef, 0x3a, 0x43, 0xbb, 0x63, 0x6f, 0x31, 0x7a, 0xfa, 0x38, 0x0d, 0xb1, 0x17, 0x4d, 0xc2, 0xa4,
+0x30, 0x82, 0x03, 0x00, 0x30, 0x82, 0x01, 0xec, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0xbd,
+0x76, 0xdf, 0x42, 0x47, 0x0a, 0x00, 0x8d, 0x47, 0x3e, 0x74, 0x3f, 0xa1, 0xdc, 0x8b, 0xbd, 0x30,
+0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x2d, 0x31, 0x2b, 0x30, 0x29,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x72,
+0x00, 0x32, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x77, 0x00, 0x73, 0x00, 0x2e,
+0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30,
+0x34, 0x32, 0x38, 0x31, 0x31, 0x34, 0x31, 0x35, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x34,
+0x32, 0x38, 0x31, 0x31, 0x34, 0x31, 0x35, 0x34, 0x5a, 0x30, 0x2d, 0x31, 0x2b, 0x30, 0x29, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x72, 0x00,
+0x32, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x77, 0x00, 0x73, 0x00, 0x2e, 0x00,
+0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0xd7, 0x32, 0x26, 0xd7, 0xfc, 0x69,
+0x57, 0x4a, 0x55, 0x08, 0x2b, 0x97, 0xc1, 0x5b, 0x90, 0xfd, 0xe8, 0xf5, 0xf7, 0x9e, 0x7d, 0x34,
+0xce, 0xe9, 0xbb, 0x38, 0xa0, 0x9f, 0xec, 0x84, 0x86, 0x3e, 0x47, 0x2e, 0x71, 0xd7, 0xc3, 0xbf,
+0x89, 0xf3, 0x80, 0xb5, 0x77, 0x80, 0xd3, 0xb0, 0x56, 0x6b, 0x9c, 0xf4, 0xd3, 0x42, 0x2b, 0x26,
+0x01, 0x5c, 0x42, 0xef, 0xf6, 0x51, 0x5a, 0xaa, 0x55, 0x6b, 0x30, 0xd3, 0x2c, 0xdc, 0xde, 0x36,
+0x4d, 0xdd, 0xf3, 0x5f, 0x59, 0xba, 0x57, 0xd8, 0x39, 0x0f, 0x5b, 0xd3, 0xe1, 0x34, 0x39, 0x22,
+0xaa, 0x71, 0x10, 0x59, 0x7a, 0xec, 0x9f, 0x1a, 0xf5, 0xa9, 0x40, 0xd6, 0x7b, 0x32, 0x5f, 0x19,
+0x85, 0xc0, 0xfd, 0xa6, 0x6c, 0x32, 0x58, 0xdc, 0x7c, 0x07, 0x42, 0x36, 0xd0, 0x57, 0x78, 0x63,
+0x60, 0x92, 0x1d, 0x1f, 0x9d, 0xbd, 0xcc, 0xd7, 0xe3, 0x1a, 0x57, 0xdb, 0x70, 0x80, 0x89, 0x36,
+0x39, 0x01, 0x71, 0x5a, 0x2a, 0x05, 0x25, 0x13, 0x80, 0xf8, 0x49, 0x48, 0x5f, 0x06, 0xd0, 0xcb,
+0x2c, 0x58, 0x9a, 0xe7, 0x8b, 0x6d, 0x17, 0x2c, 0xb2, 0x97, 0x2c, 0x15, 0xc9, 0x73, 0x6d, 0x8f,
+0x4f, 0xf3, 0xf1, 0xb9, 0x70, 0x3f, 0xcb, 0x5f, 0x80, 0x85, 0x8b, 0xdf, 0xd2, 0x05, 0x95, 0x1c,
+0xe4, 0x37, 0xee, 0xd2, 0x62, 0x49, 0x08, 0xdf, 0xf6, 0x02, 0xec, 0xe6, 0x9a, 0x37, 0xfc, 0x21,
+0x7a, 0x98, 0x12, 0x1d, 0x79, 0xbf, 0xc7, 0x0f, 0x0a, 0x20, 0xf8, 0xef, 0xa5, 0xc6, 0x0e, 0x94,
+0x5e, 0x17, 0x94, 0x12, 0x42, 0xfe, 0xd7, 0x22, 0xbd, 0x31, 0x27, 0xc7, 0xdb, 0x4a, 0x4e, 0x95,
+0xe2, 0xc1, 0xdd, 0xe8, 0x0f, 0x7d, 0x1d, 0xe4, 0xfd, 0xb1, 0x27, 0x7b, 0xc1, 0x71, 0xfe, 0x27,
+0x47, 0x89, 0xf4, 0xfc, 0x84, 0xa5, 0x57, 0x5d, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0x81, 0x11,
+0x00, 0xbd, 0x8b, 0xdc, 0xa1, 0x3f, 0x74, 0x3e, 0x47, 0x8d, 0x00, 0x0a, 0x47, 0x42, 0xdf, 0x76,
+0xbd, 0x82, 0x11, 0x00, 0xbd, 0x8b, 0xdc, 0xa1, 0x3f, 0x74, 0x3e, 0x47, 0x8d, 0x00, 0x0a, 0x47,
+0x42, 0xdf, 0x76, 0xbd, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x01, 0x00, 0xa7, 0xb0, 0x66, 0x75, 0x14, 0x7e, 0x7d, 0xb5, 0x31, 0xec, 0xb2, 0xeb,
+0x90, 0x80, 0x95, 0x25, 0x59, 0x0f, 0xe4, 0x15, 0x86, 0x2d, 0x9d, 0xd7, 0x35, 0xe9, 0x22, 0x74,
+0xe7, 0x85, 0x36, 0x19, 0x4f, 0x27, 0x5c, 0x17, 0x63, 0x7b, 0x2a, 0xfe, 0x59, 0xe9, 0x76, 0x77,
+0xd0, 0xc9, 0x40, 0x78, 0x7c, 0x31, 0x62, 0x1e, 0x87, 0x1b, 0xc1, 0x19, 0xef, 0x6f, 0x15, 0xe6,
+0xce, 0x74, 0x84, 0x6d, 0xd6, 0x3b, 0x57, 0xd9, 0xa9, 0x13, 0xf6, 0x7d, 0x84, 0xe7, 0x8f, 0xc6,
+0x01, 0x5f, 0xcf, 0xc4, 0x95, 0xc9, 0xde, 0x97, 0x17, 0x43, 0x12, 0x70, 0x27, 0xf9, 0xc4, 0xd7,
+0xe1, 0x05, 0xbb, 0x63, 0x87, 0x5f, 0xdc, 0x20, 0xbd, 0xd1, 0xde, 0xd6, 0x2d, 0x9f, 0x3f, 0x5d,
+0x0a, 0x27, 0x40, 0x11, 0x5f, 0x5d, 0x54, 0xa7, 0x28, 0xf9, 0x03, 0x2e, 0x84, 0x8d, 0x48, 0x60,
+0xa1, 0x71, 0xa3, 0x46, 0x69, 0xdb, 0x88, 0x7b, 0xc1, 0xb6, 0x08, 0x2d, 0xdf, 0x25, 0x9d, 0x32,
+0x76, 0x49, 0x0b, 0xba, 0xab, 0xdd, 0xc3, 0x00, 0x76, 0x8a, 0x94, 0xd2, 0x25, 0x43, 0xf0, 0xa9,
+0x98, 0x65, 0x94, 0xc7, 0xdd, 0x7c, 0xd4, 0xe2, 0xe8, 0x33, 0xe2, 0x9a, 0xe9, 0x75, 0xf0, 0x0f,
+0x61, 0x86, 0xee, 0x0e, 0xf7, 0x39, 0x6b, 0x30, 0x63, 0xe5, 0x46, 0xd4, 0x1c, 0x83, 0xa1, 0x28,
+0x79, 0x76, 0x81, 0x48, 0x38, 0x72, 0xbc, 0x3f, 0x25, 0x53, 0x31, 0xaa, 0x02, 0xd1, 0x9b, 0x03,
+0xa2, 0x5c, 0x94, 0x21, 0xb3, 0x8e, 0xdf, 0x2a, 0xa5, 0x4c, 0x65, 0xa2, 0xf9, 0xac, 0x38, 0x7a,
+0xf9, 0x45, 0xb3, 0xd5, 0xda, 0xe5, 0xb9, 0x56, 0x9e, 0x47, 0xd5, 0x06, 0xe6, 0xca, 0xd7, 0x6e,
+0x06, 0xdb, 0x6e, 0xa7, 0x7b, 0x4b, 0x13, 0x40, 0x3c, 0x12, 0x76, 0x99, 0x65, 0xb4, 0x54, 0xa1,
+0xd8, 0x21, 0x5c, 0x27
+};
+
+struct torture_suite *ndr_backupkey_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "backupkey");
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ bkrp_exported_RSA_key_pair,
+ exported_rsa_ndr,
+ NULL);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/cabinet.c b/source4/torture/ndr/cabinet.c
new file mode 100644
index 0000000..5b93108
--- /dev/null
+++ b/source4/torture/ndr/cabinet.c
@@ -0,0 +1,4335 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for Windows Cabinet files
+
+ Copyright (C) Guenther Deschner 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_cab.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t cab_file_plain_data[] = {
+ 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x51, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49,
+ 0x09, 0x21, 0x20, 0x00, 0x62, 0x6c, 0x6f, 0x62,
+ 0x2d, 0x41, 0x2d, 0x33, 0x32, 0x37, 0x36, 0x38,
+ 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41
+};
+
+static bool cab_file_plain_check(struct torture_context *tctx,
+ struct cab_file *r)
+{
+ DATA_BLOB blob;
+
+ torture_assert_str_equal(tctx, r->cfheader.signature, "MSCF", "signature");
+ torture_assert_int_equal(tctx, r->cfheader.reserved1, 0, "reserved1");
+ torture_assert_int_equal(tctx, r->cfheader.cbCabinet, 0x8051, "cbCabinet");
+ torture_assert_int_equal(tctx, r->cfheader.reserved2, 0, "reserved2");
+ torture_assert_int_equal(tctx, r->cfheader.coffFiles, 44, "coffFiles");
+ torture_assert_int_equal(tctx, r->cfheader.reserved3, 0, "reserved3");
+ torture_assert_int_equal(tctx, r->cfheader.versionMinor, 3, "versionMinor");
+ torture_assert_int_equal(tctx, r->cfheader.versionMajor, 1, "versionMajor");
+ torture_assert_int_equal(tctx, r->cfheader.cFolders, 1, "cFolders");
+ torture_assert_int_equal(tctx, r->cfheader.cFiles, 1, "cFiles");
+ torture_assert_int_equal(tctx, r->cfheader.flags, 0, "flags");
+ torture_assert_int_equal(tctx, r->cfheader.setID, 0, "setID");
+ torture_assert_int_equal(tctx, r->cfheader.iCabinet, 0, "iCabinet");
+
+ torture_assert_int_equal(tctx, r->cffolders[0].coffCabStart, 0x49, "coffCabStart");
+ torture_assert_int_equal(tctx, r->cffolders[0].cCFData, 1, "cCFData");
+ torture_assert_int_equal(tctx, r->cffolders[0].typeCompress, CF_COMPRESS_NONE, "typeCompress");
+
+ torture_assert_int_equal(tctx, r->cffiles[0].cbFile, 0x8000, "cbFile");
+ torture_assert_int_equal(tctx, r->cffiles[0].uoffFolderStart, 0, "uoffFolderStart");
+ torture_assert_int_equal(tctx, r->cffiles[0].iFolder, 0, "iFolder");
+ torture_assert_int_equal(tctx, r->cffiles[0].date.date, 0x4936, "date");
+ torture_assert_int_equal(tctx, r->cffiles[0].time.time, 0x2109, "time");
+ torture_assert_int_equal(tctx, r->cffiles[0].attribs, 0x0020, "attribs");
+ torture_assert_str_equal(tctx, r->cffiles[0].szName, "blob-A-32768", "szName");
+
+ torture_assert_int_equal(tctx, r->cfdata[0].csum, 0x80008000, "csum");
+ torture_assert_int_equal(tctx, r->cfdata[0].cbData, 0x8000, "cbData");
+ torture_assert_int_equal(tctx, r->cfdata[0].cbUncomp, 0x8000, "cbUncomp");
+
+ blob = data_blob(NULL, r->cfdata[0].cbUncomp);
+ memset(blob.data, 'A', blob.length);
+
+ torture_assert_data_blob_equal(tctx, r->cfdata[0].ab, blob, "ab");
+
+ data_blob_free(&blob);
+
+ return true;
+}
+
+static const uint8_t cab_file_MSZIP_data[] = {
+ 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49,
+ 0x09, 0x21, 0x20, 0x00, 0x62, 0x6c, 0x6f, 0x62,
+ 0x2d, 0x41, 0x2d, 0x33, 0x32, 0x37, 0x36, 0x38,
+ 0x00, 0x16, 0x6e, 0xdb, 0x5e, 0x31, 0x00, 0x00,
+ 0x80, 0x43, 0x4b, 0xed, 0xc1, 0x81, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x20, 0xb6, 0xfd, 0xa5, 0x16,
+ 0xa9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1a
+};
+
+static bool cab_file_MSZIP_check(struct torture_context *tctx,
+ struct cab_file *r)
+{
+ DATA_BLOB blob;
+
+ torture_assert_str_equal(tctx, r->cfheader.signature, "MSCF", "signature");
+ torture_assert_int_equal(tctx, r->cfheader.reserved1, 0, "reserved1");
+ torture_assert_int_equal(tctx, r->cfheader.cbCabinet, 130, "cbCabinet");
+ torture_assert_int_equal(tctx, r->cfheader.reserved2, 0, "reserved2");
+ torture_assert_int_equal(tctx, r->cfheader.coffFiles, 44, "coffFiles");
+ torture_assert_int_equal(tctx, r->cfheader.reserved3, 0, "reserved3");
+ torture_assert_int_equal(tctx, r->cfheader.versionMinor, 3, "versionMinor");
+ torture_assert_int_equal(tctx, r->cfheader.versionMajor, 1, "versionMajor");
+ torture_assert_int_equal(tctx, r->cfheader.cFolders, 1, "cFolders");
+ torture_assert_int_equal(tctx, r->cfheader.cFiles, 1, "cFiles");
+ torture_assert_int_equal(tctx, r->cfheader.flags, 0, "flags");
+ torture_assert_int_equal(tctx, r->cfheader.setID, 0, "setID");
+ torture_assert_int_equal(tctx, r->cfheader.iCabinet, 0, "iCabinet");
+
+ torture_assert_int_equal(tctx, r->cffolders[0].coffCabStart, 0x49, "coffCabStart");
+ torture_assert_int_equal(tctx, r->cffolders[0].cCFData, 1, "cCFData");
+ torture_assert_int_equal(tctx, r->cffolders[0].typeCompress, CF_COMPRESS_MSZIP, "typeCompress");
+
+ torture_assert_int_equal(tctx, r->cffiles[0].cbFile, 0x8000, "cbFile");
+ torture_assert_int_equal(tctx, r->cffiles[0].uoffFolderStart, 0, "uoffFolderStart");
+ torture_assert_int_equal(tctx, r->cffiles[0].iFolder, 0, "iFolder");
+ torture_assert_int_equal(tctx, r->cffiles[0].date.date, 0x4936, "date");
+ torture_assert_int_equal(tctx, r->cffiles[0].time.time, 0x2109, "time");
+ torture_assert_int_equal(tctx, r->cffiles[0].attribs, 0x0020, "attribs");
+ torture_assert_str_equal(tctx, r->cffiles[0].szName, "blob-A-32768", "szName");
+
+ torture_assert_int_equal(tctx, r->cfdata[0].csum, 0x5EDB6E16, "csum");
+ torture_assert_int_equal(tctx, r->cfdata[0].cbData, 0x31, "cbData");
+ torture_assert_int_equal(tctx, r->cfdata[0].cbUncomp, 0x8000, "cbUncomp");
+
+ blob = data_blob(NULL, r->cfdata[0].cbUncomp);
+ memset(blob.data, 'A', blob.length);
+
+ torture_assert_data_blob_equal(tctx, r->cfdata[0].ab, blob, "ab");
+
+ data_blob_free(&blob);
+
+ return true;
+}
+
+static const uint8_t cab_file_LZX_data[] = {
+ 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00,
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x03, 0x12, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49,
+ 0x09, 0x21, 0x20, 0x00, 0x62, 0x6c, 0x6f, 0x62,
+ 0x2d, 0x41, 0x2d, 0x33, 0x32, 0x37, 0x36, 0x38,
+ 0x00, 0xa2, 0x60, 0x8d, 0x04, 0x58, 0x00, 0x00,
+ 0x80, 0x5b, 0x80, 0x80, 0x8d, 0x08, 0x10, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x07, 0x31, 0xd9, 0xfc, 0xdf, 0xf7, 0x20,
+ 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
+ 0x00, 0xe5, 0x10, 0xdf, 0x67, 0xf7, 0x7d, 0x88,
+ 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
+ 0x00, 0x1f, 0xc4, 0xdd, 0x7f, 0x7c, 0x9f, 0x3f,
+ 0x6b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
+ 0xff
+};
+
+static bool cab_file_LZX_check(struct torture_context *tctx,
+ struct cab_file *r)
+{
+ DATA_BLOB blob;
+
+ torture_assert_str_equal(tctx, r->cfheader.signature, "MSCF", "signature");
+ torture_assert_int_equal(tctx, r->cfheader.reserved1, 0, "reserved1");
+ torture_assert_int_equal(tctx, r->cfheader.cbCabinet, 0xA9, "cbCabinet");
+ torture_assert_int_equal(tctx, r->cfheader.reserved2, 0, "reserved2");
+ torture_assert_int_equal(tctx, r->cfheader.coffFiles, 44, "coffFiles");
+ torture_assert_int_equal(tctx, r->cfheader.reserved3, 0, "reserved3");
+ torture_assert_int_equal(tctx, r->cfheader.versionMinor, 3, "versionMinor");
+ torture_assert_int_equal(tctx, r->cfheader.versionMajor, 1, "versionMajor");
+ torture_assert_int_equal(tctx, r->cfheader.cFolders, 1, "cFolders");
+ torture_assert_int_equal(tctx, r->cfheader.cFiles, 1, "cFiles");
+ torture_assert_int_equal(tctx, r->cfheader.flags, 0, "flags");
+ torture_assert_int_equal(tctx, r->cfheader.setID, 0, "setID");
+ torture_assert_int_equal(tctx, r->cfheader.iCabinet, 0, "iCabinet");
+
+ torture_assert_int_equal(tctx, r->cffolders[0].coffCabStart, 0x49, "coffCabStart");
+ torture_assert_int_equal(tctx, r->cffolders[0].cCFData, 1, "cCFData");
+ torture_assert_int_equal(tctx, r->cffolders[0].typeCompress, 4611, "typeCompress");
+
+ torture_assert_int_equal(tctx, r->cffiles[0].cbFile, 0x8000, "cbFile");
+ torture_assert_int_equal(tctx, r->cffiles[0].uoffFolderStart, 0, "uoffFolderStart");
+ torture_assert_int_equal(tctx, r->cffiles[0].iFolder, 0, "iFolder");
+ torture_assert_int_equal(tctx, r->cffiles[0].date.date, 0x4936, "date");
+ torture_assert_int_equal(tctx, r->cffiles[0].time.time, 0x2109, "time");
+ torture_assert_int_equal(tctx, r->cffiles[0].attribs, 0x0020, "attribs");
+ torture_assert_str_equal(tctx, r->cffiles[0].szName, "blob-A-32768", "szName");
+
+ torture_assert_int_equal(tctx, r->cfdata[0].csum, 0x48D60A2, "csum");
+ torture_assert_int_equal(tctx, r->cfdata[0].cbData, 0x58, "cbData");
+ torture_assert_int_equal(tctx, r->cfdata[0].cbUncomp, 0x8000, "cbUncomp");
+
+ blob = data_blob(NULL, r->cfdata[0].cbUncomp);
+ memset(blob.data, 'A', blob.length);
+#if 0
+ /* once we have LZX compression support we can enable this test */
+ torture_assert_data_blob_equal(tctx, r->cfdata[0].ab, blob, "ab");
+#endif
+ data_blob_free(&blob);
+
+ return true;
+}
+
+struct torture_suite *ndr_cabinet_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "cabinet");
+
+ torture_suite_add_ndr_pull_test(suite, cab_file, cab_file_plain_data, cab_file_plain_check);
+ torture_suite_add_ndr_pull_test(suite, cab_file, cab_file_MSZIP_data, cab_file_MSZIP_check);
+ torture_suite_add_ndr_pull_test(suite, cab_file, cab_file_LZX_data, cab_file_LZX_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite, cab_file, cab_file_plain_data, cab_file_plain_check);
+
+ /*
+ * we cannot validate, as libz' compression routines currently create a
+ * slightly different result
+ */
+
+ /* torture_suite_add_ndr_pull_validate_test(suite, cab_file, cab_file_MSZIP_data, cab_file_MSZIP_check); */
+
+ return suite;
+}
diff --git a/source4/torture/ndr/charset.c b/source4/torture/ndr/charset.c
new file mode 100644
index 0000000..7062ce1
--- /dev/null
+++ b/source4/torture/ndr/charset.c
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for charset ndr operations
+
+ Copyright (C) Guenther Deschner 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "torture/ndr/proto.h"
+
+static bool test_ndr_push_charset(struct torture_context *tctx)
+{
+ const char *strs[] = {
+ NULL,
+ "",
+ "test"
+ };
+ int i;
+
+ struct ndr_push *ndr;
+
+ ndr = talloc_zero(tctx, struct ndr_push);
+
+ for (i = 0; i < ARRAY_SIZE(strs); i++) {
+
+ enum ndr_err_code expected_ndr_err = NDR_ERR_SUCCESS;
+
+ if (strs[i] == NULL) {
+ expected_ndr_err = NDR_ERR_INVALID_POINTER;
+ }
+
+ torture_assert_ndr_err_equal(tctx,
+ ndr_push_charset(ndr, NDR_SCALARS, strs[i], 256, 2, CH_UTF16LE),
+ expected_ndr_err,
+ "failed to push charset");
+ }
+
+ return true;
+}
+
+static bool test_ndr_push_charset_to_null(struct torture_context *tctx)
+{
+ const char *strs[] = {
+ NULL,
+ "",
+ "test"
+ };
+ int i;
+
+ struct ndr_push *ndr;
+
+ ndr = talloc_zero(tctx, struct ndr_push);
+
+
+ for (i = 0; i < ARRAY_SIZE(strs); i++) {
+
+ torture_assert_ndr_success(tctx,
+ ndr_push_charset_to_null(ndr, NDR_SCALARS, strs[i], 256, 2, CH_UTF16LE),
+ "failed to push charset to null");
+ }
+
+ return true;
+}
+
+
+struct torture_suite *ndr_charset_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "charset");
+
+ suite->description = talloc_strdup(suite, "NDR - charset focused push/pull tests");
+
+ torture_suite_add_simple_test(suite, "push", test_ndr_push_charset);
+ torture_suite_add_simple_test(suite, "push_to_null", test_ndr_push_charset_to_null);
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/clusapi.c b/source4/torture/ndr/clusapi.c
new file mode 100644
index 0000000..db6a27c
--- /dev/null
+++ b/source4/torture/ndr/clusapi.c
@@ -0,0 +1,390 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for clusapi ndr operations
+
+ Copyright (C) Guenther Deschner 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_clusapi.h"
+#include "torture/ndr/proto.h"
+#include "param/param.h"
+#include "libcli/registry/util_reg.h"
+
+static const uint8_t clusapi_PROPERTY_LIST_data[] = {
+ 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x69, 0x00, 0x78, 0x00, 0x51, 0x00, 0x75, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x76, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x51, 0x00,
+ 0x75, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x49, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00,
+ 0x50, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x53, 0x00, 0x74, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x53, 0x00,
+ 0x74, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x53, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x56, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x75, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x52, 0x00, 0x6f, 0x00, 0x6f, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x43, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x43, 0x00, 0x6c, 0x00, 0x75, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x53, 0x00, 0x74, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x69, 0x00, 0x74, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x73, 0x00, 0x44, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00,
+ 0x69, 0x00, 0x63, 0x00, 0x57, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00,
+ 0x68, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x41, 0x00, 0x64, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x41, 0x00, 0x63, 0x00, 0x63, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x50, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool clusapi_PROPERTY_LIST_check(struct torture_context *tctx,
+ struct clusapi_PROPERTY_LIST *r)
+{
+ DATA_BLOB blob_dword_null = data_blob_talloc_zero(tctx, 4);
+ DATA_BLOB blob_dword_one = data_blob(NULL, 4);
+ const char *str;
+
+ SIVAL(blob_dword_one.data, 0, 1);
+
+ torture_assert_int_equal(tctx, r->propertyCount, 6, "propertyCount");
+
+ torture_assert_int_equal(tctx, r->propertyValues[0].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[0].size, 20, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[0].buffer, "FixQuorum", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[0].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[0].PropertyValues.Buffer, blob_dword_null, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[0].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[1].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[1].size, 28, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[1].buffer, "PreventQuorum", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[1].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[1].PropertyValues.Buffer, blob_dword_null, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[1].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[2].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[2].size, 62, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[2].buffer, "IgnorePersistentStateOnStartup", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[2].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[2].PropertyValues.Buffer, blob_dword_null, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[2].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[3].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[3].size, 36, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[3].buffer, "SharedVolumesRoot", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[3].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Size, 36, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Buffer.length, 36, "PropertyValues.Buffer.length");
+ pull_reg_sz(tctx, &r->propertyValues[3].PropertyValues.Buffer, &str);
+ torture_assert_str_equal(tctx, str, "C:\\ClusterStorage", "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[3].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[4].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[4].size, 42, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[4].buffer, "WitnessDynamicWeight", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[4].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[4].PropertyValues.Buffer, blob_dword_one, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[4].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[5].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[5].size, 34, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[5].buffer, "AdminAccessPoint", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[5].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[5].PropertyValues.Buffer, blob_dword_one, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[5].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ data_blob_free(&blob_dword_null);
+ data_blob_free(&blob_dword_one);
+
+ return true;
+}
+
+static const uint8_t clusapi_PROPERTY_LIST_data2[] = {
+ 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x61, 0x00,
+ 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
+ 0x48, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x80, 0x25, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+ 0x64, 0x00, 0x65, 0x00, 0x4c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x80, 0x25, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x61, 0x00,
+ 0x6a, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x4d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x56, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x75, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x43, 0x00, 0x53, 0x00, 0x44, 0x00, 0x56, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
+ 0x49, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00,
+ 0x63, 0x00, 0x65, 0x00, 0x49, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00,
+ 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x44, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x75, 0x00, 0x73, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+ 0x64, 0x00, 0x65, 0x00, 0x44, 0x00, 0x72, 0x00, 0x61, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x54, 0x00, 0x61, 0x00, 0x72, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x61, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x57, 0x00, 0x65, 0x00, 0x69, 0x00,
+ 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x65, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x73, 0x00, 0x50, 0x00, 0x72, 0x00, 0x65, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x51, 0x00, 0x75, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool clusapi_PROPERTY_LIST_check2(struct torture_context *tctx,
+ struct clusapi_PROPERTY_LIST *r)
+{
+ DATA_BLOB blob_dword_null = data_blob_talloc_zero(tctx, 4);
+ DATA_BLOB blob_dword_one = data_blob(NULL, 4);
+ DATA_BLOB blob_dword = data_blob(NULL, 4);
+ const char *str;
+
+ SIVAL(blob_dword_one.data, 0, 1);
+
+ torture_assert_int_equal(tctx, r->propertyCount, 12, "propertyCount");
+
+ torture_assert_int_equal(tctx, r->propertyValues[0].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[0].size, 18, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[0].buffer, "NodeName", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[0].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Size, 12, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Buffer.length, 12, "PropertyValues.Buffer.length");
+ pull_reg_sz(tctx, &r->propertyValues[0].PropertyValues.Buffer, &str);
+ torture_assert_str_equal(tctx, str, "node1", "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[0].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[0].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[1].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[1].size, 38, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[1].buffer, "NodeHighestVersion", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[1].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ SIVAL(blob_dword.data, 0, 0x00082580);
+ torture_assert_data_blob_equal(tctx, r->propertyValues[1].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[1].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[1].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[2].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[2].size, 36, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[2].buffer, "NodeLowestVersion", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[2].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ SIVAL(blob_dword.data, 0, 0x00082580);
+ torture_assert_data_blob_equal(tctx, r->propertyValues[2].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[2].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[2].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[3].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[3].size, 26, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[3].buffer, "MajorVersion", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[3].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ SIVAL(blob_dword.data, 0, 0x06);
+ torture_assert_data_blob_equal(tctx, r->propertyValues[3].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[3].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[3].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[4].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[4].size, 26, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[4].buffer, "MinorVersion", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[4].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ SIVAL(blob_dword.data, 0, 0x03);
+ torture_assert_data_blob_equal(tctx, r->propertyValues[4].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[4].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[4].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[5].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[5].size, 24, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[5].buffer, "BuildNumber", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[5].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ SIVAL(blob_dword.data, 0, 0x00002580);
+ torture_assert_data_blob_equal(tctx, r->propertyValues[5].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[5].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[5].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[6].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[6].size, 22, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[6].buffer, "CSDVersion", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[6].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Size, 2, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Buffer.length, 2, "PropertyValues.Buffer.length");
+ pull_reg_sz(tctx, &r->propertyValues[6].PropertyValues.Buffer, &str);
+ torture_assert_str_equal(tctx, str, "", "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[6].PropertyValues.Padding.length, 2, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[6].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[7].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[7].size, 30, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[7].buffer, "NodeInstanceID", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[7].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_SZ, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Size, 74, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Buffer.length, 74, "PropertyValues.Buffer.length");
+ pull_reg_sz(tctx, &r->propertyValues[7].PropertyValues.Buffer, &str);
+ torture_assert_str_equal(tctx, str, "00000000-0000-0000-0000-000000000002", "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[7].PropertyValues.Padding.length, 2, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[7].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[8].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[8].size, 32, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[8].buffer, "NodeDrainStatus", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[8].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[8].PropertyValues.Buffer, blob_dword_null, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[8].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[8].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[9].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[9].size, 32, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[9].buffer, "NodeDrainTarget", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[9].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ SIVAL(blob_dword.data, 0, 0xffffffff);
+ torture_assert_data_blob_equal(tctx, r->propertyValues[9].PropertyValues.Buffer, blob_dword, "PropertyValues.Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[9].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[9].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[10].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[10].size, 28, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[10].buffer, "DynamicWeight", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[10].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[10].PropertyValues.Buffer, blob_dword_one, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[10].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[10].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ torture_assert_int_equal(tctx, r->propertyValues[11].syntax_name, CLUSPROP_SYNTAX_NAME, "syntax_name");
+ torture_assert_int_equal(tctx, r->propertyValues[11].size, 38, "size");
+ torture_assert_str_equal(tctx, r->propertyValues[11].buffer, "NeedsPreventQuorum", "buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[11].padding.length, 0, "padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Syntax, CLUSPROP_SYNTAX_LIST_VALUE_DWORD, "PropertyValues.Syntax");
+ torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Size, 4, "PropertyValues.Size");
+ torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Buffer.length, 4, "PropertyValues.Buffer.length");
+ torture_assert_data_blob_equal(tctx, r->propertyValues[11].PropertyValues.Buffer, blob_dword_null, "Buffer");
+ torture_assert_int_equal(tctx, r->propertyValues[11].PropertyValues.Padding.length, 0, "PropertyValues.Padding.length");
+ torture_assert_int_equal(tctx, r->propertyValues[11].end_mark, CLUSPROP_SYNTAX_ENDMARK, "end_mark");
+
+ data_blob_free(&blob_dword_null);
+ data_blob_free(&blob_dword_one);
+ data_blob_free(&blob_dword);
+
+ return true;
+}
+
+struct torture_suite *ndr_clusapi_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "clusapi");
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ clusapi_PROPERTY_LIST,
+ clusapi_PROPERTY_LIST_data,
+ clusapi_PROPERTY_LIST_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ clusapi_PROPERTY_LIST,
+ clusapi_PROPERTY_LIST_data2,
+ clusapi_PROPERTY_LIST_check2);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/dcerpc.c b/source4/torture/ndr/dcerpc.c
new file mode 100644
index 0000000..459817d
--- /dev/null
+++ b/source4/torture/ndr/dcerpc.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for dcerpc ndr operations
+
+ Copyright (C) Stefan Metzmacher 2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "torture/ndr/proto.h"
+
+/*
+ * ncacn_packet: struct ncacn_packet
+ * rpc_vers : 0x05 (5)
+ * rpc_vers_minor : 0x00 (0)
+ * ptype : DCERPC_PKT_CO_CANCEL (18)
+ * pfc_flags : 0x06 (6)
+ * 0: DCERPC_PFC_FLAG_FIRST
+ * 1: DCERPC_PFC_FLAG_LAST
+ * 1: DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING
+ * 0: DCERPC_PFC_FLAG_CONC_MPX
+ * 0: DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ * 0: DCERPC_PFC_FLAG_MAYBE
+ * 0: DCERPC_PFC_FLAG_OBJECT_UUID
+ * drep: ARRAY(4)
+ * [0] : 0x10 (16)
+ * [1] : 0x00 (0)
+ * [2] : 0x00 (0)
+ * [3] : 0x00 (0)
+ * frag_length : 0x0010 (16)
+ * auth_length : 0x0000 (0)
+ * call_id : 0x00000001 (1)
+ * u : union dcerpc_payload(case 18)
+ * co_cancel: struct dcerpc_co_cancel
+ * auth_info : DATA_BLOB length=0
+ */
+static const uint8_t ncacn_packet_co_cancel_data[] = {
+ 0x05, 0x00, 0x12, 0x06, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+};
+
+static bool ncacn_packet_co_cancel_check(struct torture_context *tctx,
+ struct ncacn_packet *pkt)
+{
+ torture_assert_int_equal(tctx, pkt->rpc_vers, 5, "rpc_vers");
+ torture_assert_int_equal(tctx, pkt->rpc_vers_minor, 0, "rpc_vers_minor");
+ torture_assert_int_equal(tctx, pkt->ptype, DCERPC_PKT_CO_CANCEL, "ptype");
+ torture_assert_int_equal(tctx, pkt->pfc_flags,
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING,
+ "pfc_flags");
+ torture_assert_int_equal(tctx, pkt->drep[0], DCERPC_DREP_LE, "drep[0]");
+ torture_assert_int_equal(tctx, pkt->drep[1], 0, "drep[1]");
+ torture_assert_int_equal(tctx, pkt->drep[2], 0, "drep[2]");
+ torture_assert_int_equal(tctx, pkt->drep[3], 0, "drep[3]");
+ torture_assert_int_equal(tctx, pkt->frag_length, 16, "frag_length");
+ torture_assert_int_equal(tctx, pkt->auth_length, 0, "auth_length");
+ torture_assert_int_equal(tctx, pkt->call_id, 1, "call_id");
+ torture_assert_int_equal(tctx, pkt->u.co_cancel.auth_info.length, 0,
+ "co_cancel.auth_info.length");
+ return true;
+}
+
+/*
+ * ncacn_packet: struct ncacn_packet
+ * rpc_vers : 0x05 (5)
+ * rpc_vers_minor : 0x00 (0)
+ * ptype : DCERPC_PKT_ORPHANED (19)
+ * pfc_flags : 0x03 (3)
+ * 1: DCERPC_PFC_FLAG_FIRST
+ * 1: DCERPC_PFC_FLAG_LAST
+ * 0: DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING
+ * 0: DCERPC_PFC_FLAG_CONC_MPX
+ * 0: DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ * 0: DCERPC_PFC_FLAG_MAYBE
+ * 0: DCERPC_PFC_FLAG_OBJECT_UUID
+ * drep: ARRAY(4)
+ * [0] : 0x10 (16)
+ * [1] : 0x00 (0)
+ * [2] : 0x00 (0)
+ * [3] : 0x00 (0)
+ * frag_length : 0x0010 (16)
+ * auth_length : 0x0000 (0)
+ * call_id : 0x00000008 (8)
+ * u : union dcerpc_payload(case 19)
+ * orphaned: struct dcerpc_orphaned
+ * auth_info : DATA_BLOB length=0
+ */
+static const uint8_t ncacn_packet_orphaned_data[] = {
+ 0x05, 0x00, 0x13, 0x03, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+};
+
+static bool ncacn_packet_orphaned_check(struct torture_context *tctx,
+ struct ncacn_packet *pkt)
+{
+ torture_assert_int_equal(tctx, pkt->rpc_vers, 5, "rpc_vers");
+ torture_assert_int_equal(tctx, pkt->rpc_vers_minor, 0, "rpc_vers_minor");
+ torture_assert_int_equal(tctx, pkt->ptype, DCERPC_PKT_ORPHANED, "ptype");
+ torture_assert_int_equal(tctx, pkt->pfc_flags,
+ DCERPC_PFC_FLAG_FIRST|DCERPC_PFC_FLAG_LAST,
+ "pfc_flags");
+ torture_assert_int_equal(tctx, pkt->drep[0], DCERPC_DREP_LE, "drep[0]");
+ torture_assert_int_equal(tctx, pkt->drep[1], 0, "drep[1]");
+ torture_assert_int_equal(tctx, pkt->drep[2], 0, "drep[2]");
+ torture_assert_int_equal(tctx, pkt->drep[3], 0, "drep[3]");
+ torture_assert_int_equal(tctx, pkt->frag_length, 16, "frag_length");
+ torture_assert_int_equal(tctx, pkt->auth_length, 0, "auth_length");
+ torture_assert_int_equal(tctx, pkt->call_id, 8, "call_id");
+ torture_assert_int_equal(tctx, pkt->u.orphaned.auth_info.length, 0,
+ "orphaned.auth_info.length");
+ return true;
+}
+
+struct torture_suite *ndr_dcerpc_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dcerpc");
+ struct torture_suite *co_cancel = torture_suite_create(ctx, "co_cancel");
+ struct torture_suite *orphaned = torture_suite_create(ctx, "orphaned");
+
+ torture_suite_add_suite(suite, co_cancel);
+ torture_suite_add_ndr_pull_validate_test(co_cancel,
+ ncacn_packet,
+ ncacn_packet_co_cancel_data,
+ ncacn_packet_co_cancel_check);
+
+ torture_suite_add_suite(suite, orphaned);
+ torture_suite_add_ndr_pull_validate_test(orphaned,
+ ncacn_packet,
+ ncacn_packet_orphaned_data,
+ ncacn_packet_orphaned_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/dfs.c b/source4/torture/ndr/dfs.c
new file mode 100644
index 0000000..ac80b40
--- /dev/null
+++ b/source4/torture/ndr/dfs.c
@@ -0,0 +1,115 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for dfs ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_dfs.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t getmanagerversion_out_data[] = {
+ 0x04, 0x00, 0x00, 0x00
+};
+
+static bool getmanagerversion_out_check(struct torture_context *tctx,
+ struct dfs_GetManagerVersion *r)
+{
+ torture_assert_int_equal(tctx, *r->out.version, 4, "version");
+ return true;
+}
+
+static const uint8_t enumex_in_data300[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x64, 0x00, 0x63, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x38, 0xf5, 0x07, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+ 0x40, 0xf5, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xa8, 0xf5, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool enumex_in_check300(struct torture_context *tctx,
+ struct dfs_EnumEx *r)
+{
+ torture_assert_str_equal(tctx, r->in.dfs_name, "w2k3dc", "dfs name");
+ torture_assert_int_equal(tctx, r->in.level, 300, "level");
+ torture_assert(tctx, r->in.total != NULL, "total ptr");
+ torture_assert_int_equal(tctx, *r->in.total, 0, "total");
+ torture_assert_int_equal(tctx, r->in.bufsize, -1, "buf size");
+ torture_assert(tctx, r->in.info != NULL, "info ptr");
+ torture_assert_int_equal(tctx, r->in.info->level, 300, "info level");
+ torture_assert(tctx, r->in.info->e.info300->s == NULL, "info data ptr");
+ return true;
+}
+
+
+static const uint8_t enumex_out_data300[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00,
+ 0x33, 0x00, 0x44, 0x00, 0x43, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6f, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00,
+ 0x33, 0x00, 0x44, 0x00, 0x43, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6f, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00,
+ 0x33, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x5c, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6f, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool enumex_out_check300(struct torture_context *tctx,
+ struct dfs_EnumEx *r)
+{
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ torture_assert(tctx, r->out.total != NULL, "total ptr");
+ torture_assert_int_equal(tctx, *r->out.total, 3, "total");
+ torture_assert(tctx, r->out.info != NULL, "info ptr");
+ torture_assert_int_equal(tctx, r->out.info->level, 300, "info level");
+ torture_assert(tctx, r->out.info->e.info300 != NULL, "info data ptr");
+ torture_assert_int_equal(tctx, r->out.info->e.info300->count, 3, "info enum array");
+ torture_assert_str_equal(tctx, r->out.info->e.info300->s[0].dom_root, "\\W2K3DC\\standaloneroot", "info enum array 0");
+ torture_assert_int_equal(tctx, r->out.info->e.info300->s[0].flavor, 256, "info enum flavor 0");
+ torture_assert_str_equal(tctx, r->out.info->e.info300->s[1].dom_root, "\\W2K3DC\\standaloneroot2", "info enum array 1");
+ torture_assert_int_equal(tctx, r->out.info->e.info300->s[1].flavor, 256, "info enum flavor 1");
+ torture_assert_str_equal(tctx, r->out.info->e.info300->s[2].dom_root, "\\W2K3DOM\\testdomainroot", "info enum array 2");
+ torture_assert_int_equal(tctx, r->out.info->e.info300->s[2].flavor, 512, "info enum flavor 2");
+ return true;
+}
+
+struct torture_suite *ndr_dfs_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dfs");
+
+ torture_suite_add_ndr_pull_fn_test(suite, dfs_GetManagerVersion, getmanagerversion_out_data, NDR_OUT, getmanagerversion_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, dfs_EnumEx, enumex_in_data300, NDR_IN, enumex_in_check300 );
+ torture_suite_add_ndr_pull_fn_test(suite, dfs_EnumEx, enumex_out_data300, NDR_OUT, enumex_out_check300 );
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/dfsblob.c b/source4/torture/ndr/dfsblob.c
new file mode 100644
index 0000000..81db322
--- /dev/null
+++ b/source4/torture/ndr/dfsblob.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Test DFS blobs.
+
+ Copyright (C) Matthieu Patou <mat@matws.net> 2009-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_dfsblobs.h"
+#include "torture/ndr/proto.h"
+#include "librpc/gen_ndr/dfsblobs.h"
+
+DATA_BLOB blob;
+static const uint8_t dfs_get_ref_in[] = {
+ 0x03, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x33, 0x00, 0x00, 0x00 };
+
+static const uint8_t dfs_get_ref_out[] = {
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x58, 0x02, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+ 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x5c, 0x00, 0x6d, 0x00, 0x73, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00,
+ 0x2e, 0x00, 0x74, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x00, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x33, 0x00, 0x61, 0x00, 0x64, 0x00,
+ 0x76, 0x00, 0x7a, 0x00, 0x30, 0x00, 0x31, 0x00,
+ 0x2e, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x77, 0x00,
+ 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x2e, 0x00,
+ 0x74, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00};
+
+static const uint8_t dfs_get_ref_out2[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x58, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x58, 0x02, 0x00, 0x00, 0x22, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x57, 0x00,
+ 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x77, 0x00,
+ 0x32, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x72, 0x00,
+ 0x32, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x77, 0x00, 0x73, 0x00, 0x2e, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00
+};
+static bool dfs_referral_out_check(struct torture_context *tctx, struct dfs_referral_resp *r)
+{
+ torture_assert_str_equal(tctx,
+ r->referral_entries[0].referral.v3.referrals.r2.special_name,
+ "\\msw2k3.tst", "Special name");
+ ndr_push_struct_blob(&blob, tctx, r, (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
+ torture_assert_int_equal(tctx, blob.data[blob.length-2], 0, "expanded names not null terminated");
+ torture_assert_int_equal(tctx, blob.data[blob.length-1], 0, "expanded names not null terminated");
+ return true;
+}
+
+struct torture_suite *ndr_dfsblob_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dfsblob");
+
+ torture_suite_add_ndr_pull_test(suite, dfs_GetDFSReferral_in, dfs_get_ref_in, NULL);
+
+ torture_suite_add_ndr_pull_test(suite, dfs_referral_resp, dfs_get_ref_out2, NULL);
+
+ torture_suite_add_ndr_pull_test(suite, dfs_referral_resp, dfs_get_ref_out,dfs_referral_out_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/dnsp.c b/source4/torture/ndr/dnsp.c
new file mode 100644
index 0000000..3fc58c9
--- /dev/null
+++ b/source4/torture/ndr/dnsp.c
@@ -0,0 +1,389 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for dnsp ndr operations
+
+ Copyright (C) Stefan Metzmacher 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "torture/ndr/proto.h"
+#include "lib/util/base64.h"
+
+/*
+ * base64_decode_data_blob_talloc() => dump_data() gives:
+ *
+ * [0000] 0C 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ........ ........
+ * [0010] 81 00 00 00 02 00 00 00 AC 1F 63 21 AC 1F 63 2C ........ ..c!..c,
+ * [0020] 00 00 00 00
+ */
+static const char *dnsp_dnsProperty_ip4_array_b64 =
+ "DAAAAAAAAAAAAAAAAQAAAIEAAAACAAAArB9jIawfYywAAAAA";
+
+static bool dnsp_dnsProperty_ip4_array_check(struct torture_context *tctx,
+ struct dnsp_DnsProperty *r)
+{
+ /*
+ * NDR_PRINT_DEBUG(dnsp_DnsProperty, r); gave:
+ *
+ * r: struct dnsp_DnsProperty
+ * wDataLength : 0x0000000c (12)
+ * namelength : 0x00000000 (0)
+ * flag : 0x00000000 (0)
+ * version : 0x00000001 (1)
+ * id : DSPROPERTY_ZONE_MASTER_SERVERS (129)
+ * data : union dnsPropertyData(case 129)
+ * master_servers: struct dnsp_ip4_array
+ * addrCount : 0x00000002 (2)
+ * addrArray: ARRAY(2)
+ * addrArray : 0x21631fac (560144300)
+ * addrArray : 0x2c631fac (744693676)
+ * name : 0x00000000 (0)
+ *
+ */
+
+ torture_assert_int_equal(tctx, r->wDataLength, 12, "wDataLength");
+ torture_assert_int_equal(tctx, r->namelength, 0, "namelength");
+ torture_assert_int_equal(tctx, r->flag, 0, "flag");
+ torture_assert_int_equal(tctx, r->version, 1, "version");
+ torture_assert_int_equal(tctx, r->id, DSPROPERTY_ZONE_MASTER_SERVERS, "id");
+ torture_assert_int_equal(tctx, r->data.master_servers.addrCount, 2, "addrCount");
+ /*
+ * This should be an array of [flag(NDR_BIG_ENDIAN)] ipv4address
+ * instead of uint32!
+ * 0x21631fac is 172.31.99.33
+ * 0x2c631fac is 172.31.99.44
+ */
+ torture_assert_int_equal(tctx, r->data.master_servers.addrArray[0], 0x21631fac, "addrArray[0]");
+ torture_assert_int_equal(tctx, r->data.master_servers.addrArray[1], 0x2c631fac, "addrArray[1]");
+ torture_assert_int_equal(tctx, r->name, 0, "name");
+
+ return true;
+}
+
+/*
+ * base64_decode_data_blob_talloc() => dump_data() gives:
+ *
+ * [0000] E0 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ........ ........
+ * [0010] 91 00 00 00 03 00 00 00 03 00 00 00 00 00 00 00 ........ ........
+ * [0020] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [0030] 00 00 00 00 02 00 00 35 AC 1F 63 21 00 00 00 00 .......5 ..c!....
+ * [0040] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [0050] 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [0060] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [0070] 00 00 00 00 02 00 00 35 AC 1F 63 2C 00 00 00 00 .......5 ..c,....
+ * [0080] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [0090] 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [00A0] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [00B0] 00 00 00 00 17 00 00 35 00 00 00 00 FD 3A AA A3 .......5 .....:..
+ * [00C0] EE 87 FF 09 02 00 00 FF FE 99 FF FF 00 00 00 00 ........ ........
+ * [00D0] 00 00 00 00 1C 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [00E0] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+ * [00F0] 00 00 00 00 00 00 00 00 ........
+ */
+static const char *dnsp_dnsProperty_addr_array_b64 =
+ "4AAAAAAAAAAAAAAAAQAAAJEAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAIAADWsH2MhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAACAAA1rB9jLAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFwAANQAAAAD9Oqqj"
+ "7of/CQIAAP/+mf//AAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAA=DAAAAAAAAAAAAAAAAQAAAIEAAAACAAAArB9jIawfYywAAAAA";
+
+static bool dnsp_dnsProperty_addr_array_check(struct torture_context *tctx,
+ struct dnsp_DnsProperty *r)
+{
+ const struct dnsp_dns_addr_array *da = NULL;
+ const struct dnsp_dns_addr *a0 = NULL;
+ const struct dnsp_dns_addr *a1 = NULL;
+ const struct dnsp_dns_addr *a2 = NULL;
+
+ /*
+ * NDR_PRINT_DEBUG(dnsp_DnsProperty, r); gave:
+ *
+ * r: struct dnsp_DnsProperty
+ * wDataLength : 0x000000e0 (224)
+ * namelength : 0x00000000 (0)
+ * flag : 0x00000000 (0)
+ * version : 0x00000001 (1)
+ * id : DSPROPERTY_ZONE_MASTER_SERVERS_DA (145)
+ * data : union dnsPropertyData(case 145)
+ * z_master_servers: struct dnsp_dns_addr_array
+ * MaxCount : 0x00000003 (3)
+ * AddrCount : 0x00000003 (3)
+ * Tag : 0x00000000 (0)
+ * Family : 0x0000 (0)
+ * Reserved0 : 0x0000 (0)
+ * Flags : 0x00000000 (0)
+ * MatchFlag : 0x00000000 (0)
+ * Reserved1 : 0x00000000 (0)
+ * Reserved2 : 0x00000000 (0)
+ * AddrArray: ARRAY(3)
+ * AddrArray: struct dnsp_dns_addr
+ * family : 0x0002 (2)
+ * port : 0x0035 (53)
+ * ipv4 : 172.31.99.33
+ * ipv6 : 0000:0000:0000:0000:0000:0000:0000:0000
+ * pad: ARRAY(8)
+ * [0] : 0x00 (0)
+ * [1] : 0x00 (0)
+ * [2] : 0x00 (0)
+ * [3] : 0x00 (0)
+ * [4] : 0x00 (0)
+ * [5] : 0x00 (0)
+ * [6] : 0x00 (0)
+ * [7] : 0x00 (0)
+ * unused: ARRAY(8)
+ * unused : 0x00000010 (16)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * AddrArray: struct dnsp_dns_addr
+ * family : 0x0002 (2)
+ * port : 0x0035 (53)
+ * ipv4 : 172.31.99.44
+ * ipv6 : 0000:0000:0000:0000:0000:0000:0000:0000
+ * pad: ARRAY(8)
+ * [0] : 0x00 (0)
+ * [1] : 0x00 (0)
+ * [2] : 0x00 (0)
+ * [3] : 0x00 (0)
+ * [4] : 0x00 (0)
+ * [5] : 0x00 (0)
+ * [6] : 0x00 (0)
+ * [7] : 0x00 (0)
+ * unused: ARRAY(8)
+ * unused : 0x00000010 (16)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * AddrArray: struct dnsp_dns_addr
+ * family : 0x0017 (23)
+ * port : 0x0035 (53)
+ * ipv4 : 0.0.0.0
+ * ipv6 : fd3a:aaa3:ee87:ff09:0200:00ff:fe99:ffff
+ * pad: ARRAY(8)
+ * [0] : 0x00 (0)
+ * [1] : 0x00 (0)
+ * [2] : 0x00 (0)
+ * [3] : 0x00 (0)
+ * [4] : 0x00 (0)
+ * [5] : 0x00 (0)
+ * [6] : 0x00 (0)
+ * [7] : 0x00 (0)
+ * unused: ARRAY(8)
+ * unused : 0x0000001c (28)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * unused : 0x00000000 (0)
+ * name : 0x00000000 (0)
+ *
+ */
+
+ torture_assert_int_equal(tctx, r->wDataLength, 224, "wDataLength");
+ torture_assert_int_equal(tctx, r->namelength, 0, "namelength");
+ torture_assert_int_equal(tctx, r->flag, 0, "flag");
+ torture_assert_int_equal(tctx, r->version, 1, "version");
+ torture_assert_int_equal(tctx, r->id, DSPROPERTY_ZONE_MASTER_SERVERS_DA, "id");
+ da = &r->data.z_master_servers;
+ torture_assert_int_equal(tctx, da->MaxCount, 3, "MaxCount");
+ torture_assert_int_equal(tctx, da->AddrCount, 3, "AddrCount");
+ torture_assert_int_equal(tctx, da->Tag, 0, "Tag");
+ torture_assert_int_equal(tctx, da->Family, 0, "Family");
+ torture_assert_int_equal(tctx, da->Reserved0, 0, "Reserved0");
+ torture_assert_int_equal(tctx, da->Flags, 0, "Flags");
+ torture_assert_int_equal(tctx, da->MatchFlag, 0, "MatchFlag");
+ torture_assert_int_equal(tctx, da->Reserved1, 0, "Reserved1");
+ torture_assert_int_equal(tctx, da->Reserved2, 0, "Reserved2");
+ a0 = &da->AddrArray[0];
+ torture_assert_int_equal(tctx, a0->family, 2, "family v4");
+ torture_assert_int_equal(tctx, a0->port, 53, "port");
+ torture_assert_str_equal(tctx, a0->ipv4, "172.31.99.33", "ipv4");
+ torture_assert_str_equal(tctx, a0->ipv6,
+ "0000:0000:0000:0000:0000:0000:0000:0000",
+ "ipv6 (zero)");
+ torture_assert_int_equal(tctx, a0->pad[0], 0, "pad[0]");
+ torture_assert_int_equal(tctx, a0->pad[1], 0, "pad[1]");
+ torture_assert_int_equal(tctx, a0->pad[2], 0, "pad[2]");
+ torture_assert_int_equal(tctx, a0->pad[3], 0, "pad[3]");
+ torture_assert_int_equal(tctx, a0->pad[4], 0, "pad[4]");
+ torture_assert_int_equal(tctx, a0->pad[5], 0, "pad[5]");
+ torture_assert_int_equal(tctx, a0->pad[6], 0, "pad[6]");
+ torture_assert_int_equal(tctx, a0->pad[7], 0, "pad[7]");
+ torture_assert_int_equal(tctx, a0->unused[0], 16, "unused[0]");
+ torture_assert_int_equal(tctx, a0->unused[1], 0, "unused[1]");
+ torture_assert_int_equal(tctx, a0->unused[2], 0, "unused[2]");
+ torture_assert_int_equal(tctx, a0->unused[3], 0, "unused[3]");
+ torture_assert_int_equal(tctx, a0->unused[4], 0, "unused[4]");
+ torture_assert_int_equal(tctx, a0->unused[5], 0, "unused[5]");
+ torture_assert_int_equal(tctx, a0->unused[6], 0, "unused[6]");
+ torture_assert_int_equal(tctx, a0->unused[7], 0, "unused[7]");
+ a1 = &da->AddrArray[1];
+ torture_assert_int_equal(tctx, a1->family, 2, "family v4");
+ torture_assert_int_equal(tctx, a1->port, 53, "port");
+ torture_assert_str_equal(tctx, a1->ipv4, "172.31.99.44", "ipv4");
+ torture_assert_str_equal(tctx, a1->ipv6,
+ "0000:0000:0000:0000:0000:0000:0000:0000",
+ "ipv6 (zero)");
+ torture_assert_int_equal(tctx, a1->pad[0], 0, "pad[0]");
+ torture_assert_int_equal(tctx, a1->pad[1], 0, "pad[1]");
+ torture_assert_int_equal(tctx, a1->pad[2], 0, "pad[2]");
+ torture_assert_int_equal(tctx, a1->pad[3], 0, "pad[3]");
+ torture_assert_int_equal(tctx, a1->pad[4], 0, "pad[4]");
+ torture_assert_int_equal(tctx, a1->pad[5], 0, "pad[5]");
+ torture_assert_int_equal(tctx, a1->pad[6], 0, "pad[6]");
+ torture_assert_int_equal(tctx, a1->pad[7], 0, "pad[7]");
+ torture_assert_int_equal(tctx, a1->unused[0], 16, "unused[0]");
+ torture_assert_int_equal(tctx, a1->unused[1], 0, "unused[1]");
+ torture_assert_int_equal(tctx, a1->unused[2], 0, "unused[2]");
+ torture_assert_int_equal(tctx, a1->unused[3], 0, "unused[3]");
+ torture_assert_int_equal(tctx, a1->unused[4], 0, "unused[4]");
+ torture_assert_int_equal(tctx, a1->unused[5], 0, "unused[5]");
+ torture_assert_int_equal(tctx, a1->unused[6], 0, "unused[6]");
+ torture_assert_int_equal(tctx, a1->unused[7], 0, "unused[7]");
+ a2 = &da->AddrArray[2];
+ torture_assert_int_equal(tctx, a2->family, 23, "family v6");
+ torture_assert_int_equal(tctx, a2->port, 53, "port");
+ torture_assert_str_equal(tctx, a2->ipv4, "0.0.0.0", "ipv4 (zero)");
+ torture_assert_str_equal(tctx, a2->ipv6,
+ "fd3a:aaa3:ee87:ff09:0200:00ff:fe99:ffff",
+ "ipv6");
+ torture_assert_int_equal(tctx, a2->pad[0], 0, "pad[0]");
+ torture_assert_int_equal(tctx, a2->pad[1], 0, "pad[1]");
+ torture_assert_int_equal(tctx, a2->pad[2], 0, "pad[2]");
+ torture_assert_int_equal(tctx, a2->pad[3], 0, "pad[3]");
+ torture_assert_int_equal(tctx, a2->pad[4], 0, "pad[4]");
+ torture_assert_int_equal(tctx, a2->pad[5], 0, "pad[5]");
+ torture_assert_int_equal(tctx, a2->pad[6], 0, "pad[6]");
+ torture_assert_int_equal(tctx, a2->pad[7], 0, "pad[7]");
+ torture_assert_int_equal(tctx, a2->unused[0], 28, "unused[0]");
+ torture_assert_int_equal(tctx, a2->unused[1], 0, "unused[1]");
+ torture_assert_int_equal(tctx, a2->unused[2], 0, "unused[2]");
+ torture_assert_int_equal(tctx, a2->unused[3], 0, "unused[3]");
+ torture_assert_int_equal(tctx, a2->unused[4], 0, "unused[4]");
+ torture_assert_int_equal(tctx, a2->unused[5], 0, "unused[5]");
+ torture_assert_int_equal(tctx, a2->unused[6], 0, "unused[6]");
+ torture_assert_int_equal(tctx, a2->unused[7], 0, "unused[7]");
+ torture_assert_int_equal(tctx, r->name, 0, "name");
+
+ return true;
+}
+
+/*
+ * base64_decode_data_blob_talloc() => dump_data() gives:
+ *
+ * [0000] 26 00 00 00 01 EE C4 71 00 00 00 00 01 00 00 00 &......q ........
+ * [0010] 80 00 00 00 77 00 32 00 6B 00 33 00 2D 00 31 00 ....w.2. k.3.-.1.
+ * [0020] 39 00 31 00 2E 00 77 00 32 00 6B 00 33 00 2E 00 9.1...w. 2.k.3...
+ * [0030] 62 00 61 00 73 00 65 00 00 00 C4 71 EC F3 b.a.s.e. ...q..
+ */
+static const char *dnsp_dnsProperty_deleted_by_b64 =
+ "JgAAAAHuxHEAAAAAAQAAAIAAAAB3ADIAawAzAC0AMQA5ADEALgB3ADIAawAzAC4A"
+ "YgBhAHMAZQAAAMRx7PM=";
+
+static bool dnsp_dnsProperty_deleted_by_check(struct torture_context *tctx,
+ struct dnsp_DnsProperty *r)
+{
+ /*
+ * NDR_PRINT_DEBUG(dnsp_DnsProperty, r); gave:
+ *
+ * r: struct dnsp_DnsProperty
+ * wDataLength : 0x00000026 (38)
+ * namelength : 0x71c4ee01 (1908731393)
+ * flag : 0x00000000 (0)
+ * version : 0x00000001 (1)
+ * id : DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME (128)
+ * data : union dnsPropertyData(case 128)
+ * deleted_by_hostname : 'w2k3-191.w2k3.base'
+ * name : 0xf3ec71c4 (4092359108)
+ *
+ * Note Windows 2003 didn't seem to initialize namelength and name
+ * both are 'Not Used. The value MUST be ignored ...'
+ */
+
+ torture_assert_int_equal(tctx, r->wDataLength, 38, "wDataLength");
+ torture_assert_int_equal(tctx, r->namelength, 1908731393, "namelength (random)");
+ torture_assert_int_equal(tctx, r->flag, 0, "flag");
+ torture_assert_int_equal(tctx, r->version, 1, "version");
+ torture_assert_int_equal(tctx, r->id, DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME, "id");
+ torture_assert_str_equal(tctx, r->data.deleted_by_hostname, "w2k3-191.w2k3.base", "hostname");
+ torture_assert_int_equal(tctx, r->name, 0xf3ec71c4, "name (random)");
+
+ return true;
+}
+
+/*
+ * Copy of dnsp_dnsProperty_deleted_by_b64 with wDataLength set to 0
+ * and no data in the data element.
+ * This is a reproducer for https://bugzilla.samba.org/show_bug.cgi?id=14206
+ * The dns_property_id was retained so once parsed this structure referenced
+ * memory past it's end.
+ *
+ * [0000] 00 00 00 00 01 EE C4 71 00 00 00 00 01 00 00 00 &......q ........
+ * [0010] 80 00 00 00 77 00 32 00 6B 00 33 00 2D 00 31 00 ....w.2. k.3.-.1.
+ * [0020] 39 00 31 00 2E 00 77 00 32 00 6B 00 33 00 2E 00 9.1...w. 2.k.3...
+ * [0030] 62 00 61 00 73 00 65 00 00 00 C4 71 EC F3 b.a.s.e. ...q..
+ */
+static const uint8_t dnsp_dnsProperty_deleted_by_zero_wDataLength[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0xEE, 0xC4, 0x71, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0xC4, 0x71, 0xEC, 0xF3 };
+
+struct torture_suite *ndr_dnsp_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "dnsp");
+
+ torture_suite_add_ndr_pull_validate_test_b64(
+ suite,
+ dnsp_DnsProperty,
+ "ZONE_MASTER_SERVERS",
+ dnsp_dnsProperty_ip4_array_b64,
+ dnsp_dnsProperty_ip4_array_check);
+
+ torture_suite_add_ndr_pull_validate_test_b64(
+ suite,
+ dnsp_DnsProperty,
+ "ZONE_MASTER_SERVERS_DA",
+ dnsp_dnsProperty_addr_array_b64,
+ dnsp_dnsProperty_addr_array_check);
+
+ torture_suite_add_ndr_pull_validate_test_b64(
+ suite,
+ dnsp_DnsProperty,
+ "DELETED_FROM_HOSTNAME",
+ dnsp_dnsProperty_deleted_by_b64,
+ dnsp_dnsProperty_deleted_by_check);
+
+ torture_suite_add_ndr_pull_invalid_data_test(
+ suite,
+ dnsp_DnsProperty,
+ dnsp_dnsProperty_deleted_by_zero_wDataLength,
+ NDR_ERR_BUFSIZE);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/drsblobs.c b/source4/torture/ndr/drsblobs.c
new file mode 100644
index 0000000..0ef2d95
--- /dev/null
+++ b/source4/torture/ndr/drsblobs.c
@@ -0,0 +1,558 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for drsblobs ndr operations
+
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "torture/ndr/proto.h"
+#include "lib/util/base64.h"
+
+static const uint8_t forest_trust_info_data_out[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0xca, 0xca, 0x01, 0x00, 0xaf, 0xd5, 0x9b,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x66, 0x32, 0x2e, 0x74, 0x65, 0x73, 0x74,
+ 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xca, 0xca, 0x01,
+ 0x00, 0xaf, 0xd5, 0x9b, 0x02, 0x18, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x68, 0x4a, 0x64,
+ 0x28, 0xac, 0x88, 0xa2, 0x74, 0x17, 0x3e, 0x2d, 0x8f, 0x07, 0x00, 0x00,
+ 0x00, 0x66, 0x32, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x02, 0x00, 0x00, 0x00,
+ 0x46, 0x32
+};
+
+static bool forest_trust_info_check_out(struct torture_context *tctx,
+ struct ForestTrustInfo *r)
+{
+ torture_assert_int_equal(tctx, r->version, 1, "version");
+ torture_assert_int_equal(tctx, r->count, 2, "count");
+ torture_assert_int_equal(tctx, r->records[0].record_size, 0x00000018, "record size");
+ torture_assert_int_equal(tctx, r->records[0].record.flags, 0, "record flags");
+ torture_assert_u64_equal(tctx, r->records[0].record.timestamp, 0x9BD5AF0001CACA3EULL, "record timestamp");
+ torture_assert_int_equal(tctx, r->records[0].record.type, FOREST_TRUST_TOP_LEVEL_NAME, "record type");
+ torture_assert_int_equal(tctx, r->records[0].record.data.name.size, 7, "record name size");
+ torture_assert_str_equal(tctx, r->records[0].record.data.name.string, "f2.test", "record name string");
+ torture_assert_int_equal(tctx, r->records[1].record_size, 0x0000003a, "record size");
+ torture_assert_int_equal(tctx, r->records[1].record.flags, 0, "record flags");
+ torture_assert_u64_equal(tctx, r->records[1].record.timestamp, 0x9BD5AF0001CACA3EULL, "record timestamp");
+ torture_assert_int_equal(tctx, r->records[1].record.type, FOREST_TRUST_DOMAIN_INFO, "record type");
+ torture_assert_int_equal(tctx, r->records[1].record.data.info.sid_size, 0x00000018, "record info sid_size");
+ torture_assert_sid_equal(tctx, &r->records[1].record.data.info.sid, dom_sid_parse_talloc(tctx, "S-1-5-21-677661288-1956808876-2402106903"), "record info sid");
+ torture_assert_int_equal(tctx, r->records[1].record.data.info.dns_name.size, 7, "record name size");
+ torture_assert_str_equal(tctx, r->records[1].record.data.info.dns_name.string, "f2.test", "record info dns_name string");
+ torture_assert_int_equal(tctx, r->records[1].record.data.info.netbios_name.size, 2, "record info netbios_name size");
+ torture_assert_str_equal(tctx, r->records[1].record.data.info.netbios_name.string, "F2", "record info netbios_name string");
+
+ return true;
+}
+
+static const uint8_t trust_domain_passwords_in[] = {
+ 0x34, 0x1f, 0x6e, 0xcd, 0x5f, 0x14, 0x99, 0xf9, 0xd8, 0x34, 0x9f, 0x1d,
+ 0x1c, 0xcf, 0x1f, 0x02, 0xb8, 0x30, 0xcc, 0x77, 0x21, 0xc1, 0xf3, 0xe2,
+ 0xcf, 0x32, 0xe7, 0xf7, 0x86, 0x49, 0x28, 0xa0, 0x57, 0x81, 0xa0, 0x72,
+ 0x95, 0xd5, 0xa7, 0x49, 0xd7, 0xe7, 0x6f, 0xd1, 0x56, 0x91, 0x44, 0xb7,
+ 0xe2, 0x4e, 0x48, 0xd2, 0x3e, 0x39, 0xfe, 0x79, 0xd9, 0x1d, 0x4a, 0x92,
+ 0xc7, 0xbb, 0xe3, 0x65, 0x38, 0x28, 0xb3, 0xb5, 0x6d, 0x1a, 0xfc, 0xf9,
+ 0xd1, 0xe9, 0xc0, 0x8a, 0x52, 0x5a, 0x86, 0xc1, 0x60, 0x45, 0x85, 0xaa,
+ 0x20, 0xd8, 0xb4, 0x1f, 0x67, 0x6e, 0xe9, 0xc8, 0xed, 0x52, 0x08, 0x65,
+ 0xd2, 0x5a, 0x3c, 0xb8, 0xdd, 0x5d, 0xef, 0x59, 0x54, 0x90, 0x75, 0x35,
+ 0x23, 0x12, 0x92, 0xac, 0xf1, 0x76, 0xb0, 0x16, 0x3d, 0xd8, 0xea, 0x96,
+ 0xd1, 0xd5, 0x27, 0x37, 0xbe, 0xb8, 0x30, 0x60, 0xab, 0xda, 0x21, 0xc1,
+ 0x61, 0x66, 0x85, 0xbc, 0x4b, 0xf2, 0x0d, 0x8d, 0x28, 0x1f, 0x02, 0x1c,
+ 0xcf, 0x39, 0x99, 0x14, 0x6b, 0x1a, 0x59, 0x66, 0x8d, 0x9f, 0x6f, 0x5a,
+ 0x3d, 0x3d, 0xb4, 0x1e, 0x7d, 0xf4, 0xc3, 0xc6, 0xed, 0xed, 0x87, 0xb1,
+ 0x35, 0x08, 0xf7, 0x7f, 0x61, 0x00, 0x4b, 0x0d, 0xa7, 0xb7, 0x59, 0x53,
+ 0xc3, 0x97, 0x55, 0xf9, 0x86, 0x2e, 0x29, 0x6d, 0x00, 0x38, 0xde, 0xe1,
+ 0x80, 0x37, 0xf4, 0xcb, 0x8d, 0x0d, 0x0d, 0x1f, 0x1c, 0x99, 0xf1, 0x24,
+ 0x61, 0x14, 0x6b, 0x1a, 0xd9, 0x31, 0xc8, 0x6e, 0xd6, 0x98, 0xab, 0xdb,
+ 0xb8, 0xaf, 0x99, 0xf9, 0xf4, 0x4c, 0xfe, 0x4b, 0x0d, 0xbb, 0x4f, 0xcc,
+ 0x63, 0xd3, 0xf0, 0x0c, 0xd1, 0xd6, 0x11, 0x30, 0x68, 0x45, 0x98, 0x07,
+ 0x44, 0x80, 0xca, 0xa4, 0x7b, 0x10, 0x5b, 0x0b, 0x33, 0xb6, 0x8c, 0xa4,
+ 0x8f, 0xf1, 0x2b, 0xbf, 0xa2, 0x22, 0xd7, 0xcc, 0x92, 0x34, 0x0b, 0xa0,
+ 0x05, 0xdf, 0x2f, 0xe3, 0x66, 0x0d, 0x9f, 0x09, 0x84, 0xdb, 0x0b, 0x3a,
+ 0xfa, 0xd5, 0xa7, 0x1c, 0x46, 0x01, 0xa0, 0x3c, 0x02, 0x8a, 0x6d, 0xec,
+ 0x97, 0xc1, 0x7c, 0x2f, 0x7e, 0x5d, 0x55, 0x27, 0x37, 0x59, 0x31, 0x64,
+ 0xe9, 0xc9, 0xd6, 0xfd, 0x8f, 0xf9, 0x59, 0xe7, 0x11, 0x30, 0x4c, 0x76,
+ 0xb0, 0xe7, 0xee, 0xe9, 0xf7, 0xa2, 0x0f, 0x71, 0x90, 0xdb, 0x1d, 0xb0,
+ 0xfb, 0xa3, 0x25, 0xf8, 0x0a, 0x6c, 0x69, 0x5c, 0x21, 0xa6, 0xfb, 0x90,
+ 0x5b, 0x9d, 0x14, 0xe4, 0xea, 0x32, 0xe8, 0xe0, 0x2b, 0x5a, 0x99, 0x0b,
+ 0xbb, 0x7e, 0x14, 0x6b, 0x36, 0x42, 0x41, 0x0f, 0x44, 0x2f, 0x7f, 0xcf,
+ 0x1f, 0x89, 0x04, 0xdc, 0x07, 0x2a, 0x57, 0xdf, 0xdd, 0x42, 0x78, 0xf0,
+ 0x8d, 0x9f, 0x02, 0x1d, 0xaf, 0xff, 0x4f, 0xb2, 0x1e, 0xb4, 0x0b, 0xb2,
+ 0x4d, 0x7a, 0xdc, 0xf3, 0x7e, 0x81, 0xbb, 0x6b, 0x2e, 0x29, 0x24, 0x61,
+ 0x93, 0x1e, 0x20, 0x57, 0x66, 0x20, 0xcf, 0x4d, 0x67, 0x76, 0xb0, 0x7b,
+ 0xd9, 0x9d, 0x30, 0x95, 0xba, 0xb0, 0xcc, 0xf6, 0xcc, 0xff, 0xea, 0x32,
+ 0x55, 0x15, 0xcd, 0xdf, 0xaf, 0xf6, 0x16, 0xd1, 0x1f, 0x6f, 0xb7, 0xda,
+ 0x1a, 0x75, 0xc7, 0x4f, 0xb1, 0xeb, 0x1a, 0xe2, 0x17, 0x8b, 0xe8, 0x5f,
+ 0x41, 0x74, 0x5f, 0x41, 0xe0, 0x46, 0x08, 0x9a, 0xc6, 0x81, 0x19, 0x26,
+ 0xcd, 0x60, 0xb2, 0x3a, 0x7a, 0x39, 0x2b, 0xee, 0x83, 0x8e, 0xdb, 0x83,
+ 0x6b, 0x48, 0x24, 0x73, 0x91, 0x31, 0x64, 0xce, 0x2e, 0x43, 0x32, 0xb2,
+ 0xcd, 0x60, 0x98, 0x87, 0xa9, 0x9b, 0xc3, 0x60, 0x7c, 0xa7, 0x52, 0x3e,
+ 0xb8, 0x28, 0x4d, 0xcd, 0x5f, 0xaf, 0xe3, 0xe6, 0xa0, 0x06, 0x93, 0xfb,
+ 0xd9, 0xd4, 0x2b, 0x52, 0xed, 0xec, 0x97, 0x3a, 0x01, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x4c, 0x6b, 0x41, 0xb6,
+ 0x7c, 0x16, 0xcb, 0x01, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0xb6, 0xe4, 0x4e, 0xa0, 0xf4, 0xed, 0x90, 0x9d, 0x67, 0xff, 0xda, 0xda,
+ 0xc7, 0xe5, 0xaf, 0xc7, 0x4d, 0xc1, 0x58, 0xaf, 0x5f, 0x06, 0x5c, 0xe9,
+ 0x4c, 0x5a, 0x02, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x4c, 0x6b, 0x41, 0xb6, 0x7c, 0x16, 0xcb, 0x01,
+ 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xb6, 0xe4, 0x4e, 0xa0,
+ 0xf4, 0xed, 0x90, 0x9d, 0x67, 0xff, 0xda, 0xda, 0xc7, 0xe5, 0xaf, 0xc7,
+ 0x4d, 0xc1, 0x58, 0xaf, 0x5f, 0x06, 0x5c, 0xe9, 0x4c, 0x5a, 0x02, 0xfd,
+ 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00
+};
+
+/* these are taken from the trust objects of a w2k8r2 forest, with a
+ * trust relationship between the forest parent and a child domain
+ */
+static const char *trustAuthIncoming =
+"AQAAAAwAAAAcAQAASuQ+RXJdzAECAAAAAAEAAMOWL6UVfVKiJOUsGcT03H"
+"jHxr2ACsMMOV5ynM617Tp7idNC+c4egdqk4S9YEpvR2YvHmdZdymL6F7QKm8OkXazYZF2r/gZ/bI+"
+"jkWbsn4O8qyAc3OUKQRZwBbf+lxBW+vM4O3ZpUjz5BSKCcFQgM+MY91yVU8Nji3HNnvGnDquobFAZ"
+"hxjL+S1l5+QZgkfyfv5mQScGRbU1Lar1xg9G3JznUb7S6pvrBO2nwK8g+KZBfJy5UeULigDH4IWo/"
+"JmtaEGkKE2uiKIjdsEQd/uwnkouW26XzRc0ulfJnPFftGnT9KIcShPf7DLj/tstmQAAceRMFHJTY3"
+"PmxoowoK8HUyBK5D5Fcl3MAQIAAAAAAQAAw5YvpRV9UqIk5SwZxPTceMfGvYAKwww5XnKczrXtOnu"
+"J00L5zh6B2qThL1gSm9HZi8eZ1l3KYvoXtAqbw6RdrNhkXav+Bn9sj6ORZuyfg7yrIBzc5QpBFnAF"
+"t/6XEFb68zg7dmlSPPkFIoJwVCAz4xj3XJVTw2OLcc2e8acOq6hsUBmHGMv5LWXn5BmCR/J+/mZBJ"
+"wZFtTUtqvXGD0bcnOdRvtLqm+sE7afAryD4pkF8nLlR5QuKAMfghaj8ma1oQaQoTa6IoiN2wRB3+7"
+"CeSi5bbpfNFzS6V8mc8V+0adP0ohxKE9/sMuP+2y2ZAABx5EwUclNjc+bGijCgrwdTIA==";
+
+static const char *trustAuthOutgoing =
+"AQAAAAwAAAAcAQAASuQ+RXJdzAECAAAAAAEAAMOWL6UVfVKiJOUsGcT03H"
+"jHxr2ACsMMOV5ynM617Tp7idNC+c4egdqk4S9YEpvR2YvHmdZdymL6F7QKm8OkXazYZF2r/gZ/bI+"
+"jkWbsn4O8qyAc3OUKQRZwBbf+lxBW+vM4O3ZpUjz5BSKCcFQgM+MY91yVU8Nji3HNnvGnDquobFAZ"
+"hxjL+S1l5+QZgkfyfv5mQScGRbU1Lar1xg9G3JznUb7S6pvrBO2nwK8g+KZBfJy5UeULigDH4IWo/"
+"JmtaEGkKE2uiKIjdsEQd/uwnkouW26XzRc0ulfJnPFftGnT9KIcShPf7DLj/tstmQAAceRMFHJTY3"
+"PmxoowoK8HUyBK5D5Fcl3MAQIAAAAAAQAAw5YvpRV9UqIk5SwZxPTceMfGvYAKwww5XnKczrXtOnu"
+"J00L5zh6B2qThL1gSm9HZi8eZ1l3KYvoXtAqbw6RdrNhkXav+Bn9sj6ORZuyfg7yrIBzc5QpBFnAF"
+"t/6XEFb68zg7dmlSPPkFIoJwVCAz4xj3XJVTw2OLcc2e8acOq6hsUBmHGMv5LWXn5BmCR/J+/mZBJ"
+"wZFtTUtqvXGD0bcnOdRvtLqm+sE7afAryD4pkF8nLlR5QuKAMfghaj8ma1oQaQoTa6IoiN2wRB3+7"
+"CeSi5bbpfNFzS6V8mc8V+0adP0ohxKE9/sMuP+2y2ZAABx5EwUclNjc+bGijCgrwdTIA==";
+
+
+static bool trust_domain_passwords_check_in(struct torture_context *tctx,
+ struct trustDomainPasswords *r)
+{
+ /* torture_assert_mem_equal(tctx, r->confounder, trust_domain_passwords_in, 512, "confounder mismatch"); */
+
+ torture_assert_int_equal(tctx, r->outgoing.count, 1, "outgoing count mismatch");
+ torture_assert_int_equal(tctx, r->outgoing.current_offset, 0x0000000c, "outgoing current offset mismatch");
+ torture_assert_int_equal(tctx, r->outgoing.previous_offset, 0x00000038, "outgoing previous offset mismatch");
+
+ torture_assert_int_equal(tctx, r->outgoing.current.count, 1, "outgoing current count mismatch");
+ torture_assert_int_equal(tctx, r->outgoing.current.array[0].LastUpdateTime, 0xB6416B4C, "outgoing current last update time mismatch");
+ torture_assert_int_equal(tctx, r->outgoing.current.array[0].AuthType, TRUST_AUTH_TYPE_CLEAR, "outgoing current auth type mismatch");
+ torture_assert_int_equal(tctx, r->outgoing.current.array[0].AuthInfo.clear.size, 0x0000001c, "outgoing current auth info size mismatch");
+ torture_assert_mem_equal(tctx, r->outgoing.current.array[0].AuthInfo.clear.password, trust_domain_passwords_in+512+12+8+4+4, 0x0000001c, "outgoing current auth info password mismatch");
+
+ torture_assert_int_equal(tctx, r->outgoing.previous.count, 0, "outgoing previous count mismatch");
+
+ torture_assert_int_equal(tctx, r->incoming.count, 1, "incoming count mismatch");
+ torture_assert_int_equal(tctx, r->incoming.current_offset, 0x0000000c, "incoming current offset mismatch");
+ torture_assert_int_equal(tctx, r->incoming.previous_offset, 0x00000038, "incoming previous offset mismatch");
+
+ torture_assert_int_equal(tctx, r->incoming.current.count, 1, "incoming current count mismatch");
+ torture_assert_int_equal(tctx, r->incoming.current.array[0].LastUpdateTime, 0xB6416B4C, "incoming current last update time mismatch");
+ torture_assert_int_equal(tctx, r->incoming.current.array[0].AuthType, TRUST_AUTH_TYPE_CLEAR, "incoming current auth type mismatch");
+ torture_assert_int_equal(tctx, r->incoming.current.array[0].AuthInfo.clear.size, 0x0000001c, "incoming current auth info size mismatch");
+ torture_assert_mem_equal(tctx, r->incoming.current.array[0].AuthInfo.clear.password, trust_domain_passwords_in+512+12+8+4+4+0x0000001c+12+8+4+4, 0x0000001c, "incoming current auth info password mismatch");
+
+ torture_assert_int_equal(tctx, r->incoming.previous.count, 0, "incoming previous count mismatch");
+
+ torture_assert_int_equal(tctx, r->outgoing_size, 0x00000038, "outgoing size mismatch");
+ torture_assert_int_equal(tctx, r->incoming_size, 0x00000038, "incoming size mismatch");
+
+ return true;
+}
+
+static const uint8_t supplementalCredentials_empty1[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool supplementalCredentials_empty1_check(struct torture_context *tctx,
+ struct supplementalCredentialsBlob *r)
+{
+ torture_assert_int_equal(tctx, r->unknown1, 0, "unknown1");
+ torture_assert_int_equal(tctx, r->__ndr_size, 0, "__ndr_size");
+ torture_assert_int_equal(tctx, r->unknown2, 0, "unknown2");
+ torture_assert(tctx, r->sub.prefix == NULL, "prefix");
+ torture_assert_int_equal(tctx, r->sub.signature, 0, "signature");
+ torture_assert_int_equal(tctx, r->sub.num_packages, 0, "num_packages");
+ torture_assert_int_equal(tctx, r->unknown3, 0, "unknown3");
+
+ return true;
+}
+
+static const uint8_t supplementalCredentials_empty2[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00 /* was 0x30 */
+ /*
+ * I've changed the last byte as Samba sets it to 0x00
+ * and it's random on Windows.
+ */
+};
+
+static bool supplementalCredentials_empty2_check(struct torture_context *tctx,
+ struct supplementalCredentialsBlob *r)
+{
+ torture_assert_int_equal(tctx, r->unknown1, 0, "unknown1");
+ torture_assert_int_equal(tctx, r->__ndr_size, 0x62, "__ndr_size");
+ torture_assert_int_equal(tctx, r->unknown2, 0, "unknown2");
+ torture_assert_str_equal(tctx, r->sub.prefix, SUPPLEMENTAL_CREDENTIALS_PREFIX, "prefix");
+ torture_assert_int_equal(tctx, r->sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE, "signature");
+ torture_assert_int_equal(tctx, r->sub.num_packages, 0, "num_packages");
+ torture_assert_int_equal(tctx, r->unknown3, 0x00, "unknown3"); /* This is typically not initialized */
+
+ return true;
+}
+
+static const char *alpha13_supplementalCredentials =
+ "AAAAAPgFAAAAAAAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAg"
+ "ACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAI"
+ "AAgACAAIAAgACAAUAADACAANAEBAFAAcgBpAG0AYQByAHkAOgBLAGUAcgBiAGUAcgBvAHMAMDMwMD"
+ "AwMDAwMjAwMDAwMDNFMDAzRTAwNEMwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMwMDAwMDAwODAwMDA"
+ "wMDhBMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDgwMDAwMDA5MjAwMDAwMDAwMDAwMDAw"
+ "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA0MTAwNEMwMDUwMDA0ODAwNDEwMDMxMDAzM"
+ "zAwMkUwMDUzMDA0MTAwNEQwMDQyMDA0MTAwMkUwMDQzMDA0RjAwNTIwMDUwMDA0MTAwNjQwMDZEMD"
+ "A2OTAwNkUwMDY5MDA3MzAwNzQwMDcyMDA2MTAwNzQwMDZGMDA3MjAwMkMwREQ2QzRFQzJGMDhDQjJ"
+ "DMERENkM0RUMyRjA4Q0IQAEAAAgBQAGEAYwBrAGEAZwBlAHMANEIwMDY1MDA3MjAwNjIwMDY1MDA3"
+ "MjAwNkYwMDczMDAwMDAwNTcwMDQ0MDA2OTAwNjcwMDY1MDA3MzAwNzQwMB4AwAMBAFAAcgBpAG0AY"
+ "QByAHkAOgBXAEQAaQBnAGUAcwB0ADMxMDAwMTFEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDQ1OE"
+ "FFNDY1NjY0NkVENUIxRTZCRUQ3NjBGMzZCMUM1RDBEMzRDNDE2MERBOEQ0QzM4M0U1OTQxMzM3MDl"
+ "COUQyMDYzMTUxQTI3ODBFODkzMDQ1OTg3N0IyRURGMUU0MDQ1OEFFNDY1NjY0NkVENUIxRTZCRUQ3"
+ "NjBGMzZCMUMzOTAyNDNBNENBQUUxNDUzMEVERDMwRTUyRjg1OTREQkEzNDBEMUExQzEyNkQ5QUVDN"
+ "kI3MDE3QzEzRTFEODY0NzNDQTk4RUZCOUI2OTRBODFEMjUyNkIwNzc1ODYzNUQ2MUE2MEMxNjIyMD"
+ "kxRDE2RDY4NEE1RTk2QzI0QkIwOENBMzQzNjI3M0E3Mzk0NTA1QkZEOUI1NTMzRUMwOUE3M0MyMDF"
+ "EQTA5RTVBREZEOUMwMzExRTZEMUJBNEIzNEEzN0FFODMyMUE5RTZFREMyQzA5NERBMDcwRUI4NTgz"
+ "QTYxQTYwQzE2MjIwOTFEMTZENjg0QTVFOTZDMjRCQjA4RTgzRENFNUNBOTJERkI4ODNFQTYwNUM4M"
+ "jc1OTVGRDE0QjBBM0M2RkRCOTQ2QjM5MkYxMDgzNjEyM0NGQjVFQThFNEZFNjAxNzBFRTA4OTQ2N0"
+ "MyNUJEMEY0OTAxMDc3MzYyNTk4RUFGRUI5MjAzNEJFMjEyRDVDNTM5MTdBQzE0RTRDM0RFRTcwQjh"
+ "BRDU2QUQ5NUMwNkNGNzU3M0VDOTY5MzlGOTYzNDQzNkFDQzY4QjYzRUFEM0ZDRDQ0QUM2RjY5QzND"
+ "MTdDQjlBODA5MDA5M0M0NDQyOERDQTg0ODNERTU5M0JDQUM5NThDNUE0Rjg4NTVDODY5QjAzMTlFR"
+ "jVCMUM3OTkyQTc5Q0I4N0I3NjFBMEU0QjUzQkYzNTQ0REQxNTQ0OEUwMTAzREJBMkMyRjZDMUVDNE"
+ "IwMjU5REZCODdFQTNDMDVDRjNEMUY2QzIwNkFDQkZGNTZDOUVGRDI3QUY2NTBDRjJGQjgxRThERTA"
+ "1QzVGQzE5QjE0QkE4M0UwN0ZCRkM0MUM5RENFQTlFNDY1RTBEODVDNDg2MUZCQTBGQzQyNDI0REEx"
+ "OTU4Mzk5REE3QTY3MTE3RUM5NTUxQTI1QzBFMzg1OEM2OUZFREFGRjUwRjUwQ0RFQzA0MTdFMUQ0M"
+ "UJFRjlBNzM5QzM0QzBDOTk3NzI5MERGRTIyNzJCQzVDOTMyMTVGMzkwRUE4QzYxRTIzQ0UwMDBDNg"
+ "A=";
+
+static bool alpha13_supplementalCredentials_check(struct torture_context *tctx,
+ struct supplementalCredentialsBlob *r)
+{
+ torture_assert_int_equal(tctx, r->unknown1, 0, "unknown1");
+ torture_assert_int_equal(tctx, r->__ndr_size, 0x5F8, "__ndr_size");
+ torture_assert_int_equal(tctx, r->unknown2, 0, "unknown2");
+ torture_assert_str_equal(tctx, r->sub.prefix, SUPPLEMENTAL_CREDENTIALS_PREFIX, "prefix");
+ torture_assert_int_equal(tctx, r->sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE, "signature");
+ torture_assert_int_equal(tctx, r->sub.num_packages, 3, "num_packages");
+ torture_assert_str_equal(tctx, r->sub.packages[0].name, "Primary:Kerberos", "name of package 0");
+ torture_assert_str_equal(tctx, r->sub.packages[1].name, "Packages", "name of package 1");
+ torture_assert_str_equal(tctx, r->sub.packages[2].name, "Primary:WDigest", "name of package 2");
+ torture_assert_int_equal(tctx, r->unknown3, 0x00, "unknown3"); /* This is typically not initialized */
+
+ return true;
+}
+
+static const char *release_4_1_0rc3_supplementalCredentials =
+ "AAAAALgIAAAAAAAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAg"
+ "ACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAI"
+ "AAgACAAIAAgACAAUAAEADYAEAIBAFAAcgBpAG0AYQByAHkAOgBLAGUAcgBiAGUAcgBvAHMALQBOAG"
+ "UAdwBlAHIALQBLAGUAeQBzADA0MDAwMDAwMDQwMDAwMDAwMDAwMDAwMDUwMDA1MDAwNzgwMDAwMDA"
+ "wMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDEyMDAwMDAwMjAwMDAwMDBDODAwMDAwMDAw"
+ "MDAwMDAwMDAwMDAwMDAwMDEwMDAwMDExMDAwMDAwMTAwMDAwMDBFODAwMDAwMDAwMDAwMDAwMDAwM"
+ "DAwMDAwMDEwMDAwMDAzMDAwMDAwMDgwMDAwMDBGODAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMD"
+ "AwMDAxMDAwMDAwMDgwMDAwMDAwMDAxMDAwMDUyMDA0NTAwNEMwMDQ1MDA0MTAwNTMwMDQ1MDAyRDA"
+ "wMzQwMDJEMDAzMTAwMkQwMDMwMDA1MjAwNDMwMDMzMDAyRTAwNTMwMDQxMDA0RDAwNDIwMDQxMDAy"
+ "RTAwNDMwMDRGMDA1MjAwNTAwMDQxMDA2NDAwNkQwMDY5MDA2RTAwNjkwMDczMDA3NDAwNzIwMDYxM"
+ "DA3NDAwNkYwMDcyMDA2MTQzNDMxNERDMjZFNzM0MTBERkQ2OUVENDc1Mjk1QTU1RjJGREUyNEQ2Qj"
+ "FEMEMzMzk4QkY2NDI3OUI4REMwNjg0Nzc5ODgzNkUwOTE1NTMwMjYwMDlCMkUzMzBDQjBBNzFBOTQ"
+ "xRjdGOEY3OTYyQTcxQTk0MUY3RjhGNzk2MiAAWAEBAFAAcgBpAG0AYQByAHkAOgBLAGUAcgBiAGUA"
+ "cgBvAHMAMDMwMDAwMDAwMjAwMDAwMDUwMDA1MDAwNEMwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMwM"
+ "DAwMDAwODAwMDAwMDlDMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMDgwMDAwMDBBNDAwMD"
+ "AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA1MjAwNDUwMDRDMDA0NTA"
+ "wNDEwMDUzMDA0NTAwMkQwMDM0MDAyRDAwMzEwMDJEMDAzMDAwNTIwMDQzMDAzMzAwMkUwMDUzMDA0"
+ "MTAwNEQwMDQyMDA0MTAwMkUwMDQzMDA0RjAwNTIwMDUwMDA0MTAwNjQwMDZEMDA2OTAwNkUwMDY5M"
+ "DA3MzAwNzQwMDcyMDA2MTAwNzQwMDZGMDA3MjAwQTcxQTk0MUY3RjhGNzk2MkE3MUE5NDFGN0Y4Rj"
+ "c5NjIQAJAAAgBQAGEAYwBrAGEAZwBlAHMANEIwMDY1MDA3MjAwNjIwMDY1MDA3MjAwNkYwMDczMDA"
+ "yRDAwNEUwMDY1MDA3NzAwNjUwMDcyMDAyRDAwNEIwMDY1MDA3OTAwNzMwMDAwMDA0QjAwNjUwMDcy"
+ "MDA2MjAwNjUwMDcyMDA2RjAwNzMwMDAwMDA1NzAwNDQwMDY5MDA2NzAwNjUwMDczMDA3NDAwHgDAA"
+ "wEAUAByAGkAbQBhAHIAeQA6AFcARABpAGcAZQBzAHQAMzEwMDAxMUQwMDAwMDAwMDAwMDAwMDAwMD"
+ "AwMDAwMDBFNDUwOUQ2MERDRDZERkIxOTlBMDY5QjU4NUUyOTdCMEU0RTgwMzc4QUQxMDhFQjdENUJ"
+ "COUQwNjBDMEVFRURBOUNEMzhGQTk3RjBERUJGNkRCMTkxNDA4RkIwQTQ2OThFNDUwOUQ2MERDRDZE"
+ "RkIxOTlBMDY5QjU4NUUyOTdCMDg2NjhCREI1QjM4ODg1M0Y5NDc0OTI0RjQzRkYzMEY0NDBFREJEN"
+ "UU3MUU0Mjg4QjNFRkYyRUFEQUQyQjcwMTNBRTEwODQ0MjlCQTc4RTUwRkYyMTAxRkFEQzEwMEI1Mz"
+ "NGODYwNzYyQzc1OTU0MTNEMENCRUNEODNDODJDRUE3Njk3MjgxQjI5QTU5M0U3MzRFQUQzMEZBMkE"
+ "3N0EzQkVERjA4MjEzMDNGMTUwOThFMUM1RkMzNjhDQzY2MTZEMTI1MDU4NzQ4RTUyRkMzM0YzQ0ZC"
+ "MUE0NUIzMzNEMUJDM0Y4NjA3NjJDNzU5NTQxM0QwQ0JFQ0Q4M0M4MkNFQTczNDk4MDNFN0FEODUyN"
+ "zEyMTlBNzEyMEQ4MkE4NjA2RDlERUQxMDA2NDk2MTkyQjZEQTM0RkQxMDdGOThDMjdDOTUyQzMwND"
+ "Q0MUFDODcwMTYwODdGNDU0ODUwMTRCQ0Q1QTNDNUU4NjBFQ0Y5RTQzMzJCODI1OTUyOTJFODYxNkF"
+ "DREU1RUJERjFFMkIzNDZCNTcyRUE2RjM4MkQyOTJCNkE4MDk3NzY1RDMyMTI0M0Y4QjFCRjAzNEFB"
+ "MjZGNEI3ODYwRUJGMzY4NDc5MTExRjQzRkMyRTVFQkUzQkNGRkE3N0RDOTdEQTJBQ0I0ODQ1NjIwQ"
+ "zg3QkNFMTYwQkE3RTEyOTFFQ0MwODdFQkE4Qzg1QkNDQjc4MzVGRTYyRUU4RTA0QTBBNzQwOENDQT"
+ "MxRkVDRjdFQTQ0MjI4QjJCRjVFQjg5MEQ2QjBEODgwNzVEMzhFREYxQzc5NEY1MDgxNUE2MzcxNTM"
+ "5QURCQTEyNkFDODc0Q0EyNzNBMzgwRTM0NjRFQkZERDE4MTgzRDY1MDlDOTJEQzVCQzhCNTg4M0Iy"
+ "QTlGRTcyMUQ0RkQ0MEQ3QkI0QzlENjcxOTYxNTRFRTQ4QkIzMDkxNEE3QkREODcyOTMyMjc1M0JDR"
+ "Dk2QkI5QzY1MzdFQjc1ODg3MUZDQzhGMEUxQjkyRTgyNEIxQTBDMjU1NjE2QURCMzYyMDc5NTQ5OT"
+ "Q5MUJCRTY5NTA0AA==";
+
+static bool release_4_1_0rc3_supplementalCredentials_check(struct torture_context *tctx,
+ struct supplementalCredentialsBlob *r)
+{
+ torture_assert_int_equal(tctx, r->unknown1, 0, "unknown1");
+ torture_assert_int_equal(tctx, r->__ndr_size, 0x8b8, "__ndr_size");
+ torture_assert_int_equal(tctx, r->unknown2, 0, "unknown2");
+ torture_assert_str_equal(tctx, r->sub.prefix, SUPPLEMENTAL_CREDENTIALS_PREFIX, "prefix");
+ torture_assert_int_equal(tctx, r->sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE, "signature");
+ torture_assert_int_equal(tctx, r->sub.num_packages, 4, "num_packages");
+ torture_assert_str_equal(tctx, r->sub.packages[0].name, "Primary:Kerberos-Newer-Keys", "name of package 0");
+ torture_assert_str_equal(tctx, r->sub.packages[1].name, "Primary:Kerberos", "name of package 0");
+ torture_assert_str_equal(tctx, r->sub.packages[2].name, "Packages", "name of package 1");
+ torture_assert_str_equal(tctx, r->sub.packages[3].name, "Primary:WDigest", "name of package 2");
+ torture_assert_int_equal(tctx, r->unknown3, 0x00, "unknown3"); /* This is typically not initialized */
+
+ return true;
+}
+
+static const char *release_4_5_0pre_GPG_supplementalCredentials =
+ "AAAAADAQAAAAAAAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAg"
+ "ACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAI"
+ "AAgACAAIAAgACAAUAAFADYAdAQBAFAAcgBpAG0AYQByAHkAOgBLAGUAcgBiAGUAcgBvAHMALQBOAG"
+ "UAdwBlAHIALQBLAGUAeQBzADA0MDAwMDAwMDQwMDAwMDAwNDAwMDQwMDQyMDA0MjAwMzgwMTAwMDA"
+ "wMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDEyMDAwMDAwMjAwMDAwMDA3QTAxMDAwMDAw"
+ "MDAwMDAwMDAwMDAwMDAwMDEwMDAwMDExMDAwMDAwMTAwMDAwMDA5QTAxMDAwMDAwMDAwMDAwMDAwM"
+ "DAwMDAwMDEwMDAwMDAzMDAwMDAwMDgwMDAwMDBBQTAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMD"
+ "AwMDAxMDAwMDAwMDgwMDAwMDBCMjAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDEyMDAwMDA"
+ "wMjAwMDAwMDBCQTAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDExMDAwMDAwMTAwMDAwMDBE"
+ "QTAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAzMDAwMDAwMDgwMDAwMDBFQTAxMDAwMDAwM"
+ "DAwMDAwMDAwMDAwMDAwMDEwMDAwMDAxMDAwMDAwMDgwMDAwMDBGMjAxMDAwMDAwMDAwMDAwMDAwMD"
+ "AwMDAwMDEwMDAwMDEyMDAwMDAwMjAwMDAwMDBGQTAxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDA"
+ "wMDExMDAwMDAwMTAwMDAwMDAxQTAyMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAzMDAwMDAw"
+ "MDgwMDAwMDAyQTAyMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAxMDAwMDAwMDgwMDAwMDAzM"
+ "jAyMDAwMDQxMDA0NDAwNDQwMDRGMDA0RDAwMkUwMDUzMDA0MTAwNEQwMDQyMDA0MTAwMkUwMDQ1MD"
+ "A1ODAwNDEwMDREMDA1MDAwNEMwMDQ1MDAyRTAwNDMwMDRGMDA0RDAwNzAwMDZGMDA3MzAwNjkwMDc"
+ "4MDA3NTAwNzMwMDY1MDA3MjAwMzEwMDM3NkI0RjI5OEM2QTJBNjJGNUJFQjMyOEZDQjUxMUFFREIz"
+ "NTI3NzY1NzQ2MDkzMzcyMTZDODk5MUQ0NUM3RTI4REZDMDA2Q0MzNzlFNzEyRkU0QTIxRTNBMDg1N"
+ "zM5MDM0QzgyNjBFMUY0NTRBN0MzNEM4MjYwRTFGNDU0QTdDODBDNDA1QjgxMkM2OEFCN0Q2QjZGRT"
+ "ZFRjRCQTM1N0ZBMTA1NjRDRjZFOUVFRUY2MUZEQUNGOEREM0Y3RkI0MDAzQjhBM0U1Qzk3NzgxOUF"
+ "BNkM0NzRFQTJDRkQxRjlFMkE4NjQwQUU5NDhBQzhGMTJBODY0MEFFOTQ4QUM4RjFEMDlDMjJGMTU0"
+ "MDZBQjk1QTUzRUQ5NkYxREFFRkJCNEY4NzUwMDQ4OEE1NzE0OEJFRTIzMkZGMjE4Q0Y3REE1MkZBQ"
+ "jYyQTEwQzk5NzUwMkYzNEQ1MEQzOTZEODgwODA0MEYxNkI3Q0VDN0ZDRTAxNDBGMTZCN0NFQzdGQ0"
+ "UwMSAArAEBAFAAcgBpAG0AYQByAHkAOgBLAGUAcgBiAGUAcgBvAHMAMDMwMDAwMDAwMjAwMDIwMDQ"
+ "yMDA0MjAwNzQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMwMDAwMDAwODAwMDAwMEI2MDAwMDAwMDAw"
+ "MDAwMDAwMDAwMDAwMDAxMDAwMDAwMDgwMDAwMDBCRTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMzAwM"
+ "DAwMDA4MDAwMDAwQzYwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwODAwMDAwMENFMDAwMD"
+ "AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDQxMDA0NDAwNDQwMDRGMDA"
+ "0RDAwMkUwMDUzMDA0MTAwNEQwMDQyMDA0MTAwMkUwMDQ1MDA1ODAwNDEwMDREMDA1MDAwNEMwMDQ1"
+ "MDAyRTAwNDMwMDRGMDA0RDAwNzAwMDZGMDA3MzAwNjkwMDc4MDA3NTAwNzMwMDY1MDA3MjAwMzEwM"
+ "DM0QzgyNjBFMUY0NTRBN0MzNEM4MjYwRTFGNDU0QTdDMkE4NjQwQUU5NDhBQzhGMTJBODY0MEFFOT"
+ "Q4QUM4RjEeAMADAQBQAHIAaQBtAGEAcgB5ADoAVwBEAGkAZwBlAHMAdAAzMTAwMDExRDAwMDAwMDA"
+ "wMDAwMDAwMDAwMDAwMDAwMENFMERENjk2NEU0ODNDN0YxRTIzMjk0RjRGMTMwMUJGRjI3Rjg5NTA1"
+ "MEEwMEVCODZBMTgwNzMyMkM1MzQzMUYxMEY2OTU2MUIyQUJFRjg2ODIyMjE2RTc5RTFGN0VGMUNFM"
+ "ERENjk2NEU0ODNDN0YxRTIzMjk0RjRGMTMwMUJGRjI3Rjg5NTA1MEEwMEVCODZBMTgwNzMyMkM1Mz"
+ "QzMUY0MURCMkRENzJCQzRERTgzRkUzMTBFQTEzRjQwNTE0RkNFMERENjk2NEU0ODNDN0YxRTIzMjk"
+ "0RjRGMTMwMUJGMUY2NjY3RjcyN0I2RjA4RERBOUFENjUyODdGMjVGNEQxRjY2NjdGNzI3QjZGMDhE"
+ "REE5QUQ2NTI4N0YyNUY0RDMwNDUyNUJCNTQwNDQ2NjE4OTRFM0YyRDQ4RUI5MTAyMzhGOTZFNDVBM"
+ "Tk2RkU5MjczQjREOUQxRUVEM0ExM0UxRjY2NjdGNzI3QjZGMDhEREE5QUQ2NTI4N0YyNUY0RDE0Qj"
+ "cyMDdGQUNGMEM2NDE5REMxRjNGMDIyMUYyREVBMzhGOTZFNDVBMTk2RkU5MjczQjREOUQxRUVEM0E"
+ "xM0VFMUJGMUI3NzY3NkZCNDcwODMwREYwMDM4RTIyRUY0QUUxQkYxQjc3Njc2RkI0NzA4MzBERjAw"
+ "MzhFMjJFRjRBRDVEQjFFOEJDNDE3QUEwMjlCNUU5MDFGQTA4OTQ0MjcxM0Q2ODUyNkE2MUVENDE1N"
+ "kQ5REY3OTA1MkUyQzZDQTExMUY4NTc4MkZFODRCNUQ2RDlDMzJBMDYxNkY3Q0U0QzkxMjUzQzU1Mz"
+ "QxN0MzMTY5MjM4Qzg1MjlDMkY3RjE0NzMzMUUyRDg5N0UyRDlBRjlDMzhGRDI2RjIwMkY0NTQ3MzM"
+ "xRTJEODk3RTJEOUFGOUMzOEZEMjZGMjAyRjQ1MUY2RDAyN0VDNjc1REZFNEQyMjlEOTA0MDFDOTZG"
+ "MEY0MjdCMjA5Nzg2MEJBQkI4QjUzQ0U0MUFBNzA0QTI0OTQyN0IyMDk3ODYwQkFCQjhCNTNDRTQxQ"
+ "UE3MDRBMjQ5QTYwN0E2M0ZERTJFRjAzN0U1M0NEQzkyNEM1NTI0QUIxQzA2OUZDRDNFOThGMDNFNz"
+ "lBOEJFN0NBQzMzOERDNUVERDY5RDEwNThENEY2QzQ2NTNCNTE4NTNFMjI1OUI5Q0M3NjZGRjRFNDg"
+ "5RUI4MEZFQTRGMThFMTIyMTJEQTkQALQAAgBQAGEAYwBrAGEAZwBlAHMANEIwMDY1MDA3MjAwNjIw"
+ "MDY1MDA3MjAwNkYwMDczMDAyRDAwNEUwMDY1MDA3NzAwNjUwMDcyMDAyRDAwNEIwMDY1MDA3OTAwN"
+ "zMwMDAwMDA0QjAwNjUwMDcyMDA2MjAwNjUwMDcyMDA2RjAwNzMwMDAwMDA1NzAwNDQwMDY5MDA2Nz"
+ "AwNjUwMDczMDA3NDAwMDAwMDUzMDA2MTAwNkQwMDYyMDA2MTAwNDcwMDUwMDA0NzAwIAB2BAEAUAB"
+ "yAGkAbQBhAHIAeQA6AFMAYQBtAGIAYQBHAFAARwAyRDJEMkQyRDJENDI0NTQ3NDk0RTIwNTA0NzUw"
+ "MjA0RDQ1NTM1MzQxNDc0NTJEMkQyRDJEMkQwQTU2NjU3MjczNjk2RjZFM0EyMDQ3NkU3NTUwNDcyM"
+ "Dc2MzIwQTBBNjg1MTQ1NEQ0MTJGMzM3ODZCNDY2QTY4NDQzMzRCNkU0MTUxNjYyRjY1NDczNjc5NE"
+ "I2ODU5NjQ2OTZFNzEyRjRGMzg0QTcyNzg0QzQzMzY0NDc3NkU2NjZGNzA0QzRGNzQyRjM2NEY0QzM"
+ "yNDQ0MzQzNjc1NTUxNkM0MjUwNjMwQTMzNDE2NTMyNkU2QzU5NDUzMTc0MkYzNzdBNEM2NzY1NTA2"
+ "NDZBNDM2RjZBN0E0OTQzMzEzOTcxMzA0RjM5MkY1NzM0NEIzNTU0N0E3MzY5NjU2RjZDNkU0NTQ0N"
+ "jQzMjY3NTc0Njc1NTAzNzc4NEQ2NjQyNzI0RTY0NzM3QTM3MEE2RTYyNDg1NzdBNDc2NDM4NzU1Nj"
+ "JCNzQ0NDJGNkEzMDM4Nzk2NzcxNDI2ODdBNEI0QTU1NkE0OTU5NTY2MTUwNTQ3NjY2MzQ3NjMwNDM"
+ "3NjQ1NjI2NTQ0NDg0QzZDNTI3QTQ0Njc0Nzc5NDc3MzMxMzU0ODY0MzI1MDRDNDgzMjBBNkU2RDM1"
+ "NzU0OTc0NTk0OTY0NTczOTQyNkMzOTM4Mzk2MTU1MzczNjZENEU1MjU0NkIzOTMwMzE1MjM5NEM2O"
+ "TcwNTA2RDQ4NzU0MTc4NTE0NzQ0NTI3NTcxNEI2Rjc0NTg2QzU3NDY3NjM0NjE2NDY2NTU1NDZEMz"
+ "U2RTZCNTAwQTQ0Mzg3MzczNDU2QjMyNDM1NTZBNEQ0RjQ3NkI3MDJGMkYyQjM3MzQ0QjRBNzI2OTV"
+ "BMzg3NTcxMzE1NzMxNTY3ODY3NzE2RTc1NDY1ODREMzM3MjQyMzkzNjY2NDM1QTU4NDM0RDJGNDQ1"
+ "MjRDNjc1MzY4NjMzMDU4NTM0MjQ4MEE2ODQxNDE2QzVBMkI3MzYzNEQ1QTQ3Mzg0OTU3MkIzOTU2N"
+ "EI1QTU2NDY2QTZCNTk0RTZGNzI1MjRDNEE1QTZFNzY3MDU2NEQ2ODc2NTY2RTM1Mzk0QTYxNDE2Mj"
+ "U1NDY3MzUwNTk0Qjc0Nzg3ODJCNDU2RjZFMzczNzM4NDE1OTBBMzkzNDRCNzY1MDZFNEI1MzMzNzA"
+ "zMTQ5NjM2ODU3NTQ2QTc2NEM3MTc2NTk2Njc2NzM1NzRENjc2OTY0NEQzMDc5NUE1OTU5NEE2NzUx"
+ "NTM2QjdBNDczNzUzNEQ1OTY0NTA1QTc3NzkzMjQxNEQ2QTRFMzU0QTQzNTI2RDQ3NjkwQTY0NjUzN"
+ "jJGMzc2RjRFNTU1OTMxNEE1NTUwNTY0Njc1MzkyQjUyNUE2RDY4NjkzNTM1NEY3NzJGN0E0RjU1Nz"
+ "czMzcwNDc2NzBBM0Q3MTY4NkM0NjBBMkQyRDJEMkQyRDQ1NEU0NDIwNTA0NzUwMjA0RDQ1NTM1MzQ"
+ "xNDc0NTJEMkQyRDJEMkQwQQA=";
+
+static bool release_4_5_0pre_GPG_supplementalCredentials_check(struct torture_context *tctx,
+ struct supplementalCredentialsBlob *r)
+{
+ torture_assert_int_equal(tctx, r->unknown1, 0, "unknown1");
+ torture_assert_int_equal(tctx, r->__ndr_size, 0x1030, "__ndr_size");
+ torture_assert_int_equal(tctx, r->unknown2, 0, "unknown2");
+ torture_assert_str_equal(tctx, r->sub.prefix, SUPPLEMENTAL_CREDENTIALS_PREFIX, "prefix");
+ torture_assert_int_equal(tctx, r->sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE, "signature");
+ torture_assert_int_equal(tctx, r->sub.num_packages, 5, "num_packages");
+ torture_assert_str_equal(tctx, r->sub.packages[0].name, "Primary:Kerberos-Newer-Keys", "name of package 0");
+ torture_assert_str_equal(tctx, r->sub.packages[1].name, "Primary:Kerberos", "name of package 1");
+ torture_assert_str_equal(tctx, r->sub.packages[2].name, "Primary:WDigest", "name of package 2");
+ torture_assert_str_equal(tctx, r->sub.packages[3].name, "Packages", "name of package 3");
+ torture_assert_str_equal(tctx, r->sub.packages[4].name, "Primary:SambaGPG", "name of package 4");
+ torture_assert_int_equal(tctx, r->unknown3, 0x00, "unknown3"); /* This is typically not initialized */
+
+ return true;
+}
+
+static const char *win2012R2_supplementalCredentials =
+ "AAAAACgIAAAAAAAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAg"
+ "ACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAI"
+ "AAgACAAIAAgACAAUAAEADYA3AEBAFAAcgBpAG0AYQByAHkAOgBLAGUAcgBiAGUAcgBvAHMALQBOAG"
+ "UAdwBlAHIALQBLAGUAeQBzADA0MDAwMDAwMDMwMDAwMDAwMDAwMDAwMDNlMDAzZTAwNzgwMDAwMDA"
+ "wMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDEyMDAwMDAwMjAwMDAwMDBiNjAwMDAwMDAw"
+ "MDAwMDAwMDAwMDAwMDAwMDEwMDAwMDExMDAwMDAwMTAwMDAwMDBkNjAwMDAwMDAwMDAwMDAwMDAwM"
+ "DAwMDAwMDEwMDAwMDAzMDAwMDAwMDgwMDAwMDBlNjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD"
+ "AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDMyMDAzMDAwMzAwMDM4MDA1MjAwMzIwMDJlMDA0ODA"
+ "wNGYwMDU3MDA1NDAwNGYwMDJlMDA0MTAwNDIwMDQxMDA1MjAwNTQwMDRjMDA0NTAwNTQwMDJlMDA0"
+ "ZTAwNDUwMDU0MDA2YjAwNzIwMDYyMDA3NDAwNjcwMDc0MDAwNzNhYTVmMjVmZjU2MzUyZTI2ZWYxZ"
+ "DMxMGJhZjAzMWY0MWZmMmFkNzZlNzA1YzgzNTQyZmJlZGJhNjY0ZjM0YTBmYTAyYzQxNWE3MmFiNj"
+ "JkYjdlNzliNDBmNjJhNjhjMjVlZjc0YzE5ZDM1OGZkIAD8AAEAUAByAGkAbQBhAHIAeQA6AEsAZQB"
+ "yAGIAZQByAG8AcwAwMzAwMDAwMDAxMDAwMDAwM2UwMDNlMDAzODAwMDAwMDAwMDAwMDAwMDAwMDAw"
+ "MDAwMzAwMDAwMDA4MDAwMDAwNzYwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM"
+ "DAwMDAwMDAwMzIwMDMwMDAzMDAwMzgwMDUyMDAzMjAwMmUwMDQ4MDA0ZjAwNTcwMDU0MDA0ZjAwMm"
+ "UwMDQxMDA0MjAwNDEwMDUyMDA1NDAwNGMwMDQ1MDA1NDAwMmUwMDRlMDA0NTAwNTQwMDZiMDA3MjA"
+ "wNjIwMDc0MDA2NzAwNzQwMGMyNWVmNzRjMTlkMzU4ZmQQAJAAAgBQAGEAYwBrAGEAZwBlAHMANGIw"
+ "MDY1MDA3MjAwNjIwMDY1MDA3MjAwNmYwMDczMDAyZDAwNGUwMDY1MDA3NzAwNjUwMDcyMDAyZDAwN"
+ "GIwMDY1MDA3OTAwNzMwMDAwMDA0YjAwNjUwMDcyMDA2MjAwNjUwMDcyMDA2ZjAwNzMwMDAwMDA1Nz"
+ "AwNDQwMDY5MDA2NzAwNjUwMDczMDA3NDAwHgDAAwEAUAByAGkAbQBhAHIAeQA6AFcARABpAGcAZQB"
+ "zAHQAMzEwMDAxMWQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA3ZGE1MjA2NjllNTdkYzhjMzI1NDQ0"
+ "Y2ZkYjU5ZjkxZGZiZDE1MzZhNDIxMjgyNjc4MjE4MWI5OTM2ZjczYWIzOWYyN2QxYjM4YmRlNzhiO"
+ "TVhOTJmNDM1YWQyNDAzNDU3ZGE1MjA2NjllNTdkYzhjMzI1NDQ0Y2ZkYjU5ZjkxZGZiZDE1MzZhND"
+ "IxMjgyNjc4MjE4MWI5OTM2ZjczYWIzNjFjNTgyZGY1NWZiOGZmMzMyMzc0ZDU4NDExNWI2Y2U3ZGE"
+ "1MjA2NjllNTdkYzhjMzI1NDQ0Y2ZkYjU5ZjkxZDU3NGM4MmQxMWZjNzcyOGNiYmY0NWI1Yjc0NmMx"
+ "NmY0NjhhZmFhYTI0OTEwODM2ZWMyMGYyMTBjNmQ1ODZmZTE3ZjQxN2RkOWIzMjE5OWJiOTkzZmMxN"
+ "mQ3NzA5MjFiMDU3NGM4MmQxMWZjNzcyOGNiYmY0NWI1Yjc0NmMxNmY0NjhhZmFhYTI0OTEwODM2ZW"
+ "MyMGYyMTBjNmQ1ODZmZTE5ODZlNWM1ZDM2NjllZDI0ZDgyM2RlNWYyZmZhNjk1ZTU3NGM4MmQxMWZ"
+ "jNzcyOGNiYmY0NWI1Yjc0NmMxNmY0OGNjZGJjMWZhZWM0OWFmOGY2ZGQ0N2M5MmViM2JmNjMwMzAy"
+ "Njc2NmI4ZWQzYjU0ZTQyNGU1ZDNlNDVkNjlkNmIwYzI3Y2ZhMzZmNjliN2NmNDVjMGNhYjU3NmY1M"
+ "zRiOWU3NTJhOWUyNTYzMmU4M2FkMmE5MDBmMWUyOGY5ZjE0MjFkYzUwODMyMjQ1Nzc3NTg5ODIyZT"
+ "EwNGY2NjNkNjY3YzJiZTc3Y2E4MzMwNzVkZmRlZTRlYTUwZWIxNzc3YjMxOGNmZTJlMzQzOTg0ZDU"
+ "xOTBlODAwMzA4ZmMxODBiMzE4Y2ZlMmUzNDM5ODRkNTE5MGU4MDAzMDhmYzE4MDRhYmIyZDQzMjE0"
+ "ZGQxNGFkNDA0YzdiYzE4ZGI0NzFjNDRjZjcyZmI2YmUwM2IwZWRiZjNhNzYyNTgwZGIzOTYzZjk5M"
+ "zVjNmM4N2Q2NWJhZmU0NGY4Zjc2NzViODE3NjgwN2RmZThiZGZlYjJiMTcyMzc4MWQzMThhZGRkZW"
+ "NmNzQ5MmIwZjE3ZmIwZmRmMjhkN2E2MWMzNTFlYTRkYWU2MDc0MzMxMTAwYjk5YWJiOTY1NTk5ZDY"
+ "1NjkxNDVjOWM5MTJjOWI2Yzk0ZjNiMDA3ZmM5YTA2OGFiMDhkNTA5gA==";
+
+
+static bool win2012R2_supplementalCredentials_check(struct torture_context *tctx,
+ struct supplementalCredentialsBlob *r)
+{
+ torture_assert_int_equal(tctx, r->unknown1, 0, "unknown1");
+ torture_assert_int_equal(tctx, r->__ndr_size, 0x828, "__ndr_size");
+ torture_assert_int_equal(tctx, r->unknown2, 0, "unknown2");
+ torture_assert_str_equal(tctx, r->sub.prefix, SUPPLEMENTAL_CREDENTIALS_PREFIX, "prefix");
+ torture_assert_int_equal(tctx, r->sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE, "signature");
+ torture_assert_int_equal(tctx, r->sub.num_packages, 4, "num_packages");
+ torture_assert_str_equal(tctx, r->sub.packages[0].name, "Primary:Kerberos-Newer-Keys", "name of package 0");
+ torture_assert_str_equal(tctx, r->sub.packages[1].name, "Primary:Kerberos", "name of package 0");
+ torture_assert_str_equal(tctx, r->sub.packages[2].name, "Packages", "name of package 1");
+ torture_assert_str_equal(tctx, r->sub.packages[3].name, "Primary:WDigest", "name of package 2");
+ torture_assert_int_equal(tctx, r->unknown3, 0x00, "unknown3"); /* This is typically not initialized, we force to 0 */
+
+ return true;
+}
+
+struct torture_suite *ndr_drsblobs_suite(TALLOC_CTX *ctx)
+{
+ DATA_BLOB win2012R2_supplementalCredentials_blob;
+ struct torture_suite *suite = torture_suite_create(ctx, "drsblobs");
+ struct torture_suite *empty1_suite = torture_suite_create(ctx, "empty1");
+ struct torture_suite *empty2_suite = torture_suite_create(ctx, "empty2");
+ struct torture_suite *alpha13_suite = torture_suite_create(ctx, "alpha13");
+ struct torture_suite *release_4_1_0rc3_suite = torture_suite_create(ctx, "release-4-1-0rc3");
+ struct torture_suite *release_4_5_0pre_GPG_suite = torture_suite_create(ctx, "release-4-5-0pre-GPG");
+ struct torture_suite *win2012R2_suite = torture_suite_create(ctx, "win2012R2_suite");
+ torture_suite_add_suite(suite, empty1_suite);
+ torture_suite_add_suite(suite, empty2_suite);
+ torture_suite_add_suite(suite, alpha13_suite);
+ torture_suite_add_suite(suite, release_4_1_0rc3_suite);
+ torture_suite_add_suite(suite, release_4_5_0pre_GPG_suite);
+ torture_suite_add_suite(suite, win2012R2_suite);
+
+ torture_suite_add_ndr_pull_test(suite, ForestTrustInfo, forest_trust_info_data_out, forest_trust_info_check_out);
+ torture_suite_add_ndr_pull_test(suite, trustDomainPasswords, trust_domain_passwords_in, trust_domain_passwords_check_in);
+
+ torture_suite_add_ndr_pull_validate_test_blob(suite,
+ trustAuthInOutBlob,
+ base64_decode_data_blob_talloc(suite, trustAuthIncoming),
+ NULL);
+
+ torture_suite_add_ndr_pull_validate_test_blob(suite,
+ trustAuthInOutBlob,
+ base64_decode_data_blob_talloc(suite, trustAuthOutgoing),
+ NULL);
+
+ torture_suite_add_ndr_pull_validate_test(empty1_suite, supplementalCredentialsBlob,
+ supplementalCredentials_empty1,
+ supplementalCredentials_empty1_check);
+
+ torture_suite_add_ndr_pull_validate_test(empty2_suite, supplementalCredentialsBlob,
+ supplementalCredentials_empty2,
+ supplementalCredentials_empty2_check);
+
+ torture_suite_add_ndr_pull_validate_test_blob(alpha13_suite,
+ supplementalCredentialsBlob,
+ base64_decode_data_blob_talloc(suite, alpha13_supplementalCredentials),
+ alpha13_supplementalCredentials_check);
+
+ torture_suite_add_ndr_pull_validate_test_blob(release_4_1_0rc3_suite,
+ supplementalCredentialsBlob,
+ base64_decode_data_blob_talloc(suite, release_4_1_0rc3_supplementalCredentials),
+ release_4_1_0rc3_supplementalCredentials_check);
+
+ torture_suite_add_ndr_pull_validate_test_blob(release_4_5_0pre_GPG_suite,
+ supplementalCredentialsBlob,
+ base64_decode_data_blob_talloc(suite, release_4_5_0pre_GPG_supplementalCredentials),
+ release_4_5_0pre_GPG_supplementalCredentials_check);
+
+ /* This last byte is typically not initialized, we force to zero to allow pull/push */
+ win2012R2_supplementalCredentials_blob = base64_decode_data_blob_talloc(suite, win2012R2_supplementalCredentials);
+ win2012R2_supplementalCredentials_blob.data[win2012R2_supplementalCredentials_blob.length-1] = 0;
+ torture_suite_add_ndr_pull_validate_test_blob(win2012R2_suite,
+ supplementalCredentialsBlob,
+ win2012R2_supplementalCredentials_blob,
+ win2012R2_supplementalCredentials_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/drsuapi.c b/source4/torture/ndr/drsuapi.c
new file mode 100644
index 0000000..5d26c4b
--- /dev/null
+++ b/source4/torture/ndr/drsuapi.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for drsuapi ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t DsAddEntry_req1_dat[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x52, 0xd7, 0x26, 0x47, 0x58, 0xd3, 0xd4, 0x45,
+ 0xaf, 0xa3, 0x85, 0x49, 0x9d, 0x26, 0xb6, 0x11, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x87, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00,
+ 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x44, 0x00,
+ 0x53, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x73, 0x00, 0x2c, 0x00, 0x43, 0x00,
+ 0x4e, 0x00, 0x3d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00,
+ 0x2d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x37, 0x00, 0x2c, 0x00, 0x43, 0x00,
+ 0x4e, 0x00, 0x3d, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x2c, 0x00, 0x43, 0x00, 0x4e, 0x00,
+ 0x3d, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x2d, 0x00, 0x64, 0x00, 0x65, 0x00, 0x73, 0x00, 0x2d, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x2d, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x74, 0x00, 0x73, 0x00, 0x2c, 0x00, 0x43, 0x00,
+ 0x4e, 0x00, 0x3d, 0x00, 0x53, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x73, 0x00, 0x2c, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x43, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00, 0x67, 0x00, 0x75, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x19, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00,
+ 0x0e, 0x03, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0x73, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00,
+ 0x0e, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x2c, 0x07, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x02, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x02, 0x00,
+ 0x1c, 0x07, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x02, 0x00,
+ 0xb3, 0x05, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x02, 0x00,
+ 0x77, 0x01, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x02, 0x00,
+ 0x03, 0x02, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0xa0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x80, 0x68, 0x00, 0x00, 0x00,
+ 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x54, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
+ 0x94, 0x00, 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xfd, 0x01, 0x0f, 0x00,
+ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x16, 0xd8, 0xd8, 0x2d, 0x03, 0xe4, 0xc3, 0x74, 0x65, 0x8b, 0xdd, 0x61,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xff, 0x01, 0x0f, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00,
+ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x16, 0xd8, 0xd8, 0x2d, 0x03, 0xe4, 0xc3, 0x74, 0x65, 0x8b, 0xdd, 0x61,
+ 0x00, 0x02, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x16, 0xd8, 0xd8, 0x2d, 0x03, 0xe4, 0xc3, 0x74,
+ 0x65, 0x8b, 0xdd, 0x61, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x2f, 0x00, 0x17, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x02, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x4e, 0x00,
+ 0x54, 0x00, 0x44, 0x00, 0x53, 0x00, 0x2d, 0x00, 0x44, 0x00, 0x53, 0x00,
+ 0x41, 0x00, 0x2c, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x53, 0x00,
+ 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x2c, 0x00,
+ 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x66, 0x00, 0x69, 0x00, 0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0xae, 0xa5, 0x70, 0xc5,
+ 0x6d, 0x2a, 0x27, 0x4e, 0xa1, 0xcc, 0xde, 0x11, 0xcb, 0x76, 0x56, 0x22,
+ 0x03, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00,
+ 0x7a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x02, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x43, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00, 0x67, 0x00, 0x75, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x44, 0x00, 0x43, 0x00,
+ 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00,
+ 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00,
+ 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00,
+ 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3a, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x53, 0x00,
+ 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x2c, 0x00,
+ 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x66, 0x00, 0x69, 0x00, 0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00,
+ 0x3c, 0x00, 0x02, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00,
+ 0xb0, 0x00, 0x00, 0x00, 0x44, 0x00, 0x02, 0x00, 0x9c, 0x00, 0x00, 0x00,
+ 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00,
+ 0x3d, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00,
+ 0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00,
+ 0x33, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00,
+ 0x6d, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00,
+ 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00,
+ 0x3d, 0x00, 0x53, 0x00, 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x2c, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x43, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00, 0x67, 0x00, 0x75, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xb0, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x00,
+ 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00,
+ 0x3d, 0x00, 0x53, 0x00, 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x61, 0x00, 0x2c, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x43, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00, 0x67, 0x00, 0x75, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x00, 0x00, 0x54, 0x00, 0x02, 0x00, 0x7a, 0x00, 0x00, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x44, 0x00, 0x43, 0x00,
+ 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x2c, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x6e, 0x00,
+ 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00,
+ 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00,
+ 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x02, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
+ 0xac, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x02, 0x00, 0xac, 0x00, 0x00, 0x00,
+ 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x43, 0x00, 0x4e, 0x00,
+ 0x3d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x33, 0x00, 0x2d, 0x00,
+ 0x31, 0x00, 0x30, 0x00, 0x37, 0x00, 0x2c, 0x00, 0x43, 0x00, 0x4e, 0x00,
+ 0x3d, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x75, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00,
+ 0x2c, 0x00, 0x44, 0x00, 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x2c, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x3d, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t DsAddEntry_resp1_dat[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x88, 0xf1, 0x0d, 0x4a, 0xb8, 0xa0, 0xea, 0x47, 0xbb, 0xe5, 0xe6, 0x14,
+ 0x72, 0x3f, 0x16, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+static const uint8_t DsBind_req1_dat[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x9c, 0xb9, 0xfa, 0x6a, 0x26, 0x6e, 0x4a, 0x46,
+ 0x97, 0x5f, 0xf5, 0x8f, 0x10, 0x52, 0x18, 0xbc, 0x04, 0x00, 0x02, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x7f, 0xfb, 0xff, 0x1f,
+ 0xda, 0x95, 0x70, 0x26, 0xc1, 0x67, 0xae, 0x4e, 0xb6, 0xfe, 0xf2, 0x83,
+ 0x15, 0xe3, 0x87, 0xe8, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71, 0x02, 0x40, 0x28, 0x00,
+ 0x35, 0x42, 0x51, 0xe3, 0x06, 0x4b, 0xd1, 0x11, 0xab, 0x04, 0x00, 0xc0,
+ 0x4f, 0xc2, 0xdc, 0xd2, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
+ 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00
+};
+*/
+
+static const uint8_t DsBind_resp1_dat[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x7f, 0xfb, 0xff, 0x1f, 0x81, 0xa6, 0xff, 0x5d, 0x80, 0x13, 0x94, 0x41,
+ 0xa3, 0x72, 0xe9, 0xb7, 0x79, 0xd7, 0x02, 0x68, 0xf8, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xc6, 0x55, 0x68,
+ 0xcf, 0x05, 0x42, 0x4a, 0xbb, 0xd3, 0x74, 0xcc, 0x6c, 0xaa, 0xdc, 0x73,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+static const uint8_t DsBind_req2_dat[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x9c, 0xb9, 0xfa, 0x6a, 0x26, 0x6e, 0x4a, 0x46,
+ 0x97, 0x5f, 0xf5, 0x8f, 0x10, 0x52, 0x18, 0xbc, 0x04, 0x00, 0x02, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x7f, 0xfb, 0xff, 0x1f,
+ 0xda, 0x95, 0x70, 0x26, 0xc1, 0x67, 0xae, 0x4e, 0xb6, 0xfe, 0xf2, 0x83,
+ 0x15, 0xe3, 0x87, 0xe8, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+*/
+
+static const uint8_t DsBind_resp2_dat[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x7f, 0xfb, 0xff, 0x1f, 0x81, 0xa6, 0xff, 0x5d, 0x80, 0x13, 0x94, 0x41,
+ 0xa3, 0x72, 0xe9, 0xb7, 0x79, 0xd7, 0x02, 0x68, 0xf8, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xd7, 0x26, 0x47,
+ 0x58, 0xd3, 0xd4, 0x45, 0xaf, 0xa3, 0x85, 0x49, 0x9d, 0x26, 0xb6, 0x11,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+struct torture_suite *ndr_drsuapi_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "drsuapi");
+
+ torture_suite_add_ndr_pull_fn_test(suite, drsuapi_DsAddEntry, DsAddEntry_req1_dat, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, drsuapi_DsAddEntry, DsAddEntry_resp1_dat, NDR_OUT, NULL );
+
+ /*torture_suite_add_ndr_pull_fn_test(suite, drsuapi_DsBind, DsBind_req1_dat, NDR_IN, NULL );*/
+ torture_suite_add_ndr_pull_fn_test(suite, drsuapi_DsBind, DsBind_resp1_dat, NDR_OUT, NULL );
+
+ /* torture_suite_add_ndr_pull_fn_test(suite, drsuapi_DsBind, DsBind_req2_dat, NDR_IN, NULL ); */
+ torture_suite_add_ndr_pull_fn_test(suite, drsuapi_DsBind, DsBind_resp2_dat, NDR_OUT, NULL );
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/epmap.c b/source4/torture/ndr/epmap.c
new file mode 100644
index 0000000..ddc1e74
--- /dev/null
+++ b/source4/torture/ndr/epmap.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for epmap ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t map_in_data[] = {
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x13, 0x00,
+ 0x0d, 0x78, 0x57, 0x34, 0x12, 0x34, 0x12, 0xcd, 0xab, 0xef, 0x00, 0x01,
+ 0x23, 0x45, 0x67, 0x89, 0xac, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x0d, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8,
+ 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x02, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
+};
+
+static bool map_in_check(struct torture_context *tctx,
+ struct epm_Map *r)
+{
+ /* FIXME: Object */
+ torture_assert_int_equal(tctx, r->in.max_towers, 1, "max towers");
+ torture_assert(tctx, r->in.map_tower != NULL, "map tower");
+ torture_assert_int_equal(tctx, r->in.map_tower->tower_length, 75, "tower len");
+ /* FIXME: entry handle */
+
+ return true;
+}
+
+#if 0
+static const uint8_t map_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0xc3, 0x47, 0xdd, 0xe6, 0x5a, 0x8b, 0x42,
+ 0xb3, 0xb7, 0xc7, 0x79, 0x7b, 0xf0, 0x45, 0xe0, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00
+};
+
+static bool map_out_check(struct torture_context *tctx,
+ struct epm_Map *r)
+{
+ torture_assert_int_equal(tctx, *r->out.num_towers, 1, "num towers");
+ torture_assert_int_equal(tctx, r->out.result, 0x4b, "return code");
+ /* FIXME: entry handle */
+
+ return true;
+}
+#endif
+
+struct torture_suite *ndr_epmap_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "epmap");
+
+ torture_suite_add_ndr_pull_fn_test(suite, epm_Map, map_in_data, NDR_IN, map_in_check );
+ /* torture_suite_add_ndr_pull_fn_test(suite, epm_Map, map_out_data, NDR_OUT, map_out_check ); */
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/krb5pac.c b/source4/torture/ndr/krb5pac.c
new file mode 100644
index 0000000..fe0309f
--- /dev/null
+++ b/source4/torture/ndr/krb5pac.c
@@ -0,0 +1,705 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for PAC ndr operations
+
+ Copyright (C) Guenther Deschner 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+#include "torture/ndr/proto.h"
+#include "lib/krb5_wrap/krb5_samba.h"
+
+static const uint8_t PAC_DATA_data[] = {
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
+ 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0xb2, 0x98, 0xae, 0xb6, 0x70, 0xd8, 0xcd, 0x01, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xb2, 0xd0, 0x46, 0x15, 0x4c, 0xce, 0xcd, 0x01, 0xb2, 0xd0, 0x46, 0x15,
+ 0x4c, 0xce, 0xcd, 0x01, 0xb2, 0x50, 0xa0, 0x0a, 0x4d, 0xef, 0xcd, 0x01,
+ 0x1a, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0x9e, 0x03, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x20, 0x00, 0x02, 0x00,
+ 0x0e, 0x00, 0x10, 0x00, 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x47, 0x00, 0x44, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00,
+ 0x52, 0x00, 0x32, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00,
+ 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x58, 0xcd, 0x06, 0x06, 0xed, 0x40, 0x2a, 0x76, 0x83, 0xc8, 0xe3, 0x99,
+ 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x20,
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x58, 0xcd, 0x06, 0x06, 0xed, 0x40, 0x2a, 0x76,
+ 0x83, 0xc8, 0xe3, 0x99, 0x3c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x56, 0x9d, 0x59, 0x71, 0xd8, 0xcd, 0x01, 0x1a, 0x00, 0x61, 0x00,
+ 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x58, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x64, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x40, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x38, 0x00, 0x64, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x38, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x2e, 0x00,
+ 0x42, 0x00, 0x45, 0x00, 0x52, 0x00, 0x2e, 0x00, 0x52, 0x00, 0x45, 0x00,
+ 0x44, 0x00, 0x48, 0x00, 0x41, 0x00, 0x54, 0x00, 0x2e, 0x00, 0x43, 0x00,
+ 0x4f, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff,
+ 0x1a, 0x46, 0xc3, 0x88, 0x72, 0x36, 0xa4, 0x0f, 0x60, 0x0e, 0xed, 0x03,
+ 0xc8, 0xa6, 0x1a, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff,
+ 0xd6, 0x4f, 0xa7, 0xac, 0x53, 0x73, 0x9b, 0x5c, 0xdf, 0xb1, 0xdf, 0xa6,
+ 0xdd, 0x84, 0x8e, 0xfb, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool PAC_DATA_check(struct torture_context *tctx,
+ struct PAC_DATA *r)
+{
+ int i;
+
+ torture_assert_int_equal(tctx, r->num_buffers, 5, "num_buffers");
+
+ for (i=0; i < r->num_buffers; i++) {
+ switch (r->buffers[i].type) {
+ case PAC_TYPE_UPN_DNS_INFO:
+ torture_assert_int_equal(tctx,
+ r->buffers[i].info->upn_dns_info.upn_name_size,
+ 2*strlen_m("Administrator@w2k8dom.ber.redhat.com"),
+ "upn_name_size");
+ torture_assert_str_equal(tctx,
+ r->buffers[i].info->upn_dns_info.upn_name,
+ "Administrator@w2k8dom.ber.redhat.com",
+ "upn_name");
+ torture_assert_int_equal(tctx,
+ r->buffers[i].info->upn_dns_info.dns_domain_name_size,
+ 2*strlen_m("W2K8DOM.BER.REDHAT.COM"),
+ "dns_domain_name_size");
+ torture_assert_str_equal(tctx,
+ r->buffers[i].info->upn_dns_info.dns_domain_name,
+ "W2K8DOM.BER.REDHAT.COM",
+ "dns_domain_name");
+ break;
+ default:
+ continue;
+ }
+ }
+
+ return true;
+}
+
+static const uint8_t PAC_DATA_data2[] = {
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x18, 0x02, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x70, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00,
+ 0x98, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x4f, 0xb3, 0xf4, 0xa3, 0x8d, 0x00, 0xce, 0x01, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0xff, 0xd2, 0x34, 0x6e, 0x6b, 0xfe, 0xcd, 0x01, 0xff, 0x92, 0x9e, 0x98,
+ 0x34, 0xff, 0xcd, 0x01, 0xff, 0x52, 0x8e, 0x63, 0x6c, 0x1f, 0xce, 0x01,
+ 0x1a, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x20, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x12, 0x00, 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00,
+ 0x34, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x02, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x47, 0x00, 0x44, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x31, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x31, 0x00,
+ 0x32, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x3a, 0x89, 0x96, 0x1a, 0x4d, 0x4c, 0x08, 0xc4, 0xe5, 0x87, 0x18, 0x44,
+ 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x3a, 0x89, 0x96, 0x1a,
+ 0x4d, 0x4c, 0x08, 0xc4, 0xe5, 0x87, 0x18, 0x44, 0x01, 0x00, 0x00, 0x00,
+ 0x3c, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x70, 0xe2, 0xbf, 0x8d, 0x00, 0xce, 0x01, 0x1a, 0x00, 0x61, 0x00,
+ 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x10, 0x00, 0x2e, 0x00, 0x60, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x64, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x40, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x32, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x31, 0x00,
+ 0x32, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x2e, 0x00, 0x42, 0x00,
+ 0x45, 0x00, 0x52, 0x00, 0x2e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x48, 0x00, 0x41, 0x00, 0x54, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x4f, 0x00,
+ 0x4d, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xa9, 0x20, 0x93, 0x4b,
+ 0x8e, 0xc6, 0x88, 0x88, 0x7a, 0xd6, 0x12, 0xc6, 0xf3, 0x6f, 0x98, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0xd5, 0xfe, 0x5a, 0x1e,
+ 0x73, 0xa4, 0x22, 0x64, 0x48, 0x72, 0x2d, 0xd8, 0x0f, 0xef, 0xe5, 0x81,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool PAC_DATA_check2(struct torture_context *tctx,
+ struct PAC_DATA *r)
+{
+ int i;
+
+ torture_assert_int_equal(tctx, r->num_buffers, 5, "num_buffers");
+
+ for (i=0; i < r->num_buffers; i++) {
+ switch (r->buffers[i].type) {
+ case PAC_TYPE_UPN_DNS_INFO:
+ torture_assert_int_equal(tctx,
+ r->buffers[i].info->upn_dns_info.upn_name_size,
+ 2*strlen_m("Administrator@w2k12dom.ber.redhat.com"),
+ "upn_name_size");
+ torture_assert_str_equal(tctx,
+ r->buffers[i].info->upn_dns_info.upn_name,
+ "Administrator@w2k12dom.ber.redhat.com",
+ "upn_name");
+ torture_assert_int_equal(tctx,
+ r->buffers[i].info->upn_dns_info.dns_domain_name_size,
+ 2*strlen_m("W2K12DOM.BER.REDHAT.COM"),
+ "dns_domain_name_size");
+ torture_assert_str_equal(tctx,
+ r->buffers[i].info->upn_dns_info.dns_domain_name,
+ "W2K12DOM.BER.REDHAT.COM",
+ "dns_domain_name");
+ break;
+ default:
+ continue;
+ }
+ }
+
+ return true;
+}
+
+/* Thanks to Tris Mabbs <TM-Samba201302 at Firstgrade.Co.UK> for this sample. */
+
+static const uint8_t PAC_DATA_data3[] = {
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0xb0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x08, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xac, 0x03, 0xe5, 0x76,
+ 0xaa, 0x13, 0xce, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x7f, 0x9d, 0x37, 0xcc, 0x87, 0x4d, 0x13, 0xce, 0x01, 0x9d, 0xf7, 0x35, 0xb2,
+ 0x16, 0x14, 0xce, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x06, 0x00, 0x06, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x02, 0x00, 0x24, 0x00, 0x24, 0x00, 0x10, 0x00, 0x02, 0x00, 0x22, 0x00, 0x22, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x04, 0x00, 0x04, 0x00, 0x18, 0x00, 0x02, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x5b, 0x08, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x20, 0x00, 0x02, 0x00, 0x14, 0x00, 0x16, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x44, 0x00, 0x4d, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x47, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x77, 0x00, 0x61, 0x00, 0x79, 0x00, 0x5c, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x66, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x73, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x47, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x77, 0x00, 0x61, 0x00, 0x79, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x3a, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x6d, 0x04, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x50, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x6b, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x55, 0x08, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x53, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x6c, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x7a, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5d, 0x04, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x47, 0x00, 0x45, 0x00, 0x44, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x4e, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x46, 0x00, 0x49, 0x00,
+ 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x47, 0x00, 0x52, 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x7d, 0xbc, 0x30, 0x51, 0xd8, 0x07, 0x05, 0x60, 0x40, 0x59, 0x47, 0xb5, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbd, 0xde, 0x76, 0xaa, 0x13, 0xce, 0x01, 0x06, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x7a, 0x00,
+ 0x28, 0x00, 0x10, 0x00, 0x20, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x40, 0x00, 0x46, 0x00, 0x69, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x43, 0x00,
+ 0x6f, 0x00, 0x2e, 0x00, 0x55, 0x00, 0x4b, 0x00, 0x46, 0x00, 0x49, 0x00, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x47, 0x00, 0x52, 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x2e, 0x00, 0x43, 0x00,
+ 0x4f, 0x00, 0x2e, 0x00, 0x55, 0x00, 0x4b, 0x00, 0x76, 0xff, 0xff, 0xff, 0xff, 0x37, 0xcd, 0x48,
+ 0x1b, 0x6f, 0x9f, 0xca, 0x37, 0xe1, 0x02, 0x1c, 0xaa, 0x46, 0x0a, 0xf4, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xff, 0xff, 0xff, 0x3b, 0x96, 0xcc, 0xbb, 0xbb, 0x9d, 0xe4, 0x57, 0x13, 0xc9, 0x6d, 0x1c,
+ 0x65, 0xa0, 0xb1, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t PAC_DATA_pkinit_AS[] = {
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
+ 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0xc0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+ 0xd8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x48, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xa2, 0xd4, 0x65, 0xa4,
+ 0x59, 0x48, 0xd1, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x7f, 0x70, 0x0b, 0xe4, 0x66, 0x97, 0x47, 0xd1, 0x01, 0x70, 0xcb, 0x4d, 0x91,
+ 0x60, 0x48, 0xd1, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x0e, 0x00, 0x0e, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x50, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x18, 0x00, 0x20, 0x00, 0x02, 0x00, 0x12, 0x00, 0x14, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x4b, 0x00,
+ 0x20, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x49, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x52, 0x00,
+ 0x32, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x33, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x34, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x4f, 0x00, 0x4d, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x55, 0x93, 0x92, 0x10,
+ 0xf4, 0xb0, 0xa6, 0xca, 0x96, 0x47, 0x97, 0x56, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0xdc, 0xb1, 0xe1, 0x35, 0x5f, 0x4d, 0xa7, 0xef, 0x84, 0x86, 0x04, 0x42, 0x9f, 0x4f, 0x5e, 0x5b,
+ 0x22, 0x14, 0x66, 0x04, 0xc4, 0xf4, 0x18, 0x8d, 0x53, 0x30, 0xbe, 0x8c, 0xf4, 0xf7, 0x50, 0x0a,
+ 0x87, 0xef, 0x73, 0x3d, 0xd7, 0x7a, 0x0b, 0xf3, 0xd7, 0x30, 0x57, 0xb7, 0x1a, 0x1b, 0x8a, 0x35,
+ 0xc2, 0xde, 0x5b, 0xed, 0x4a, 0x25, 0xad, 0xc5, 0x15, 0x1b, 0xfc, 0xaf, 0x00, 0xb5, 0x7a, 0xea,
+ 0xda, 0xad, 0x77, 0x75, 0xf0, 0xf6, 0x17, 0x46, 0xf3, 0x5f, 0x7e, 0x89, 0x0c, 0xb3, 0x70, 0x31,
+ 0x09, 0x23, 0x16, 0x00, 0x9a, 0xf4, 0x03, 0x5f, 0xd4, 0xab, 0x3b, 0x6a, 0xc2, 0x7d, 0xb3, 0x8a,
+ 0x61, 0x8d, 0x15, 0xfb, 0x43, 0x38, 0x3d, 0x3b, 0x77, 0xda, 0xf4, 0x66, 0x0c, 0x0d, 0x36, 0xf5,
+ 0xc7, 0x01, 0xf9, 0xfb, 0xa4, 0xf8, 0x1f, 0xb8, 0x55, 0x65, 0x7a, 0xc2, 0xf3, 0x23, 0x8f, 0x9b,
+ 0x1e, 0xf1, 0xb8, 0x56, 0x70, 0x01, 0x75, 0xb4, 0x7d, 0xcb, 0x04, 0xbe, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x09, 0x4e, 0x6f, 0x33, 0x49, 0xd1, 0x01, 0x0e, 0x00, 0x70, 0x00, 0x6b, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x69, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x69, 0x00, 0x74, 0x00, 0x31, 0x00, 0x40, 0x00, 0x77, 0x00, 0x34, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2d, 0x00, 0x6c, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x34, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x4f, 0x00, 0x4d, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x42, 0x00, 0x41, 0x00,
+ 0x53, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc2, 0x78, 0x2b, 0x92,
+ 0x2c, 0x06, 0x36, 0x32, 0xb0, 0x72, 0x75, 0x9a, 0x76, 0xff, 0xff, 0xff, 0x9c, 0x73, 0x1e, 0xb8,
+ 0x3a, 0xd8, 0xca, 0x01, 0x53, 0x60, 0xd4, 0x1d, 0x1a, 0x69, 0xde, 0x38, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t PAC_DATA_pkinit_TGS[] = {
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
+ 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0xc0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+ 0xd8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x48, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xa2, 0xd4, 0x65, 0xa4,
+ 0x59, 0x48, 0xd1, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x7f, 0x70, 0x0b, 0xe4, 0x66, 0x97, 0x47, 0xd1, 0x01, 0x70, 0xcb, 0x4d, 0x91,
+ 0x60, 0x48, 0xd1, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x0e, 0x00, 0x0e, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x50, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x18, 0x00, 0x20, 0x00, 0x02, 0x00, 0x12, 0x00, 0x14, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x4b, 0x00,
+ 0x20, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x49, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x52, 0x00,
+ 0x32, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x33, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x34, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x4f, 0x00, 0x4d, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x55, 0x93, 0x92, 0x10,
+ 0xf4, 0xb0, 0xa6, 0xca, 0x96, 0x47, 0x97, 0x56, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0xdc, 0xb1, 0xe1, 0x35, 0x5f, 0x4d, 0xa7, 0xef, 0x84, 0x86, 0x04, 0x42, 0x9f, 0x4f, 0x5e, 0x5b,
+ 0x22, 0x14, 0x66, 0x04, 0xc4, 0xf4, 0x18, 0x8d, 0x53, 0x30, 0xbe, 0x8c, 0xf4, 0xf7, 0x50, 0x0a,
+ 0x87, 0xef, 0x73, 0x3d, 0xd7, 0x7a, 0x0b, 0xf3, 0xd7, 0x30, 0x57, 0xb7, 0x1a, 0x1b, 0x8a, 0x35,
+ 0xc2, 0xde, 0x5b, 0xed, 0x4a, 0x25, 0xad, 0xc5, 0x15, 0x1b, 0xfc, 0xaf, 0x00, 0xb5, 0x7a, 0xea,
+ 0xda, 0xad, 0x77, 0x75, 0xf0, 0xf6, 0x17, 0x46, 0xf3, 0x5f, 0x7e, 0x89, 0x0c, 0xb3, 0x70, 0x31,
+ 0x09, 0x23, 0x16, 0x00, 0x9a, 0xf4, 0x03, 0x5f, 0xd4, 0xab, 0x3b, 0x6a, 0xc2, 0x7d, 0xb3, 0x8a,
+ 0x61, 0x8d, 0x15, 0xfb, 0x43, 0x38, 0x3d, 0x3b, 0x77, 0xda, 0xf4, 0x66, 0x0c, 0x0d, 0x36, 0xf5,
+ 0xc7, 0x01, 0xf9, 0xfb, 0xa4, 0xf8, 0x1f, 0xb8, 0x55, 0x65, 0x7a, 0xc2, 0xf3, 0x23, 0x8f, 0x9b,
+ 0x1e, 0xf1, 0xb8, 0x56, 0x70, 0x01, 0x75, 0xb4, 0x7d, 0xcb, 0x04, 0xbe, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x09, 0x4e, 0x6f, 0x33, 0x49, 0xd1, 0x01, 0x0e, 0x00, 0x70, 0x00, 0x6b, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x69, 0x00, 0x74, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x69, 0x00, 0x74, 0x00, 0x31, 0x00, 0x40, 0x00, 0x77, 0x00, 0x34, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2d, 0x00, 0x6c, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x34, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x4f, 0x00, 0x4d, 0x00, 0x2d, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x42, 0x00, 0x41, 0x00,
+ 0x53, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x82, 0xcd, 0xb1, 0x67,
+ 0xaa, 0x7c, 0xca, 0xa5, 0x0c, 0xf0, 0xbe, 0x75, 0x76, 0xff, 0xff, 0xff, 0x8b, 0x4e, 0xb0, 0x67,
+ 0x3c, 0x17, 0xe6, 0x05, 0x90, 0x66, 0x20, 0x45, 0x34, 0x2f, 0x32, 0x9b, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t PAC_DATA_pkinit_PAC_CREDENTIAL_DATA_NDR[] = {
+ 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4c, 0x00, 0x4d, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x3e, 0x95, 0x63,
+ 0x88, 0x8b, 0x12, 0x02, 0x9f, 0x6e, 0x2b, 0x8d, 0xf6, 0x9a, 0x6e, 0xb3, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x3e, 0x95, 0x63, 0x88, 0x8b, 0x12, 0x02,
+ 0x9f, 0x6e, 0x2b, 0x8d, 0xf6, 0x9a, 0x6e, 0xb3,
+};
+
+static bool PAC_DATA_pkinit(struct torture_context *tctx,
+ struct PAC_DATA *r)
+{
+ DATA_BLOB reply_key_blob = data_blob_null;
+ krb5_context ctx;
+ krb5_keyblock reply_key;
+ krb5_enc_data input;
+ krb5_data plain_data;
+ DATA_BLOB plain_data_blob = data_blob_null;
+
+ torture_assert_int_equal(tctx, r->version, 0, "version");
+
+ torture_assert_int_equal(tctx, r->num_buffers, 6, "num_buffers");
+
+ torture_assert_int_equal(tctx, r->buffers[0].type, PAC_TYPE_LOGON_INFO, "PAC_TYPE_LOGON_INFO");
+ torture_assert_int_equal(tctx, r->buffers[0]._ndr_size, 448, "PAC_TYPE_LOGON_INFO _ndr_size");
+ torture_assert(tctx, r->buffers[0].info != NULL, "PAC_TYPE_LOGON_INFO info");
+
+ torture_assert_int_equal(tctx, r->buffers[1].type, PAC_TYPE_CREDENTIAL_INFO, "PAC_TYPE_CREDENTIAL_INFO");
+ torture_assert_int_equal(tctx, r->buffers[1]._ndr_size, 148, "PAC_TYPE_CREDENTIALS_INFO _ndr_size");
+ torture_assert(tctx, r->buffers[1].info != NULL, "PAC_TYPE_CREDENTIALS_INFO info");
+ torture_assert_int_equal(tctx,
+ r->buffers[1].info->credential_info.version,
+ 0,
+ "PAC_TYPE_CREDENTIALS_INFO version");
+ torture_assert_int_equal(tctx,
+ r->buffers[1].info->credential_info.encryption_type,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ "PAC_TYPE_CREDENTIALS_INFO encryption_type");
+ torture_assert_data_blob_equal(tctx,
+ r->buffers[1].info->credential_info.encrypted_data,
+ data_blob_const(PAC_DATA_pkinit_AS+0x230, 140),
+ "PAC_TYPE_CREDENTIALS_INFO encrypted_data");
+
+ /*
+ * This is the PKINIT based reply key.
+ */
+ reply_key_blob = strhex_to_data_blob(tctx,
+ "c9deb5412b3fba34250b0e4b1f3b6cba3d70bdcdac0f097a9b6a7c763a5524ed");
+ torture_assert_int_equal(tctx, reply_key_blob.length, 32, "reply_key_blob.length");
+ torture_assert_int_equal(tctx, krb5_init_context(&ctx), 0, "krb5_init_context");
+ torture_assert_int_equal(tctx, smb_krb5_keyblock_init_contents(ctx,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ reply_key_blob.data, reply_key_blob.length,
+ &reply_key), 0,
+ "smb_krb5_keyblock_init_contents");
+
+ ZERO_STRUCT(input);
+
+ input.ciphertext.data = (char *)r->buffers[1].info->credential_info.encrypted_data.data;
+ input.ciphertext.length = r->buffers[1].info->credential_info.encrypted_data.length;
+ input.enctype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+
+ plain_data.data = malloc(r->buffers[1].info->credential_info.encrypted_data.length);
+ plain_data.length = r->buffers[1].info->credential_info.encrypted_data.length;
+ torture_assert(tctx, plain_data.data, "malloc failed");
+
+ torture_assert_krb5_error_equal(tctx, krb5_c_decrypt(ctx,
+#ifdef SAMBA4_USES_HEIMDAL
+ reply_key,
+#else
+ &reply_key,
+#endif
+ KRB5_KU_OTHER_ENCRYPTED,
+ NULL,
+ &input,
+ &plain_data), 0,
+ "krb5_decrypt");
+
+ torture_assert_int_equal(tctx, plain_data.length, 112, "plain_data.length");
+ plain_data_blob = data_blob_talloc(tctx, plain_data.data, plain_data.length);
+ torture_assert_int_equal(tctx, plain_data_blob.length, 112, "plain_data_blob.length");
+ smb_krb5_free_data_contents(ctx, &plain_data);
+ krb5_free_keyblock_contents(ctx, &reply_key);
+ krb5_free_context(ctx);
+ torture_assert_data_blob_equal(tctx,
+ plain_data_blob,
+ data_blob_const(PAC_DATA_pkinit_PAC_CREDENTIAL_DATA_NDR,
+ sizeof(PAC_DATA_pkinit_PAC_CREDENTIAL_DATA_NDR)),
+ "PAC_CREDENTIALS_DATA_NDR plain_data");
+
+ torture_assert_int_equal(tctx, r->buffers[2].type, PAC_TYPE_LOGON_NAME, "PAC_TYPE_LOGON_NAME");
+ torture_assert_int_equal(tctx, r->buffers[2]._ndr_size, 24, "PAC_TYPE_LOGON_NAME _ndr_size");
+ torture_assert(tctx, r->buffers[2].info != NULL, "PAC_TYPE_LOGON_NAME info");
+ torture_assert_int_equal(tctx,
+ r->buffers[2].info->logon_name.size,
+ 2*strlen_m("pkinit1"),
+ "size");
+ torture_assert_str_equal(tctx,
+ r->buffers[2].info->logon_name.account_name,
+ "pkinit1",
+ "account_name");
+ torture_assert_u64_equal(tctx,
+ r->buffers[2].info->logon_name.logon_time,
+ 130966349430000000ULL,
+ "logon_time");
+
+ torture_assert_int_equal(tctx, r->buffers[3].type, PAC_TYPE_UPN_DNS_INFO, "PAC_TYPE_UPN_DNS_INFO");
+ torture_assert_int_equal(tctx, r->buffers[3]._ndr_size, 96, "PAC_TYPE_UPN_DNS_INFO _ndr_size");
+ torture_assert(tctx, r->buffers[3].info != NULL, "PAC_TYPE_UPN_DNS_INFO info");
+ torture_assert_int_equal(tctx,
+ r->buffers[3].info->upn_dns_info.upn_name_size,
+ 2*strlen_m("pkinit1@w4edom-l4.base"),
+ "upn_name_size");
+ torture_assert_str_equal(tctx,
+ r->buffers[3].info->upn_dns_info.upn_name,
+ "pkinit1@w4edom-l4.base",
+ "upn_name");
+ torture_assert_int_equal(tctx,
+ r->buffers[3].info->upn_dns_info.dns_domain_name_size,
+ 2*strlen_m("W4EDOM-L4.BASE"),
+ "dns_domain_name_size");
+ torture_assert_str_equal(tctx,
+ r->buffers[3].info->upn_dns_info.dns_domain_name,
+ "W4EDOM-L4.BASE",
+ "dns_domain_name");
+
+ torture_assert_int_equal(tctx, r->buffers[4].type, PAC_TYPE_SRV_CHECKSUM, "PAC_TYPE_SRV_CHECKSUM");
+ torture_assert_int_equal(tctx, r->buffers[4]._ndr_size, 16, "PAC_TYPE_SRV_CHECKSUM _ndr_size");
+ torture_assert(tctx, r->buffers[4].info != NULL, "PAC_TYPE_SRV_CHECKSUM info");
+ torture_assert_int_equal(tctx,
+ r->buffers[4].info->srv_cksum.type,
+ CKSUMTYPE_HMAC_SHA1_96_AES_256,
+ "srv_cksum");
+ torture_assert_int_equal(tctx,
+ r->buffers[4].info->srv_cksum.signature.length,
+ 12,
+ "PAC_TYPE_SRV_CHECKSUM signature.length");
+
+ torture_assert_int_equal(tctx, r->buffers[5].type, PAC_TYPE_KDC_CHECKSUM, "PAC_TYPE_KDC_CHECKSUM");
+ torture_assert_int_equal(tctx, r->buffers[5]._ndr_size, 20, "PAC_TYPE_KDC_CHECKSUM _ndr_size");
+ torture_assert(tctx, r->buffers[5].info != NULL, "PAC_TYPE_KDC_CHECKSUM info");
+ torture_assert_int_equal(tctx,
+ r->buffers[5].info->kdc_cksum.type,
+ CKSUMTYPE_HMAC_MD5,
+ "kdc_cksum");
+ torture_assert_int_equal(tctx,
+ r->buffers[5].info->kdc_cksum.signature.length,
+ 16,
+ "PAC_TYPE_KDC_CHECKSUM signature.length");
+
+ return true;
+}
+
+static bool PAC_CREDENTIAL_DATA_NDR_check(struct torture_context *tctx,
+ struct PAC_CREDENTIAL_DATA_NDR *r)
+{
+ torture_assert(tctx, r->ctr.data != NULL, "data");
+
+ torture_assert_int_equal(tctx, r->ctr.data->credential_count, 1, "credential_count");
+ torture_assert_int_equal(tctx,
+ r->ctr.data->credentials[0].package_name.size,
+ 2*strlen_m("NTLM"),
+ "package_name.size");
+ torture_assert_int_equal(tctx,
+ r->ctr.data->credentials[0].package_name.length,
+ 2*strlen_m("NTLM"),
+ "package_name.length");
+ torture_assert_str_equal(tctx,
+ r->ctr.data->credentials[0].package_name.string,
+ "NTLM",
+ "package_name.string");
+ torture_assert_int_equal(tctx,
+ r->ctr.data->credentials[0].credential_size,
+ sizeof(PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG),
+ "credential_size");
+ torture_assert_data_blob_equal(tctx,
+ data_blob_const(r->ctr.data->credentials[0].credential,
+ r->ctr.data->credentials[0].credential_size),
+ data_blob_const(PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG,
+ sizeof(PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG)),
+ "PAC_CREDENTIAL_NTLM_SECPKG credential");
+
+ return true;
+}
+
+static bool PAC_CREDENTIAL_NTLM_SECPKG_check(struct torture_context *tctx,
+ struct PAC_CREDENTIAL_NTLM_SECPKG *r)
+{
+ torture_assert_int_equal(tctx, r->version, 0, "version");
+
+ torture_assert_int_equal(tctx,
+ r->flags,
+ PAC_CREDENTIAL_NTLM_HAS_NT_HASH,
+ "flags");
+
+ torture_assert_data_blob_equal(tctx,
+ data_blob_const(r->lm_password.hash,
+ sizeof(r->lm_password.hash)),
+ data_blob_const(PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG+0x08,
+ 16),
+ "lm_password");
+ torture_assert_data_blob_equal(tctx,
+ data_blob_const(r->nt_password.hash,
+ sizeof(r->nt_password.hash)),
+ data_blob_const(PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG+0x18,
+ 16),
+ "nt_password");
+
+ return true;
+}
+
+struct torture_suite *ndr_krb5pac_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "krb5pac");
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA_RAW,
+ PAC_DATA_data,
+ NULL);
+ /*
+ * We can't use torture_suite_add_ndr_pull_validate_test()
+ * here with PAC_DATA, as we don't match the unique
+ * pointer values inside PAC_LOGON_INFO, for these
+ * case where we have S-1-5-18-1, as extra sid.
+ */
+ torture_suite_add_ndr_pull_test(suite,
+ PAC_DATA,
+ PAC_DATA_data,
+ PAC_DATA_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA_RAW,
+ PAC_DATA_data2,
+ NULL);
+ /*
+ * We can't use torture_suite_add_ndr_pull_validate_test()
+ * here with PAC_DATA, as we don't match the unique
+ * pointer values inside PAC_LOGON_INFO, for these
+ * case where we have S-1-5-18-1, as extra sid.
+ */
+ torture_suite_add_ndr_pull_test(suite,
+ PAC_DATA,
+ PAC_DATA_data2,
+ PAC_DATA_check2);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA_RAW,
+ PAC_DATA_data3,
+ NULL);
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA,
+ PAC_DATA_data3,
+ NULL);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA_RAW,
+ PAC_DATA_pkinit_AS,
+ NULL);
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA,
+ PAC_DATA_pkinit_AS,
+ PAC_DATA_pkinit);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA_RAW,
+ PAC_DATA_pkinit_TGS,
+ NULL);
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_DATA,
+ PAC_DATA_pkinit_AS,
+ PAC_DATA_pkinit);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_CREDENTIAL_DATA_NDR,
+ PAC_DATA_pkinit_PAC_CREDENTIAL_DATA_NDR,
+ PAC_CREDENTIAL_DATA_NDR_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ PAC_CREDENTIAL_NTLM_SECPKG,
+ PAC_DATA_pkinit_PAC_CREDENTIAL_NTLM_SECPKG,
+ PAC_CREDENTIAL_NTLM_SECPKG_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/lsa.c b/source4/torture/ndr/lsa.c
new file mode 100644
index 0000000..2f8f47c
--- /dev/null
+++ b/source4/torture/ndr/lsa.c
@@ -0,0 +1,2229 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for atsvc ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t lsarlookupnames_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x64, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x15, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x22, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x2b, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x2d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x2e, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x35, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x39, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x3d, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x44, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x45, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x46, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x47, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x49, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x4b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x4e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x4f, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x50, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x51, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x52, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x55, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x57, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x59, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x5a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x5b, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x5d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x5e, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x63, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupnames_in_check(struct torture_context *tctx,
+ struct lsa_LookupNames *r)
+{
+ int i;
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.num_names, 100, "num names");
+ for (i = 0; i < 100; i++) {
+ torture_assert_str_equal(tctx, r->in.names[i].string, "Users", "names");
+ }
+ torture_assert(tctx, r->in.sids != NULL, "sids");
+ torture_assert_int_equal(tctx, r->in.sids->count, 0, "sids count");
+ torture_assert(tctx, r->in.sids->sids == NULL, "sids domains");
+ torture_assert_int_equal(tctx, r->in.level, 1, "level");
+ torture_assert(tctx, r->in.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->in.count, 0, "count");
+ return true;
+}
+
+static const uint8_t lsarlookupnames_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6f, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x70, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x72, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x69, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x55, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5f, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x35, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x57, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x45, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x43, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x73, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x76, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x65, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb4, 0xfc, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd8, 0x9f, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x42, 0x48, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0xbf, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf4, 0x98, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc4, 0x18, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x94, 0xb3, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x9b, 0x92, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf7, 0x59, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x75, 0xa3, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x37, 0xeb, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x98, 0xbe, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5a, 0x7e, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x7c, 0xae, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xcb, 0x87, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x1c, 0x77, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x45, 0xa9, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6f, 0xbf, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x86, 0x6d, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xbc, 0x61, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x18, 0xa7, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5f, 0xa8, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x44, 0x3c, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x4e, 0x0d, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xcf, 0xb0, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd1, 0x87, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x48, 0xc1, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa8, 0xb3, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x52, 0xf4, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x62, 0x3e, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb6, 0x7f, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xee, 0x43, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc1, 0x85, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x8a, 0x80, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xe1, 0x1e, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5b, 0xdf, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x98, 0xe0, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x85, 0x8b, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc9, 0xb4, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x60, 0xba, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x9b, 0x95, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0f, 0x10, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc9, 0xed, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x72, 0xa6, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xbe, 0x11, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x37, 0xcd, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc3, 0x40, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x51, 0x12, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd3, 0x25, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x4f, 0x72, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x33, 0xd7, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfb, 0x70, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xdc, 0xd2, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x1f, 0xeb, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xd0, 0x98, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x87, 0x14, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xc6, 0xb5, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x94, 0x74, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5a, 0x50, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x5d, 0x43, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x34, 0x6a, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6d, 0x30, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x01, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf7, 0x37, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0x90, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x91, 0xf6, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x8e, 0x0d, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x54, 0x87, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xb2, 0x14, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf8, 0x8d, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x25, 0x23, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x2c, 0x2f, 0x21, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupnames_out_check(struct torture_context *tctx,
+ struct lsa_LookupNames *r)
+{
+ struct lsa_RefDomainList *domains = *(r->out.domains);
+ torture_assert(tctx, r->out.domains != NULL, "domains ptr");
+ torture_assert_int_equal(tctx, domains->count, 1, "domains count");
+ torture_assert_int_equal(tctx, domains->max_size, 32, "domains size");
+ torture_assert(tctx, domains->domains != NULL, "domains domains");
+ torture_assert_str_equal(tctx, domains->domains[0].name.string, "BUILTIN", "domain name");
+ /* FIXME: SID */
+ torture_assert(tctx, r->out.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->out.count, 100, "count");
+
+ torture_assert_int_equal(tctx, r->out.sids->count, 100, "sids count");
+ torture_assert_int_equal(tctx, r->out.sids->sids[0].sid_type, 4, "sid type");
+ torture_assert_int_equal(tctx, r->out.sids->sids[0].rid, 0x221, "sid rid");
+ torture_assert_int_equal(tctx, r->out.sids->sids[0].sid_index, 0, "sid index");
+ return true;
+}
+
+static const uint8_t lsarlookupsids_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x64, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+ 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00,
+ 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x51, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
+ 0x5a, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00,
+ 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00,
+ 0x63, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x21, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupsids_in_check(struct torture_context *tctx,
+ struct lsa_LookupSids *r)
+{
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.sids->num_sids, 100, "num sids");
+ torture_assert(tctx, r->in.sids->sids != NULL, "sids sids");
+ torture_assert_int_equal(tctx, r->in.names->count, 0, "names count");
+ torture_assert(tctx, r->in.names->names == NULL, "names names");
+ torture_assert_int_equal(tctx, r->in.level, 1, "level");
+ torture_assert(tctx, r->in.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->in.count, 0, "count");
+
+ return true;
+}
+
+static const uint8_t lsarlookupsids_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x24, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x30, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x3c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x40, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x44, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x48, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x4c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x54, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x58, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x5c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x68, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x6c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x74, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x7c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x84, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x88, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x8c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x90, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x94, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x9c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xa0, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xa4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xa8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xac, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xb0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xde, 0x36,
+ 0x0a, 0x00, 0x0a, 0x00, 0xb4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xb8, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xbc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xc0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xc4, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xc8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xd0, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xd4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xd8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xdc, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xe0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xe4, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xe8, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xec, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xf4, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0c, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x14, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x18, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x1c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x24, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x28, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x2c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x30, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x34, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x38, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x3c, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x40, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x44, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x48, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x4c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x50, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x54, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x58, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x5c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x60, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x64, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x68, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x6c, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x70, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x74, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x7c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x80, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x84, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x88, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x8c, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x90, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0x94, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x98, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x9c, 0x01, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+ 0xa0, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x55, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupsids_out_check(struct torture_context *tctx,
+ struct lsa_LookupSids *r)
+{
+ struct lsa_RefDomainList *domains = *(r->out.domains);
+ torture_assert(tctx, domains != NULL, "domains");
+ torture_assert_int_equal(tctx, domains->count, 1, "domains count");
+ torture_assert_int_equal(tctx, domains->max_size, 32, "domains size");
+ torture_assert(tctx, domains->domains != NULL, "domains domains");
+ torture_assert_str_equal(tctx, domains->domains[0].name.string, "BUILTIN", "name");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsaropenpolicy2_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool lsaropenpolicy2_in_check(struct torture_context *tctx,
+ struct lsa_OpenPolicy2 *r)
+{
+ torture_assert_str_equal(tctx, r->in.system_name, "\\", "system name");
+ torture_assert(tctx, r->in.attr != NULL, "attr ptr");
+ torture_assert_int_equal(tctx, r->in.attr->len, 0, "attr len");
+ torture_assert(tctx, r->in.attr->root_dir == NULL, "attr root");
+ torture_assert(tctx, r->in.attr->object_name == NULL, "attr object name");
+ torture_assert_int_equal(tctx, r->in.attr->attributes, 0, "attr attributes");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x02000000, "access mask");
+ return true;
+}
+
+static const uint8_t lsaropenpolicy2_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsaropenpolicy2_out_check(struct torture_context *tctx,
+ struct lsa_OpenPolicy2 *r)
+{
+ /* FIXME: handle */
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsaropenpolicy_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool lsaropenpolicy_in_check(struct torture_context *tctx,
+ struct lsa_OpenPolicy *r)
+{
+ torture_assert(tctx, r->in.system_name != NULL, "system name");
+ torture_assert(tctx, r->in.attr != NULL, "attr ptr");
+ torture_assert_int_equal(tctx, r->in.attr->len, 0, "attr len");
+ torture_assert(tctx, r->in.attr->root_dir == NULL, "attr root");
+ torture_assert(tctx, r->in.attr->object_name == NULL, "attr object name");
+ torture_assert_int_equal(tctx, r->in.attr->attributes, 0, "attr attributes");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x02000000, "access mask");
+
+ return true;
+}
+
+static const uint8_t lsaropenpolicy_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xbd, 0xf1, 0xb1, 0xe8, 0xd7, 0xf8, 0x43,
+ 0xae, 0xb4, 0x5f, 0x9b, 0xbe, 0x06, 0xf2, 0xce, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsaropenpolicy_out_check(struct torture_context *tctx,
+ struct lsa_OpenPolicy *r)
+{
+ /* FIXME: Handle */
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarcreateaccount_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xb4, 0x71, 0xbc, 0x00,
+ 0xe1, 0x10, 0x00, 0x00, 0x26, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool lsarcreateaccount_in_check(struct torture_context *tctx,
+ struct lsa_CreateAccount *r)
+{
+ /* FIXME: Handle */
+ /* FIXME: Sid */
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x2000000, "access mask");
+ return true;
+}
+
+static const uint8_t lsarcreateaccount_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x28, 0x64, 0xd8, 0x9a, 0xad, 0x2f, 0x48,
+ 0xa5, 0x37, 0x26, 0xb4, 0x17, 0x71, 0x3a, 0xe8, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarcreateaccount_out_check(struct torture_context *tctx,
+ struct lsa_CreateAccount *r)
+{
+ /* FIXME */
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsardelete_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x28, 0x64, 0xd8, 0x9a, 0xad, 0x2f, 0x48,
+ 0xa5, 0x37, 0x26, 0xb4, 0x17, 0x71, 0x3a, 0xe8
+};
+
+static bool lsardelete_in_check(struct torture_context *tctx,
+ struct lsa_Delete *r)
+{
+ /* FIXME: Handle */
+ return true;
+}
+
+static const uint8_t lsardelete_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsardelete_out_check(struct torture_context *tctx,
+ struct lsa_Delete *r)
+{
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarcreatesecret_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x2e, 0x00, 0x2e, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x74, 0x00,
+ 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x35, 0x00,
+ 0x32, 0x00, 0x38, 0x00, 0x38, 0x00, 0x35, 0x00, 0x33, 0x00, 0x35, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool lsarcreatesecret_in_check(struct torture_context *tctx,
+ struct lsa_CreateSecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert_str_equal(tctx, r->in.name.string, "torturesecret-852885356", "name");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x2000000, "access mask");
+ return true;
+}
+
+static const uint8_t lsarcreatesecret_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x2d, 0x02, 0x15, 0x3d, 0xfb, 0x27, 0x4c,
+ 0xaa, 0x22, 0x13, 0x79, 0x20, 0x14, 0x7f, 0xad, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarcreatesecret_out_check(struct torture_context *tctx,
+ struct lsa_CreateSecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsaropensecret_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x2e, 0x00, 0x2e, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x74, 0x00,
+ 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x63, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x35, 0x00,
+ 0x32, 0x00, 0x38, 0x00, 0x38, 0x00, 0x35, 0x00, 0x33, 0x00, 0x35, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool lsaropensecret_in_check(struct torture_context *tctx,
+ struct lsa_OpenSecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert_str_equal(tctx, r->in.name.string, "torturesecret-852885356", "name");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x2000000, "access mask");
+ return true;
+}
+
+static const uint8_t lsaropensecret_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x9f, 0x6d, 0x07, 0x35, 0x08, 0x43, 0xd9, 0x4b,
+ 0xbb, 0xcf, 0xeb, 0x4a, 0x91, 0xd2, 0x24, 0xe7, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsaropensecret_out_check(struct torture_context *tctx,
+ struct lsa_OpenSecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarsetsecret_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x2d, 0x02, 0x15, 0x3d, 0xfb, 0x27, 0x4c,
+ 0xaa, 0x22, 0x13, 0x79, 0x20, 0x14, 0x7f, 0xad, 0x01, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0xda, 0xb8, 0x19, 0xb6, 0xaf, 0x8c, 0x0f, 0xf5, 0x28, 0x81, 0xca, 0xce,
+ 0xcc, 0x8b, 0x70, 0xc4, 0x8a, 0xe5, 0xad, 0x51, 0x1a, 0x0e, 0xb5, 0xaa,
+ 0x3b, 0xdc, 0xbf, 0x38, 0x30, 0xb4, 0x18, 0x6d, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarsetsecret_in_check(struct torture_context *tctx,
+ struct lsa_SetSecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert(tctx, r->in.new_val != NULL, "new val ptr");
+ torture_assert(tctx, r->in.old_val == NULL, "old val ptr");
+ torture_assert_int_equal(tctx, r->in.new_val->length, 32, "new val len");
+ torture_assert_int_equal(tctx, r->in.new_val->size, 32, "new val size");
+ return true;
+}
+
+
+static const uint8_t lsarsetsecret_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarsetsecret_out_check(struct torture_context *tctx,
+ struct lsa_SetSecret *r)
+{
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarquerysecret_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x2d, 0x02, 0x15, 0x3d, 0xfb, 0x27, 0x4c,
+ 0xaa, 0x22, 0x13, 0x79, 0x20, 0x14, 0x7f, 0xad, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarquerysecret_in_check(struct torture_context *tctx,
+ struct lsa_QuerySecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert(tctx, r->in.new_val != NULL, "new val ptr");
+ torture_assert(tctx, r->in.new_val->buf == NULL, "new val ptr ptr");
+ torture_assert(tctx, r->in.new_mtime != NULL, "new mtime ptr");
+ /* FIXME: *new_mtime */
+ torture_assert(tctx, r->in.old_val == NULL, "old val ptr");
+ torture_assert(tctx, r->in.old_mtime == NULL, "old mtime ptr");
+ return true;
+}
+
+
+static const uint8_t lsarquerysecret_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xda, 0xb8, 0x19, 0xb6,
+ 0xaf, 0x8c, 0x0f, 0xf5, 0x28, 0x81, 0xca, 0xce, 0xcc, 0x8b, 0x70, 0xc4,
+ 0x8a, 0xe5, 0xad, 0x51, 0x1a, 0x0e, 0xb5, 0xaa, 0x3b, 0xdc, 0xbf, 0x38,
+ 0x30, 0xb4, 0x18, 0x6d, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x90, 0x3e, 0x63, 0x7e, 0xee, 0xf1, 0xc4, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarquerysecret_out_check(struct torture_context *tctx,
+ struct lsa_QuerySecret *r)
+{
+ /* FIXME: Handle */
+ torture_assert(tctx, r->out.new_val != NULL, "new val ptr");
+ torture_assert(tctx, r->out.new_mtime != NULL, "new mtime ptr");
+ /* FIXME: *new_mtime */
+ torture_assert(tctx, r->out.old_val == NULL, "old val ptr");
+ torture_assert(tctx, r->out.old_mtime == NULL, "old mtime ptr");
+ return true;
+}
+
+static const uint8_t lsarcreatetrusteddomain_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x1a, 0x00, 0x1a, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x76, 0x7c, 0x01, 0x00, 0x93, 0xcb, 0x05, 0x00,
+ 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool lsarcreatetrusteddomain_in_check(struct torture_context *tctx,
+ struct lsa_CreateTrustedDomain *r)
+{
+ /* FIXME: Handle */
+ torture_assert_str_equal(tctx, r->in.info->name.string, "torturedomain", "name");
+ torture_assert(tctx, r->in.info->sid != NULL, "sid");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x2000000, "access mask");
+ return true;
+}
+
+static const uint8_t lsarcreatetrusteddomain_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb5, 0x23, 0x36, 0x5f, 0x33, 0x92, 0x41, 0x4c,
+ 0x9a, 0x73, 0x7d, 0x6a, 0x23, 0x14, 0x62, 0x56, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarcreatetrusteddomain_out_check(struct torture_context *tctx,
+ struct lsa_CreateTrustedDomain *r)
+{
+ /* FIXME: Handle */
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarenumerateaccounts_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00
+};
+
+static bool lsarenumerateaccounts_in_check(struct torture_context *tctx,
+ struct lsa_EnumAccounts *r)
+{
+ /* FIXME: handle */
+ torture_assert(tctx, r->in.resume_handle != NULL, "resume handle ptr");
+ torture_assert_int_equal(tctx, *r->in.resume_handle, 0, "resume handle");
+ torture_assert_int_equal(tctx, r->in.num_entries, 100, "num entries");
+ return true;
+}
+
+static const uint8_t lsarenumerateaccounts_out_data[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x0c, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00,
+ 0x18, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x14, 0xcd, 0xfb, 0x2b, 0x07, 0x32, 0xfb, 0xb2,
+ 0xcc, 0x04, 0x9c, 0x4c, 0xe9, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarenumerateaccounts_out_check(struct torture_context *tctx,
+ struct lsa_EnumAccounts *r)
+{
+ torture_assert(tctx, r->out.resume_handle != NULL, "resume handle ptr");
+ torture_assert_int_equal(tctx, *r->out.resume_handle, 7, "resume handle");
+ torture_assert_int_equal(tctx, r->out.sids->num_sids, 7, "num sids");
+ torture_assert(tctx, r->out.sids->sids != NULL, "sids sids");
+ torture_assert(tctx, r->out.sids->sids[0].sid != NULL, "sids sids");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarlookupsids2_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x07, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x20, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x14, 0xcd, 0xfb, 0x2b,
+ 0x07, 0x32, 0xfb, 0xb2, 0xcc, 0x04, 0x9c, 0x4c, 0xe9, 0x03, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0b, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupsids2_in_check(struct torture_context *tctx,
+ struct lsa_LookupSids2 *r)
+{
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.sids->num_sids, 7, "num sids");
+ torture_assert(tctx, r->in.sids->sids != NULL, "sids sids");
+ torture_assert(tctx, r->in.sids->sids[0].sid != NULL, "sids sids");
+ torture_assert(tctx, r->in.names != NULL, "names ptr");
+ torture_assert_int_equal(tctx, r->in.names->count, 0, "names count");
+ torture_assert(tctx, r->in.names->names == NULL, "names");
+ torture_assert_int_equal(tctx, r->in.level, 1, "level");
+ torture_assert(tctx, r->in.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->in.count, 7, "count");
+ torture_assert_int_equal(tctx, r->in.lookup_options, 0, "unknown 1");
+ torture_assert_int_equal(tctx, r->in.client_revision, 0, "unknown 2");
+
+ return true;
+}
+
+static const uint8_t lsarlookupsids2_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x1a, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x10, 0x00,
+ 0x18, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x12, 0x00, 0x14, 0x00,
+ 0x20, 0x00, 0x02, 0x00, 0x24, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00,
+ 0x20, 0x00, 0x41, 0x00, 0x55, 0x00, 0x54, 0x00, 0x48, 0x00, 0x4f, 0x00,
+ 0x52, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x33, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x14, 0xcd, 0xfb, 0x2b, 0x07, 0x32, 0xfb, 0xb2,
+ 0xcc, 0x04, 0x9c, 0x4c, 0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x22, 0x00,
+ 0x2c, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x20, 0x00, 0x34, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x20, 0x00,
+ 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x3c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x12, 0x00,
+ 0x26, 0x00, 0x28, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00,
+ 0x44, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x63, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x20, 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x53, 0x00, 0x55, 0x00, 0x50, 0x00, 0x50, 0x00,
+ 0x4f, 0x00, 0x52, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x33, 0x00, 0x38, 0x00,
+ 0x38, 0x00, 0x39, 0x00, 0x34, 0x00, 0x35, 0x00, 0x61, 0x00, 0x30, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x45, 0x00, 0x54, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x52, 0x00,
+ 0x4b, 0x00, 0x20, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00,
+ 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x4f, 0x00,
+ 0x43, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x20, 0x00, 0x53, 0x00, 0x45, 0x00,
+ 0x52, 0x00, 0x56, 0x00, 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x64, 0x00, 0x20, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x73, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x45, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x79, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupsids2_out_check(struct torture_context *tctx,
+ struct lsa_LookupSids2 *r)
+{
+ struct lsa_RefDomainList *domains = *(r->out.domains);
+ /* FIXME: Handle */
+ torture_assert(tctx, r->out.names != NULL, "names ptr");
+ torture_assert(tctx, r->out.domains != NULL, "domains ptr");
+ torture_assert_int_equal(tctx, domains->count, 4, "domains count");
+ torture_assert_int_equal(tctx, domains->max_size, 32, "domains size");
+ torture_assert_str_equal(tctx, domains->domains[0].name.string, "NT AUTHORITY", "trust info name");
+ torture_assert_int_equal(tctx, r->out.names->count, 7, "names count");
+ torture_assert_str_equal(tctx, r->out.names->names[0].name.string, "Account Operators", "name str 1");
+ torture_assert_str_equal(tctx, r->out.names->names[1].name.string, "Administrators", "name str 2");
+ torture_assert_str_equal(tctx, r->out.names->names[2].name.string, "SUPPORT_388945a0", "name str 3");
+ torture_assert(tctx, r->out.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->out.count, 7, "count");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+static const uint8_t lsarlookupnames2_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x26, 0x00, 0x26, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x63, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x20, 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x53, 0x00, 0x55, 0x00, 0x50, 0x00, 0x50, 0x00,
+ 0x4f, 0x00, 0x52, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x33, 0x00, 0x38, 0x00,
+ 0x38, 0x00, 0x39, 0x00, 0x34, 0x00, 0x35, 0x00, 0x61, 0x00, 0x30, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x45, 0x00, 0x54, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x52, 0x00,
+ 0x4b, 0x00, 0x20, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00,
+ 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x4f, 0x00,
+ 0x43, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x20, 0x00, 0x53, 0x00, 0x45, 0x00,
+ 0x52, 0x00, 0x56, 0x00, 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x64, 0x00, 0x20, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x73, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x45, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x79, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupnames2_in_check(struct torture_context *tctx,
+ struct lsa_LookupNames2 *r)
+{
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.num_names, 7, "num names");
+ torture_assert_str_equal(tctx, r->in.names[0].string, "Account Operators",
+ "names[0]");
+ torture_assert_str_equal(tctx, r->in.names[1].string, "Administrators",
+ "names[1]");
+ torture_assert_int_equal(tctx, r->in.level, 1, "level");
+ torture_assert_int_equal(tctx, r->in.lookup_options, 0, "lookup_options");
+ torture_assert_int_equal(tctx, r->in.client_revision, 0, "client_revision");
+ torture_assert_int_equal(tctx, *r->in.count, 0, "count");
+ torture_assert_int_equal(tctx, r->in.sids->count, 0, "sids count");
+ torture_assert(tctx, r->in.sids->sids == NULL, "sids sids");
+ return true;
+}
+
+static const uint8_t lsarlookupnames2_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x1a, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x10, 0x00,
+ 0x18, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x12, 0x00, 0x14, 0x00,
+ 0x20, 0x00, 0x02, 0x00, 0x24, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00,
+ 0x20, 0x00, 0x41, 0x00, 0x55, 0x00, 0x54, 0x00, 0x48, 0x00, 0x4f, 0x00,
+ 0x52, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x33, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x14, 0xcd, 0xfb, 0x2b, 0x07, 0x32, 0xfb, 0xb2,
+ 0xcc, 0x04, 0x9c, 0x4c, 0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x20, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xe9, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupnames2_out_check(struct torture_context *tctx,
+ struct lsa_LookupNames2 *r)
+{
+ torture_assert_int_equal(tctx, *r->out.count, 7, "count");
+ torture_assert_int_equal(tctx, r->out.sids->count, 7, "sids count");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarlookupnames3_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x07, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x26, 0x00, 0x26, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x63, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x20, 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x53, 0x00, 0x55, 0x00, 0x50, 0x00, 0x50, 0x00,
+ 0x4f, 0x00, 0x52, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x33, 0x00, 0x38, 0x00,
+ 0x38, 0x00, 0x39, 0x00, 0x34, 0x00, 0x35, 0x00, 0x61, 0x00, 0x30, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x4e, 0x00, 0x45, 0x00, 0x54, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x52, 0x00,
+ 0x4b, 0x00, 0x20, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00,
+ 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x4f, 0x00,
+ 0x43, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x20, 0x00, 0x53, 0x00, 0x45, 0x00,
+ 0x52, 0x00, 0x56, 0x00, 0x49, 0x00, 0x43, 0x00, 0x45, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x64, 0x00, 0x20, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x73, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x45, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x79, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupnames3_in_check(struct torture_context *tctx, struct lsa_LookupNames3 *r)
+{
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.num_names, 7, "num names");
+ torture_assert_str_equal(tctx, r->in.names[0].string, "Account Operators",
+ "names[0]");
+ torture_assert_str_equal(tctx, r->in.names[1].string, "Administrators",
+ "names[1]");
+ torture_assert_int_equal(tctx, r->in.level, 1, "level");
+ torture_assert_int_equal(tctx, r->in.lookup_options, 0, "lookup_options");
+ torture_assert_int_equal(tctx, r->in.client_revision, 0, "client_revision");
+ torture_assert_int_equal(tctx, *r->in.count, 0, "count");
+ torture_assert_int_equal(tctx, r->in.sids->count, 0, "sids count");
+ torture_assert(tctx, r->in.sids->sids == NULL, "sids sids");
+ return true;
+}
+
+static const uint8_t lsarlookupnames3_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x1a, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x10, 0x00,
+ 0x18, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x12, 0x00, 0x14, 0x00,
+ 0x20, 0x00, 0x02, 0x00, 0x24, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00,
+ 0x20, 0x00, 0x41, 0x00, 0x55, 0x00, 0x54, 0x00, 0x48, 0x00, 0x4f, 0x00,
+ 0x52, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x33, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x14, 0xcd, 0xfb, 0x2b, 0x07, 0x32, 0xfb, 0xb2,
+ 0xcc, 0x04, 0x9c, 0x4c, 0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x38, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00,
+ 0x3c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x44, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00,
+ 0x24, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x14, 0xcd, 0xfb, 0x2b, 0x07, 0x32, 0xfb, 0xb2,
+ 0xcc, 0x04, 0x9c, 0x4c, 0xe9, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupnames3_out_check(struct torture_context *tctx,
+ struct lsa_LookupNames3 *r)
+{
+ torture_assert_int_equal(tctx, *r->out.count, 7, "count");
+ torture_assert_int_equal(tctx, r->out.sids->count, 7, "sids count");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+
+
+static const uint8_t lsarlookupsids3_in_data[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x14, 0xcd, 0xfb, 0x2b, 0x07, 0x32, 0xfb, 0xb2, 0xcc, 0x04, 0x9c, 0x4c,
+ 0xe9, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x13, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarlookupsids3_in_check(struct torture_context *tctx,
+ struct lsa_LookupSids3 *r)
+{
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.sids->num_sids, 7, "num sids");
+ torture_assert(tctx, r->in.sids->sids != NULL, "sids sids");
+ torture_assert(tctx, r->in.sids->sids[0].sid != NULL, "sids sids");
+ torture_assert(tctx, r->in.names != NULL, "names ptr");
+ torture_assert_int_equal(tctx, r->in.names->count, 0, "names count");
+ torture_assert(tctx, r->in.names->names == NULL, "names");
+ torture_assert_int_equal(tctx, r->in.level, 1, "level");
+ torture_assert(tctx, r->in.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->in.count, 7, "count");
+ torture_assert_int_equal(tctx, r->in.lookup_options, 0, "unknown 1");
+ torture_assert_int_equal(tctx, r->in.client_revision, 0, "unknown 2");
+
+ return true;
+}
+
+#if 0
+static const uint8_t lsarlookupsids3_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0xc0
+};
+
+static bool lsarlookupsids3_out_check(struct torture_context *tctx,
+ struct lsa_LookupSids3 *r)
+{
+ struct lsa_RefDomainList *domains = *(r->out.domains);
+ /* FIXME: Handle */
+ torture_assert(tctx, r->out.names != NULL, "names ptr");
+ torture_assert(tctx, r->out.domains != NULL, "domains ptr");
+ torture_assert_int_equal(tctx, domains->count, 4, "domains count");
+ torture_assert_int_equal(tctx, domains->max_size, 32, "domains size");
+ torture_assert_str_equal(tctx, domains->domains[0].name.string, "NT AUTHORITY", "trust info name");
+ torture_assert_int_equal(tctx, r->out.names->count, 7, "names count");
+ torture_assert_str_equal(tctx, r->out.names->names[0].name.string, "Account Operators", "name str 1");
+ torture_assert_str_equal(tctx, r->out.names->names[1].name.string, "Administrators", "name str 2");
+ torture_assert_str_equal(tctx, r->out.names->names[2].name.string, "SUPPORT_388945a0", "name str 3");
+ torture_assert(tctx, r->out.count != NULL, "count ptr");
+ torture_assert_int_equal(tctx, *r->out.count, 7, "count");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+#endif
+
+static const uint8_t lsarenumerateprivileges_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xab, 0xb8, 0x84, 0x36, 0xc6, 0xed, 0x4f,
+ 0x83, 0x16, 0x04, 0xe8, 0x63, 0x15, 0xeb, 0x84, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x00
+};
+
+static bool lsarenumerateprivileges_in_check(struct torture_context *tctx,
+ struct lsa_EnumPrivs *r)
+{
+ /* FIXME handle */
+ torture_assert(tctx, r->in.resume_handle != NULL, "resume handle ptr");
+ torture_assert_int_equal(tctx, *r->in.resume_handle, 0, "resume handle");
+ torture_assert_int_equal(tctx, r->in.max_count, 100, "max count");
+ return true;
+}
+
+static const uint8_t lsarenumerateprivileges_out_data[] = {
+ 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x1d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x3c, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2a, 0x00, 0x2c, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x32, 0x00, 0x10, 0x00, 0x02, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x34, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x1e, 0x00, 0x18, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x02, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x32, 0x00,
+ 0x20, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2a, 0x00, 0x2c, 0x00, 0x24, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x32, 0x00, 0x28, 0x00, 0x02, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x2c, 0x00,
+ 0x2c, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x40, 0x00, 0x30, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x02, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x34, 0x00,
+ 0x38, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x34, 0x00, 0x36, 0x00, 0x3c, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x24, 0x00, 0x40, 0x00, 0x02, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x26, 0x00,
+ 0x44, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x00, 0x28, 0x00, 0x48, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x22, 0x00, 0x4c, 0x00, 0x02, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x22, 0x00,
+ 0x50, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x3a, 0x00, 0x54, 0x00, 0x02, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x58, 0x00, 0x02, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x34, 0x00,
+ 0x5c, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x00, 0x24, 0x00, 0x60, 0x00, 0x02, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x64, 0x00, 0x02, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x38, 0x00,
+ 0x68, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x30, 0x00, 0x6c, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x70, 0x00, 0x02, 0x00,
+ 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x30, 0x00,
+ 0x74, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x43, 0x00, 0x72, 0x00, 0x65, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x6b, 0x00, 0x65, 0x00,
+ 0x6e, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x41, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00,
+ 0x79, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x6b, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x4c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x4d, 0x00, 0x65, 0x00,
+ 0x6d, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x79, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6e, 0x00,
+ 0x63, 0x00, 0x72, 0x00, 0x65, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x51, 0x00, 0x75, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x61, 0x00, 0x50, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x4d, 0x00, 0x61, 0x00,
+ 0x63, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x41, 0x00,
+ 0x63, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x54, 0x00, 0x63, 0x00, 0x62, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x53, 0x00, 0x65, 0x00, 0x63, 0x00, 0x75, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x54, 0x00, 0x61, 0x00,
+ 0x6b, 0x00, 0x65, 0x00, 0x4f, 0x00, 0x77, 0x00, 0x6e, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x50, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x4c, 0x00, 0x6f, 0x00,
+ 0x61, 0x00, 0x64, 0x00, 0x44, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x66, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x53, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00,
+ 0x73, 0x00, 0x73, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x42, 0x00, 0x61, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x43, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x50, 0x00, 0x61, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x66, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x43, 0x00, 0x72, 0x00, 0x65, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x50, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6e, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x42, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00,
+ 0x75, 0x00, 0x70, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x52, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x53, 0x00, 0x68, 0x00, 0x75, 0x00, 0x74, 0x00,
+ 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x6e, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x44, 0x00, 0x65, 0x00,
+ 0x62, 0x00, 0x75, 0x00, 0x67, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x41, 0x00, 0x75, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x74, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x1d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00,
+ 0x45, 0x00, 0x6e, 0x00, 0x76, 0x00, 0x69, 0x00, 0x72, 0x00, 0x6f, 0x00,
+ 0x6e, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x50, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x43, 0x00, 0x68, 0x00,
+ 0x61, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x79, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x52, 0x00, 0x65, 0x00,
+ 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x53, 0x00, 0x68, 0x00,
+ 0x75, 0x00, 0x74, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x6e, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x55, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x6b, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x53, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x41, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x62, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x44, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x4d, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00,
+ 0x56, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00,
+ 0x49, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x50, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x00, 0x00, 0x00, 0x53, 0x00, 0x65, 0x00, 0x43, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x47, 0x00, 0x6c, 0x00,
+ 0x6f, 0x00, 0x62, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x67, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsarenumerateprivileges_out_check(struct torture_context *tctx,
+ struct lsa_EnumPrivs *r)
+{
+ torture_assert(tctx, r->out.resume_handle != NULL, "resume handle ptr");
+ torture_assert_int_equal(tctx, *r->out.resume_handle, 29, "resume handle");
+ torture_assert_str_equal(tctx, r->out.privs->privs[0].name.string, "SeCreateTokenPrivilege", "name");
+ torture_assert_str_equal(tctx, r->out.privs->privs[1].name.string, "SeAssignPrimaryTokenPrivilege", "name");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t lsarsetforesttrustsinformation_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x42, 0x3e, 0xd4, 0x20, 0x20, 0xe8, 0xa1, 0x43,
+ 0x96, 0x67, 0x8c, 0xd1, 0xb9, 0x48, 0xa0, 0x3d, 0x0e, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0x04, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x60, 0xcc, 0x85, 0x53, 0x92, 0x64, 0x11, 0x5e, 0x37, 0xa1, 0x11, 0x65,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x46, 0x00, 0x31, 0x00, 0x01
+};
+
+static bool lsarsetforesttrustsinformation_in_check(struct torture_context *tctx,
+ struct lsa_lsaRSetForestTrustInformation *r)
+{
+ /* FIXME: Handle */
+ torture_assert_str_equal(tctx, r->in.trusted_domain_name->string, "f1.test", "trusted domain name");
+ torture_assert_int_equal(tctx, r->in.highest_record_type, 2, "highest record type");
+ torture_assert(tctx, r->in.forest_trust_info != NULL, "forest trust info");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->count, 2, "number of forest trust records");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->entries[0]->flags, 0, "first entry flags");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->entries[0]->type, 0, "first entry type");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->entries[0]->time, 0, "first entry time");
+ torture_assert_str_equal(tctx, r->in.forest_trust_info->entries[0]->forest_trust_data.top_level_name.string, "f1.test", "first entry data");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->entries[1]->flags, 0, "second entry flags");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->entries[1]->type, 2, "second entry type");
+ torture_assert_int_equal(tctx, r->in.forest_trust_info->entries[1]->time, 0, "second entry time");
+ torture_assert_str_equal(tctx, r->in.forest_trust_info->entries[1]->forest_trust_data.domain_info.dns_domain_name.string, "f1.test", "second entry data");
+ torture_assert_str_equal(tctx, r->in.forest_trust_info->entries[1]->forest_trust_data.domain_info.netbios_domain_name.string, "F1", "second entry data");
+ torture_assert_int_equal(tctx, r->in.check_only, 1, "check only");
+
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+static const uint8_t lsasettrusteddomaininfobyname_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe2, 0xbe, 0xb5, 0xfe, 0x4a, 0xe2, 0x25, 0x43,
+ 0xaf, 0x37, 0x14, 0x77, 0xa5, 0xd6, 0xd9, 0x31, 0x0e, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x10, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x02, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x31, 0x00,
+ 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x31, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x60, 0xcc, 0x85, 0x53,
+ 0x92, 0x64, 0x11, 0x5e, 0x37, 0xa1, 0x11, 0x65, 0x44, 0x02, 0x00, 0x00,
+ 0x25, 0xf5, 0x9e, 0xfc, 0x2c, 0x36, 0x8e, 0x0d, 0xd8, 0x6b, 0x98, 0x14,
+ 0xb6, 0x78, 0xcc, 0xca, 0xb2, 0xbd, 0xa0, 0x8d, 0x59, 0xd9, 0x51, 0x90,
+ 0x14, 0x0e, 0x0c, 0x3f, 0xac, 0xed, 0x67, 0x98, 0xd9, 0x44, 0xe7, 0xec,
+ 0x72, 0xd7, 0x83, 0xba, 0x12, 0x3e, 0xcb, 0x8a, 0xaa, 0x87, 0xdb, 0xf2,
+ 0xf8, 0x35, 0x00, 0x9c, 0xc7, 0x76, 0x85, 0x8d, 0x04, 0x08, 0x4c, 0xa3,
+ 0x05, 0x4b, 0x02, 0x85, 0xcd, 0x1c, 0x83, 0xd4, 0x1e, 0xcc, 0xd8, 0xa3,
+ 0x32, 0x9e, 0xa5, 0x6f, 0xd8, 0x3d, 0xe2, 0xcd, 0xa1, 0x44, 0xf5, 0x03,
+ 0x47, 0x79, 0x22, 0xf3, 0xb4, 0x14, 0x3d, 0x6c, 0xe3, 0x98, 0x91, 0x96,
+ 0x89, 0x78, 0x26, 0xa1, 0x77, 0x78, 0x58, 0xa1, 0xba, 0x84, 0xb7, 0xb3,
+ 0x7a, 0xad, 0xcf, 0x77, 0x5c, 0x92, 0x97, 0x3a, 0x19, 0x0f, 0xfa, 0x7d,
+ 0x48, 0xa4, 0x11, 0x33, 0xdd, 0x51, 0xd6, 0x0c, 0x48, 0xd6, 0xd2, 0x59,
+ 0x83, 0x4d, 0xf6, 0x8b, 0x6b, 0x4d, 0x6a, 0x0e, 0xcc, 0x15, 0xd6, 0x1a,
+ 0x2f, 0x44, 0x61, 0x45, 0x8f, 0xa8, 0x1b, 0x3f, 0x2d, 0xbd, 0x3a, 0xdb,
+ 0xe0, 0x74, 0x44, 0x27, 0x02, 0x85, 0x02, 0xb4, 0xf9, 0x7f, 0x81, 0xcb,
+ 0x28, 0x27, 0x83, 0xfb, 0xa7, 0x92, 0x43, 0x70, 0x73, 0x2b, 0x89, 0xda,
+ 0x03, 0x83, 0x48, 0x58, 0x04, 0xba, 0x1e, 0xe2, 0x84, 0xf3, 0xa2, 0xfa,
+ 0x22, 0xe8, 0x5f, 0x41, 0xf3, 0xe6, 0x47, 0x92, 0x06, 0x61, 0x77, 0x31,
+ 0x00, 0x1b, 0x9f, 0x9b, 0x8f, 0xfd, 0x1d, 0x9e, 0xcb, 0x09, 0xd7, 0xdc,
+ 0x19, 0x94, 0xf4, 0x18, 0xfa, 0x96, 0x3e, 0xb3, 0xf0, 0x6b, 0x1c, 0x21,
+ 0xe4, 0x52, 0xb3, 0x48, 0x19, 0x5d, 0x10, 0x8e, 0xf1, 0xb5, 0x8b, 0x72,
+ 0x69, 0xdb, 0x60, 0x7b, 0x7c, 0xef, 0x5c, 0x16, 0x1b, 0x11, 0xf2, 0x97,
+ 0x2e, 0xf4, 0xd1, 0xc5, 0x13, 0x52, 0xb4, 0xc7, 0xca, 0xf8, 0xc0, 0x46,
+ 0x61, 0xdc, 0x9b, 0x8a, 0x5b, 0xcd, 0xf1, 0x1d, 0x7a, 0xc4, 0x0f, 0x02,
+ 0x0c, 0x22, 0x4f, 0x42, 0x12, 0xbb, 0xa6, 0xe2, 0xbb, 0x92, 0xda, 0xdb,
+ 0x12, 0xea, 0xe8, 0x61, 0xf2, 0xdd, 0x45, 0x3c, 0x35, 0x2c, 0x89, 0x92,
+ 0x22, 0x35, 0xb0, 0x24, 0x5b, 0xa7, 0x54, 0x58, 0xe1, 0x8c, 0xf5, 0x36,
+ 0x4d, 0x04, 0xdf, 0x25, 0x36, 0x48, 0x7b, 0x84, 0xc9, 0xb9, 0xc2, 0x2a,
+ 0xc5, 0x62, 0x06, 0xcb, 0xa1, 0xf5, 0x26, 0x05, 0xb4, 0x20, 0xcc, 0x8b,
+ 0xed, 0x2e, 0xa2, 0x4b, 0xa4, 0x85, 0x3e, 0x7f, 0x26, 0x25, 0x39, 0x69,
+ 0x2f, 0x89, 0x47, 0x7e, 0xde, 0xc7, 0xa4, 0x12, 0x01, 0xc5, 0x98, 0x01,
+ 0xf5, 0xae, 0x2e, 0x3e, 0xbd, 0xb7, 0x62, 0xaa, 0x57, 0x5d, 0xa0, 0x6f,
+ 0xac, 0xc5, 0x4e, 0x09, 0xcc, 0x87, 0x8e, 0x76, 0x93, 0xf2, 0xc6, 0x08,
+ 0x45, 0x88, 0x9f, 0x18, 0x9b, 0xeb, 0xa6, 0x1b, 0xf7, 0x64, 0x47, 0x73,
+ 0x0c, 0xb2, 0xc7, 0xc5, 0xe5, 0x62, 0x56, 0x7f, 0x0a, 0xe4, 0x79, 0xaf,
+ 0x7e, 0x71, 0xe6, 0x09, 0x22, 0x3d, 0x22, 0x10, 0x5c, 0x94, 0x71, 0x35,
+ 0xfd, 0x28, 0x20, 0x79, 0x89, 0x47, 0x5c, 0x37, 0x41, 0xd1, 0xfe, 0xee,
+ 0x2e, 0xd8, 0x41, 0x8e, 0x1c, 0x4d, 0x77, 0x09, 0x43, 0x6a, 0xee, 0x3c,
+ 0x80, 0x9b, 0xb7, 0xe7, 0x4c, 0xe8, 0x38, 0xd1, 0x6b, 0xc0, 0x03, 0x4b,
+ 0xbf, 0x8d, 0x19, 0x06, 0xad, 0x28, 0x22, 0xe7, 0x1a, 0x4e, 0x14, 0xa9,
+ 0x90, 0xba, 0xc4, 0x13, 0x8c, 0xde, 0x30, 0xfc, 0xe2, 0xb8, 0x97, 0x90,
+ 0x63, 0x3f, 0x30, 0xfc, 0xf5, 0x0d, 0xd2, 0xc2, 0xbe, 0xd2, 0xe3, 0x7f,
+ 0x52, 0x4e, 0xc5, 0x91, 0x38, 0xfc, 0xa7, 0x0d, 0xec, 0xa5, 0x4f, 0xd5,
+ 0x65, 0xb3, 0x51, 0x44, 0x21, 0x2a, 0x2e, 0x87, 0xe6, 0x91, 0x09, 0x8c,
+ 0xa5, 0x89, 0x13, 0x69, 0x01, 0x28, 0xa8, 0x64, 0x4f, 0x87, 0x0d, 0x12,
+ 0xe5, 0xeb, 0xce, 0xb9, 0xfa, 0xca, 0x10, 0x69, 0xa6, 0x95, 0x3b, 0x6d,
+ 0x6e, 0xca, 0x9e, 0x75, 0x25, 0x1c, 0xfa, 0xd6, 0x68, 0x84, 0xe0, 0x1f,
+ 0x35, 0x7e, 0x6e, 0xe8, 0xb7, 0x0a, 0x32, 0x9f, 0xc3, 0x31, 0x35, 0x84,
+ 0xa6, 0xc7, 0x5a, 0xa2, 0x0c, 0x8c, 0x07, 0x6a, 0x66, 0xd8, 0x58, 0xb1,
+ 0x4c, 0xb9, 0xbc, 0x46
+};
+
+static bool lsasettrusteddomaininfobyname_in_check(struct torture_context *tctx,
+ struct lsa_SetTrustedDomainInfoByName *r)
+{
+ /* FIXME: Handle */
+ torture_assert_str_equal(tctx, r->in.trusted_domain->string, "f1.test", "trusted domain");
+ torture_assert_int_equal(tctx, r->in.level, LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL, "level");
+ torture_assert(tctx, r->in.info != NULL, "trust info");
+ torture_assert_str_equal(tctx, r->in.info->full_info_internal.info_ex.domain_name.string, "f1.test", "domain name");
+ torture_assert_str_equal(tctx, r->in.info->full_info_internal.info_ex.netbios_name.string, "F1", "netbios name");
+ torture_assert(tctx, r->in.info->full_info_internal.info_ex.sid != NULL, "domain sid ptr");
+ torture_assert_sid_equal(tctx, r->in.info->full_info_internal.info_ex.sid, dom_sid_parse_talloc(tctx, "S-1-5-21-1401277536-1578198162-1695654199"), "domain sid");
+ torture_assert_int_equal(tctx, r->in.info->full_info_internal.info_ex.trust_direction, 3, "trust direction");
+ torture_assert_int_equal(tctx, r->in.info->full_info_internal.info_ex.trust_type, LSA_TRUST_TYPE_UPLEVEL, "trust type");
+ torture_assert_int_equal(tctx, r->in.info->full_info_internal.info_ex.trust_attributes, 8, "trust attributes");
+ torture_assert_int_equal(tctx, r->in.info->full_info_internal.posix_offset.posix_offset, 0, "posix offset");
+ torture_assert_int_equal(tctx, r->in.info->full_info_internal.auth_info.auth_blob.size, 580, "auth blob size");
+
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+static const uint8_t lsa_lsaRQueryForestTrustInformation_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd, 0xa1, 0xb8, 0x04, 0x3a, 0xa2, 0x46,
+ 0xb1, 0x45, 0x5c, 0xaa, 0xf7, 0x54, 0x13, 0x9a, 0x16, 0x00, 0x16, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x61, 0x00, 0x64, 0x00, 0x32, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x02, 0x00
+};
+
+static bool lsa_lsaRQueryForestTrustInformation_in_check(struct torture_context *tctx,
+ struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ return true;
+}
+
+static const uint8_t lsa_lsaRQueryForestTrustInformation_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xd1, 0x06, 0xc6,
+ 0xb9, 0xba, 0xcf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x18, 0x00,
+ 0x0c, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x61, 0x00, 0x64, 0x00, 0x32, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0xbe, 0xd1, 0x06, 0xc6, 0xb9, 0xba, 0xcf, 0x01, 0x02, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x02, 0x00, 0x16, 0x00, 0x18, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0x0c, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x51, 0xd1, 0xbb, 0x42, 0xa8, 0x23, 0x83, 0xb1, 0x31, 0x59, 0xf1, 0x8d,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x61, 0x00, 0x64, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00,
+ 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x44, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool lsa_lsaRQueryForestTrustInformation_out_check(struct torture_context *tctx,
+ struct lsa_lsaRQueryForestTrustInformation *r)
+{
+ return true;
+}
+
+struct torture_suite *ndr_lsa_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "lsa");
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_OpenPolicy, lsaropenpolicy_in_data, NDR_IN, lsaropenpolicy_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_OpenPolicy, lsaropenpolicy_out_data, NDR_OUT, lsaropenpolicy_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_OpenPolicy2, lsaropenpolicy2_in_data, NDR_IN, lsaropenpolicy2_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_OpenPolicy2, lsaropenpolicy2_out_data, NDR_OUT, lsaropenpolicy2_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupNames, lsarlookupnames_in_data, NDR_IN, lsarlookupnames_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupNames, lsarlookupnames_out_data, NDR_OUT, lsarlookupnames_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupSids, lsarlookupsids_in_data, NDR_IN, lsarlookupsids_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupSids, lsarlookupsids_out_data, NDR_OUT, lsarlookupsids_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_CreateAccount, lsarcreateaccount_in_data, NDR_IN, lsarcreateaccount_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_CreateAccount, lsarcreateaccount_out_data, NDR_OUT, lsarcreateaccount_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_Delete, lsardelete_in_data, NDR_IN, lsardelete_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_Delete, lsardelete_out_data, NDR_OUT, lsardelete_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_CreateSecret, lsarcreatesecret_in_data, NDR_IN, lsarcreatesecret_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_CreateSecret, lsarcreatesecret_out_data, NDR_OUT, lsarcreatesecret_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_OpenSecret, lsaropensecret_in_data, NDR_IN, lsaropensecret_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_OpenSecret, lsaropensecret_out_data, NDR_OUT, lsaropensecret_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_SetSecret, lsarsetsecret_in_data, NDR_IN, lsarsetsecret_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_SetSecret, lsarsetsecret_out_data, NDR_OUT, lsarsetsecret_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_QuerySecret, lsarquerysecret_in_data, NDR_IN, lsarquerysecret_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_QuerySecret, lsarquerysecret_out_data, NDR_OUT, lsarquerysecret_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_CreateTrustedDomain, lsarcreatetrusteddomain_in_data, NDR_IN, lsarcreatetrusteddomain_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_CreateTrustedDomain, lsarcreatetrusteddomain_out_data, NDR_OUT, lsarcreatetrusteddomain_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_EnumAccounts, lsarenumerateaccounts_in_data, NDR_IN, lsarenumerateaccounts_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_EnumAccounts, lsarenumerateaccounts_out_data, NDR_OUT, lsarenumerateaccounts_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupSids2, lsarlookupsids2_in_data, NDR_IN, lsarlookupsids2_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupSids2, lsarlookupsids2_out_data, NDR_OUT, lsarlookupsids2_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupNames2, lsarlookupnames2_in_data, NDR_IN, lsarlookupnames2_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupNames2, lsarlookupnames2_out_data, NDR_OUT, lsarlookupnames2_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupNames3, lsarlookupnames3_in_data, NDR_IN, lsarlookupnames3_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupNames3, lsarlookupnames3_out_data, NDR_OUT, lsarlookupnames3_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupSids3, lsarlookupsids3_in_data, NDR_IN, lsarlookupsids3_in_check);
+ /* torture_suite_add_ndr_pull_fn_test(suite, lsa_LookupSids3, lsarlookupsids3_out_data, NDR_OUT, lsarlookupsids3_out_check); */
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_EnumPrivs, lsarenumerateprivileges_in_data, NDR_IN, lsarenumerateprivileges_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_EnumPrivs, lsarenumerateprivileges_out_data, NDR_OUT, lsarenumerateprivileges_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_lsaRSetForestTrustInformation, lsarsetforesttrustsinformation_in_data, NDR_IN, lsarsetforesttrustsinformation_in_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_SetTrustedDomainInfoByName, lsasettrusteddomaininfobyname_in_data, NDR_IN, lsasettrusteddomaininfobyname_in_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_lsaRQueryForestTrustInformation, lsa_lsaRQueryForestTrustInformation_in_data, NDR_IN, lsa_lsaRQueryForestTrustInformation_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, lsa_lsaRQueryForestTrustInformation, lsa_lsaRQueryForestTrustInformation_out_data, NDR_OUT, lsa_lsaRQueryForestTrustInformation_out_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/nbt.c b/source4/torture/ndr/nbt.c
new file mode 100644
index 0000000..ec5cb90
--- /dev/null
+++ b/source4/torture/ndr/nbt.c
@@ -0,0 +1,253 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for nbt ndr operations
+
+ Copyright (C) Guenther Deschner 2010-2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t netlogon_logon_request_req_data[] = {
+ 0x00, 0x00, 0x57, 0x49, 0x4e, 0x39, 0x38, 0x00, 0x47, 0x44, 0x00, 0x5c,
+ 0x4d, 0x41, 0x49, 0x4c, 0x53, 0x4c, 0x4f, 0x54, 0x5c, 0x54, 0x45, 0x4d,
+ 0x50, 0x5c, 0x4e, 0x45, 0x54, 0x4c, 0x4f, 0x47, 0x4f, 0x4e, 0x00, 0x01,
+ 0x01, 0x00, 0xff, 0xff
+};
+
+static bool netlogon_logon_request_req_check(struct torture_context *tctx,
+ struct nbt_netlogon_packet *r)
+{
+ torture_assert_int_equal(tctx, r->command, LOGON_REQUEST, "command");
+ torture_assert_str_equal(tctx, r->req.logon0.computer_name, "WIN98", "computer name");
+ torture_assert_str_equal(tctx, r->req.logon0.user_name, "GD", "user_name");
+ torture_assert_str_equal(tctx, r->req.logon0.mailslot_name, "\\MAILSLOT\\TEMP\\NETLOGON", "mailslot_name");
+ torture_assert_int_equal(tctx, r->req.logon0.request_count, 1, "request_count");
+ torture_assert_int_equal(tctx, r->req.logon0.lmnt_token, 1, "lmnt_token");
+ torture_assert_int_equal(tctx, r->req.logon0.lm20_token, 0xffff, "lm20_token");
+
+ return true;
+}
+
+static const uint8_t netlogon_logon_request_resp_data[] = {
+ 0x06, 0x00, 0x5c, 0x5c, 0x4d, 0x54, 0x48, 0x45, 0x4c, 0x45, 0x4e, 0x41,
+ 0x00, 0xff, 0xff
+};
+
+static bool netlogon_logon_request_resp_check(struct torture_context *tctx,
+ struct nbt_netlogon_response2 *r)
+{
+ torture_assert_int_equal(tctx, r->command, LOGON_RESPONSE2, "command");
+ torture_assert_str_equal(tctx, r->pdc_name, "\\\\MTHELENA", "pdc_name");
+ torture_assert_int_equal(tctx, r->lm20_token, 0xffff, "lm20_token");
+
+ return true;
+}
+
+static const uint8_t netlogon_samlogon_response_data[] = {
+/* 0x04, 0x74, 0x17, 0x00, 0x00, 0x00, 0xfd, 0x33, 0x00, 0x00, 0x03, 0x13, */
+ 0x17, 0x00, 0x00, 0x00, 0xfd, 0x33, 0x00, 0x00, 0x03, 0x13,
+ 0x44, 0xcd, 0x1c, 0x00, 0x4c, 0x46, 0xa6, 0x21, 0xe9, 0xd6, 0xb9, 0xb1,
+ 0x2f, 0xe9, 0x07, 0x77, 0x32, 0x6b, 0x38, 0x64, 0x6f, 0x6d, 0x03, 0x62,
+ 0x65, 0x72, 0x06, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, 0x03, 0x63, 0x6f,
+ 0x6d, 0x00, 0xc0, 0x18, 0x08, 0x67, 0x64, 0x77, 0x32, 0x6b, 0x38, 0x72,
+ 0x32, 0xc0, 0x18, 0x07, 0x57, 0x32, 0x4b, 0x38, 0x44, 0x4f, 0x4d, 0x00,
+ 0x08, 0x47, 0x44, 0x57, 0x32, 0x4b, 0x38, 0x52, 0x32, 0x00, 0x00, 0x17,
+ 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x46, 0x69, 0x72, 0x73,
+ 0x74, 0x2d, 0x53, 0x69, 0x74, 0x65, 0x2d, 0x4e, 0x61, 0x6d, 0x65, 0x00,
+ 0xc0, 0x51, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+};
+
+static bool netlogon_samlogon_response_check(struct torture_context *tctx,
+ struct netlogon_samlogon_response *r)
+{
+ struct GUID guid;
+ torture_assert_ntstatus_ok(tctx, GUID_from_string("cd441303-001c-464c-a621-e9d6b9b12fe9", &guid), "");
+
+ torture_assert_int_equal(tctx, r->ntver, 5, "ntver");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX, "command");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.sbz, 0, "sbz");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.server_type, 0x000033fd, "server_type");
+ torture_assert_guid_equal(tctx, r->data.nt5_ex.domain_uuid, guid, "domain_uuid");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.forest, "w2k8dom.ber.redhat.com", "forest");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.dns_domain, "w2k8dom.ber.redhat.com", "dns_domain");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.pdc_dns_name, "gdw2k8r2.w2k8dom.ber.redhat.com", "pdc_dns_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.domain_name, "W2K8DOM", "domain_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.pdc_name, "GDW2K8R2", "pdc_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.user_name, "", "user_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.server_site, "Default-First-Site-Name", "server_site");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.client_site, "Default-First-Site-Name", "client_site");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.sockaddr_size, 0, "sockaddr_size");
+ /* sockaddr: struct nbt_sockaddr
+ * sockaddr_family : 0x00000000 (0)
+ * pdc_ip : (null)
+ * remaining : DATA_BLOB length=0 */
+ torture_assert_int_equal(tctx, r->data.nt5_ex.nt_version, 5, "nt_version");
+ /* next_closest_site NULL */
+ torture_assert_int_equal(tctx, r->data.nt5_ex.lmnt_token, 0xffff, "lmnt_token");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.lm20_token, 0xffff, "lm20_token");
+
+ return true;
+}
+
+static const uint8_t nbt_netlogon_packet_data[] = {
+ 0x12, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x4e, 0x00,
+ 0x59, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x4e, 0x00,
+ 0x59, 0x00, 0x24, 0x00, 0x00, 0x00, 0x5c, 0x4d, 0x41, 0x49, 0x4c, 0x53,
+ 0x4c, 0x4f, 0x54, 0x5c, 0x4e, 0x45, 0x54, 0x5c, 0x47, 0x45, 0x54, 0x44,
+ 0x43, 0x35, 0x32, 0x45, 0x41, 0x41, 0x38, 0x43, 0x30, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x9c, 0x4e, 0x59, 0xff,
+ 0xe1, 0xa0, 0x39, 0xac, 0x29, 0xa6, 0xe2, 0xda, 0x01, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+};
+
+static bool nbt_netlogon_packet_check(struct torture_context *tctx,
+ struct nbt_netlogon_packet *r)
+{
+ torture_assert_int_equal(tctx, r->command, LOGON_SAM_LOGON_REQUEST, "command");
+ torture_assert_int_equal(tctx, r->req.logon.request_count, 0, "request_count");
+ torture_assert_str_equal(tctx, r->req.logon.computer_name, "LENNY", "computer_name");
+ torture_assert_str_equal(tctx, r->req.logon.user_name, "LENNY$", "user_name");
+ torture_assert_str_equal(tctx, r->req.logon.mailslot_name, "\\MAILSLOT\\NET\\GETDC52EAA8C0", "mailslot_name");
+ torture_assert_int_equal(tctx, r->req.logon.acct_control, 0x00000080, "acct_control");
+ torture_assert_int_equal(tctx, r->req.logon.sid_size, 24, "sid_size");
+ torture_assert_int_equal(tctx, r->req.logon._pad.length, 2, "_pad.length");
+ torture_assert_sid_equal(tctx, &r->req.logon.sid, dom_sid_parse_talloc(tctx, "S-1-5-21-4284042908-2889457889-3672286761"), "sid");
+ torture_assert_int_equal(tctx, r->req.logon.nt_version, NETLOGON_NT_VERSION_1, "nt_version");
+ torture_assert_int_equal(tctx, r->req.logon.lmnt_token, 0xffff, "lmnt_token");
+ torture_assert_int_equal(tctx, r->req.logon.lm20_token, 0xffff, "lm20_token");
+
+ return true;
+}
+
+static const uint8_t nbt_netlogon_packet_logon_primary_query_data[] = {
+ 0x07, 0x00, 0x58, 0x50, 0x44, 0x41, 0x54, 0x45, 0x56, 0x2d, 0x50, 0x52,
+ 0x4f, 0x00, 0x5c, 0x4d, 0x41, 0x49, 0x4c, 0x53, 0x4c, 0x4f, 0x54, 0x5c,
+ 0x4e, 0x45, 0x54, 0x5c, 0x47, 0x45, 0x54, 0x44, 0x43, 0x38, 0x31, 0x37,
+ 0x00, 0x00, 0x58, 0x00, 0x50, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00,
+ 0x45, 0x00, 0x56, 0x00, 0x2d, 0x00, 0x50, 0x00, 0x52, 0x00, 0x4f, 0x00,
+ 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+static bool nbt_netlogon_packet_logon_primary_query_check(struct torture_context *tctx,
+ struct nbt_netlogon_packet *r)
+{
+ torture_assert_int_equal(tctx, r->command, LOGON_PRIMARY_QUERY, "command");
+ torture_assert_str_equal(tctx, r->req.pdc.computer_name, "XPDATEV-PRO", "computer_name");
+ torture_assert_str_equal(tctx, r->req.pdc.mailslot_name, "\\MAILSLOT\\NET\\GETDC817", "mailslot_name");
+ torture_assert_int_equal(tctx, r->req.pdc._pad.length, 1, "_pad.length");
+ torture_assert_int_equal(tctx, r->req.pdc._pad.data[0], 0, "_pad.data");
+ torture_assert_str_equal(tctx, r->req.pdc.unicode_name, "XPDATEV-PRO", "unicode_name");
+ torture_assert_int_equal(tctx, r->req.pdc.nt_version, 0x0000000b, "nt_version");
+ torture_assert_int_equal(tctx, r->req.pdc.lmnt_token, 0xffff, "lmnt_token");
+ torture_assert_int_equal(tctx, r->req.pdc.lm20_token, 0xffff, "lm20_token");
+
+ return true;
+}
+
+static const uint8_t netlogon_samlogon_response_data2[] = {
+/* 0x04, 0x77, 0x17, 0x00, 0x00, 0x00, 0xfd, 0x33, 0x00, 0x00, 0x55, 0xaf,*/
+ 0x17, 0x00, 0x00, 0x00, 0xfd, 0x33, 0x00, 0x00, 0x55, 0xaf,
+ 0x8d, 0x13, 0x8c, 0x91, 0x70, 0x41, 0x9d, 0x46, 0xd4, 0xd5, 0x04, 0x90,
+ 0xaa, 0x13, 0x03, 0x62, 0x6c, 0x61, 0x04, 0x62, 0x61, 0x73, 0x65, 0x00,
+ 0xc0, 0x18, 0x0a, 0x57, 0x32, 0x4b, 0x38, 0x52, 0x32, 0x2d, 0x32, 0x31,
+ 0x39, 0xc0, 0x18, 0x03, 0x42, 0x4c, 0x41, 0x00, 0x0a, 0x57, 0x32, 0x4b,
+ 0x38, 0x52, 0x32, 0x2d, 0x32, 0x31, 0x39, 0x00, 0x0a, 0x77, 0x32, 0x30,
+ 0x31, 0x32, 0x72, 0x32, 0x2d, 0x6c, 0x36, 0x05, 0x62, 0x61, 0x73, 0x65,
+ 0x2e, 0x00, 0x17, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x46,
+ 0x69, 0x72, 0x73, 0x74, 0x2d, 0x53, 0x69, 0x74, 0x65, 0x2d, 0x4e, 0x61,
+ 0x6d, 0x65, 0x00, 0xc0, 0x54, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff
+};
+
+static bool netlogon_samlogon_response_check2(struct torture_context *tctx,
+ struct netlogon_samlogon_response *r)
+{
+ struct GUID guid;
+ torture_assert_ntstatus_ok(tctx, GUID_from_string("138daf55-918c-4170-9d46-d4d50490aa13", &guid), "");
+
+ torture_assert_int_equal(tctx, r->ntver, 5, "ntver");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.command, LOGON_SAM_LOGON_RESPONSE_EX, "command");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.sbz, 0, "sbz");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.server_type, 0x000033fd, "server_type");
+ torture_assert_guid_equal(tctx, r->data.nt5_ex.domain_uuid, guid, "domain_uuid");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.forest, "bla.base", "forest");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.dns_domain, "bla.base", "dns_domain");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.pdc_dns_name, "W2K8R2-219.bla.base", "pdc_dns_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.domain_name, "BLA", "domain_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.pdc_name, "W2K8R2-219", "pdc_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.user_name, "w2012r2-l6.base.", "user_name");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.server_site, "Default-First-Site-Name", "server_site");
+ torture_assert_str_equal(tctx, r->data.nt5_ex.client_site, "Default-First-Site-Name", "client_site");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.sockaddr_size, 0, "sockaddr_size");
+ /*
+ * sockaddr: struct nbt_sockaddr
+ * sockaddr_family : 0x00000000 (0)
+ * pdc_ip : (null)
+ * remaining : DATA_BLOB length=0
+ */
+ torture_assert_int_equal(tctx, r->data.nt5_ex.nt_version, 5, "nt_version");
+ /* next_closest_site NULL */
+ torture_assert_int_equal(tctx, r->data.nt5_ex.lmnt_token, 0xffff, "lmnt_token");
+ torture_assert_int_equal(tctx, r->data.nt5_ex.lm20_token, 0xffff, "lm20_token");
+
+ return true;
+}
+
+
+struct torture_suite *ndr_nbt_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "nbt");
+
+ torture_suite_add_ndr_pull_test(suite, nbt_netlogon_packet, netlogon_logon_request_req_data, netlogon_logon_request_req_check);
+
+ torture_suite_add_ndr_pull_test(suite,
+ nbt_netlogon_packet,
+ nbt_netlogon_packet_logon_primary_query_data,
+ nbt_netlogon_packet_logon_primary_query_check);
+
+ torture_suite_add_ndr_pull_test(suite, nbt_netlogon_response2, netlogon_logon_request_resp_data, netlogon_logon_request_resp_check);
+
+ torture_suite_add_ndr_pull_test(suite,
+ netlogon_samlogon_response,
+ netlogon_samlogon_response_data,
+ netlogon_samlogon_response_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ netlogon_samlogon_response,
+ netlogon_samlogon_response_data,
+ netlogon_samlogon_response_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ nbt_netlogon_packet,
+ nbt_netlogon_packet_data,
+ nbt_netlogon_packet_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ nbt_netlogon_packet,
+ nbt_netlogon_packet_logon_primary_query_data,
+ nbt_netlogon_packet_logon_primary_query_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ netlogon_samlogon_response,
+ netlogon_samlogon_response_data2,
+ netlogon_samlogon_response_check2);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/ndr.c b/source4/torture/ndr/ndr.c
new file mode 100644
index 0000000..0faef1a
--- /dev/null
+++ b/source4/torture/ndr/ndr.c
@@ -0,0 +1,831 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for winreg ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "torture/ndr/proto.h"
+#include "../lib/util/dlinklist.h"
+#include "param/param.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+
+struct ndr_pull_test_data {
+ DATA_BLOB data;
+ DATA_BLOB data_context;
+ size_t struct_size;
+ ndr_pull_flags_fn_t pull_fn;
+ ndr_push_flags_fn_t push_fn;
+ ndr_print_fn_t print_fn;
+ ndr_print_function_t print_function;
+ ndr_flags_type ndr_flags;
+ libndr_flags flags;
+ enum ndr_err_code ndr_err;
+};
+
+static enum ndr_err_code torture_ndr_push_struct_blob_flags(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, ndr_flags_type flags, libndr_flags ndr_flags, const void *p, ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ ndr->flags |= ndr_flags;
+
+ NDR_CHECK(fn(ndr, flags, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
+}
+
+static bool torture_ndrdump(struct torture_context *tctx,
+ struct ndr_pull *ndr,
+ const struct ndr_pull_test_data *data,
+ ndr_flags_type flags,
+ void *ds,
+ const char *name)
+{
+ struct ndr_print *ndr_print;
+ const char *name_raw;
+ ndr_flags_type ndr_flags = data->ndr_flags | flags;
+
+ ndr_print = talloc_zero(tctx, struct ndr_print);
+ torture_assert(tctx, ndr_print, "out of memory");
+
+ if (DEBUGLEVEL >= 10) {
+ ndr_print->print = ndr_print_debug_helper;
+ } else {
+ ndr_print->print = ndr_print_string_helper;
+ }
+
+ ndr_print->depth = 1;
+
+ torture_assert(tctx, ndr_flags, "no flags have been set");
+
+ if (ndr_flags & (NDR_BUFFERS|NDR_SCALARS)) {
+ data->print_fn(ndr_print, name, ds);
+ } else {
+ data->print_function(ndr_print, name, ndr_flags, ds);
+ }
+
+ name_raw = talloc_asprintf(tctx, "%s (RAW DATA)", name);
+ torture_assert(tctx, name_raw, "out of memory");
+
+ ndr_print_DATA_BLOB(ndr_print, name_raw, data->data);
+
+ talloc_free(ndr_print);
+
+ return true;
+}
+
+static bool wrap_ndr_pullpush_test(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*check_fn) (struct torture_context *ctx, void *data) = test->fn;
+ const struct ndr_pull_test_data *data = (const struct ndr_pull_test_data *)test->data;
+ struct ndr_pull *ndr = ndr_pull_init_blob(&(data->data), tctx);
+ void *ds = talloc_zero_size(ndr, data->struct_size);
+ bool ret = true;
+ uint32_t highest_ofs;
+
+ torture_assert(tctx, data, "out of memory");
+ torture_assert(tctx, ndr, "out of memory");
+ torture_assert(tctx, ds, "out of memory");
+
+ ndr->flags |= data->flags;
+
+ ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ torture_assert_ndr_success(tctx, data->pull_fn(ndr, data->ndr_flags, ds),
+ "pulling");
+
+ if (ndr->offset > ndr->relative_highest_offset) {
+ highest_ofs = ndr->offset;
+ } else {
+ highest_ofs = ndr->relative_highest_offset;
+ }
+
+ torture_assert(tctx, highest_ofs == ndr->data_size,
+ talloc_asprintf(tctx,
+ "%d unread bytes", ndr->data_size - highest_ofs));
+
+ if (check_fn != NULL) {
+ ret = check_fn(tctx, ds);
+ } else {
+ ret = true;
+ }
+
+ torture_ndrdump(tctx, ndr, data, data->ndr_flags, ds, "ds");
+
+ if (data->push_fn != NULL) {
+ DATA_BLOB outblob;
+ torture_assert_ndr_success(tctx, torture_ndr_push_struct_blob_flags(&outblob, ndr, data->ndr_flags, ndr->flags, ds, data->push_fn), "pushing");
+ torture_assert_data_blob_equal(tctx, outblob, data->data, "ndr push compare");
+ }
+
+ talloc_free(ndr);
+ return ret;
+}
+
+_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pullpush_test(
+ struct torture_suite *suite,
+ const char *name,
+ ndr_pull_flags_fn_t pull_fn,
+ ndr_push_flags_fn_t push_fn,
+ ndr_print_fn_t print_fn,
+ ndr_print_function_t print_function,
+ const char *db_name,
+ DATA_BLOB db,
+ size_t struct_size,
+ ndr_flags_type ndr_flags,
+ libndr_flags flags,
+ const char *check_fn_name,
+ bool (*check_fn) (struct torture_context *ctx, void *data))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+ struct ndr_pull_test_data *data;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, check_fn_name);
+ test->description = talloc_asprintf(test, "db:%s",
+ db_name);
+ test->run = wrap_ndr_pullpush_test;
+
+ data = talloc_zero(test, struct ndr_pull_test_data);
+ data->data = db;
+ data->ndr_flags = ndr_flags;
+ data->flags = flags;
+ data->struct_size = struct_size;
+ data->pull_fn = pull_fn;
+ data->push_fn = push_fn;
+ data->print_fn = print_fn;
+ data->print_function = print_function;
+
+ test->data = data;
+ test->fn = check_fn;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+
+static bool wrap_ndr_inout_pull_test(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*check_fn) (struct torture_context *ctx, void *data) = test->fn;
+ const struct ndr_pull_test_data *data = (const struct ndr_pull_test_data *)test->data;
+ void *ds = talloc_zero_size(tctx, data->struct_size);
+ struct ndr_pull *ndr;
+ uint32_t highest_ofs;
+ bool ret = false;
+
+ torture_assert(tctx, data, "out of memory");
+ torture_assert(tctx, ds, "out of memory");
+
+ /* handle NDR_IN context */
+
+ ndr = ndr_pull_init_blob(&(data->data_context), tctx);
+ torture_assert(tctx, ndr, "ndr init failed");
+
+ ndr->flags |= data->flags;
+ ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ torture_assert_ndr_success(tctx,
+ data->pull_fn(ndr, NDR_IN, ds),
+ "ndr pull of context failed");
+
+ if (ndr->offset > ndr->relative_highest_offset) {
+ highest_ofs = ndr->offset;
+ } else {
+ highest_ofs = ndr->relative_highest_offset;
+ }
+
+ torture_assert(tctx, highest_ofs == ndr->data_size,
+ talloc_asprintf(tctx, "%d unread bytes", ndr->data_size - highest_ofs));
+
+ torture_ndrdump(tctx, ndr, data, NDR_IN, ds, "ds");
+
+ talloc_free(ndr);
+
+ /* handle NDR_OUT */
+
+ ndr = ndr_pull_init_blob(&(data->data), tctx);
+ torture_assert(tctx, ndr, "ndr init failed");
+
+ ndr->flags |= data->flags;
+ ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ torture_assert_ndr_success(tctx,
+ data->pull_fn(ndr, NDR_OUT, ds),
+ "ndr pull failed");
+
+ if (ndr->offset > ndr->relative_highest_offset) {
+ highest_ofs = ndr->offset;
+ } else {
+ highest_ofs = ndr->relative_highest_offset;
+ }
+
+ torture_assert(tctx, highest_ofs == ndr->data_size,
+ talloc_asprintf(tctx, "%d unread bytes", ndr->data_size - highest_ofs));
+
+ if (check_fn) {
+ ret = check_fn(tctx, ds);
+ } else {
+ ret = true;
+ }
+
+ torture_ndrdump(tctx, ndr, data, NDR_OUT, ds, "ds");
+
+ talloc_free(ndr);
+
+ return ret;
+}
+
+_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_inout_test(
+ struct torture_suite *suite,
+ const char *name,
+ ndr_pull_flags_fn_t pull_fn,
+ ndr_print_function_t print_function,
+ const char *db_in_name,
+ DATA_BLOB db_in,
+ const char *db_out_name,
+ DATA_BLOB db_out,
+ size_t struct_size,
+ libndr_flags flags,
+ const char *check_fn_name,
+ bool (*check_fn) (struct torture_context *ctx, void *data))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+ struct ndr_pull_test_data *data;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, check_fn_name);
+ test->description = talloc_asprintf(test, "db_in:%s db_out:%s",
+ db_in_name,
+ db_out_name);
+ test->run = wrap_ndr_inout_pull_test;
+ data = talloc_zero(test, struct ndr_pull_test_data);
+ data->data = db_out;
+ data->data_context = db_in;
+ data->ndr_flags = 0;
+ data->flags = flags;
+ data->struct_size = struct_size;
+ data->pull_fn = pull_fn;
+ data->print_function = print_function;
+ test->data = data;
+ test->fn = check_fn;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+static bool wrap_ndr_pull_invalid_data_test(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ const struct ndr_pull_test_data *data = (const struct ndr_pull_test_data *)test->data;
+ struct ndr_pull *ndr = ndr_pull_init_blob(&(data->data), tctx);
+ void *ds = talloc_zero_size(ndr, data->struct_size);
+ bool ret = true;
+
+ torture_assert(tctx, data, "out of memory");
+ torture_assert(tctx, ndr, "out of memory");
+ torture_assert(tctx, ds, "out of memory");
+
+ ndr->flags |= data->flags;
+
+ ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ torture_assert_ndr_err_equal(
+ tctx,
+ data->pull_fn(ndr, data->ndr_flags, ds),
+ NDR_ERR_BUFSIZE,
+ "pulling invalid data");
+
+ talloc_free(ndr);
+ return ret;
+}
+
+_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_invalid_data_test(
+ struct torture_suite *suite,
+ const char *name,
+ ndr_pull_flags_fn_t pull_fn,
+ const char *db_name,
+ DATA_BLOB db,
+ size_t struct_size,
+ ndr_flags_type ndr_flags,
+ libndr_flags flags,
+ enum ndr_err_code ndr_err)
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+ struct ndr_pull_test_data *data;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, db_name);
+ test->description = NULL;
+ test->run = wrap_ndr_pull_invalid_data_test;
+
+ data = talloc_zero(test, struct ndr_pull_test_data);
+ data->data = db;
+ data->ndr_flags = ndr_flags;
+ data->flags = flags;
+ data->struct_size = struct_size;
+ data->pull_fn = pull_fn;
+ data->ndr_err = ndr_err;
+
+ test->data = data;
+ test->fn = NULL;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+static bool test_check_string_terminator(struct torture_context *tctx)
+{
+ struct ndr_pull *ndr;
+ DATA_BLOB blob;
+ TALLOC_CTX *mem_ctx = tctx;
+
+ /* Simple test */
+ blob = strhex_to_data_blob(tctx, "0000");
+
+ ndr = ndr_pull_init_blob(&blob, mem_ctx);
+
+ torture_assert_ndr_success(tctx, ndr_check_string_terminator(ndr, 1, 2),
+ "simple check_string_terminator test failed");
+
+ torture_assert(tctx, ndr->offset == 0,
+ "check_string_terminator did not reset offset");
+
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_check_string_terminator(ndr, 1, 3))) {
+ torture_fail(tctx, "check_string_terminator checked beyond string boundaries");
+ }
+
+ torture_assert(tctx, ndr->offset == 0,
+ "check_string_terminator did not reset offset");
+
+ talloc_free(ndr);
+
+ blob = strhex_to_data_blob(tctx, "11220000");
+ ndr = ndr_pull_init_blob(&blob, mem_ctx);
+
+ torture_assert_ndr_success(tctx,
+ ndr_check_string_terminator(ndr, 4, 1),
+ "check_string_terminator failed to recognize terminator");
+
+ torture_assert_ndr_success(tctx,
+ ndr_check_string_terminator(ndr, 3, 1),
+ "check_string_terminator failed to recognize terminator");
+
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_check_string_terminator(ndr, 2, 1))) {
+ torture_fail(tctx, "check_string_terminator erroneously reported terminator");
+ }
+
+ torture_assert(tctx, ndr->offset == 0,
+ "check_string_terminator did not reset offset");
+ return true;
+}
+
+static bool test_guid_from_string_valid(struct torture_context *tctx)
+{
+ /* FIXME */
+ return true;
+}
+
+static bool test_guid_from_string_null(struct torture_context *tctx)
+{
+ struct GUID guid;
+ torture_assert_ntstatus_equal(tctx, NT_STATUS_INVALID_PARAMETER,
+ GUID_from_string(NULL, &guid),
+ "NULL failed");
+ return true;
+}
+
+static bool test_guid_from_string_invalid(struct torture_context *tctx)
+{
+ struct GUID g1;
+ bool failed = false;
+ int i;
+ const char *bad_guids[] = {
+ "bla",
+ "",
+ /*
+ "00000001-0002-0003-0405-060708090a0b", correct
+ */
+ "00000001-0002-0003-0405-060708090a0b1", /* too long */
+ "00000001-0002-0003-0405-060708090a0", /* too short */
+ "00000001-0002-0003-0405--060708090a0", /* negative */
+ "00000001-0002-0003--0405-060708090a0", /* negative */
+ "-0000001-0002-0003-0405-060708090a0b", /* negative */
+ "-0000001-0002-0003-04-5-060708090a0b", /* negative */
+ "d0000001-0002-0003-0405-060708090a-b", /* negative */
+ "00000001- -2-0003-0405-060708090a0b", /* negative, space */
+ "00000001-0002-0003-0405- 060708090a0", /* whitespace */
+ " 0000001-0002-0003--0405-060708090a0", /* whitespace */
+ "00000001-0002-0003--0405-060708090a ", /* whitespace */
+ "0000001-00002-0003-04050-60708090a0b", /* misshapen */
+ "00000010-0002-0003-04050-60708090a0b", /* misshapen */
+ "00000001-0002-0003-0405-0z0708090a0b", /* bad char */
+ "00000001-00x2-0x03-0405-060708090a0b", /* bad char (00x) */
+ "0x000001-0002-0003-0405-060708090a0b", /* 0x char */
+ "00000001-0x02-0x03-0405-060708090a0b", /* 0x char */
+ };
+
+ for (i = 0; i < ARRAY_SIZE(bad_guids); i++) {
+ NTSTATUS status = GUID_from_string(bad_guids[i], &g1);
+ if (! NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ torture_comment(tctx, "bad guid %s parsed as OK\n",
+ bad_guids[i]);
+ failed = true;
+ }
+ }
+ if (failed) {
+ torture_fail(tctx, "wrongly allowing invalid guids");
+ }
+ return true;
+}
+
+static bool test_guid_from_string(struct torture_context *tctx)
+{
+ struct GUID g1, exp;
+ /* we are asserting all these guids are valid and equal */
+ const char *guids[5] = {
+ "00000001-0002-0003-0405-060708090a0b",
+ "{00000001-0002-0003-0405-060708090a0b}",
+ "{00000001-0002-0003-0405-060708090a0B}", /* mixed */
+ "00000001-0002-0003-0405-060708090A0B", /* upper */
+ "01000000020003000405060708090a0b", /* hex string */
+ };
+ int i;
+
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(guids[0], &g1),
+ "invalid return code");
+ exp.time_low = 1;
+ exp.time_mid = 2;
+ exp.time_hi_and_version = 3;
+ exp.clock_seq[0] = 4;
+ exp.clock_seq[1] = 5;
+ exp.node[0] = 6;
+ exp.node[1] = 7;
+ exp.node[2] = 8;
+ exp.node[3] = 9;
+ exp.node[4] = 10;
+ exp.node[5] = 11;
+
+ for (i = 1; i < ARRAY_SIZE(guids); i++) {
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(guids[i], &g1),
+ "invalid return code");
+ torture_assert(tctx, GUID_equal(&g1, &exp),
+ "UUID parsed incorrectly");
+ }
+ return true;
+}
+
+static bool test_guid_from_data_blob(struct torture_context *tctx)
+{
+ struct GUID g1, exp;
+ const uint8_t bin[16] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b };
+ const char *hexstr = "01000000020003000405060708090a0b";
+ const DATA_BLOB blobs[2] = {
+ data_blob_const(bin, sizeof(bin)),
+ data_blob_string_const(hexstr),
+ };
+ int i;
+
+ exp.time_low = 1;
+ exp.time_mid = 2;
+ exp.time_hi_and_version = 3;
+ exp.clock_seq[0] = 4;
+ exp.clock_seq[1] = 5;
+ exp.node[0] = 6;
+ exp.node[1] = 7;
+ exp.node[2] = 8;
+ exp.node[3] = 9;
+ exp.node[4] = 10;
+ exp.node[5] = 11;
+
+ for (i = 1; i < ARRAY_SIZE(blobs); i++) {
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_data_blob(&blobs[i], &g1),
+ "invalid return code");
+ torture_assert(tctx, GUID_equal(&g1, &exp),
+ "UUID parsed incorrectly");
+ }
+
+ return true;
+}
+
+static bool test_guid_string_valid(struct torture_context *tctx)
+{
+ struct GUID g;
+ g.time_low = 1;
+ g.time_mid = 2;
+ g.time_hi_and_version = 3;
+ g.clock_seq[0] = 4;
+ g.clock_seq[1] = 5;
+ g.node[0] = 6;
+ g.node[1] = 7;
+ g.node[2] = 8;
+ g.node[3] = 9;
+ g.node[4] = 10;
+ g.node[5] = 11;
+ torture_assert_str_equal(tctx, "00000001-0002-0003-0405-060708090a0b",
+ GUID_string(tctx, &g),
+ "parsing guid failed");
+ return true;
+}
+
+static bool test_guid_string2_valid(struct torture_context *tctx)
+{
+ struct GUID g;
+ g.time_low = 1;
+ g.time_mid = 2;
+ g.time_hi_and_version = 3;
+ g.clock_seq[0] = 4;
+ g.clock_seq[1] = 5;
+ g.node[0] = 6;
+ g.node[1] = 7;
+ g.node[2] = 8;
+ g.node[3] = 9;
+ g.node[4] = 10;
+ g.node[5] = 11;
+ torture_assert_str_equal(tctx, "{00000001-0002-0003-0405-060708090a0b}",
+ GUID_string2(tctx, &g),
+ "parsing guid failed");
+ return true;
+}
+
+static bool test_guid_into_blob(struct torture_context *tctx)
+{
+ enum ndr_err_code ndr_err;
+ static const char exp_guid[16] =
+ { 0x1, 0x0, 0x0, 0x0,
+ 0x2, 0x0, 0x3, 0x0,
+ 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb };
+ DATA_BLOB exp = data_blob_const(exp_guid, 16);
+ char ndr_guid[16] =
+ { 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0 };
+ DATA_BLOB b = data_blob_const(ndr_guid, 16);
+ struct GUID guid;
+ guid.time_low = 1;
+ guid.time_mid = 2;
+ guid.time_hi_and_version = 3;
+ guid.clock_seq[0] = 4;
+ guid.clock_seq[1] = 5;
+ guid.node[0] = 6;
+ guid.node[1] = 7;
+ guid.node[2] = 8;
+ guid.node[3] = 9;
+ guid.node[4] = 10;
+ guid.node[5] = 11;
+
+ ndr_err = ndr_push_struct_into_fixed_blob(&b, &guid,
+ (ndr_push_flags_fn_t)ndr_push_GUID);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS,
+ "wrong NDR error");
+ torture_assert_data_blob_equal(tctx, b, exp,
+ "GUID packed wrongly");
+
+ return true;
+}
+
+/* Really a test of ndr_push_struct_into_fixed_blob error handling */
+static bool test_guid_into_long_blob(struct torture_context *tctx)
+{
+ enum ndr_err_code ndr_err;
+ char ndr_guid[17] =
+ { 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0 };
+ DATA_BLOB b = data_blob_const(ndr_guid, 17);
+ struct GUID guid;
+ guid.time_low = 1;
+ guid.time_mid = 2;
+ guid.time_hi_and_version = 3;
+ guid.clock_seq[0] = 4;
+ guid.clock_seq[1] = 5;
+ guid.node[0] = 6;
+ guid.node[1] = 7;
+ guid.node[2] = 8;
+ guid.node[3] = 9;
+ guid.node[4] = 10;
+ guid.node[5] = 11;
+
+ torture_assert(tctx, b.data != NULL, "data_blob_talloc failed");
+ ndr_err = ndr_push_struct_into_fixed_blob(
+ &b, &guid, (ndr_push_flags_fn_t)ndr_push_GUID);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_BUFSIZE,
+ "wrong NDR error");
+
+ return true;
+}
+
+static bool test_guid_into_short_blob(struct torture_context *tctx)
+{
+ enum ndr_err_code ndr_err;
+ char ndr_guid[15] =
+ { 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0 };
+ DATA_BLOB b = data_blob_const(ndr_guid, 15);
+ struct GUID guid;
+ guid.time_low = 1;
+ guid.time_mid = 2;
+ guid.time_hi_and_version = 3;
+ guid.clock_seq[0] = 4;
+ guid.clock_seq[1] = 5;
+ guid.node[0] = 6;
+ guid.node[1] = 7;
+ guid.node[2] = 8;
+ guid.node[3] = 9;
+ guid.node[4] = 10;
+ guid.node[5] = 11;
+
+ ndr_err = ndr_push_struct_into_fixed_blob(
+ &b, &guid, (ndr_push_flags_fn_t)ndr_push_GUID);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_BUFSIZE,
+ "wrong NDR error");
+
+ return true;
+}
+
+static bool test_compare_uuid(struct torture_context *tctx)
+{
+ struct GUID g1, g2;
+ ZERO_STRUCT(g1); ZERO_STRUCT(g2);
+ torture_assert_int_equal(tctx, 0, GUID_compare(&g1, &g2),
+ "GUIDs not equal");
+ g1.time_low = 1;
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+
+ g1.time_low = 10;
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+
+ g1.time_low = 0;
+ g1.clock_seq[1] = 20;
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+
+ g1.time_low = ~0;
+ torture_assert_int_equal(tctx, 1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+
+ g1.time_low = 0;
+ g2.time_low = ~0;
+ torture_assert_int_equal(tctx, -1, GUID_compare(&g1, &g2),
+ "GUID diff invalid");
+ return true;
+}
+
+static bool test_syntax_id_from_string(struct torture_context *tctx)
+{
+ struct ndr_syntax_id s, exp;
+ const char *id = "00000001-0002-0003-0405-060708090a0b/0x12345678";
+
+ exp.uuid.time_low = 1;
+ exp.uuid.time_mid = 2;
+ exp.uuid.time_hi_and_version = 3;
+ exp.uuid.clock_seq[0] = 4;
+ exp.uuid.clock_seq[1] = 5;
+ exp.uuid.node[0] = 6;
+ exp.uuid.node[1] = 7;
+ exp.uuid.node[2] = 8;
+ exp.uuid.node[3] = 9;
+ exp.uuid.node[4] = 10;
+ exp.uuid.node[5] = 11;
+ exp.if_version = 0x12345678;
+
+ torture_assert(tctx,
+ ndr_syntax_id_from_string(id, &s),
+ "invalid return code");
+ torture_assert(tctx, ndr_syntax_id_equal(&s, &exp),
+ "NDR syntax id parsed incorrectly");
+ return true;
+}
+
+struct torture_suite *torture_local_ndr(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "ndr");
+
+ torture_suite_add_suite(suite, ndr_dcerpc_suite(suite));
+ torture_suite_add_suite(suite, ndr_winreg_suite(suite));
+ torture_suite_add_suite(suite, ndr_atsvc_suite(suite));
+ torture_suite_add_suite(suite, ndr_lsa_suite(suite));
+ torture_suite_add_suite(suite, ndr_epmap_suite(suite));
+ torture_suite_add_suite(suite, ndr_dfs_suite(suite));
+ torture_suite_add_suite(suite, ndr_dfsblob_suite(suite));
+ torture_suite_add_suite(suite, ndr_netlogon_suite(suite));
+ torture_suite_add_suite(suite, ndr_drsuapi_suite(suite));
+ torture_suite_add_suite(suite, ndr_spoolss_suite(suite));
+ torture_suite_add_suite(suite, ndr_winspool_suite(suite));
+ torture_suite_add_suite(suite, ndr_ntprinting_suite(suite));
+ torture_suite_add_suite(suite, ndr_samr_suite(suite));
+ torture_suite_add_suite(suite, ndr_drsblobs_suite(suite));
+ torture_suite_add_suite(suite, ndr_dnsp_suite(suite));
+ torture_suite_add_suite(suite, ndr_nbt_suite(suite));
+ torture_suite_add_suite(suite, ndr_ntlmssp_suite(suite));
+ torture_suite_add_suite(suite, ndr_backupkey_suite(suite));
+ torture_suite_add_suite(suite, ndr_witness_suite(suite));
+ torture_suite_add_suite(suite, ndr_clusapi_suite(suite));
+ torture_suite_add_suite(suite, ndr_negoex_suite(suite));
+ torture_suite_add_suite(suite, ndr_string_suite(suite));
+ torture_suite_add_suite(suite, ndr_krb5pac_suite(suite));
+ torture_suite_add_suite(suite, ndr_cabinet_suite(suite));
+ torture_suite_add_suite(suite, ndr_charset_suite(suite));
+ torture_suite_add_suite(suite, ndr_svcctl_suite(suite));
+ torture_suite_add_suite(suite, ndr_ODJ_suite(suite));
+
+ torture_suite_add_simple_test(suite, "string terminator",
+ test_check_string_terminator);
+
+ torture_suite_add_simple_test(suite, "guid_from_string_null",
+ test_guid_from_string_null);
+
+ torture_suite_add_simple_test(suite, "guid_from_string",
+ test_guid_from_string);
+
+ torture_suite_add_simple_test(suite, "guid_from_data_blob",
+ test_guid_from_data_blob);
+
+ torture_suite_add_simple_test(suite, "guid_from_string_invalid",
+ test_guid_from_string_invalid);
+
+ torture_suite_add_simple_test(suite, "guid_string_valid",
+ test_guid_string_valid);
+
+ torture_suite_add_simple_test(suite, "guid_string2_valid",
+ test_guid_string2_valid);
+
+ torture_suite_add_simple_test(suite, "guid_from_string_valid",
+ test_guid_from_string_valid);
+
+ torture_suite_add_simple_test(suite, "compare_uuid",
+ test_compare_uuid);
+
+ torture_suite_add_simple_test(suite, "guid_into_blob",
+ test_guid_into_blob);
+
+ torture_suite_add_simple_test(suite, "guid_into_short_blob",
+ test_guid_into_short_blob);
+
+ torture_suite_add_simple_test(suite, "guid_into_long_blob",
+ test_guid_into_long_blob);
+
+ torture_suite_add_simple_test(suite, "syntax_id_from_string",
+ test_syntax_id_from_string);
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/ndr.h b/source4/torture/ndr/ndr.h
new file mode 100644
index 0000000..82ccc69
--- /dev/null
+++ b/source4/torture/ndr/ndr.h
@@ -0,0 +1,249 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TORTURE_NDR_H__
+#define __TORTURE_NDR_H__
+
+#include "torture/torture.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/security/security.h"
+
+_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pullpush_test(
+ struct torture_suite *suite,
+ const char *name,
+ ndr_pull_flags_fn_t pull_fn,
+ ndr_push_flags_fn_t push_fn,
+ ndr_print_fn_t print_fn,
+ ndr_print_function_t print_function,
+ const char *db_name,
+ DATA_BLOB db,
+ size_t struct_size,
+ ndr_flags_type ndr_flags,
+ libndr_flags flags,
+ const char *check_fn_name,
+ bool (*check_fn) (struct torture_context *, void *data));
+
+_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_inout_test(
+ struct torture_suite *suite,
+ const char *name,
+ ndr_pull_flags_fn_t pull_fn,
+ ndr_print_function_t print_fn,
+ const char *db_in_name,
+ DATA_BLOB db_in,
+ const char *db_out_name,
+ DATA_BLOB db_out,
+ size_t struct_size,
+ libndr_flags flags,
+ const char *check_fn_name,
+ bool (*check_fn) (struct torture_context *ctx, void *data));
+
+_PUBLIC_ struct torture_test *_torture_suite_add_ndr_pull_invalid_data_test(
+ struct torture_suite *suite,
+ const char *name,
+ ndr_pull_flags_fn_t pull_fn,
+ const char *db_name,
+ DATA_BLOB db,
+ size_t struct_size,
+ ndr_flags_type ndr_flags,
+ libndr_flags flags,
+ enum ndr_err_code ndr_err);
+
+#define torture_suite_add_ndr_pull_test(suite,name,data,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ NULL, \
+ (ndr_print_fn_t)ndr_print_ ## name, \
+ NULL, \
+ #data, \
+ data_blob_const(data, sizeof(data)), \
+ sizeof(struct name), \
+ NDR_SCALARS|NDR_BUFFERS, 0, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_invalid_data_test(suite,name,data,ndr_err) \
+ _torture_suite_add_ndr_pull_invalid_data_test( \
+ suite, \
+ #name, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ #data, \
+ data_blob_const(data, sizeof(data)), \
+ sizeof(struct name), \
+ NDR_SCALARS|NDR_BUFFERS, 0, \
+ ndr_err);
+
+#define torture_suite_add_ndr_pull_fn_test(suite,name,data,flags,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name "_" #flags, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ NULL, \
+ NULL, \
+ (ndr_print_function_t)ndr_print_ ## name, \
+ #data, \
+ data_blob_const(data, sizeof(data)), \
+ sizeof(struct name), \
+ flags, 0, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_fn_test_flags(suite,name,data,flags,flags2,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name "_" #flags "_" #flags2, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ NULL, \
+ NULL, \
+ (ndr_print_function_t)ndr_print_ ## name, \
+ #data, \
+ data_blob_const(data, sizeof(data)), \
+ sizeof(struct name), \
+ flags, flags2, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_validate_test(suite,name,data,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name "_VALIDATE", \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ (ndr_push_flags_fn_t)ndr_push_ ## name, \
+ (ndr_print_fn_t)ndr_print_ ## name, \
+ NULL, \
+ #data, \
+ data_blob_const(data, sizeof(data)), \
+ sizeof(struct name), \
+ NDR_SCALARS|NDR_BUFFERS, 0, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_validate_test_blob(suite,name,data_blob,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name "_VALIDATE", \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ (ndr_push_flags_fn_t)ndr_push_ ## name, \
+ (ndr_print_fn_t)ndr_print_ ## name, \
+ NULL, \
+ #data_blob, \
+ data_blob, \
+ sizeof(struct name), \
+ NDR_SCALARS|NDR_BUFFERS, 0, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_validate_test_b64(suite,name,tname,b64,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name "_" tname, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ (ndr_push_flags_fn_t)ndr_push_ ## name, \
+ (ndr_print_fn_t)ndr_print_ ## name, \
+ NULL, \
+ #b64, \
+ base64_decode_data_blob_talloc(suite, b64), \
+ sizeof(struct name), \
+ NDR_SCALARS|NDR_BUFFERS, 0, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pullpush_fn_test_flags(suite,name,data,flags,flags2,check_fn) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pullpush_test(suite, #name, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ (ndr_push_flags_fn_t)ndr_push_ ## name, \
+ NULL, \
+ (ndr_print_function_t)ndr_print_ ## name, \
+ #data, \
+ data_blob_const(data, sizeof(data)), \
+ sizeof(struct name), \
+ flags, flags2, \
+ #check_fn, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_io_test(suite,name,data_in,data_out,check_fn_out) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn_out; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pull_inout_test(suite, #name "_INOUT", \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ (ndr_print_function_t)ndr_print_ ## name, \
+ #data_in, \
+ data_blob_const(data_in, sizeof(data_in)), \
+ #data_out, \
+ data_blob_const(data_out, sizeof(data_out)), \
+ sizeof(struct name), \
+ 0, \
+ #check_fn_out, \
+ check_fn_anon); \
+ } while(0)
+
+#define torture_suite_add_ndr_pull_io_test_flags(suite,name,data_in,data_out,flags,check_fn_out) \
+ do { \
+ bool (*check_fn_typed) (struct torture_context *, struct name *) = \
+ check_fn_out; \
+ bool (*check_fn_anon) (struct torture_context *, void *) = \
+ (bool (*) (struct torture_context *, void *)) check_fn_typed; \
+ _torture_suite_add_ndr_pull_inout_test(suite, #name "_INOUT_" #flags, \
+ (ndr_pull_flags_fn_t)ndr_pull_ ## name, \
+ (ndr_print_function_t)ndr_print_ ## name, \
+ #data_in, \
+ data_blob_const(data_in, sizeof(data_in)), \
+ #data_out, \
+ data_blob_const(data_out, sizeof(data_out)), \
+ sizeof(struct name), \
+ flags, \
+ #check_fn_out, \
+ check_fn_anon); \
+ } while(0)
+
+#endif /* __TORTURE_NDR_H__ */
diff --git a/source4/torture/ndr/negoex.c b/source4/torture/ndr/negoex.c
new file mode 100644
index 0000000..1cd2d54
--- /dev/null
+++ b/source4/torture/ndr/negoex.c
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for negoex ndr operations
+
+ Copyright (C) Guenther Deschner 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_negoex.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t negoex_MESSAGE_ARRAY_data[] = {
+ 0x4e, 0x45, 0x47, 0x4f, 0x45, 0x58, 0x54, 0x53, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
+ 0x06, 0xcb, 0x30, 0x71, 0x62, 0x20, 0x1b, 0x6a, 0x40, 0x9e, 0x35, 0x14,
+ 0xc2, 0x6b, 0x17, 0x73, 0xba, 0x25, 0xdd, 0x80, 0x91, 0xfb, 0xae, 0x2c,
+ 0x68, 0x4b, 0x99, 0x28, 0xf0, 0x3c, 0x3e, 0xf3, 0xe2, 0xcf, 0x60, 0xa3,
+ 0x29, 0xee, 0xa0, 0xf9, 0xb1, 0x10, 0x4b, 0x56, 0xc3, 0x83, 0xc7, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x33, 0x53, 0x0d, 0xea, 0xf9, 0x0d, 0x4d, 0xb2, 0xec, 0x4a, 0xe3,
+ 0x78, 0x6e, 0xc3, 0x08, 0x4e, 0x45, 0x47, 0x4f, 0x45, 0x58, 0x54, 0x53,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x98, 0x00, 0x00, 0x00, 0x06, 0xcb, 0x30, 0x71, 0x62, 0x20, 0x1b, 0x6a,
+ 0x40, 0x9e, 0x35, 0x14, 0xc2, 0x6b, 0x17, 0x73, 0x5c, 0x33, 0x53, 0x0d,
+ 0xea, 0xf9, 0x0d, 0x4d, 0xb2, 0xec, 0x4a, 0xe3, 0x78, 0x6e, 0xc3, 0x08,
+ 0x40, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x30, 0x56, 0xa0, 0x54,
+ 0x30, 0x52, 0x30, 0x27, 0x80, 0x25, 0x30, 0x23, 0x31, 0x21, 0x30, 0x1f,
+ 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
+ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x50, 0x75, 0x62,
+ 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x27, 0x80, 0x25, 0x30,
+ 0x23, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18,
+ 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e,
+ 0x67, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4b, 0x65, 0x79
+};
+
+static bool negoex_MESSAGE_ARRAY_check(struct torture_context *tctx,
+ struct negoex_MESSAGE_ARRAY *r)
+{
+ struct GUID guid;
+ struct negoex_MESSAGE m;
+
+ torture_assert_int_equal(tctx, r->count, 2, "count");
+
+ m = r->messages[0];
+
+ torture_assert_str_equal(tctx, m.signature, "NEGOEXTS", "signature");
+ torture_assert_int_equal(tctx, m.type, NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO, "type");
+ torture_assert_int_equal(tctx, m.sequence_number, 0, "sequence_number");
+ torture_assert_int_equal(tctx, m.header_length, 96, "header_length");
+ torture_assert_int_equal(tctx, m.message_length, 112, "message_length");
+ GUID_from_string("7130cb06-2062-6a1b-409e-3514c26b1773", &guid);
+ torture_assert_guid_equal(tctx, m.conversation_id, guid, "conversation_id");
+ /* torture_assert_int_equal(tctx, m.p.nego.random, ba25dd8091fbae2c684b9928f03c3ef3e2cf60a329eea0f9b1104b56c383c732, "p.nego.random"); */
+ torture_assert_int_equal(tctx, m.p.nego.protocol_version, 0, "p.nego.protocol_version");
+ torture_assert_int_equal(tctx, m.p.nego.auth_schemes.count, 1, "p.nego.auth_schemes.count");
+ GUID_from_string("0d53335c-f9ea-4d0d-b2ec-4ae3786ec308", &guid);
+ torture_assert_guid_equal(tctx, m.p.nego.auth_schemes.array[0].guid, guid, "p.nego.auth_schemes.array[0].guid");
+ torture_assert_int_equal(tctx, m.p.nego.extensions.count, 0, "p.nego.extensions.count");
+
+ m = r->messages[1];
+
+ torture_assert_str_equal(tctx, m.signature, "NEGOEXTS", "signature");
+ torture_assert_int_equal(tctx, m.type, NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA, "type");
+ torture_assert_int_equal(tctx, m.sequence_number, 1, "sequence_number");
+ torture_assert_int_equal(tctx, m.header_length, 64, "header_length");
+ torture_assert_int_equal(tctx, m.message_length, 152, "message_length");
+ GUID_from_string("7130cb06-2062-6a1b-409e-3514c26b1773", &guid);
+ torture_assert_guid_equal(tctx, m.conversation_id, guid, "conversation_id");
+ GUID_from_string("0d53335c-f9ea-4d0d-b2ec-4ae3786ec308", &guid);
+ torture_assert_guid_equal(tctx, m.p.exchange.auth_scheme.guid, guid, "auth_scheme.guid");
+ torture_assert_int_equal(tctx, m.p.exchange.exchange.blob.length, 88, "exchange.blob.length");
+
+ return true;
+}
+
+struct torture_suite *ndr_negoex_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "negoex");
+
+ torture_suite_add_ndr_pull_validate_test(suite, negoex_MESSAGE_ARRAY,
+ negoex_MESSAGE_ARRAY_data,
+ negoex_MESSAGE_ARRAY_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/netlogon.c b/source4/torture/ndr/netlogon.c
new file mode 100644
index 0000000..bfd7a61
--- /dev/null
+++ b/source4/torture/ndr/netlogon.c
@@ -0,0 +1,825 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for netlogon ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t netrserverauthenticate3_in_data[] = {
+ 0xb0, 0x2e, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x4e, 0x00, 0x41, 0x00,
+ 0x54, 0x00, 0x49, 0x00, 0x56, 0x00, 0x45, 0x00, 0x2d, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x2e, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x56, 0x00, 0x45, 0x00, 0x2e, 0x00, 0x42, 0x00, 0x41, 0x00, 0x53, 0x00,
+ 0x45, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x56, 0x00, 0x45, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x24, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x56, 0x00, 0x45, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x00, 0x00,
+ 0x68, 0x8e, 0x3c, 0xdf, 0x23, 0x02, 0xb1, 0x51, 0xff, 0xff, 0x07, 0x60
+};
+
+static bool netrserverauthenticate3_in_check(struct torture_context *tctx,
+ struct netr_ServerAuthenticate3 *r)
+{
+ uint8_t cred_expected[8] = { 0x68, 0x8e, 0x3c, 0xdf, 0x23, 0x02, 0xb1, 0x51 };
+ torture_assert_str_equal(tctx, r->in.server_name, "\\\\NATIVE-DC.NATIVE.BASE", "server name");
+ torture_assert_str_equal(tctx, r->in.account_name, "NATIVE-2K$", "account name");
+ torture_assert_int_equal(tctx, r->in.secure_channel_type, 2, "secure channel type");
+ torture_assert_str_equal(tctx, r->in.computer_name, "NATIVE-2K", "computer name");
+ torture_assert_int_equal(tctx, *r->in.negotiate_flags, 0x6007ffff, "negotiate flags");
+ torture_assert_mem_equal(tctx, cred_expected, r->in.credentials->data, 8, "credentials");
+ return true;
+}
+
+static const uint8_t netrserverauthenticate3_out_data[] = {
+ 0x22, 0x0c, 0x86, 0x8a, 0xe9, 0x92, 0x93, 0xc9, 0xff, 0xff, 0x07, 0x60,
+ 0x54, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool netrserverauthenticate3_out_check(struct torture_context *tctx,
+ struct netr_ServerAuthenticate3 *r)
+{
+ uint8_t cred_expected[8] = { 0x22, 0x0c, 0x86, 0x8a, 0xe9, 0x92, 0x93, 0xc9 };
+ torture_assert_mem_equal(tctx, cred_expected, r->out.return_credentials->data, 8, "return_credentials");
+ torture_assert_int_equal(tctx, *r->out.negotiate_flags, 0x6007ffff, "negotiate flags");
+ torture_assert_int_equal(tctx, *r->out.rid, 0x454, "rid");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+static const uint8_t netrserverreqchallenge_in_data[] = {
+ 0xb0, 0x2e, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x4e, 0x00, 0x41, 0x00,
+ 0x54, 0x00, 0x49, 0x00, 0x56, 0x00, 0x45, 0x00, 0x2d, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x2e, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x56, 0x00, 0x45, 0x00, 0x2e, 0x00, 0x42, 0x00, 0x41, 0x00, 0x53, 0x00,
+ 0x45, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00,
+ 0x56, 0x00, 0x45, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x00, 0x00,
+ 0xa3, 0x2c, 0xa2, 0x95, 0x40, 0xcc, 0xb7, 0xbb
+};
+
+static bool netrserverreqchallenge_in_check(struct torture_context *tctx,
+ struct netr_ServerReqChallenge *r)
+{
+ uint8_t cred_expected[8] = { 0xa3, 0x2c, 0xa2, 0x95, 0x40, 0xcc, 0xb7, 0xbb };
+ torture_assert_str_equal(tctx, r->in.server_name, "\\\\NATIVE-DC.NATIVE.BASE", "server name");
+ torture_assert_str_equal(tctx, r->in.computer_name, "NATIVE-2K", "account name");
+ torture_assert_mem_equal(tctx, cred_expected, r->in.credentials->data, 8, "credentials");
+
+ return true;
+}
+
+static const uint8_t netrserverreqchallenge_out_data[] = {
+ 0x22, 0xfc, 0xc1, 0x17, 0xc0, 0xae, 0x27, 0x8e, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool netrserverreqchallenge_out_check(struct torture_context *tctx,
+ struct netr_ServerReqChallenge *r)
+{
+ uint8_t cred_expected[8] = { 0x22, 0xfc, 0xc1, 0x17, 0xc0, 0xae, 0x27, 0x8e };
+ torture_assert_mem_equal(tctx, cred_expected, r->out.return_credentials->data, 8, "return_credentials");
+ torture_assert_ntstatus_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+static const uint8_t netrlogonsamlogon_w2k_in_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x53, 0x00, 0x52, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x54, 0x00, 0x48, 0x00, 0x45, 0x00,
+ 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x08, 0xaf, 0x72, 0x50, 0xa0, 0x5b, 0x50, 0x19,
+ 0x02, 0xc3, 0x39, 0x4d, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x10, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xad, 0xde, 0x00, 0x00, 0xef, 0xbe, 0x00, 0x00,
+ 0x1a, 0x00, 0x1a, 0x00, 0x18, 0x00, 0x02, 0x00, 0x14, 0x00, 0x14, 0x00,
+ 0x1c, 0x00, 0x02, 0x00, 0x31, 0xeb, 0xf4, 0x68, 0x62, 0x93, 0xfe, 0x38,
+ 0x51, 0xc1, 0x1d, 0x41, 0x0a, 0xbd, 0x5d, 0xdf, 0xe3, 0x4f, 0x76, 0x7f,
+ 0x19, 0x12, 0xcd, 0xfe, 0x9c, 0x68, 0xed, 0x9b, 0x1e, 0x9c, 0x66, 0xf6,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x61, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x6d, 0x00, 0x74, 0x00,
+ 0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00,
+ 0x06, 0x00
+};
+
+static bool netrlogonsamlogon_w2k_in_check(struct torture_context *tctx,
+ struct netr_LogonSamLogon *r)
+{
+ uint8_t credential_expected[8] = { 0x08, 0xaf, 0x72, 0x50, 0xa0, 0x5b, 0x50, 0x19 };
+ uint8_t return_authenticator_expected[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ uint8_t lmpassword_expected[16] = { 0x31, 0xeb, 0xf4, 0x68, 0x62, 0x93, 0xfe, 0x38, 0x51, 0xc1, 0x1d, 0x41, 0x0a, 0xbd, 0x5d, 0xdf };
+ uint8_t ntpassword_expected[16] = { 0xe3, 0x4f, 0x76, 0x7f, 0x19, 0x12, 0xcd, 0xfe, 0x9c, 0x68, 0xed, 0x9b, 0x1e, 0x9c, 0x66, 0xf6 };
+
+ torture_assert_str_equal(tctx, r->in.server_name, "\\\\W2KSRV", "server_name");
+ torture_assert_str_equal(tctx, r->in.computer_name, "MTHELENA", "computer_name");
+ torture_assert_mem_equal(tctx, r->in.credential->cred.data, credential_expected, 8, "credential");
+/* torture_assert_int_equal(tctx, r->in.credential->timestamp, 0, "credential.timestamp"); */
+ torture_assert_mem_equal(tctx, r->in.return_authenticator->cred.data, return_authenticator_expected, 8, "return_authenticator.cred.data");
+ torture_assert_int_equal(tctx, r->in.return_authenticator->timestamp, 0, "return_authenticator.timestamp");
+ torture_assert_int_equal(tctx, r->in.logon_level, NetlogonInteractiveInformation, "logon_level");
+ torture_assert(tctx, r->in.logon, "logon NULL pointer");
+ torture_assert(tctx, r->in.logon->password, "logon->password NULL pointer");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.domain_name.length, 12, "domain_name.length");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.domain_name.size, 12, "domain_name.size");
+ torture_assert_str_equal(tctx, r->in.logon->password->identity_info.domain_name.string, "W2KDOM", "domain_name.string");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.parameter_control, 0, "parameter_control");
+ torture_assert_u64_equal(tctx, r->in.logon->password->identity_info.logon_id, 0xbeef0000dead, "logon_id");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.account_name.length, 26, "account_name.length");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.account_name.size, 26, "account_name.size");
+ torture_assert_str_equal(tctx, r->in.logon->password->identity_info.account_name.string, "administrator", "account_name.string");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.workstation.length, 20, "workstation.length");
+ torture_assert_int_equal(tctx, r->in.logon->password->identity_info.workstation.size, 20, "workstation.size");
+ torture_assert_str_equal(tctx, r->in.logon->password->identity_info.workstation.string, "\\\\mthelena", "workstation.string");
+ torture_assert_mem_equal(tctx, r->in.logon->password->lmpassword.hash, lmpassword_expected, 16, "lmpassword");
+ torture_assert_mem_equal(tctx, r->in.logon->password->ntpassword.hash, ntpassword_expected, 16, "ntpassword");
+ torture_assert_int_equal(tctx, r->in.validation_level, 6, "validation_level");
+
+ return true;
+}
+
+#if 0
+static const uint8_t netrlogonsamlogon_w2k_out_data[] = {
+ 0x6c, 0xdb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0xc0
+};
+
+static bool netrlogonsamlogon_w2k_out_check(struct torture_context *tctx,
+ struct netr_LogonSamLogon *r)
+{
+ uint8_t return_authenticator_expected[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ torture_assert_mem_equal(tctx, r->out.return_authenticator->cred.data, return_authenticator_expected, 8, "return_authenticator.cred.data");
+ torture_assert_int_equal(tctx, r->out.return_authenticator->timestamp, 0, "return_authenticator.timestamp");
+ torture_assert(tctx, r->out.validation, "validation NULL pointer");
+ torture_assert(tctx, (r->out.validation->sam6 == NULL), "sam6 not NULL");
+ torture_assert_int_equal(tctx, *r->out.authoritative, 1, "authoritative");
+ torture_assert_ntstatus_equal(tctx, r->out.result, NT_STATUS_INVALID_INFO_CLASS, "unexpected result");
+
+ return true;
+}
+#endif
+
+static const uint8_t netrlogongetdomaininfo_in_data[] = {
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x64, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x64, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x54, 0x00, 0x48, 0x00, 0x45, 0x00,
+ 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x22, 0xbd, 0x03, 0x67, 0x3d, 0xdf, 0x17, 0xd3, 0x98, 0x81, 0x5d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool netrlogongetdomaininfo_in_check(struct torture_context *tctx,
+ struct netr_LogonGetDomainInfo *r)
+{
+ return true;
+}
+
+static const uint8_t netrlogongetdomaininfo_out_data[] = {
+ 0x81, 0x3f, 0x80, 0x20, 0x4b, 0x4a, 0x18, 0x93, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x12, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x32, 0x00, 0x34, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x32, 0x00, 0x34, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x99, 0x7c, 0x28, 0xfd,
+ 0x3b, 0xc8, 0x03, 0x4d, 0x84, 0x9e, 0x30, 0xc4, 0xf0, 0x62, 0xe2, 0xd3,
+ 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2e, 0x00,
+ 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x2e, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00,
+ 0x36, 0x00, 0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
+ 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00,
+ 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x80, 0x9f, 0x75, 0x68, 0x0c, 0x07, 0x89, 0x1a, 0xd7, 0x39, 0x71, 0x13,
+ 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0x2e, 0x00, 0x30, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x10, 0x00, 0x24, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x12, 0x00, 0x28, 0x00, 0x02, 0x00, 0x30, 0x00, 0x32, 0x00,
+ 0x2c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x99, 0x7c, 0x28, 0xfd, 0x3b, 0xc8, 0x03, 0x4d, 0x84, 0x9e, 0x30, 0xc4,
+ 0xf0, 0x62, 0xe2, 0xd3, 0x30, 0x00, 0x02, 0x00, 0x10, 0x00, 0x10, 0x00,
+ 0x34, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x31, 0x00, 0x32, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x32, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x05, 0xee, 0xb6, 0x98, 0x1b, 0xf2, 0x46, 0x5d,
+ 0x27, 0x50, 0x57, 0x3d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2e, 0x00,
+ 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x75, 0x68, 0x0c, 0x07, 0x89, 0x1a,
+ 0xd7, 0x39, 0x71, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool netrlogongetdomaininfo_out_check_common(struct torture_context *tctx,
+ struct netr_LogonGetDomainInfo *r)
+{
+ struct GUID guid;
+ struct dom_sid sid;
+ struct netr_OneDomainInfo p;
+
+ p = r->out.info->domain_info->primary_domain;
+
+ torture_assert_str_equal(tctx,
+ p.domainname.string,
+ "W2K16DOM", "domainname.string");
+ torture_assert_str_equal(tctx,
+ p.dns_domainname.string,
+ "w2k16.dom.ber.redhat.com.", "dns_domainname.string");
+ torture_assert_str_equal(tctx,
+ p.dns_forestname.string,
+ "w2k16.dom.ber.redhat.com.", "dns_forestname.string");
+ GUID_from_string("fd287c99-c83b-4d03-849e-30c4f062e2d3", &guid);
+ torture_assert_guid_equal(tctx,
+ p.domain_guid,
+ guid,
+ "domain_guid");
+ string_to_sid(&sid, "S-1-5-21-1752539008-445187852-326187479");
+ torture_assert_sid_equal(tctx,
+ p.domain_sid,
+ &sid,
+ "domain_sid");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.length,
+ 0,
+ "trust_extension.length");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.size,
+ 0,
+ "trust_extension.size");
+ torture_assert(tctx,
+ p.trust_extension.info == NULL,
+ "trust_extension.info");
+ /* dummy_string2, dummy_string3, dummy_string4,
+ dummy_long1, dummy_long2, dummy_long3, dummy_long4 */
+
+ torture_assert_int_equal(tctx,
+ r->out.info->domain_info->trusted_domain_count, 2,
+ "trusted_domain_count");
+
+ /* trusted domain 0 */
+
+ p = r->out.info->domain_info->trusted_domains[0];
+
+ torture_assert_str_equal(tctx,
+ p.domainname.string,
+ "W2K12DOM", "domainname.string");
+ torture_assert_str_equal(tctx,
+ p.dns_domainname.string,
+ "w2k12dom.ber.redhat.com", "dns_domainname.string");
+ torture_assert_str_equal(tctx,
+ p.dns_forestname.string,
+ NULL, "dns_forestname.string");
+ guid = GUID_zero();
+ torture_assert_guid_equal(tctx,
+ p.domain_guid,
+ guid,
+ "domain_guid");
+ string_to_sid(&sid, "S-1-5-21-2562125317-1564930587-1029132327");
+ torture_assert_sid_equal(tctx,
+ p.domain_sid,
+ &sid,
+ "domain_sid");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.length,
+ 16,
+ "trust_extension.length");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.size,
+ 16,
+ "trust_extension.size");
+ torture_assert(tctx,
+ p.trust_extension.info,
+ "trust_extension.info");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->length, 8,
+ "trust_extension.info->length");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->dummy, 0,
+ "trust_extension.info->dummy");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->size, 8,
+ "trust_extension.info->size");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.flags,
+ NETR_TRUST_FLAG_OUTBOUND,
+ "trust_extension.info->info.flags");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.parent_index, 0,
+ "trust_extension.info->info.parent_index");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.trust_type,
+ LSA_TRUST_TYPE_UPLEVEL,
+ "trust_extension.info->info.trust_type");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.trust_attributes,
+ LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE |
+ LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION,
+ "trust_extension.info->info.trust_attributes");
+ /* dummy_string2, dummy_string3, dummy_string4,
+ dummy_long1, dummy_long2, dummy_long3, dummy_long4 */
+
+ /* trusted domain 1 */
+
+ p = r->out.info->domain_info->trusted_domains[1];
+
+ torture_assert_str_equal(tctx,
+ p.domainname.string,
+ "W2K16DOM", "domainname.string");
+ torture_assert_str_equal(tctx,
+ p.dns_domainname.string,
+ "w2k16.dom.ber.redhat.com", "dns_domainname.string");
+ torture_assert_str_equal(tctx,
+ p.dns_forestname.string,
+ NULL, "dns_forestname.string");
+ GUID_from_string("fd287c99-c83b-4d03-849e-30c4f062e2d3", &guid);
+ torture_assert_guid_equal(tctx,
+ p.domain_guid,
+ guid,
+ "domain_guid");
+ string_to_sid(&sid, "S-1-5-21-1752539008-445187852-326187479");
+ torture_assert_sid_equal(tctx,
+ p.domain_sid,
+ &sid,
+ "domain_sid");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.length,
+ 16,
+ "trust_extension.length");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.size,
+ 16,
+ "trust_extension.size");
+ torture_assert(tctx,
+ p.trust_extension.info,
+ "trust_extension.info");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->length, 8,
+ "trust_extension.info->length");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->dummy, 0,
+ "trust_extension.info->dummy");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->size, 8,
+ "trust_extension.info->size");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.flags,
+ NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT |
+ NETR_TRUST_FLAG_PRIMARY | NETR_TRUST_FLAG_NATIVE,
+ "trust_extension.info->info.flags");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.parent_index, 0,
+ "trust_extension.info->info.parent_index");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.trust_type,
+ LSA_TRUST_TYPE_UPLEVEL,
+ "trust_extension.info->info.trust_type");
+ torture_assert_int_equal(tctx,
+ p.trust_extension.info->info.trust_attributes, 0,
+ "trust_extension.info->info.trust_attributes");
+ /* dummy_string2, dummy_string3, dummy_string4,
+ dummy_long1, dummy_long2, dummy_long3, dummy_long4 */
+
+ torture_assert_int_equal(tctx,
+ r->out.info->domain_info->lsa_policy.policy_size, 0,
+ "lsa_policy.policy_size");
+ torture_assert(tctx,
+ r->out.info->domain_info->lsa_policy.policy == NULL,
+ "lsa_policy.policy");
+ torture_assert_str_equal(tctx,
+ r->out.info->domain_info->dns_hostname.string, NULL,
+ "dns_hostname");
+ /* dummy_string2, dummy_string3, dummy_string4 */
+ torture_assert_int_equal(tctx,
+ r->out.info->domain_info->workstation_flags, 0,
+ "workstation_flags");
+
+ return true;
+}
+
+static bool netrlogongetdomaininfo_out_check(struct torture_context *tctx,
+ struct netr_LogonGetDomainInfo *r)
+{
+ uint8_t return_authenticator_expected[8] = { 0x81, 0x3f, 0x80, 0x20, 0x4b, 0x4a, 0x18, 0x93 };
+ bool ok;
+
+ torture_assert_mem_equal(tctx,
+ r->out.return_authenticator->cred.data,
+ return_authenticator_expected, 8,
+ "return_authenticator.cred.data");
+ /* torture_assert_int_equal(tctx, r->out.return_authenticator->timestamp, 0, "return_authenticator.timestamp"); */
+
+ ok = netrlogongetdomaininfo_out_check_common(tctx, r);
+ if (!ok) {
+ return false;
+ }
+
+ torture_assert_int_equal(tctx,
+ r->out.info->domain_info->supported_enc_types,
+ 0x0000001f,
+ "supported_enc_types");
+ /* dummy_long3, dummy_long4 */
+
+ return true;
+}
+
+static bool netrlogongetdomaininfo_out_check64(struct torture_context *tctx,
+ struct netr_LogonGetDomainInfo *r)
+{
+ uint8_t return_authenticator_expected[8] = { 0x5c, 0x69, 0xfe, 0xcf, 0x9b, 0xd5, 0x00, 0xa0 };
+ bool ok;
+
+ torture_assert_mem_equal(tctx,
+ r->out.return_authenticator->cred.data,
+ return_authenticator_expected, 8,
+ "return_authenticator.cred.data");
+ /* torture_assert_int_equal(tctx, r->out.return_authenticator->timestamp, 0, "return_authenticator.timestamp"); */
+
+ ok = netrlogongetdomaininfo_out_check_common(tctx, r);
+ if (!ok) {
+ return false;
+ }
+
+ torture_assert_int_equal(tctx,
+ r->out.info->domain_info->supported_enc_types,
+ 0xffffffff,
+ "supported_enc_types");
+ /* dummy_long3, dummy_long4 */
+
+ return true;
+}
+
+static const uint8_t netrlogongetdomaininfo_in_data64[] = {
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x47, 0x00, 0x44, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x44, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x81, 0x19, 0x6e, 0x66,
+ 0x55, 0x71, 0x21, 0x4b, 0x42, 0x61, 0x82, 0x5d, 0x81, 0x19, 0x6e, 0x66,
+ 0x55, 0x71, 0x21, 0x4b, 0x42, 0x61, 0x82, 0x5d, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t netrlogongetdomaininfo_out_data64[] = {
+ 0x5c, 0x69, 0xfe, 0xcf, 0x9b, 0xd5, 0x00, 0xa0, 0x33, 0x68, 0x82, 0x5d,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x7c, 0x28, 0xfd,
+ 0x3b, 0xc8, 0x03, 0x4d, 0x84, 0x9e, 0x30, 0xc4, 0xf0, 0x62, 0xe2, 0xd3,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2e, 0x00,
+ 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x80, 0x9f, 0x75, 0x68, 0x0c, 0x07, 0x89, 0x1a, 0xd7, 0x39, 0x71, 0x13,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x99, 0x7c, 0x28, 0xfd, 0x3b, 0xc8, 0x03, 0x4d,
+ 0x84, 0x9e, 0x30, 0xc4, 0xf0, 0x62, 0xe2, 0xd3, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x31, 0x00, 0x32, 0x00, 0x44, 0x00,
+ 0x4f, 0x00, 0x4d, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00,
+ 0x32, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0x05, 0xee, 0xb6, 0x98, 0x1b, 0xf2, 0x46, 0x5d, 0x27, 0x50, 0x57, 0x3d,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x31, 0x00,
+ 0x36, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00,
+ 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x75, 0x68, 0x0c, 0x07, 0x89, 0x1a,
+ 0xd7, 0x39, 0x71, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t netrlogongetdomaininfo_in_data64_osversion[] = {
+ 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x30, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x65, 0x00,
+ 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x68, 0x00, 0x2e, 0x00, 0x6d, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x6b, 0x00, 0x79, 0x00, 0x77, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x2d, 0x00,
+ 0x43, 0x00, 0x4c, 0x00, 0x49, 0x00, 0x30, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x4d, 0x33, 0xf7, 0x0d, 0xe7, 0xeb, 0x15, 0x4b, 0xd4, 0xe9, 0x4b, 0x5d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x1c, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x2c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x2d, 0x00,
+ 0x43, 0x00, 0x4c, 0x00, 0x49, 0x00, 0x30, 0x00, 0x31, 0x00, 0x2e, 0x00,
+ 0x65, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x68, 0x00, 0x2e, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x6b, 0x00, 0x79, 0x00, 0x77, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00,
+ 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x46, 0x00, 0x69, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x69, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x4e, 0x00, 0x61, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xee, 0x42, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xb0, 0x4a, 0x02, 0xae, 0x6e, 0x01, 0x00, 0x00, 0x80, 0x4a, 0x16, 0xae,
+ 0x6e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc5, 0x96, 0xcc, 0x46, 0xff, 0x7f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0xc8, 0x4a, 0x16, 0xae, 0x6e, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xec, 0x2f, 0x80, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x2f, 0x80, 0x6d, 0x00, 0x00, 0x00,
+ 0xa0, 0x4a, 0x16, 0xae, 0x6e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0xad,
+ 0x6e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf4, 0xed, 0x2f, 0x80, 0x6d, 0x00, 0x00, 0x00, 0x60, 0xe8, 0x2f, 0x80,
+ 0x6d, 0x00, 0x00, 0x00, 0xe0, 0xea, 0x2f, 0x80, 0x6d, 0x00, 0x00, 0x00,
+ 0x20, 0xec, 0x2f, 0x80, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x31, 0x00, 0x30, 0x00,
+ 0x20, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x73, 0x00, 0x65, 0x00
+};
+
+static bool netrlogongetdomaininfo_in_check_osversion(struct torture_context *tctx,
+ struct netr_LogonGetDomainInfo *r)
+{
+ return true;
+}
+
+struct torture_suite *ndr_netlogon_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "netlogon");
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ netr_ServerReqChallenge,
+ netrserverreqchallenge_in_data,
+ NDR_IN,
+ netrserverreqchallenge_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite,
+ netr_ServerReqChallenge,
+ netrserverreqchallenge_out_data,
+ NDR_OUT,
+ netrserverreqchallenge_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ netr_ServerAuthenticate3,
+ netrserverauthenticate3_in_data,
+ NDR_IN,
+ netrserverauthenticate3_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite,
+ netr_ServerAuthenticate3,
+ netrserverauthenticate3_out_data,
+ NDR_OUT,
+ netrserverauthenticate3_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ netr_LogonSamLogon,
+ netrlogonsamlogon_w2k_in_data,
+ NDR_IN,
+ netrlogonsamlogon_w2k_in_check);
+#if 0
+ /* samba currently fails to parse a validation level 6 samlogon reply
+ * from w2k and other servers - gd */
+ torture_suite_add_ndr_pull_io_test(suite,
+ netr_LogonSamLogon,
+ netrlogonsamlogon_w2k_in_data,
+ netrlogonsamlogon_w2k_out_data,
+ netrlogonsamlogon_w2k_out_check);
+#endif
+ torture_suite_add_ndr_pull_fn_test(suite,
+ netr_LogonGetDomainInfo,
+ netrlogongetdomaininfo_in_data,
+ NDR_IN,
+ netrlogongetdomaininfo_in_check);
+ torture_suite_add_ndr_pull_io_test(suite,
+ netr_LogonGetDomainInfo,
+ netrlogongetdomaininfo_in_data,
+ netrlogongetdomaininfo_out_data,
+ netrlogongetdomaininfo_out_check);
+
+ torture_suite_add_ndr_pull_fn_test_flags(suite,
+ netr_LogonGetDomainInfo,
+ netrlogongetdomaininfo_in_data64,
+ NDR_IN,
+ LIBNDR_FLAG_NDR64,
+ netrlogongetdomaininfo_in_check);
+ torture_suite_add_ndr_pull_io_test_flags(suite,
+ netr_LogonGetDomainInfo,
+ netrlogongetdomaininfo_in_data64,
+ netrlogongetdomaininfo_out_data64,
+ LIBNDR_FLAG_NDR64,
+ netrlogongetdomaininfo_out_check64);
+
+ torture_suite_add_ndr_pull_fn_test_flags(suite,
+ netr_LogonGetDomainInfo,
+ netrlogongetdomaininfo_in_data64_osversion,
+ NDR_IN,
+ LIBNDR_FLAG_NDR64,
+ netrlogongetdomaininfo_in_check_osversion);
+#if 0
+ /* currently fails, most likely due to pointer value calculations - gd */
+ torture_suite_add_ndr_pullpush_fn_test_flags(suite,
+ netr_LogonGetDomainInfo,
+ netrlogongetdomaininfo_in_data64_osversion,
+ NDR_IN,
+ LIBNDR_FLAG_NDR64,
+ netrlogongetdomaininfo_in_check_osversion);
+#endif
+
+ return suite;
+}
diff --git a/source4/torture/ndr/ntlmssp.c b/source4/torture/ndr/ntlmssp.c
new file mode 100644
index 0000000..4127ce8
--- /dev/null
+++ b/source4/torture/ndr/ntlmssp.c
@@ -0,0 +1,296 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for ntlmssp ndr operations
+
+ Copyright (C) Guenther Deschner 2010,2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_ntlmssp.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t ntlmssp_NEGOTIATE_MESSAGE_data[] = {
+ 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x97, 0x82, 0x08, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0xb0, 0x1d,
+ 0x00, 0x00, 0x00, 0x0f
+};
+
+static bool ntlmssp_NEGOTIATE_MESSAGE_check(struct torture_context *tctx,
+ struct NEGOTIATE_MESSAGE *r)
+{
+ torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature");
+ torture_assert_int_equal(tctx, r->MessageType, NtLmNegotiate, "MessageType");
+ torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2088297, "NegotiateFlags");
+ torture_assert_int_equal(tctx, r->DomainNameLen, 0, "DomainNameLen");
+ torture_assert_int_equal(tctx, r->DomainNameMaxLen, 0, "DomainNameMaxLen");
+ torture_assert(tctx, r->DomainName == NULL, "DomainName");
+ torture_assert_int_equal(tctx, r->WorkstationLen, 0, "WorkstationLen");
+ torture_assert_int_equal(tctx, r->WorkstationMaxLen, 0, "WorkstationMaxLen");
+ torture_assert(tctx, r->Workstation == NULL, "Workstation");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0x1db0, "ProductBuild");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent");
+
+ return true;
+}
+
+static const uint8_t ntlmssp_CHALLENGE_MESSAGE_data[] = {
+ 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x00, 0x00, 0x95, 0x82, 0x89, 0xe2,
+ 0xed, 0xc8, 0x2b, 0x7d, 0x2e, 0xd7, 0xd0, 0xd9, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x78, 0x00, 0x42, 0x00, 0x00, 0x00,
+ 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x53, 0x00, 0x41, 0x00,
+ 0x4d, 0x00, 0x42, 0x00, 0x41, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x53, 0x00,
+ 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x41, 0x00, 0x01, 0x00, 0x10, 0x00,
+ 0x4d, 0x00, 0x54, 0x00, 0x48, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x45, 0x00,
+ 0x4e, 0x00, 0x41, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x03, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x2e, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool ntlmssp_CHALLENGE_MESSAGE_check(struct torture_context *tctx,
+ struct CHALLENGE_MESSAGE *r)
+{
+ uint8_t chal[8] = { 0xed, 0xc8, 0x2b, 0x7d, 0x2e, 0xd7, 0xd0, 0xd9 };
+ uint8_t data[8] = { 0 };
+
+ torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature");
+ torture_assert_int_equal(tctx, r->MessageType, NtLmChallenge, "MessageType");
+ torture_assert_int_equal(tctx, r->TargetNameLen, 10, "TargetNameLen");
+ torture_assert_int_equal(tctx, r->TargetNameMaxLen, 10, "TargetNameMaxLen");
+ torture_assert_str_equal(tctx, r->TargetName, "SAMBA", "TargetName");
+ torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2898295, "NegotiateFlags");
+ torture_assert_mem_equal(tctx, r->ServerChallenge, chal, 8, "ServerChallenge");
+ torture_assert_mem_equal(tctx, r->Reserved, data, 8, "Reserved");
+ torture_assert_int_equal(tctx, r->TargetInfoLen, 120, "TargetInfoLen");
+ torture_assert_int_equal(tctx, r->TargetInfoMaxLen, 120, "TargetInfoMaxLen");
+ torture_assert_int_equal(tctx, r->TargetInfo->count, 5, "TargetInfo->count");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[0].AvId, MsvAvNbDomainName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[0].AvLen, 10, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[0].Value.AvNbDomainName, "SAMBA", "AvNbDomainName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[1].AvId, MsvAvNbComputerName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[1].AvLen, 16, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[1].Value.AvNbComputerName, "MTHELENA", "AvNbComputerName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[2].AvId, MsvAvDnsDomainName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[2].AvLen, 28, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[2].Value.AvDnsDomainName, "ber.redhat.com", "AvDnsDomainName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[3].AvId, MsvAvDnsComputerName, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[3].AvLen, 46, "AvLen");
+ torture_assert_str_equal(tctx, r->TargetInfo->pair[3].Value.AvDnsComputerName, "mthelena.ber.redhat.com", "AvDnsComputerName");
+
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[4].AvId, MsvAvEOL, "AvId");
+ torture_assert_int_equal(tctx, r->TargetInfo->pair[4].AvLen, 0, "AvLen");
+
+ torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0, "ProductBuild");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent");
+
+ return true;
+}
+
+static const uint8_t ntlmssp_AUTHENTICATE_MESSAGE_data[] = {
+ 0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x18, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x0e, 0x01,
+ 0xa4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x1a, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xb2, 0x01, 0x00, 0x00,
+ 0x15, 0x82, 0x88, 0xe2, 0x06, 0x01, 0xb0, 0x1d, 0x00, 0x00, 0x00, 0x0f,
+ 0x50, 0xe2, 0xb2, 0xa7, 0xf5, 0x83, 0x3e, 0xda, 0x71, 0xa7, 0xe8, 0x6e,
+ 0x95, 0x1e, 0x3a, 0x57, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00,
+ 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xcf, 0xfb, 0x39,
+ 0x5a, 0xb3, 0x4c, 0x58, 0x86, 0x35, 0xa3, 0xe7, 0x1e, 0x00, 0x98, 0x43,
+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x79, 0x02, 0x77,
+ 0x1e, 0x54, 0xcb, 0x01, 0x3c, 0x21, 0x0a, 0xe9, 0xde, 0x61, 0xc0, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x53, 0x00, 0x41, 0x00,
+ 0x4d, 0x00, 0x42, 0x00, 0x41, 0x00, 0x01, 0x00, 0x10, 0x00, 0x4d, 0x00,
+ 0x54, 0x00, 0x48, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00,
+ 0x41, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x03, 0x00,
+ 0x2e, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x08, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0a, 0xfd, 0x3b, 0x2c,
+ 0xad, 0x43, 0x46, 0x8b, 0x49, 0x01, 0x6c, 0xa5, 0xf3, 0xbc, 0xd2, 0x13,
+ 0xbb, 0x70, 0xe2, 0x65, 0x96, 0xba, 0x0d, 0x8d, 0x5d, 0x31, 0xe6, 0x47,
+ 0x94, 0x61, 0xed, 0x28, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x1a, 0x00, 0x63, 0x00, 0x69, 0x00, 0x66, 0x00, 0x73, 0x00,
+ 0x2f, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xa4, 0x23, 0xd4, 0x5c, 0x16, 0x52, 0x8d, 0x56, 0x34, 0x2d,
+ 0x1c, 0xff, 0x86, 0x17, 0xc9, 0x4f
+};
+
+static bool ntlmssp_AUTHENTICATE_MESSAGE_check(struct torture_context *tctx,
+ struct AUTHENTICATE_MESSAGE *r)
+{
+ uint8_t lm_challenge_response[24] = { 0 };
+ struct NTLMv2_RESPONSE v2;
+ struct AV_PAIR_LIST AvPairs;
+ uint8_t Response[16] = {
+ 0x38, 0xcf, 0xfb, 0x39, 0x5a, 0xb3, 0x4c, 0x58,
+ 0x86, 0x35, 0xa3, 0xe7, 0x1e, 0x00, 0x98, 0x43
+ };
+ uint8_t ChallengeFromClient[8] = {
+ 0x3c, 0x21, 0x0a, 0xe9, 0xde, 0x61, 0xc0, 0x7e
+ };
+ uint8_t MachineId[32] = {
+ 0x0a, 0xfd, 0x3b, 0x2c, 0xad, 0x43, 0x46, 0x8b,
+ 0x49, 0x01, 0x6c, 0xa5, 0xf3, 0xbc, 0xd2, 0x13,
+ 0xbb, 0x70, 0xe2, 0x65, 0x96, 0xba, 0x0d, 0x8d,
+ 0x5d, 0x31, 0xe6, 0x47, 0x94, 0x61, 0xed, 0x28
+ };
+ uint8_t EncryptedRandomSessionKey[16] = {
+ 0xA4, 0x23, 0xD4, 0x5C, 0x16, 0x52, 0x8D, 0x56,
+ 0x34, 0x2D, 0x1C, 0xFF, 0x86, 0x17, 0xC9, 0x4F
+ };
+
+ torture_assert_str_equal(tctx, r->Signature, "NTLMSSP", "Signature");
+ torture_assert_int_equal(tctx, r->MessageType, NtLmAuthenticate, "MessageType");
+ torture_assert_int_equal(tctx, r->LmChallengeResponseLen, 24, "LmChallengeResponseLen");
+ torture_assert_int_equal(tctx, r->LmChallengeResponseMaxLen, 24, "LmChallengeResponseMaxLen");
+ torture_assert_mem_equal(tctx, r->LmChallengeResponse->v1.Response, lm_challenge_response, 24, "LmChallengeResponse");
+
+ torture_assert_int_equal(tctx, r->NtChallengeResponseLen, 270, "NtChallengeResponseLen");
+ torture_assert_int_equal(tctx, r->NtChallengeResponseMaxLen, 270, "NtChallengeResponseMaxLen");
+
+ v2 = r->NtChallengeResponse->v2;
+
+ torture_assert_mem_equal(tctx, v2.Response, Response, 16, "v2.Response");
+ torture_assert_int_equal(tctx, v2.Challenge.RespType, 1, "RespType");
+ torture_assert_int_equal(tctx, v2.Challenge.HiRespType, 1, "HiRespType");
+ torture_assert_int_equal(tctx, v2.Challenge.Reserved1, 0, "Reserved1");
+ torture_assert_int_equal(tctx, v2.Challenge.Reserved2, 0, "Reserved2");
+ /* TimeStamp : Tue Sep 14 17:06:53 2010 CEST */
+ torture_assert_mem_equal(tctx, v2.Challenge.ChallengeFromClient, ChallengeFromClient, 8, "v2.Challenge.ChallengeFromClient");
+ torture_assert_int_equal(tctx, v2.Challenge.Reserved3, 0, "Reserved3");
+
+ AvPairs = v2.Challenge.AvPairs;
+
+ torture_assert_int_equal(tctx, AvPairs.count, 8, "AvPairs.count");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[0].AvId, MsvAvNbDomainName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[0].AvLen, 10, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[0].Value.AvNbDomainName, "SAMBA", "Value.AvNbDomainName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[1].AvId, MsvAvNbComputerName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[1].AvLen, 16, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[1].Value.AvNbComputerName, "MTHELENA", "Value.AvNbComputerName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[2].AvId, MsvAvDnsDomainName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[2].AvLen, 28, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[2].Value.AvDnsDomainName, "ber.redhat.com", "Value.AvDnsDomainName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[3].AvId, MsvAvDnsComputerName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[3].AvLen, 46, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[3].Value.AvDnsComputerName, "mthelena.ber.redhat.com", "Value.AvDnsComputerName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[4].AvId, MsvAvSingleHost, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].AvLen, 48, "AvLen");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.Size, 48, "Value.AvSingleHost.Size");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.Z4, 0, "Value.AvSingleHost.Z4");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.Flags, 0, "Value.AvSingleHost.token_info.Flags");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.TokenIL, 0x00003000, "Value.AvSingleHost.token_info.TokenIL");
+ torture_assert_mem_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.token_info.MachineId, MachineId, 32, "Value.AvSingleHost.token_info.MachineId");
+ torture_assert_int_equal(tctx, AvPairs.pair[4].Value.AvSingleHost.remaining.length, 0, "Value.AvSingleHost.remaining.length");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[5].AvId, MsvChannelBindings, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[5].AvLen, 16, "AvLen");
+ torture_assert_mem_equal(tctx, AvPairs.pair[5].Value.ChannelBindings, lm_challenge_response, 16, "Value.ChannelBindings");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[6].AvId, MsvAvTargetName, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[6].AvLen, 26, "AvLen");
+ torture_assert_str_equal(tctx, AvPairs.pair[6].Value.AvTargetName, "cifs/mthelena", "Value.AvTargetName");
+
+ torture_assert_int_equal(tctx, AvPairs.pair[7].AvId, MsvAvEOL, "AvId");
+ torture_assert_int_equal(tctx, AvPairs.pair[7].AvLen, 0, "AvLen");
+
+ torture_assert_int_equal(tctx, r->DomainNameLen, 14, "DomainNameLen");
+ torture_assert_int_equal(tctx, r->DomainNameMaxLen, 14, "DomainNameMaxLen");
+ torture_assert_str_equal(tctx, r->DomainName, "W2K8DOM", "DomainName");
+
+ torture_assert_int_equal(tctx, r->UserNameLen, 26, "UserNameLen");
+ torture_assert_int_equal(tctx, r->UserNameMaxLen, 26, "UserNameMaxLen");
+ torture_assert_str_equal(tctx, r->UserName, "Administrator", "UserName");
+
+ torture_assert_int_equal(tctx, r->WorkstationLen, 12, "WorkstationLen");
+ torture_assert_int_equal(tctx, r->WorkstationMaxLen, 12, "WorkstationMaxLen");
+ torture_assert_str_equal(tctx, r->Workstation, "W2K8R2", "Workstation");
+
+ torture_assert_int_equal(tctx, r->EncryptedRandomSessionKeyLen, 16, "EncryptedRandomSessionKeyLen");
+ torture_assert_int_equal(tctx, r->EncryptedRandomSessionKeyMaxLen, 16, "EncryptedRandomSessionKeyMaxLen");
+ torture_assert_mem_equal(tctx, r->EncryptedRandomSessionKey->data, EncryptedRandomSessionKey, 16, "EncryptedRandomSessionKeyMaxLen");
+
+ torture_assert_int_equal(tctx, r->NegotiateFlags, 0xe2888215, "NegotiateFlags");
+
+ torture_assert_int_equal(tctx, r->Version.version.ProductMajorVersion, NTLMSSP_WINDOWS_MAJOR_VERSION_6, "ProductMajorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductMinorVersion, NTLMSSP_WINDOWS_MINOR_VERSION_1, "ProductMinorVersion");
+ torture_assert_int_equal(tctx, r->Version.version.ProductBuild, 0x1db0, "ProductBuild");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[0], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[1], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.Reserved[2], 0x00, "Reserved");
+ torture_assert_int_equal(tctx, r->Version.version.NTLMRevisionCurrent, NTLMSSP_REVISION_W2K3, "NTLMRevisionCurrent");
+
+ return true;
+}
+
+struct torture_suite *ndr_ntlmssp_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ntlmssp");
+
+ torture_suite_add_ndr_pull_test(suite, NEGOTIATE_MESSAGE, ntlmssp_NEGOTIATE_MESSAGE_data, ntlmssp_NEGOTIATE_MESSAGE_check);
+ torture_suite_add_ndr_pull_test(suite, CHALLENGE_MESSAGE, ntlmssp_CHALLENGE_MESSAGE_data, ntlmssp_CHALLENGE_MESSAGE_check);
+ torture_suite_add_ndr_pull_test(suite, AUTHENTICATE_MESSAGE, ntlmssp_AUTHENTICATE_MESSAGE_data, ntlmssp_AUTHENTICATE_MESSAGE_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ NEGOTIATE_MESSAGE,
+ ntlmssp_NEGOTIATE_MESSAGE_data,
+ ntlmssp_NEGOTIATE_MESSAGE_check);
+
+ torture_suite_add_ndr_pull_validate_test(suite,
+ CHALLENGE_MESSAGE,
+ ntlmssp_CHALLENGE_MESSAGE_data,
+ ntlmssp_CHALLENGE_MESSAGE_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/ntprinting.c b/source4/torture/ndr/ntprinting.c
new file mode 100644
index 0000000..d5e7e90
--- /dev/null
+++ b/source4/torture/ndr/ntprinting.c
@@ -0,0 +1,655 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for ntprinting ndr operations
+
+ Copyright (C) Guenther Deschner 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_ntprinting.h"
+#include "torture/ndr/proto.h"
+#include "param/param.h"
+
+static const uint8_t ntprinting_printer_data[] = {
+ 0x48, 0x10, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x0e, 0x03, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x13, 0xb8, 0x4e, 0x00, 0x4b, 0x79, 0x6f,
+ 0x63, 0x65, 0x72, 0x61, 0x2d, 0x35, 0x30, 0x30, 0x00, 0x6b, 0x79, 0x6f,
+ 0x63, 0x65, 0x72, 0x61, 0x2d, 0x35, 0x30, 0x30, 0x00, 0x53, 0x61, 0x6d,
+ 0x62, 0x61, 0x20, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x50,
+ 0x6f, 0x72, 0x74, 0x00, 0x6b, 0x79, 0x6f, 0x63, 0x65, 0x72, 0x61, 0x2d,
+ 0x35, 0x30, 0x30, 0x00, 0x4b, 0x79, 0x6f, 0x63, 0x65, 0x72, 0x61, 0x20,
+ 0x54, 0x61, 0x73, 0x6b, 0x41, 0x6c, 0x66, 0x61, 0x20, 0x35, 0x30, 0x30,
+ 0x63, 0x69, 0x00, 0x62, 0x75, 0x6c, 0x6c, 0x70, 0x65, 0x6e, 0x00, 0x00,
+ 0x77, 0x69, 0x6e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x52, 0x41, 0x57,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x5c, 0x69, 0x72, 0x6f, 0x62,
+ 0x6f, 0x74, 0x5c, 0x4b, 0x79, 0x6f, 0x63, 0x65, 0x72, 0x61, 0x2d, 0x35,
+ 0x30, 0x30, 0x00, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x00, 0x01, 0x04,
+ 0x00, 0x06, 0xdc, 0x00, 0x60, 0x08, 0x01, 0x00, 0x01, 0x00, 0xea, 0x0a,
+ 0x6f, 0x08, 0x64, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x58, 0x02, 0x02, 0x00,
+ 0x01, 0x00, 0x58, 0x02, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x53, 0xff,
+ 0x81, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x08,
+ 0x00, 0x00, 0x50, 0x52, 0x49, 0x56, 0xe2, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x27, 0x10, 0x27, 0x10, 0x27, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x54, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x10, 0x00, 0x5c, 0x4b,
+ 0x03, 0x00, 0x68, 0x43, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x75,
+ 0xbf, 0xbb, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x53, 0x4d,
+ 0x54, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x03, 0x6b, 0x00,
+ 0x79, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x2d, 0x00, 0x35, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4a, 0x43,
+ 0x4c, 0x54, 0x72, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x00, 0x4d, 0x65,
+ 0x64, 0x69, 0x75, 0x6d, 0x00, 0x4a, 0x43, 0x4c, 0x48, 0x61, 0x6c, 0x66,
+ 0x74, 0x6f, 0x6e, 0x65, 0x00, 0x47, 0x72, 0x61, 0x64, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x00, 0x4a, 0x43, 0x4c, 0x52, 0x65, 0x64, 0x4c, 0x65, 0x76,
+ 0x65, 0x6c, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x47,
+ 0x72, 0x65, 0x65, 0x6e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x00, 0x4e, 0x6f,
+ 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x42, 0x6c, 0x75, 0x65, 0x4c, 0x65,
+ 0x76, 0x65, 0x6c, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c,
+ 0x48, 0x75, 0x65, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00, 0x4e, 0x6f,
+ 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x48, 0x75, 0x65, 0x52, 0x65, 0x64,
+ 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x48, 0x75, 0x65,
+ 0x59, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00,
+ 0x4a, 0x43, 0x4c, 0x48, 0x75, 0x65, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x00,
+ 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x48, 0x75, 0x65, 0x43,
+ 0x79, 0x61, 0x6e, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c,
+ 0x48, 0x75, 0x65, 0x42, 0x6c, 0x75, 0x65, 0x00, 0x4e, 0x6f, 0x6e, 0x65,
+ 0x00, 0x4a, 0x43, 0x4c, 0x48, 0x75, 0x65, 0x4d, 0x61, 0x67, 0x65, 0x6e,
+ 0x74, 0x61, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x4c,
+ 0x69, 0x67, 0x68, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x47, 0x61, 0x6d, 0x6d,
+ 0x61, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c, 0x4c, 0x69,
+ 0x67, 0x68, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72,
+ 0x61, 0x73, 0x74, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4a, 0x43, 0x4c,
+ 0x53, 0x61, 0x74, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x4e,
+ 0x6f, 0x6e, 0x65, 0x00, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69,
+ 0x6f, 0x6e, 0x00, 0x36, 0x30, 0x30, 0x64, 0x70, 0x69, 0x00, 0x4b, 0x43,
+ 0x45, 0x63, 0x6f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x4f, 0x66, 0x66,
+ 0x00, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x00,
+ 0x43, 0x4d, 0x59, 0x4b, 0x00, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x72, 0x65,
+ 0x70, 0x72, 0x6f, 0x64, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72,
+ 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x43, 0x49, 0x45,
+ 0x00, 0x50, 0x72, 0x6e, 0x44, 0x65, 0x66, 0x00, 0x50, 0x61, 0x67, 0x65,
+ 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x00, 0x4f, 0x6e, 0x00, 0x50, 0x61,
+ 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x00, 0x4c, 0x65, 0x74, 0x74, 0x65,
+ 0x72, 0x00, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e,
+ 0x00, 0x00, 0x4c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x64, 0x67,
+ 0x65, 0x00, 0x00, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x6c, 0x6f, 0x74,
+ 0x00, 0x2a, 0x55, 0x73, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x54, 0x72, 0x61,
+ 0x79, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x4d, 0x65, 0x64, 0x69, 0x61,
+ 0x54, 0x79, 0x70, 0x65, 0x00, 0x41, 0x75, 0x74, 0x6f, 0x00, 0x4f, 0x75,
+ 0x74, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x00, 0x4e, 0x6f, 0x6e, 0x65,
+ 0x00, 0x4b, 0x43, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x00, 0x4e, 0x6f,
+ 0x6e, 0x65, 0x00, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x75,
+ 0x6e, 0x74, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4b, 0x43, 0x50, 0x75,
+ 0x6e, 0x63, 0x68, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4b, 0x43, 0x42,
+ 0x6f, 0x6f, 0x6b, 0x6c, 0x65, 0x74, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00,
+ 0x4b, 0x43, 0x46, 0x6f, 0x6c, 0x64, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00,
+ 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x00, 0x46, 0x61, 0x6c, 0x73, 0x65,
+ 0x00, 0x4a, 0x6f, 0x67, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x44, 0x75,
+ 0x70, 0x6c, 0x65, 0x78, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4b, 0x43,
+ 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x65, 0x00, 0x50, 0x72, 0x6e, 0x44,
+ 0x65, 0x66, 0x00, 0x4b, 0x6d, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x6d, 0x65,
+ 0x6e, 0x74, 0x00, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x4b,
+ 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x44, 0x65, 0x66,
+ 0x61, 0x75, 0x6c, 0x74, 0x00, 0x63, 0x75, 0x70, 0x73, 0x4a, 0x6f, 0x62,
+ 0x48, 0x6f, 0x6c, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x00, 0x6e, 0x6f,
+ 0x2d, 0x68, 0x6f, 0x6c, 0x64, 0x00, 0x63, 0x75, 0x70, 0x73, 0x4a, 0x6f,
+ 0x62, 0x53, 0x68, 0x65, 0x65, 0x74, 0x73, 0x53, 0x74, 0x61, 0x72, 0x74,
+ 0x00, 0x6e, 0x6f, 0x6e, 0x65, 0x00, 0x63, 0x75, 0x70, 0x73, 0x4a, 0x6f,
+ 0x62, 0x53, 0x68, 0x65, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x64, 0x00, 0x6e,
+ 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x53, 0x50, 0x55, 0x43, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x44, 0x72, 0x69,
+ 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e,
+ 0x74, 0x65, 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74,
+ 0x61, 0x5c, 0x54, 0x72, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x6d, 0x53, 0x69,
+ 0x7a, 0x65, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xce,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61,
+ 0x5c, 0x54, 0x72, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x6d, 0x54, 0x61, 0x62,
+ 0x6c, 0x65, 0x00, 0x03, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xce,
+ 0x00, 0x43, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74,
+ 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x4c,
+ 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73,
+ 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x32,
+ 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65,
+ 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x61,
+ 0x00, 0x73, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65,
+ 0x00, 0x20, 0x00, 0x33, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74,
+ 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x43, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74,
+ 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x34, 0x00, 0x00, 0x00, 0x4c,
+ 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x79, 0x00, 0x70, 0x00, 0x61,
+ 0x00, 0x73, 0x00, 0x73, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61,
+ 0x00, 0x79, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74,
+ 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72,
+ 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x5c, 0x54,
+ 0x72, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x6d, 0x4d, 0x61, 0x70, 0x53, 0x69,
+ 0x7a, 0x65, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x39,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61,
+ 0x5c, 0x54, 0x72, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x6d, 0x4d, 0x61, 0x70,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x50, 0x46, 0x37,
+ 0x30, 0x30, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x46, 0x37, 0x30,
+ 0x30, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x46, 0x37, 0x30, 0x30,
+ 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x46, 0x37, 0x30, 0x30, 0x44,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x46, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x72,
+ 0x69, 0x6e, 0x74, 0x65, 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44,
+ 0x61, 0x74, 0x61, 0x5c, 0x54, 0x72, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x6d,
+ 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x44,
+ 0x72, 0x69, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x5c, 0x54, 0x72,
+ 0x61, 0x79, 0x46, 0x6f, 0x72, 0x6d, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72,
+ 0x64, 0x00, 0x03, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x50, 0x46,
+ 0x37, 0x30, 0x30, 0x41, 0x00, 0x00, 0x50, 0x46, 0x37, 0x30, 0x30, 0x42,
+ 0x00, 0x00, 0x50, 0x46, 0x37, 0x30, 0x30, 0x43, 0x00, 0x00, 0x50, 0x46,
+ 0x37, 0x30, 0x30, 0x44, 0x00, 0x00, 0x4d, 0x46, 0x31, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f, 0x6f, 0x6c, 0x65,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f, 0x6f, 0x6c, 0x65, 0x72, 0x5c,
+ 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x52, 0x00, 0x4f,
+ 0x00, 0x42, 0x00, 0x4f, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f, 0x6f, 0x6c, 0x65, 0x72, 0x5c, 0x73,
+ 0x68, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61,
+ 0x6d, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x49,
+ 0x00, 0x52, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x4f, 0x00, 0x54, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f, 0x6f, 0x6c,
+ 0x65, 0x72, 0x5c, 0x75, 0x4e, 0x43, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x49,
+ 0x00, 0x52, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x4f, 0x00, 0x54, 0x00, 0x5c,
+ 0x00, 0x6b, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72,
+ 0x00, 0x61, 0x00, 0x2d, 0x00, 0x35, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t ntprinting_printer_data_latin1[] = {
+ 0x48, 0x1a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x94, 0x46, 0x50, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x94, 0xee, 0xb9, 0x50, 0x00, 0x53, 0x30, 0x42,
+ 0x43, 0x00, 0x53, 0x30, 0x42, 0x43, 0x00, 0x53,
+ 0x61, 0x6d, 0x62, 0x61, 0x20, 0x50, 0x72, 0x69,
+ 0x6e, 0x74, 0x65, 0x72, 0x20, 0x50, 0x6f, 0x72,
+ 0x74, 0x00, 0x48, 0x50, 0x20, 0x44, 0x65, 0x73,
+ 0x69, 0x67, 0x6e, 0x6a, 0x65, 0x74, 0x20, 0x38,
+ 0x30, 0x30, 0x50, 0x53, 0x20, 0x34, 0x32, 0x20,
+ 0x62, 0x79, 0x20, 0x48, 0x50, 0x00, 0x22, 0x20,
+ 0x53, 0x41, 0x4c, 0x41, 0x20, 0x44, 0x41, 0x20,
+ 0x52, 0x45, 0x43, 0x45, 0x50, 0xc7, 0xc3, 0x4f,
+ 0x20, 0x44, 0x41, 0x20, 0x43, 0x4f, 0x4e, 0x53,
+ 0x54, 0x52, 0x55, 0xc7, 0xc3, 0x4f, 0x20, 0x2d,
+ 0x20, 0x52, 0x41, 0x4e, 0x44, 0x30, 0x20, 0x4c,
+ 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x00, 0x55,
+ 0x54, 0x47, 0x43, 0x41, 0x20, 0x00, 0x00, 0x77,
+ 0x69, 0x6e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00,
+ 0x52, 0x41, 0x57, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x5c, 0x5c, 0x4c, 0x4f, 0x43, 0x41, 0x4c,
+ 0x48, 0x4f, 0x53, 0x54, 0x5c, 0x53, 0x30, 0x42,
+ 0x43, 0x00, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72,
+ 0x00, 0x01, 0x04, 0x00, 0x04, 0xdc, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x64, 0x00, 0x01, 0x00, 0x0f, 0x00, 0xfc,
+ 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x47, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x72, 0x69,
+ 0x6e, 0x74, 0x65, 0x72, 0x44, 0x72, 0x69, 0x76,
+ 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72,
+ 0x44, 0x61, 0x74, 0x61, 0x5c, 0x44, 0x72, 0x76,
+ 0x50, 0x61, 0x70, 0x65, 0x72, 0x53, 0x74, 0x61,
+ 0x6e, 0x64, 0x61, 0x72, 0x64, 0x73, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x61,
+ 0xc2, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x50,
+ 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x44, 0x72,
+ 0x69, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61,
+ 0x5c, 0x44, 0x72, 0x76, 0x44, 0x65, 0x76, 0x4d,
+ 0x6f, 0x64, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x42, 0x02, 0x00, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x36, 0x00,
+ 0x36, 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x33, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00, 0x31, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x31, 0x00, 0x30, 0x00, 0x37, 0x00, 0x33, 0x00,
+ 0x37, 0x00, 0x34, 0x00, 0x31, 0x00, 0x39, 0x00,
+ 0x30, 0x00, 0x35, 0x00, 0x3b, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00, 0x35, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x35, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x36, 0x00,
+ 0x32, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x36, 0x00,
+ 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x32, 0x00,
+ 0x31, 0x00, 0x36, 0x00, 0x3b, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x36, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x3b, 0x00, 0x32, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x35, 0x00,
+ 0x35, 0x00, 0x33, 0x00, 0x35, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x36, 0x00, 0x33, 0x00, 0x31, 0x00,
+ 0x37, 0x00, 0x32, 0x00, 0x3b, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x31, 0x00,
+ 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x37, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x30, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x3b, 0x00,
+ 0x30, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x3b, 0x00,
+ 0x31, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x39, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, 0x00,
+ 0x3b, 0x00, 0x32, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x39, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, 0x00,
+ 0x3b, 0x00, 0x32, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x39, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, 0x00,
+ 0x3b, 0x00, 0x32, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x39, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, 0x00,
+ 0x3b, 0x00, 0x32, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x31, 0x00,
+ 0x35, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x39, 0x00, 0x34, 0x00, 0x3b, 0x00,
+ 0x32, 0x00, 0x31, 0x00, 0x35, 0x00, 0x39, 0x00,
+ 0x3b, 0x00, 0x32, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x34, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00,
+ 0x3b, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x3b, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x30, 0x00,
+ 0x3b, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44,
+ 0x61, 0x74, 0x61, 0x5c, 0x44, 0x72, 0x76, 0x45,
+ 0x57, 0x53, 0x49, 0x50, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f,
+ 0x6f, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f, 0x6f, 0x6c,
+ 0x65, 0x72, 0x5c, 0x70, 0x72, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x53,
+ 0x00, 0x30, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x73, 0x53,
+ 0x70, 0x6f, 0x6f, 0x6c, 0x65, 0x72, 0x5c, 0x73,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d,
+ 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00,
+ 0x00, 0x00, 0x53, 0x00, 0x36, 0x00, 0x30, 0x00,
+ 0x32, 0x00, 0x30, 0x00, 0x50, 0x00, 0x53, 0x00,
+ 0x36, 0x00, 0x36, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x44, 0x73, 0x53, 0x70, 0x6f, 0x6f,
+ 0x6c, 0x65, 0x72, 0x5c, 0x73, 0x68, 0x6f, 0x72,
+ 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e,
+ 0x61, 0x6d, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x53, 0x00, 0x36, 0x00,
+ 0x30, 0x00, 0x32, 0x00, 0x30, 0x00, 0x50, 0x00,
+ 0x53, 0x00, 0x36, 0x00, 0x36, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x44, 0x73, 0x53, 0x70,
+ 0x6f, 0x6f, 0x6c, 0x65, 0x72, 0x5c, 0x75, 0x4e,
+ 0x43, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x5c, 0x00,
+ 0x5c, 0x00, 0x53, 0x00, 0x36, 0x00, 0x30, 0x00,
+ 0x32, 0x00, 0x30, 0x00, 0x50, 0x00, 0x53, 0x00,
+ 0x36, 0x00, 0x36, 0x00, 0x5c, 0x00, 0x53, 0x00,
+ 0x30, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool ntprinting_printer_check(struct torture_context *tctx,
+ struct ntprinting_printer *r)
+{
+ torture_assert_int_equal(tctx, r->info.attributes, 0x00081048, "attributes");
+ torture_assert_int_equal(tctx, r->info.priority, 1, "priority");
+ torture_assert_int_equal(tctx, r->info.default_priority, 1, "default_priority");
+ torture_assert_int_equal(tctx, r->info.starttime, 0, "startime");
+ torture_assert_int_equal(tctx, r->info.untiltime, 0, "untiltime");
+ torture_assert_int_equal(tctx, r->info.status, 0, "status");
+ torture_assert_int_equal(tctx, r->info.cjobs, 5, "cjobs");
+ torture_assert_int_equal(tctx, r->info.averageppm, 0, "averageppm");
+ torture_assert_int_equal(tctx, r->info.changeid, 0x09030e9d, "changeid");
+ torture_assert_int_equal(tctx, r->info.c_setprinter, 0, "c_setprinter");
+ torture_assert_int_equal(tctx, r->info.setuptime, 0x4eb81324, "setuptime");
+ torture_assert_str_equal(tctx, r->info.servername, "", "servername");
+ torture_assert_str_equal(tctx, r->info.printername, "Kyocera-500", "printername");
+ torture_assert_str_equal(tctx, r->info.sharename, "kyocera-500", "sharename");
+ torture_assert_str_equal(tctx, r->info.portname, "Samba Printer Port", "portname");
+ torture_assert_str_equal(tctx, r->info.drivername, "kyocera-500", "drivername");
+ torture_assert_str_equal(tctx, r->info.comment, "Kyocera TaskAlfa 500ci", "comment");
+ torture_assert_str_equal(tctx, r->info.location, "bullpen", "comment");
+ torture_assert_str_equal(tctx, r->info.sepfile, "", "sepfile");
+ torture_assert_str_equal(tctx, r->info.printprocessor, "winprint", "printprocessor");
+ torture_assert_str_equal(tctx, r->info.datatype, "RAW", "datatype");
+ torture_assert_str_equal(tctx, r->info.parameters, "", "parameters");
+
+ torture_assert(tctx, r->devmode, "devmode");
+ torture_assert_str_equal(tctx, r->devmode->devicename, "\\\\irobot\\Kyocera-500", "devicename");
+ torture_assert_str_equal(tctx, r->devmode->formname, "Letter", "formname");
+ torture_assert_int_equal(tctx, r->devmode->specversion, 0x0401, "specversion");
+ torture_assert_int_equal(tctx, r->devmode->driverversion, 0x0600, "driverversion");
+ torture_assert_int_equal(tctx, r->devmode->size, 0x00dc, "size");
+ torture_assert_int_equal(tctx, r->devmode->driverextra, 0x0860, "driverextra");
+ torture_assert_int_equal(tctx, r->devmode->orientation, 1, "orientation");
+ torture_assert_int_equal(tctx, r->devmode->papersize, 1, "papersize");
+ torture_assert_int_equal(tctx, r->devmode->paperlength, 0x0aea, "paperlength");
+ torture_assert_int_equal(tctx, r->devmode->paperwidth, 0x086f, "paperwidth");
+ torture_assert_int_equal(tctx, r->devmode->scale, 0x0064, "scale");
+ torture_assert_int_equal(tctx, r->devmode->copies, 1, "copies");
+ torture_assert_int_equal(tctx, r->devmode->defaultsource, 0x000f, "defaultsource");
+ torture_assert_int_equal(tctx, r->devmode->printquality, 0x0258, "printquality");
+ torture_assert_int_equal(tctx, r->devmode->color, 2, "color");
+ torture_assert_int_equal(tctx, r->devmode->duplex, 1, "duplex");
+ torture_assert_int_equal(tctx, r->devmode->yresolution, 0x0258, "yresolution");
+ torture_assert_int_equal(tctx, r->devmode->ttoption, 2, "ttoption");
+ torture_assert_int_equal(tctx, r->devmode->collate, 1, "collate");
+ torture_assert_int_equal(tctx, r->devmode->logpixels, 0, "logpixels");
+ torture_assert_int_equal(tctx, r->devmode->fields, 0x0381ff53, "fields");
+ torture_assert_int_equal(tctx, r->devmode->bitsperpel, 0, "bitsperpel");
+ torture_assert_int_equal(tctx, r->devmode->pelswidth, 0, "pelswidth");
+ torture_assert_int_equal(tctx, r->devmode->pelsheight, 0, "pelsheight");
+ torture_assert_int_equal(tctx, r->devmode->displayflags, 1, "displayflags");
+ torture_assert_int_equal(tctx, r->devmode->displayfrequency, 0, "displayfrequency");
+ torture_assert_int_equal(tctx, r->devmode->icmmethod, 1, "icmmethod");
+ torture_assert_int_equal(tctx, r->devmode->icmintent, 2, "icmintent");
+ torture_assert_int_equal(tctx, r->devmode->mediatype, 0x00000101, "mediatype");
+ torture_assert_int_equal(tctx, r->devmode->dithertype, 0, "dithertype");
+ torture_assert_int_equal(tctx, r->devmode->reserved1, 0, "reserved1");
+ torture_assert_int_equal(tctx, r->devmode->reserved2, 0, "reserved2");
+ torture_assert_int_equal(tctx, r->devmode->panningwidth, 0, "panningwidth");
+ torture_assert_int_equal(tctx, r->devmode->panningheight, 0, "panningheight");
+
+ torture_assert(tctx, r->devmode->nt_dev_private, "nt_dev_private");
+ torture_assert_int_equal(tctx, r->devmode->nt_dev_private->length, 2144, "nt_dev_private->length");
+
+ torture_assert_int_equal(tctx, r->count, 11, "count");
+
+ torture_assert_int_equal(tctx, r->printer_data[0].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[0].name, "PrinterDriverData", "name");
+ torture_assert_int_equal(tctx, r->printer_data[0].type, 0, "type");
+ torture_assert_int_equal(tctx, r->printer_data[0].data.length, 0, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[1].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[1].name, "PrinterDriverData\\TrayFormSize", "name");
+ torture_assert_int_equal(tctx, r->printer_data[1].type, 4, "type");
+ torture_assert_int_equal(tctx, r->printer_data[1].data.length, 4, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[2].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[2].name, "PrinterDriverData\\TrayFormTable", "name");
+ torture_assert_int_equal(tctx, r->printer_data[2].type, 3, "type");
+ torture_assert_int_equal(tctx, r->printer_data[2].data.length, 206, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[3].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[3].name, "PrinterDriverData\\TrayFormMapSize", "name");
+ torture_assert_int_equal(tctx, r->printer_data[3].type, 4, "type");
+ torture_assert_int_equal(tctx, r->printer_data[3].data.length, 4, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[4].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[4].name, "PrinterDriverData\\TrayFormMap", "name");
+ torture_assert_int_equal(tctx, r->printer_data[4].type, 3, "type");
+ torture_assert_int_equal(tctx, r->printer_data[4].data.length, 57, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[5].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[5].name, "PrinterDriverData\\TrayFormKeywordSize", "name");
+ torture_assert_int_equal(tctx, r->printer_data[5].type, 4, "type");
+ torture_assert_int_equal(tctx, r->printer_data[5].data.length, 4, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[6].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[6].name, "PrinterDriverData\\TrayFormKeyword", "name");
+ torture_assert_int_equal(tctx, r->printer_data[6].type, 3, "type");
+ torture_assert_int_equal(tctx, r->printer_data[6].data.length, 38, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[7].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[7].name, "DsSpooler", "name");
+ torture_assert_int_equal(tctx, r->printer_data[7].type, 0, "type");
+ torture_assert_int_equal(tctx, r->printer_data[7].data.length, 0, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[8].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[8].name, "DsSpooler\\serverName", "name");
+ torture_assert_int_equal(tctx, r->printer_data[8].type, 1, "type");
+ torture_assert_int_equal(tctx, r->printer_data[8].data.length, 14, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[9].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[9].name, "DsSpooler\\shortServerName", "name");
+ torture_assert_int_equal(tctx, r->printer_data[9].type, 1, "type");
+ torture_assert_int_equal(tctx, r->printer_data[9].data.length, 14, "data.length");
+
+ torture_assert_int_equal(tctx, r->printer_data[10].ptr, 1, "ptr");
+ torture_assert_str_equal(tctx, r->printer_data[10].name, "DsSpooler\\uNCName", "name");
+ torture_assert_int_equal(tctx, r->printer_data[10].type, 1, "type");
+ torture_assert_int_equal(tctx, r->printer_data[10].data.length, 42, "data.length");
+
+ return true;
+}
+
+static bool ntprinting_printer_latin1_check(struct torture_context *tctx)
+{
+ enum ndr_err_code ndr_err;
+ struct ntprinting_printer r;
+ DATA_BLOB blob;
+ bool ok;
+
+ ok = lpcfg_do_global_parameter(tctx->lp_ctx, "dos charset", "CP1252");
+ if (!ok) {
+ torture_comment(tctx, "Could not set 'dos charset' option.\n");
+ return false;
+ }
+ reload_charcnv(tctx->lp_ctx);
+
+ ZERO_STRUCT(r);
+ r.info.string_flags = LIBNDR_FLAG_STR_ASCII;
+
+ blob = data_blob_const(ntprinting_printer_data_latin1,
+ sizeof(ntprinting_printer_data_latin1));
+
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, &r,
+ (ndr_pull_flags_fn_t)ndr_pull_ntprinting_printer);
+
+ torture_assert_ndr_success(tctx,
+ ndr_err,
+ "ndr_pull_ntprinting_printer");
+#if 0
+ NDR_PRINT_DEBUG(1, ntprinting_printer, &r);
+#endif
+ torture_assert_str_equal(tctx,
+ r.info.printername,
+ "S0BC",
+ "printername");
+ /* latin1 encoding check */
+ torture_assert_str_equal(tctx,
+ r.info.comment,
+ "\" SALA DA RECEPÇÃO DA CONSTRUÇÃO - RAND0 LOCATIO",
+ "comment");
+ torture_assert_str_equal(tctx,
+ r.info.location,
+ "UTGCA ",
+ "location");
+
+ return true;
+}
+
+struct torture_suite *ndr_ntprinting_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ntprinting");
+
+ torture_suite_add_simple_test(suite,
+ "ntprinting latin1 check",
+ ntprinting_printer_latin1_check);
+
+ torture_suite_add_ndr_pull_test(suite,
+ ntprinting_printer,
+ ntprinting_printer_data,
+ ntprinting_printer_check);
+
+ /* pullpush not working atm.
+ torture_suite_add_ndr_pull_validate_test(suite,
+ ntprinting_printer,
+ data_blob_const(ntprinting_printer_data, sizeof(ntprinting_printer_data)),
+ ntprinting_printer_check);
+ */
+ return suite;
+}
diff --git a/source4/torture/ndr/odj.c b/source4/torture/ndr/odj.c
new file mode 100644
index 0000000..78d4725
--- /dev/null
+++ b/source4/torture/ndr/odj.c
@@ -0,0 +1,210 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for Windows Offline Join files
+
+ Copyright (C) Guenther Deschner 2021
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_ODJ.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t ODJ_PROVISION_DATA_data[] = {
+ 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xb0, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x18, 0x03, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x08, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9c, 0x4f, 0x93,
+ 0x20, 0xfc, 0x4f, 0x93, 0x90, 0xbf, 0x50, 0x93, 0x60, 0xbf, 0x50, 0x93,
+ 0x10, 0x00, 0x12, 0x00, 0x40, 0x7f, 0x4f, 0x93, 0x2e, 0x00, 0x30, 0x00,
+ 0x60, 0xf3, 0x4f, 0x93, 0x2e, 0x00, 0x30, 0x00, 0x50, 0xf4, 0x4f, 0x93,
+ 0x96, 0x1a, 0x76, 0xc0, 0x42, 0xe2, 0xc2, 0x4e, 0x91, 0x60, 0x7a, 0x66,
+ 0xa4, 0xac, 0x49, 0x29, 0x00, 0x85, 0x4f, 0x93, 0x30, 0xa1, 0x4f, 0x93,
+ 0x80, 0xf1, 0x4f, 0x93, 0x01, 0x00, 0x00, 0x00, 0x96, 0x1a, 0x76, 0xc0,
+ 0x42, 0xe2, 0xc2, 0x4e, 0x91, 0x60, 0x7a, 0x66, 0xa4, 0xac, 0x49, 0x29,
+ 0x10, 0xfd, 0x4f, 0x93, 0x40, 0xf5, 0x4f, 0x93, 0xfd, 0xf3, 0x03, 0xe0,
+ 0xf0, 0xf9, 0x4f, 0x93, 0xb0, 0xfd, 0x4f, 0x93, 0x04, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x75, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x77, 0x00, 0x75, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0xe8, 0xf2, 0x4b, 0x12, 0x6a, 0xe6, 0x55, 0x41,
+ 0x43, 0xa4, 0xb4, 0x74, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x64, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x63, 0x00, 0x2e, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00,
+ 0x39, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00,
+ 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00,
+ 0x35, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x38, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00,
+ 0x39, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00,
+ 0x39, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00,
+ 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x46, 0x00, 0x69, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x69, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x4e, 0x00, 0x61, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00,
+ 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x46, 0x00, 0x69, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x69, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x4e, 0x00, 0x61, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x04, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x76, 0x1c, 0x63,
+ 0x89, 0x52, 0x21, 0x43, 0xbc, 0x9e, 0x80, 0xf8, 0x43, 0xf8, 0x68, 0xc3,
+ 0x01, 0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xcf, 0x0c, 0xfc,
+ 0xfa, 0x7f, 0x4a, 0x47, 0x86, 0x11, 0x69, 0xff, 0xe2, 0x69, 0x64, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00,
+ 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x08, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x9c, 0x4f, 0x93, 0x20, 0xfc, 0x4f, 0x93,
+ 0x90, 0xbf, 0x50, 0x93, 0x60, 0xbf, 0x50, 0x93, 0x10, 0x00, 0x12, 0x00,
+ 0x40, 0x7f, 0x4f, 0x93, 0x2e, 0x00, 0x30, 0x00, 0x60, 0xf3, 0x4f, 0x93,
+ 0x2e, 0x00, 0x30, 0x00, 0x50, 0xf4, 0x4f, 0x93, 0x96, 0x1a, 0x76, 0xc0,
+ 0x42, 0xe2, 0xc2, 0x4e, 0x91, 0x60, 0x7a, 0x66, 0xa4, 0xac, 0x49, 0x29,
+ 0x00, 0x85, 0x4f, 0x93, 0x30, 0xa1, 0x4f, 0x93, 0x80, 0xf1, 0x4f, 0x93,
+ 0x01, 0x00, 0x00, 0x00, 0x96, 0x1a, 0x76, 0xc0, 0x42, 0xe2, 0xc2, 0x4e,
+ 0x91, 0x60, 0x7a, 0x66, 0xa4, 0xac, 0x49, 0x29, 0x10, 0xfd, 0x4f, 0x93,
+ 0x40, 0xf5, 0x4f, 0x93, 0xfd, 0xf3, 0x03, 0xe0, 0xf0, 0xf9, 0x4f, 0x93,
+ 0xb0, 0xfd, 0x4f, 0x93, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x77, 0x00, 0x75, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x75, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x31, 0x00,
+ 0x39, 0x00, 0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
+ 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
+ 0xe8, 0xf2, 0x4b, 0x12, 0x6a, 0xe6, 0x55, 0x41, 0x43, 0xa4, 0xb4, 0x74,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x64, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00, 0x63, 0x00, 0x2e, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00,
+ 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x36, 0x00,
+ 0x2e, 0x00, 0x31, 0x00, 0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x31, 0x00, 0x39, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x2e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x68, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00, 0x75, 0x00, 0x6c, 0x00,
+ 0x74, 0x00, 0x2d, 0x00, 0x46, 0x00, 0x69, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x2d, 0x00, 0x4e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x44, 0x00, 0x65, 0x00, 0x66, 0x00, 0x61, 0x00, 0x75, 0x00, 0x6c, 0x00,
+ 0x74, 0x00, 0x2d, 0x00, 0x46, 0x00, 0x69, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x74, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x2d, 0x00, 0x4e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x88, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x45, 0x06, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x2d, 0x00,
+ 0x31, 0x00, 0x2d, 0x00, 0x35, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x31, 0x00,
+ 0x2d, 0x00, 0x33, 0x00, 0x30, 0x00, 0x36, 0x00, 0x39, 0x00, 0x36, 0x00,
+ 0x37, 0x00, 0x32, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x31, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x36, 0x00, 0x31, 0x00, 0x34, 0x00, 0x38, 0x00,
+ 0x35, 0x00, 0x38, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x39, 0x00,
+ 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x39, 0x00, 0x35, 0x00, 0x35, 0x00,
+ 0x38, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x36, 0x00, 0x30, 0x00,
+ 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool ODJ_PROVISION_DATA_check(struct torture_context *tctx,
+ struct ODJ_PROVISION_DATA_serialized_ptr *r)
+{
+ return true;
+}
+
+struct torture_suite *ndr_ODJ_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ODJ");
+
+ torture_suite_add_ndr_pull_test(suite,
+ ODJ_PROVISION_DATA_serialized_ptr,
+ ODJ_PROVISION_DATA_data,
+ ODJ_PROVISION_DATA_check);
+ return suite;
+}
diff --git a/source4/torture/ndr/samr.c b/source4/torture/ndr/samr.c
new file mode 100644
index 0000000..9f2f8ee
--- /dev/null
+++ b/source4/torture/ndr/samr.c
@@ -0,0 +1,355 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for samr ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t samr_connect5_in_data[] = {
+ 0xa8, 0x71, 0x0e, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x61, 0x00, 0x6d, 0x00,
+ 0x79, 0x00, 0x2e, 0x00, 0x73, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x62, 0x00,
+ 0x61, 0x00, 0x34, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x72, 0x00, 0x74, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x2e, 0x00,
+ 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_connect5_out_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0xe9, 0xb9, 0x40,
+ 0x50, 0x94, 0xa5, 0x4d, 0xb1, 0x9b, 0x3a, 0x32, 0xd0, 0xd4, 0x45, 0x0b,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_opendomain_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xc9, 0xe9, 0xb9, 0x40, 0x50, 0x94, 0xa5, 0x4d,
+ 0xb1, 0x9b, 0x3a, 0x32, 0xd0, 0xd4, 0x45, 0x0b, 0x00, 0x02, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0xfa, 0x50, 0x5e, 0x04, 0x12, 0x95, 0x23, 0x02,
+ 0xe5, 0xa3, 0xd0, 0x03
+};
+
+static const uint8_t samr_opendomain_out_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x16, 0x2b, 0x52, 0x19, 0x4a, 0x47,
+ 0x9e, 0x88, 0x8b, 0xe8, 0x93, 0xe6, 0xbf, 0x36, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_lookupnamesindomain_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x16, 0x2b, 0x52, 0x19, 0x4a, 0x47,
+ 0x9e, 0x88, 0x8b, 0xe8, 0x93, 0xe6, 0xbf, 0x36, 0x01, 0x00, 0x00, 0x00,
+ 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x14, 0x00, 0x60, 0x6f, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x58, 0x00, 0x50, 0x00,
+ 0x50, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x50, 0x00, 0x32, 0x00,
+ 0x24, 0x00
+};
+
+static const uint8_t samr_lookupnamesindomain_out_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xeb, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_openuser_in_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x16, 0x2b, 0x52, 0x19, 0x4a, 0x47,
+ 0x9e, 0x88, 0x8b, 0xe8, 0x93, 0xe6, 0xbf, 0x36, 0xb0, 0x00, 0x00, 0x00,
+ 0xeb, 0x03, 0x00, 0x00
+};
+
+static const uint8_t samr_openuser_out_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0xd8, 0x6e, 0xec, 0x8c, 0xe1, 0x1f, 0x2d, 0x41,
+ 0x99, 0x53, 0x13, 0xe9, 0xa4, 0x51, 0xe8, 0x1d, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_queryuserinfo_in_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0xd8, 0x6e, 0xec, 0x8c, 0xe1, 0x1f, 0x2d, 0x41,
+ 0x99, 0x53, 0x13, 0xe9, 0xa4, 0x51, 0xe8, 0x1d, 0x10, 0x00
+};
+
+static const uint8_t samr_queryuserinfo_out_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_setuserinfo_in_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0xd8, 0x6e, 0xec, 0x8c, 0xe1, 0x1f, 0x2d, 0x41,
+ 0x99, 0x53, 0x13, 0xe9, 0xa4, 0x51, 0xe8, 0x1d, 0x10, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_setuserinfo_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_setuserinfo2_in_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0xd8, 0x6e, 0xec, 0x8c, 0xe1, 0x1f, 0x2d, 0x41,
+ 0x99, 0x53, 0x13, 0xe9, 0xa4, 0x51, 0xe8, 0x1d, 0x1a, 0x00, 0x1a, 0x00,
+ 0xe9, 0x83, 0x46, 0xc5, 0x1b, 0xc6, 0xd9, 0x97, 0xaf, 0x87, 0xf4, 0xb4,
+ 0xd4, 0x58, 0x0f, 0xfe, 0x00, 0x86, 0x28, 0x09, 0xc6, 0x76, 0x77, 0x85,
+ 0xd7, 0xa1, 0xf6, 0xb1, 0xe4, 0xed, 0xe1, 0xca, 0x6a, 0xf8, 0x44, 0x2a,
+ 0x11, 0x10, 0x16, 0x70, 0x9c, 0x55, 0x03, 0x0f, 0xfe, 0xdb, 0x41, 0xb7,
+ 0xed, 0x10, 0xc9, 0x3c, 0x8b, 0x28, 0xe6, 0x94, 0x6e, 0x69, 0xc2, 0x9d,
+ 0x81, 0x22, 0xe1, 0xc8, 0xb3, 0xb8, 0xc0, 0x81, 0x50, 0x2f, 0xf3, 0xad,
+ 0x2b, 0x2e, 0xfe, 0xf6, 0x58, 0x14, 0x2d, 0x33, 0x4a, 0x74, 0x58, 0x4c,
+ 0xfe, 0x38, 0xe6, 0x21, 0xc3, 0x65, 0x29, 0xc3, 0xc7, 0x77, 0xb7, 0x1c,
+ 0xfe, 0x0b, 0x22, 0xb7, 0x2b, 0xab, 0x3e, 0x9b, 0xd1, 0x8f, 0xd9, 0x07,
+ 0x14, 0x65, 0x37, 0x35, 0x9d, 0x08, 0xdb, 0x81, 0x7d, 0x8d, 0x96, 0x96,
+ 0x9d, 0x14, 0x8d, 0xeb, 0x4f, 0x0b, 0x68, 0xee, 0xf1, 0x64, 0xf4, 0x27,
+ 0x75, 0x13, 0xaf, 0x1a, 0x41, 0xc8, 0x96, 0x98, 0xe2, 0x8c, 0x33, 0x98,
+ 0x4b, 0xa3, 0x98, 0xa9, 0xdd, 0xfe, 0x37, 0x86, 0xdd, 0x18, 0xea, 0x77,
+ 0x44, 0xfc, 0xba, 0xdb, 0xfd, 0xfb, 0x40, 0x01, 0x65, 0x05, 0x1e, 0x73,
+ 0x93, 0x25, 0xc4, 0x73, 0xf7, 0x1b, 0xd9, 0xd8, 0xbc, 0xb4, 0xc4, 0x0c,
+ 0x47, 0x3c, 0xc3, 0x62, 0xd5, 0xf3, 0x0b, 0x00, 0x74, 0x75, 0x09, 0x7e,
+ 0x58, 0x40, 0x9c, 0x0b, 0x2f, 0x15, 0x26, 0xa9, 0xdc, 0xe6, 0xd2, 0x5a,
+ 0xf2, 0xef, 0xd2, 0x4d, 0x6f, 0x2f, 0x86, 0xe9, 0x95, 0xba, 0xfe, 0xe0,
+ 0x13, 0x7a, 0xb3, 0x01, 0x93, 0x23, 0x0f, 0x43, 0xf7, 0x40, 0x1c, 0xbe,
+ 0x2e, 0x25, 0x61, 0x35, 0xda, 0x5a, 0x43, 0x82, 0x3b, 0xff, 0x05, 0x08,
+ 0x7f, 0x64, 0xf2, 0xc9, 0xeb, 0x71, 0x34, 0x9c, 0x37, 0x77, 0xe9, 0x5a,
+ 0x23, 0x89, 0xdc, 0x88, 0xa5, 0x27, 0x16, 0x05, 0xc8, 0xf1, 0xbf, 0xbb,
+ 0xb3, 0xe7, 0xa8, 0x08, 0xf5, 0xe9, 0x46, 0xc9, 0x63, 0xb4, 0x5d, 0x11,
+ 0x38, 0x69, 0x49, 0x5d, 0x92, 0x95, 0x25, 0x35, 0x56, 0x4b, 0x3e, 0xba,
+ 0x6b, 0xb3, 0x99, 0x72, 0x70, 0x1c, 0xb5, 0x7e, 0x26, 0x5c, 0xbf, 0xd0,
+ 0xbf, 0xd8, 0x58, 0xf4, 0xeb, 0xc2, 0x37, 0xad, 0x98, 0x7d, 0xa8, 0x05,
+ 0x7e, 0xf7, 0x48, 0xd9, 0x73, 0x49, 0x39, 0xaa, 0x02, 0x75, 0x67, 0x5b,
+ 0x44, 0xda, 0xda, 0x01, 0xe6, 0x5b, 0x4e, 0x0a, 0x15, 0xe7, 0x63, 0x70,
+ 0x1c, 0x16, 0x73, 0x79, 0x24, 0x3d, 0x69, 0x30, 0x85, 0xb1, 0x50, 0x65,
+ 0xa1, 0x12, 0x73, 0xf1, 0xaf, 0x8d, 0xe9, 0x23, 0x25, 0x99, 0xa2, 0x8a,
+ 0x83, 0x6a, 0x39, 0x99, 0xe6, 0x6c, 0xd0, 0xe1, 0x58, 0x9a, 0xb2, 0x3f,
+ 0x02, 0x77, 0x48, 0x3a, 0xb0, 0x9e, 0x1a, 0x33, 0x51, 0x5e, 0xe2, 0x46,
+ 0xe6, 0x3d, 0x0f, 0x01, 0x64, 0xc6, 0xd1, 0xe9, 0x42, 0xf6, 0xe0, 0x38,
+ 0x1a, 0x33, 0xc7, 0x30, 0x80, 0xa6, 0x28, 0xc5, 0x18, 0xbb, 0xe0, 0x5a,
+ 0x8b, 0xf2, 0x33, 0x53, 0x4d, 0xbf, 0xe1, 0x4c, 0x98, 0x7e, 0x79, 0x1a,
+ 0x0a, 0xdc, 0xdc, 0x04, 0x2e, 0x58, 0x57, 0xba, 0xde, 0x09, 0xa1, 0xe0,
+ 0x5b, 0xfc, 0x38, 0x90, 0x58, 0x00, 0xf1, 0xa3, 0x9e, 0x3d, 0x51, 0x7c,
+ 0x1e, 0x50, 0xfa, 0x15, 0x55, 0xb2, 0xde, 0x8b, 0x27, 0xc2, 0xbe, 0xbf,
+ 0x27, 0xa4, 0x5b, 0x56, 0x38, 0x97, 0xbf, 0x3d, 0xe1, 0x73, 0x22, 0x98,
+ 0x9e, 0x25, 0x6d, 0x5d, 0xc5, 0x05, 0xdd, 0x72, 0x7d, 0x50, 0x06, 0x32,
+ 0xd8, 0x3f, 0x16, 0x13, 0x7e, 0x5e, 0xc9, 0x45, 0xf0, 0xa7, 0xc2, 0xeb,
+ 0xda, 0x79, 0xef, 0x62, 0x3a, 0x96, 0x58, 0x4a, 0xc7, 0xf8, 0xc1, 0xba,
+ 0x0b, 0x94, 0xb8, 0xd6, 0x78, 0x6d, 0xc1, 0x42, 0xff, 0xc4, 0x8f, 0x5f,
+ 0x3f, 0x21, 0xc1, 0x0f, 0x5f, 0x42, 0xc9, 0xbb, 0xfd, 0x0f, 0x71, 0xf6,
+ 0xcc, 0xfe, 0x81, 0x20, 0x00
+};
+
+static const uint8_t samr_setuserinfo2_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_getuserpwinfo_in_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0xd8, 0x6e, 0xec, 0x8c, 0xe1, 0x1f, 0x2d, 0x41,
+ 0x99, 0x53, 0x13, 0xe9, 0xa4, 0x51, 0xe8, 0x1d
+};
+
+static const uint8_t samr_getuserpwinfo_out_data[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_closehandle_in_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0xd8, 0x6e, 0xec, 0x8c, 0xe1, 0x1f, 0x2d, 0x41,
+ 0x99, 0x53, 0x13, 0xe9, 0xa4, 0x51, 0xe8, 0x1d
+};
+
+static const uint8_t samr_closehandle_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t samr_changepassworduser3_w2k_in_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x10, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x53, 0x00,
+ 0x52, 0x00, 0x56, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x67, 0x00, 0x64, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x8a, 0x5d, 0x1b, 0x5c,
+ 0xf4, 0xf8, 0xb6, 0x79, 0xe0, 0xbf, 0x34, 0x0a, 0x9b, 0x73, 0xdb, 0x34,
+ 0x6e, 0xbe, 0xe1, 0x1f, 0x75, 0x33, 0xff, 0x3c, 0xa1, 0xca, 0xc0, 0xa8,
+ 0xfa, 0x78, 0xbe, 0x93, 0x9d, 0xb7, 0x9e, 0x15, 0xad, 0x6e, 0x27, 0xb3,
+ 0x01, 0xdb, 0x6c, 0xb8, 0x5a, 0x2b, 0x73, 0xb9, 0x5a, 0x25, 0xd1, 0xf7,
+ 0x33, 0xe8, 0x7e, 0x97, 0x7e, 0xb4, 0x90, 0x89, 0x85, 0xc8, 0x20, 0x8d,
+ 0x25, 0x02, 0x68, 0xb9, 0xe4, 0x09, 0xd1, 0xd5, 0x50, 0x6e, 0x83, 0x0a,
+ 0x21, 0x45, 0x33, 0xb2, 0xe8, 0x3b, 0xb6, 0x5a, 0x8e, 0x3c, 0x36, 0x51,
+ 0xe9, 0xb5, 0x22, 0xfe, 0xeb, 0x19, 0x44, 0xa1, 0x01, 0xa9, 0x0c, 0x2c,
+ 0x5a, 0xd1, 0xfe, 0x69, 0x10, 0x86, 0xae, 0x78, 0x01, 0xaa, 0x5d, 0xbb,
+ 0x16, 0x02, 0x2b, 0xa5, 0x26, 0xcc, 0x7c, 0x9d, 0xc0, 0x6c, 0x9c, 0x24,
+ 0x5b, 0x8b, 0x34, 0xc3, 0xbc, 0x40, 0x5e, 0x3d, 0x7c, 0x2a, 0x55, 0x36,
+ 0xfd, 0x34, 0x08, 0x08, 0x05, 0xca, 0xd2, 0xd1, 0x0e, 0xe4, 0x8f, 0xea,
+ 0xfe, 0x3f, 0x7d, 0x56, 0x3c, 0x9a, 0x59, 0x68, 0x83, 0x89, 0x21, 0x3e,
+ 0x7d, 0x33, 0xfd, 0x73, 0x70, 0xa6, 0xec, 0x36, 0xe8, 0x9d, 0x62, 0x40,
+ 0x0e, 0x97, 0x3d, 0xb0, 0xc9, 0x9d, 0x11, 0xb1, 0x55, 0x51, 0xd0, 0x1d,
+ 0x72, 0xdb, 0xf1, 0x18, 0x0a, 0x39, 0x94, 0x0f, 0xf8, 0x9a, 0xba, 0x79,
+ 0x75, 0x37, 0x83, 0x8d, 0x1a, 0x8e, 0x8b, 0x38, 0x0a, 0x44, 0xf1, 0x46,
+ 0x60, 0xef, 0x8b, 0xd8, 0x83, 0xb7, 0x10, 0x91, 0x2a, 0x42, 0x09, 0x0f,
+ 0x6a, 0x43, 0xa9, 0xca, 0x44, 0x5d, 0x7f, 0x3b, 0x96, 0xde, 0xa9, 0xd3,
+ 0x69, 0x3f, 0x0e, 0x27, 0x52, 0x32, 0x54, 0xcf, 0x4c, 0xcb, 0xf1, 0x84,
+ 0xab, 0x13, 0x5e, 0x56, 0x18, 0x96, 0xce, 0x67, 0x4f, 0x73, 0xf8, 0xb2,
+ 0xde, 0x82, 0xa6, 0x0c, 0x15, 0x72, 0x73, 0x1a, 0x00, 0x9a, 0x54, 0x85,
+ 0x4d, 0x83, 0x6d, 0x78, 0x13, 0xc5, 0x7c, 0x86, 0xa9, 0x4b, 0x34, 0x54,
+ 0xbc, 0x40, 0x13, 0x9d, 0x99, 0x0d, 0xa4, 0xc8, 0xeb, 0x6e, 0xef, 0x3f,
+ 0x94, 0x6f, 0xc4, 0x4d, 0x2d, 0x13, 0x9f, 0xd6, 0x29, 0xc6, 0x55, 0xc1,
+ 0x73, 0x86, 0xe7, 0x77, 0xe2, 0x85, 0xb4, 0x03, 0xaf, 0xe2, 0x7a, 0x9c,
+ 0x62, 0x8e, 0xc7, 0xcb, 0xa5, 0x0c, 0x1f, 0xd5, 0xa2, 0x6b, 0x59, 0xb5,
+ 0xe7, 0xde, 0xf9, 0x1c, 0xa0, 0x96, 0x48, 0xcd, 0x20, 0x52, 0x23, 0x23,
+ 0xfb, 0x88, 0x91, 0xda, 0x64, 0x41, 0x24, 0xd4, 0x30, 0x1e, 0x92, 0x69,
+ 0x4e, 0xad, 0xb9, 0x41, 0x0f, 0x7f, 0x00, 0xdc, 0xdd, 0x17, 0xe8, 0x56,
+ 0xfc, 0xbd, 0x2f, 0x57, 0x46, 0x41, 0x5a, 0xab, 0xe8, 0xbc, 0x81, 0xc1,
+ 0xdf, 0x2b, 0x5b, 0xd0, 0xb8, 0x2b, 0x54, 0xaf, 0x8c, 0xd1, 0x1a, 0x91,
+ 0x93, 0x61, 0x21, 0xd7, 0x65, 0xc4, 0x3a, 0x8b, 0xf5, 0xb5, 0x4e, 0x9b,
+ 0xf9, 0xe5, 0x77, 0x59, 0x25, 0x60, 0xd0, 0xe4, 0x73, 0x58, 0x1b, 0x03,
+ 0x9c, 0xf4, 0x80, 0x82, 0xd1, 0xa2, 0x27, 0xe9, 0x60, 0x87, 0xfd, 0x7d,
+ 0x8f, 0x25, 0x6d, 0x66, 0x8c, 0xb3, 0x7e, 0x92, 0x6a, 0xae, 0x10, 0x10,
+ 0x29, 0xcc, 0x7a, 0xeb, 0x07, 0x6e, 0x82, 0x01, 0xd0, 0xee, 0xa0, 0xb3,
+ 0x2f, 0xf0, 0x9d, 0x4c, 0x82, 0x1d, 0x3e, 0x07, 0xf1, 0xbe, 0x64, 0x01,
+ 0x6a, 0xf8, 0x28, 0xb4, 0x08, 0x51, 0xf0, 0x01, 0x1b, 0x1b, 0x58, 0x5e,
+ 0x4b, 0x8c, 0x02, 0x92, 0xcb, 0x80, 0x26, 0x9d, 0x60, 0x33, 0xee, 0x6a,
+ 0x17, 0x39, 0x46, 0x3d, 0x10, 0x04, 0x6d, 0x60, 0x91, 0xdd, 0xb7, 0x6c,
+ 0xd5, 0x28, 0x36, 0x75, 0x32, 0xf8, 0xd7, 0xc3, 0xe7, 0x90, 0x82, 0xdc,
+ 0x2a, 0xe8, 0x72, 0x05, 0x95, 0x96, 0x07, 0x40, 0x10, 0x00, 0x02, 0x00,
+ 0xa7, 0x0f, 0x62, 0x18, 0xfb, 0xca, 0x87, 0x81, 0x92, 0x4a, 0x42, 0xa1,
+ 0x04, 0x9b, 0xf8, 0x65, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+static const uint8_t samr_changepassworduser3_w2k_out_data[] = {
+ 0xbb, 0x00, 0x00, 0xc0
+};
+*/
+
+static const uint8_t samr_changepassworduser3_w2k8r2_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xa6, 0x0a, 0xff, 0xde, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0xc0
+};
+
+static bool samr_changepassworduser3_w2k8r2_out_check(struct torture_context *tctx,
+ struct samr_ChangePasswordUser3 *r)
+{
+ struct samr_DomInfo1 *dominfo = *r->out.dominfo;
+ struct userPwdChangeFailureInformation *reject = *r->out.reject;
+
+ torture_assert_int_equal(tctx, dominfo->min_password_length, 7, "min_password_length");
+ torture_assert_int_equal(tctx, dominfo->password_history_length, 0, "password_history_length");
+ torture_assert_int_equal(tctx, dominfo->password_properties, DOMAIN_PASSWORD_COMPLEX, "password_properties");
+ torture_assert_u64_equal(tctx, dominfo->max_password_age, 0xffffdeff0aa68000, "max_password_age");
+ torture_assert_u64_equal(tctx, dominfo->min_password_age, 0x0000000000000000, "min_password_age");
+
+ torture_assert_int_equal(tctx, reject->extendedFailureReason, SAM_PWD_CHANGE_NOT_COMPLEX, "extendedFailureReason");
+ torture_assert_int_equal(tctx, reject->filterModuleName.length, 0, "filterModuleName.length");
+ torture_assert_int_equal(tctx, reject->filterModuleName.size, 0, "filterModuleName.size");
+
+ torture_assert_ntstatus_equal(tctx, r->out.result, NT_STATUS_PASSWORD_RESTRICTION, "result");
+
+ return true;
+}
+
+struct torture_suite *ndr_samr_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "samr");
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_Connect5, samr_connect5_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_Connect5, samr_connect5_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_LookupNames, samr_lookupnamesindomain_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_LookupNames, samr_lookupnamesindomain_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_OpenDomain, samr_opendomain_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_OpenDomain, samr_opendomain_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_OpenUser, samr_openuser_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_OpenUser, samr_openuser_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_QueryUserInfo, samr_queryuserinfo_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, samr_QueryUserInfo, samr_queryuserinfo_in_data, samr_queryuserinfo_out_data, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_SetUserInfo, samr_setuserinfo_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_SetUserInfo, samr_setuserinfo_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_SetUserInfo2, samr_setuserinfo2_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_SetUserInfo2, samr_setuserinfo2_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_GetUserPwInfo, samr_getuserpwinfo_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_GetUserPwInfo, samr_getuserpwinfo_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_Close, samr_closehandle_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, samr_Close, samr_closehandle_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, samr_ChangePasswordUser3, samr_changepassworduser3_w2k_in_data, NDR_IN, NULL);
+#if 0
+ /* Samba currently fails to parse a w2k reply */
+ torture_suite_add_ndr_pull_fn_test(suite, samr_ChangePasswordUser3, samr_changepassworduser3_w2k_out_data, NDR_OUT, NULL);
+#endif
+ torture_suite_add_ndr_pull_fn_test(suite,
+ samr_ChangePasswordUser3,
+ samr_changepassworduser3_w2k8r2_out_data,
+ NDR_OUT,
+ samr_changepassworduser3_w2k8r2_out_check);
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/spoolss.c b/source4/torture/ndr/spoolss.c
new file mode 100644
index 0000000..1628665
--- /dev/null
+++ b/source4/torture/ndr/spoolss.c
@@ -0,0 +1,2064 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for spoolss ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2009-2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "librpc/gen_ndr/ndr_winspool.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t openprinterex_req_data[] = {
+ 0xf0, 0xa8, 0x39, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x32, 0x00,
+ 0x6b, 0x00, 0x33, 0x00, 0x64, 0x00, 0x63, 0x00, 0x00, 0x00, 0xc9, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x1c, 0xf5, 0x89, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x66, 0x39, 0x00,
+ 0x78, 0xf5, 0x89, 0x00, 0x28, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x58, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00
+};
+
+static const uint8_t openprinterex_resp_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf8, 0xb9, 0x70, 0x9e, 0x14, 0x6b, 0x47,
+ 0xb1, 0x95, 0x57, 0xe2, 0x90, 0x94, 0xfb, 0xdc, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t openprinterex_devmode_req_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x6f, 0x00,
+ 0x67, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x6d, 0x00, 0x75, 0x00,
+ 0x63, 0x00, 0x5c, 0x00, 0x6b, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x63, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x2d, 0x00, 0x6d, 0x00, 0x75, 0x00,
+ 0x63, 0x00, 0x2d, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0x07, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7c, 0x07, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6f, 0x00,
+ 0x6e, 0x00, 0x2d, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x63, 0x00, 0x5c, 0x00,
+ 0x6b, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x2d, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x63, 0x00, 0x2d, 0x00,
+ 0x6e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0xd8, 0x2a, 0x00, 0x00, 0x00,
+ 0x76, 0x00, 0x6d, 0x00, 0x01, 0x04, 0x00, 0x06, 0xdc, 0x00, 0xa0, 0x06,
+ 0x53, 0xff, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x02, 0x00, 0x0f, 0x00, 0xb0, 0x04, 0x01, 0x00, 0x01, 0x00,
+ 0xb0, 0x04, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x33, 0x00, 0xf3, 0xd8, 0x08, 0x02, 0x08, 0x34, 0x00, 0x0c,
+ 0x00, 0xf8, 0xfb, 0x0b, 0x08, 0x34, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x50, 0x52, 0x49, 0x56, 0xe2, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x27, 0x10, 0x27, 0x10, 0x27, 0x00, 0x00, 0x10, 0x27,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x94, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x10, 0x00,
+ 0x28, 0x88, 0x04, 0x00, 0x50, 0x34, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3d, 0xc1, 0xf9, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x53, 0x4d, 0x54, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xb0, 0x01,
+ 0x6b, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x2d, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x63, 0x00, 0x00, 0x00,
+ 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x31,
+ 0x32, 0x30, 0x30, 0x64, 0x70, 0x69, 0x00, 0x4b, 0x43, 0x45, 0x63, 0x6f,
+ 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x4f, 0x66, 0x66, 0x00, 0x53, 0x6d,
+ 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x54, 0x72, 0x75, 0x65,
+ 0x00, 0x50, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x00, 0x41, 0x34,
+ 0x00, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x00,
+ 0x00, 0x4c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x45, 0x64, 0x67, 0x65,
+ 0x00, 0x00, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x6c, 0x6f, 0x74, 0x00,
+ 0x50, 0x46, 0x36, 0x30, 0x41, 0x00, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54,
+ 0x79, 0x70, 0x65, 0x00, 0x50, 0x72, 0x6e, 0x44, 0x65, 0x66, 0x00, 0x4f,
+ 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x00, 0x4e, 0x6f, 0x6e,
+ 0x65, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x65, 0x78, 0x00, 0x4e, 0x6f, 0x6e,
+ 0x65, 0x00, 0x4b, 0x43, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x65, 0x00,
+ 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x4b, 0x6d, 0x4d, 0x61, 0x6e, 0x61, 0x67,
+ 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
+ 0x00, 0x4b, 0x43, 0x53, 0x75, 0x70, 0x65, 0x72, 0x57, 0x61, 0x74, 0x65,
+ 0x72, 0x6d, 0x61, 0x72, 0x6b, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x50,
+ 0x61, 0x67, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x00, 0x4f, 0x6e,
+ 0x00, 0x4b, 0x4d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x44,
+ 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x63, 0x75, 0x70, 0x73, 0x4a,
+ 0x6f, 0x62, 0x48, 0x6f, 0x6c, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x00,
+ 0x6e, 0x6f, 0x2d, 0x68, 0x6f, 0x6c, 0x64, 0x00, 0x63, 0x75, 0x70, 0x73,
+ 0x4a, 0x6f, 0x62, 0x53, 0x68, 0x65, 0x65, 0x74, 0x73, 0x53, 0x74, 0x61,
+ 0x72, 0x74, 0x00, 0x6e, 0x6f, 0x6e, 0x65, 0x00, 0x63, 0x75, 0x70, 0x73,
+ 0x4a, 0x6f, 0x62, 0x53, 0x68, 0x65, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x64,
+ 0x00, 0x6e, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x02, 0x00, 0x00, 0x53, 0x50, 0x55, 0x43, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00,
+ 0xce, 0x0e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x54, 0x00, 0x45, 0x00,
+ 0x52, 0x00, 0x4d, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x41, 0x00, 0x4c, 0x00,
+ 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00,
+ 0x65, 0x00, 0x00, 0x00
+};
+
+static const uint8_t closeprinter_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf8, 0xb9, 0x70, 0x9e, 0x14, 0x6b, 0x47,
+ 0xb1, 0x95, 0x57, 0xe2, 0x90, 0x94, 0xfb, 0xdc
+};
+
+static const uint8_t closeprinter_resp_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getprinter_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x1d, 0x7e, 0x6c, 0xfd, 0x7c, 0x90, 0x53, 0x4c,
+ 0xb8, 0x6f, 0x66, 0xb5, 0xff, 0x73, 0xd9, 0xac, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getprinter_resp_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getprinterdata_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0xee, 0x56, 0x27, 0x7f, 0xef, 0xf7, 0x42,
+ 0x84, 0x54, 0xd5, 0x7b, 0xec, 0xe3, 0xcc, 0x55, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x55, 0x00, 0x49, 0x00,
+ 0x53, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x4a, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x75, 0x00, 0x73, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getprinterdata_resp_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00
+};
+
+static const uint8_t replyopenprinter_req_data[] = {
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x58, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t replyopenprinter_resp_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xef, 0x4a, 0x33, 0x05, 0x22, 0xf4, 0xc4, 0x4a,
+ 0xa2, 0xde, 0x52, 0x17, 0xa6, 0xc8, 0x19, 0xd0, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t RFFPCNEX_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0xee, 0x56, 0x27, 0x7f, 0xef, 0xf7, 0x42,
+ 0x84, 0x54, 0xd5, 0x7b, 0xec, 0xe3, 0xcc, 0x55, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x21, 0x26, 0x74, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x58, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x0d, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x0d, 0x0b, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x0d, 0x0b, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x12, 0x00, 0x05, 0x00,
+ 0x06, 0x00, 0x04, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x0d, 0x00
+};
+
+static const uint8_t RFFPCNEX_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t RRPCN_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x9b, 0x8b, 0xe5, 0x32, 0x9a, 0xd5, 0x45,
+ 0xa8, 0x0a, 0x10, 0x30, 0x5b, 0x87, 0x6f, 0x69, 0x01, 0x00, 0x00, 0x00,
+ 0x44, 0x0d, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t RRPCN_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0d, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0f, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x15, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x8c, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x17, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0d, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0f, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x15, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x8c, 0x22, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x17, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x77, 0x00, 0x32, 0x00, 0x6b, 0x00, 0x33, 0x00,
+ 0x64, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00,
+ 0x4c, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x57, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00,
+ 0x31, 0x00, 0x32, 0x00, 0x2f, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00,
+ 0x20, 0x00, 0x50, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x64, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x00, 0x00, 0xd6, 0x07, 0x07, 0x00,
+ 0x06, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x11, 0x00, 0x01, 0x00, 0x60, 0x03,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0xd6, 0x07, 0x07, 0x00, 0x06, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x11, 0x00,
+ 0x0b, 0x00, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumforms_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x5c, 0x46, 0xe5, 0x74, 0xa1, 0x9e, 0x46,
+ 0x95, 0x80, 0x19, 0xf1, 0xaa, 0x63, 0xc9, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumforms_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterdataex_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x5c, 0x46, 0xe5, 0x74, 0xa1, 0x9e, 0x46,
+ 0x95, 0x80, 0x19, 0xf1, 0xaa, 0x63, 0xc9, 0x01, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x73, 0x00,
+ 0x44, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterdataex_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0xea, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterdataex_w2k8r2_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x62, 0x2a, 0xa4, 0x60, 0x12, 0x99, 0xea, 0x4f,
+ 0x88, 0xc9, 0xea, 0x0d, 0xb7, 0xc3, 0x61, 0x99, 0x12, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x44, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x44, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0c, 0x21, 0x00, 0x00
+};
+
+static const uint8_t enumprinterdataex_w2k8r2_out_data[] = {
+ 0x0c, 0x21, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x08, 0x02, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x18, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x14, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x34, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x00,
+ 0x30, 0x02, 0x00, 0x00, 0x58, 0x04, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x70, 0x04, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x90, 0x04, 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, 0x7a, 0x06, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x06, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x78, 0x06, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x96, 0x06, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00,
+ 0x4e, 0x09, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x68, 0x09, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x58, 0x09, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7c, 0x09, 0x00, 0x00,
+ 0x10, 0x04, 0x00, 0x00, 0x78, 0x0d, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x94, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x84, 0x0d, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xac, 0x0d, 0x00, 0x00, 0xdc, 0x0b, 0x00, 0x00, 0x74, 0x19, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x19, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x78, 0x19, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x90, 0x19, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0xa4, 0x19, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xcc, 0x19, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0x19, 0x00, 0x00,
+ 0x2a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe8, 0x19, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0xd8, 0x19, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0xf4, 0x19, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xe4, 0x19, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x1a, 0x00, 0x00, 0xe4, 0x02, 0x00, 0x00, 0xd0, 0x1c, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0xe0, 0x1c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xf8, 0x1c, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00,
+ 0xb6, 0x1d, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xe0, 0x1d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd0, 0x1d, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf0, 0x1d, 0x00, 0x00,
+ 0x39, 0x01, 0x00, 0x00, 0x16, 0x1f, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x28, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x49, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x74, 0x00, 0x44, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x56, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x00, 0x00, 0x46, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00,
+ 0x4d, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+ 0x4a, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x54, 0x00, 0x69, 0x00, 0x6d, 0x00,
+ 0x65, 0x00, 0x4f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x6f, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x44, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x61, 0x00, 0x53, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0x30, 0x02, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x44, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x61, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x02, 0x80, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
+ 0x64, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x97, 0xda, 0x0b,
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x46, 0x00, 0x65, 0x00, 0x61, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00,
+ 0x65, 0x00, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x77, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x53, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, 0x46, 0x00, 0x65, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x4b, 0x00,
+ 0x65, 0x00, 0x79, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x64, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x75, 0x70, 0x6c, 0x65, 0x78, 0x55, 0x6e,
+ 0x69, 0x74, 0x00, 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
+ 0x6c, 0x65, 0x64, 0x00, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f,
+ 0x72, 0x79, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x73,
+ 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x0a, 0x49, 0x6e, 0x73, 0x74, 0x61,
+ 0x6c, 0x6c, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x00, 0x33,
+ 0x38, 0x34, 0x2d, 0x34, 0x39, 0x35, 0x4d, 0x42, 0x00, 0x0a, 0x50, 0x72,
+ 0x69, 0x6e, 0x74, 0x65, 0x72, 0x48, 0x61, 0x72, 0x64, 0x44, 0x69, 0x73,
+ 0x6b, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x00,
+ 0x0a, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f,
+ 0x6e, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x00,
+ 0x0a, 0x48, 0x50, 0x50, 0x61, 0x73, 0x73, 0x74, 0x68, 0x72, 0x6f, 0x75,
+ 0x67, 0x68, 0x00, 0x54, 0x72, 0x75, 0x65, 0x00, 0x0a, 0x44, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x49, 0x73, 0x4d, 0x6f, 0x70, 0x69, 0x65, 0x72, 0x00,
+ 0x4e, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64,
+ 0x00, 0x0a, 0x41, 0x75, 0x74, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x4e, 0x6f, 0x74, 0x49,
+ 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x0a, 0x48, 0x50,
+ 0x4d, 0x65, 0x64, 0x69, 0x61, 0x50, 0x4d, 0x4c, 0x52, 0x61, 0x6e, 0x67,
+ 0x65, 0x00, 0x31, 0x35, 0x2d, 0x31, 0x39, 0x00, 0x0a, 0x48, 0x50, 0x4f,
+ 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x50, 0x4d, 0x4c, 0x52,
+ 0x61, 0x6e, 0x67, 0x65, 0x00, 0x30, 0x2d, 0x30, 0x00, 0x0a, 0x48, 0x50,
+ 0x50, 0x72, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x00, 0x48, 0x50, 0x43, 0x61,
+ 0x62, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x0a, 0x48,
+ 0x50, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65,
+ 0x48, 0x43, 0x4f, 0x00, 0x33, 0x30, 0x30, 0x30, 0x53, 0x74, 0x61, 0x63,
+ 0x6b, 0x65, 0x72, 0x2d, 0x43, 0x38, 0x30, 0x38, 0x34, 0x00, 0x0a, 0x48,
+ 0x50, 0x4d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x48,
+ 0x43, 0x4f, 0x4d, 0x61, 0x70, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x0a,
+ 0x48, 0x50, 0x4d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e,
+ 0x48, 0x43, 0x4f, 0x50, 0x4d, 0x4c, 0x4d, 0x61, 0x70, 0x00, 0x4e, 0x6f,
+ 0x6e, 0x65, 0x00, 0x0a, 0x48, 0x50, 0x50, 0x44, 0x4c, 0x54, 0x79, 0x70,
+ 0x65, 0x00, 0x50, 0x44, 0x4c, 0x5f, 0x50, 0x53, 0x00, 0x0a, 0x53, 0x63,
+ 0x61, 0x6c, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4c, 0x61, 0x72, 0x67, 0x65,
+ 0x50, 0x61, 0x70, 0x65, 0x72, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
+ 0x6c, 0x65, 0x64, 0x00, 0x0a, 0x41, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x43,
+ 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x33,
+ 0x30, 0x36, 0x30, 0x37, 0x30, 0x5f, 0x34, 0x36, 0x39, 0x39, 0x30, 0x30,
+ 0x00, 0x0a, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x4d, 0x65, 0x64,
+ 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x73, 0x41, 0x6e, 0x64, 0x49, 0x6e,
+ 0x70, 0x75, 0x74, 0x42, 0x69, 0x6e, 0x73, 0x00, 0x49, 0x6e, 0x73, 0x74,
+ 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x46, 0x00,
+ 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x3f, 0x00, 0x00, 0x00,
+ 0xc6, 0x97, 0xda, 0x0b, 0x44, 0x00, 0x65, 0x00, 0x70, 0x00, 0x65, 0x00,
+ 0x6e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x46, 0x00,
+ 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x73, 0x00, 0x00, 0x00, 0x48, 0x00,
+ 0x50, 0x00, 0x5a, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x4c, 0x00, 0x48, 0x00,
+ 0x4e, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x48, 0x00, 0x4d, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x4c, 0x00, 0x53, 0x00, 0x4c, 0x00,
+ 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x53, 0x00, 0x53, 0x00,
+ 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00,
+ 0x53, 0x00, 0x52, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00,
+ 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x5a, 0x00, 0x53, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00,
+ 0x2e, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x49, 0x00, 0x00, 0x00, 0x48, 0x00,
+ 0x50, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x50, 0x00, 0x44, 0x00, 0x50, 0x00,
+ 0x53, 0x00, 0x2e, 0x00, 0x58, 0x00, 0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x53, 0x00, 0x43, 0x00, 0x4c, 0x00,
+ 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x54, 0x00, 0x44, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x46, 0x00, 0x4e, 0x00,
+ 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00, 0x4e, 0x00, 0x54, 0x00,
+ 0x46, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x4d, 0x00, 0x43, 0x00,
+ 0x50, 0x00, 0x44, 0x00, 0x32, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x43, 0x00,
+ 0x46, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00,
+ 0x53, 0x00, 0x54, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00,
+ 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x5a, 0x00, 0x45, 0x00, 0x56, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00,
+ 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00,
+ 0x50, 0x00, 0x43, 0x00, 0x44, 0x00, 0x4d, 0x00, 0x43, 0x00, 0x4c, 0x00,
+ 0x48, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x49, 0x00, 0x44, 0x00, 0x52, 0x00,
+ 0x31, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x49, 0x00, 0x4e, 0x00,
+ 0x57, 0x00, 0x31, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x49, 0x00,
+ 0x50, 0x00, 0x4d, 0x00, 0x31, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x5a, 0x00,
+ 0x49, 0x00, 0x50, 0x00, 0x52, 0x00, 0x31, 0x00, 0x32, 0x00, 0x2e, 0x00,
+ 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x5a, 0x00, 0x49, 0x00, 0x50, 0x00, 0x54, 0x00, 0x31, 0x00, 0x32, 0x00,
+ 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00,
+ 0x50, 0x00, 0x5a, 0x00, 0x49, 0x00, 0x53, 0x00, 0x4e, 0x00, 0x31, 0x00,
+ 0x32, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x49, 0x00, 0x41, 0x00,
+ 0x50, 0x00, 0x49, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x42, 0x00, 0x4d, 0x00, 0x49, 0x00,
+ 0x4e, 0x00, 0x49, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x42, 0x00, 0x4f, 0x00, 0x49, 0x00,
+ 0x44, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x42, 0x00, 0x4f, 0x00, 0x49, 0x00, 0x44, 0x00,
+ 0x50, 0x00, 0x53, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x42, 0x00, 0x50, 0x00, 0x52, 0x00,
+ 0x4f, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x42, 0x00, 0x50, 0x00, 0x52, 0x00, 0x4f, 0x00,
+ 0x50, 0x00, 0x53, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x45, 0x00, 0x41, 0x00, 0x43, 0x00,
+ 0x4c, 0x00, 0x48, 0x00, 0x4e, 0x00, 0x2e, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x49, 0x00, 0x00, 0x00, 0x50, 0x00, 0x53, 0x00, 0x43, 0x00, 0x52, 0x00,
+ 0x49, 0x00, 0x50, 0x00, 0x54, 0x00, 0x2e, 0x00, 0x4e, 0x00, 0x54, 0x00,
+ 0x46, 0x00, 0x00, 0x00, 0x50, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x53, 0x00,
+ 0x43, 0x00, 0x48, 0x00, 0x4d, 0x00, 0x2e, 0x00, 0x47, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x75, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x54, 0x00, 0x52, 0x00, 0x41, 0x00, 0x59, 0x00,
+ 0x49, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x45, 0x00,
+ 0x47, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6c, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x63, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x50,
+ 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72,
+ 0x00, 0x20, 0x00, 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x20,
+ 0x00, 0x53, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x4d, 0x00, 0x61, 0x00,
+ 0x6e, 0x00, 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x46, 0x00,
+ 0x65, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x54, 0x00, 0x72,
+ 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x01, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x20, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x54,
+ 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x33, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00,
+ 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x35,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x01, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20,
+ 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x0a, 0x01, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79,
+ 0x00, 0x20, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00,
+ 0x45, 0x00, 0x78, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x35, 0x00,
+ 0x29, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x45, 0x00, 0x78,
+ 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20,
+ 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x36, 0x00, 0x29, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x45, 0x00, 0x78, 0x00, 0x20, 0x00,
+ 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x28, 0x00,
+ 0x4d, 0x00, 0x50, 0x00, 0x37, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x0e,
+ 0x01, 0x00, 0x00, 0x45, 0x00, 0x78, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72,
+ 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50,
+ 0x00, 0x38, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00,
+ 0x45, 0x00, 0x78, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x39, 0x00,
+ 0x29, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x45, 0x00, 0x78,
+ 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20,
+ 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00,
+ 0x76, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x65, 0x00,
+ 0x20, 0x00, 0x46, 0x00, 0x65, 0x00, 0x65, 0x00, 0x64, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x4d, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x61, 0x00, 0x43, 0x00,
+ 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x4d, 0x00, 0x45, 0x00,
+ 0x44, 0x00, 0x49, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x46, 0x00,
+ 0x4f, 0x00, 0x52, 0x00, 0x45, 0x00, 0x47, 0x00, 0x44, 0x00, 0x41, 0x00,
+ 0x54, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x6e, 0x00,
+ 0x73, 0x00, 0x70, 0x00, 0x65, 0x00, 0x63, 0x00, 0x69, 0x00, 0x66, 0x00,
+ 0x69, 0x00, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x50, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00, 0x65, 0x00,
+ 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x4c, 0x00, 0x65,
+ 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x68, 0x00, 0x65,
+ 0x00, 0x61, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00,
+ 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x70, 0x00,
+ 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x79, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x50, 0x00, 0x72, 0x00, 0x65,
+ 0x00, 0x70, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x65,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x4c, 0x00,
+ 0x61, 0x00, 0x62, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x06, 0x01, 0x00, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x64,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00,
+ 0x63, 0x00, 0x79, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x64, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6c,
+ 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00,
+ 0x4c, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, 0x00, 0x74, 0x00, 0x20, 0x00,
+ 0x3c, 0x00, 0x37, 0x00, 0x35, 0x00, 0x20, 0x00, 0x67, 0x00, 0x2f, 0x00,
+ 0x6d, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x48,
+ 0x00, 0x65, 0x00, 0x61, 0x00, 0x76, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x01, 0x00, 0x00, 0x43, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00,
+ 0x3e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x33, 0x00, 0x20, 0x00, 0x67, 0x00,
+ 0x2f, 0x00, 0x6d, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00,
+ 0x00, 0x47, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x73, 0x00, 0x79,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x20, 0x00, 0x48, 0x00, 0x65, 0x00, 0x61, 0x00, 0x76, 0x00, 0x79, 0x00,
+ 0x20, 0x00, 0x47, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x73, 0x00,
+ 0x79, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x54, 0x00, 0x6f,
+ 0x00, 0x75, 0x00, 0x67, 0x00, 0x68, 0x00, 0x20, 0x00, 0x70, 0x00, 0x61,
+ 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01,
+ 0x00, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x76, 0x00, 0x65, 0x00, 0x6c, 0x00,
+ 0x6f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x13, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x69, 0x00,
+ 0x64, 0x00, 0x69, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x49, 0x00, 0x6e, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x44, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x00, 0x00, 0x31, 0x00, 0x31, 0x00,
+ 0x2f, 0x00, 0x32, 0x00, 0x36, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, 0x3a, 0x00,
+ 0x31, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x43, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x4d, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x61, 0x00, 0x53, 0x00, 0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x75, 0x00,
+ 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x49, 0x00, 0x6e, 0x00,
+ 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x43, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00,
+ 0x53, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe4, 0x02, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x54, 0x00, 0x61, 0x00,
+ 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0xe4, 0x02, 0x50, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x20, 0x00, 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x20, 0x00,
+ 0x53, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00,
+ 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x61, 0x00,
+ 0x6e, 0x00, 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x46, 0x00,
+ 0x65, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x32, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x35, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x38, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00,
+ 0x39, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
+ 0x78, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x35, 0x00, 0x29, 0x00,
+ 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x78, 0x00,
+ 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00,
+ 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x36, 0x00, 0x29, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x78, 0x00, 0x20, 0x00,
+ 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x28, 0x00,
+ 0x4d, 0x00, 0x50, 0x00, 0x37, 0x00, 0x29, 0x00, 0x00, 0x00, 0x4c, 0x00,
+ 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x78, 0x00, 0x20, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00,
+ 0x50, 0x00, 0x38, 0x00, 0x29, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x45, 0x00, 0x78, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00,
+ 0x39, 0x00, 0x29, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x00, 0x78, 0x00, 0x20, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x79, 0x00, 0x20, 0x00, 0x28, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x31, 0x00,
+ 0x30, 0x00, 0x29, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x00, 0x6e, 0x00, 0x76, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6f, 0x00,
+ 0x70, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x65, 0x00, 0x65, 0x00,
+ 0x64, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x65, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x4d, 0x00, 0x61, 0x00,
+ 0x70, 0x00, 0x53, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x00, 0x00,
+ 0xd1, 0x00, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00,
+ 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x4d, 0x00, 0x61, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x41, 0x75, 0x74, 0x6f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x46, 0x65, 0x65, 0x64, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x31, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x54, 0x72, 0x61, 0x79, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x72,
+ 0x61, 0x79, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x79,
+ 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x36, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x37, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x54, 0x72, 0x61, 0x79, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x72,
+ 0x61, 0x79, 0x45, 0x78, 0x74, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
+ 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x33, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x34, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x35, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x36, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x45, 0x6e, 0x76, 0x46, 0x65, 0x65, 0x64, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00,
+ 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x6d, 0x00, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x77, 0x00, 0x6f, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x53, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x54, 0x00, 0x72, 0x00,
+ 0x61, 0x00, 0x79, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00,
+ 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x41, 0x75, 0x74, 0x6f, 0x00, 0x4c, 0x45, 0x54,
+ 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x4d, 0x61, 0x6e, 0x75, 0x61,
+ 0x6c, 0x46, 0x65, 0x65, 0x64, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52,
+ 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79, 0x31, 0x00, 0x4c, 0x45,
+ 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79,
+ 0x32, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00,
+ 0x54, 0x72, 0x61, 0x79, 0x33, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52,
+ 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79, 0x34, 0x00, 0x4c, 0x45,
+ 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79,
+ 0x35, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00,
+ 0x54, 0x72, 0x61, 0x79, 0x36, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52,
+ 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79, 0x37, 0x00, 0x4c, 0x45,
+ 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79,
+ 0x38, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00,
+ 0x54, 0x72, 0x61, 0x79, 0x39, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52,
+ 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x31,
+ 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x54,
+ 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x32, 0x00, 0x4c, 0x45, 0x54, 0x54,
+ 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78,
+ 0x74, 0x33, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50,
+ 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x34, 0x00, 0x4c, 0x45,
+ 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79,
+ 0x45, 0x78, 0x74, 0x35, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a,
+ 0x48, 0x50, 0x00, 0x54, 0x72, 0x61, 0x79, 0x45, 0x78, 0x74, 0x36, 0x00,
+ 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52, 0x3a, 0x48, 0x50, 0x00, 0x45, 0x6e,
+ 0x76, 0x46, 0x65, 0x65, 0x64, 0x00, 0x4c, 0x45, 0x54, 0x54, 0x45, 0x52,
+ 0x3a, 0x48, 0x50, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00, 0x44, 0x00,
+ 0x55, 0x00, 0x4d, 0x00, 0x4d, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x21, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterkey_in_data2[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xcc, 0x89, 0x90, 0x8a, 0xfc, 0xca, 0x4c,
+ 0xa5, 0x44, 0xdc, 0x30, 0x10, 0x20, 0xd9, 0x8f, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterkey_out_data2[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterkey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x5c, 0x46, 0xe5, 0x74, 0xa1, 0x9e, 0x46,
+ 0x95, 0x80, 0x19, 0xf1, 0xaa, 0x63, 0xc9, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x11,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t enumprinterkey_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00
+};
+
+static const uint8_t FCPN_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0xcf, 0xe5, 0x98, 0xfd, 0x15, 0x4b,
+ 0xba, 0x28, 0x03, 0x70, 0x74, 0x35, 0x8d, 0x14
+};
+
+static const uint8_t FCPN_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t replycloseprinter_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0xe4, 0xdf, 0x77, 0xb1, 0xbf, 0x43, 0x4f,
+ 0xbf, 0xb4, 0x58, 0x5c, 0x44, 0xc6, 0x3e, 0x09
+};
+
+static const uint8_t replycloseprinter_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getprinterdriverdir_in_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x78, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x54, 0x00,
+ 0x20, 0x00, 0x78, 0x00, 0x38, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0xac, 0x26, 0x00, 0x7f, 0xde, 0x15, 0x5f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x69, 0x4d, 0x88, 0x7f, 0x94, 0xd2, 0xa9, 0x01,
+ 0xdb, 0xe4, 0x15, 0x5f, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xfc, 0xd2, 0xa9, 0x01, 0x7f, 0xe5, 0x15, 0x5f, 0xfc, 0xdb, 0xa9, 0x01,
+ 0x18, 0xac, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x14, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0xce, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe8, 0xd2, 0xa9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7c, 0xf3, 0x77,
+ 0x40, 0x9e, 0x0a, 0x00, 0xe1, 0x67, 0xf3, 0x77, 0x18, 0x07, 0x08, 0x00,
+ 0xf9, 0x67, 0xf3, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0x9e, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x98, 0xd0, 0xa9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xd2, 0xa9, 0x01,
+ 0x34, 0x5a, 0xf3, 0x77, 0x70, 0x95, 0xf7, 0x77, 0xff, 0xff, 0xff, 0xff,
+ 0xf3, 0x73, 0xf3, 0x77, 0x08, 0x02, 0x00, 0x00
+};
+
+static const uint8_t getprinterdriverdir_out_data[] = {
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x78, 0x00,
+ 0x34, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x33, 0x00, 0x32, 0x00,
+ 0x58, 0x00, 0x38, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t addprinterdriverex_in_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x78, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x02, 0x00,
+ 0x10, 0x00, 0x02, 0x00, 0x14, 0x00, 0x02, 0x00, 0x18, 0x00, 0x02, 0x00,
+ 0x1c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x02, 0x00, 0x00, 0x40, 0x2a, 0x7c, 0xdd, 0x68, 0xc2, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x0e, 0x02, 0x00, 0x05, 0x00,
+ 0x28, 0x00, 0x02, 0x00, 0x2c, 0x00, 0x02, 0x00, 0x30, 0x00, 0x02, 0x00,
+ 0x34, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x48, 0x00, 0x65, 0x00, 0x77, 0x00, 0x6c, 0x00,
+ 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x50, 0x00, 0x61, 0x00,
+ 0x63, 0x00, 0x6b, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x20, 0x00,
+ 0x48, 0x00, 0x50, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x4c, 0x00, 0x2f, 0x00,
+ 0x32, 0x00, 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00,
+ 0x4e, 0x00, 0x54, 0x00, 0x20, 0x00, 0x78, 0x00, 0x38, 0x00, 0x36, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2d, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x78, 0x00, 0x34, 0x00, 0x5c, 0x00,
+ 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00,
+ 0x5c, 0x00, 0x57, 0x00, 0x33, 0x00, 0x32, 0x00, 0x58, 0x00, 0x38, 0x00,
+ 0x36, 0x00, 0x5c, 0x00, 0x34, 0x00, 0x30, 0x00, 0x34, 0x00, 0x30, 0x00,
+ 0x33, 0x00, 0x31, 0x00, 0x31, 0x00, 0x36, 0x00, 0x5c, 0x00, 0x50, 0x00,
+ 0x4c, 0x00, 0x4f, 0x00, 0x54, 0x00, 0x54, 0x00, 0x45, 0x00, 0x52, 0x00,
+ 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00,
+ 0x6f, 0x00, 0x78, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x57, 0x00,
+ 0x33, 0x00, 0x32, 0x00, 0x58, 0x00, 0x38, 0x00, 0x36, 0x00, 0x5c, 0x00,
+ 0x34, 0x00, 0x30, 0x00, 0x34, 0x00, 0x30, 0x00, 0x33, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x36, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x50, 0x00, 0x47, 0x00,
+ 0x4c, 0x00, 0x32, 0x00, 0x50, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x2e, 0x00,
+ 0x50, 0x00, 0x43, 0x00, 0x44, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x78, 0x00,
+ 0x34, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x33, 0x00, 0x32, 0x00,
+ 0x58, 0x00, 0x38, 0x00, 0x36, 0x00, 0x5c, 0x00, 0x34, 0x00, 0x30, 0x00,
+ 0x34, 0x00, 0x30, 0x00, 0x33, 0x00, 0x31, 0x00, 0x31, 0x00, 0x36, 0x00,
+ 0x5c, 0x00, 0x50, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x54, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00,
+ 0x6f, 0x00, 0x78, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x57, 0x00,
+ 0x33, 0x00, 0x32, 0x00, 0x58, 0x00, 0x38, 0x00, 0x36, 0x00, 0x5c, 0x00,
+ 0x34, 0x00, 0x30, 0x00, 0x34, 0x00, 0x30, 0x00, 0x33, 0x00, 0x31, 0x00,
+ 0x31, 0x00, 0x36, 0x00, 0x5c, 0x00, 0x50, 0x00, 0x4c, 0x00, 0x4f, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x49, 0x00, 0x2e, 0x00, 0x48, 0x00, 0x4c, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x50, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x00, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00,
+ 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x67, 0x00, 0x6f, 0x00, 0x2e, 0x00,
+ 0x6d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00,
+ 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6d, 0x00, 0x2f, 0x00, 0x66, 0x00, 0x77, 0x00, 0x6c, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x6b, 0x00, 0x2f, 0x00, 0x3f, 0x00, 0x4c, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x6b, 0x00, 0x49, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x33, 0x00,
+ 0x37, 0x00, 0x26, 0x00, 0x70, 0x00, 0x72, 0x00, 0x64, 0x00, 0x3d, 0x00,
+ 0x31, 0x00, 0x30, 0x00, 0x37, 0x00, 0x39, 0x00, 0x38, 0x00, 0x26, 0x00,
+ 0x73, 0x00, 0x62, 0x00, 0x70, 0x00, 0x3d, 0x00, 0x50, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x68, 0x00, 0x70, 0x00, 0x68, 0x00, 0x65, 0x00,
+ 0x77, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x2d, 0x00,
+ 0x70, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x61, 0x00, 0x72, 0x00,
+ 0x64, 0x00, 0x5f, 0x00, 0x68, 0x00, 0x70, 0x00, 0x37, 0x00, 0x33, 0x00,
+ 0x31, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x69, 0x00,
+ 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00,
+ 0x74, 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00
+};
+
+static const uint8_t getprinterdriver2_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x74, 0xc9, 0xc0, 0x9f, 0x5f, 0x6f, 0x46,
+ 0xbb, 0x14, 0x48, 0xe6, 0xb6, 0xa8, 0x47, 0x40, 0x00, 0x00, 0x02, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00,
+ 0x73, 0x00, 0x20, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x88, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x04, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
+};
+
+static bool getprinterdriver2_in_check(struct torture_context *tctx,
+ struct spoolss_GetPrinterDriver2 *r)
+{
+ torture_assert_str_equal(tctx, r->in.architecture, "Windows x64", "architecture");
+ torture_assert_int_equal(tctx, r->in.level, 6, "level");
+ torture_assert_int_equal(tctx, r->in.offered, 1160, "offered");
+ torture_assert_int_equal(tctx, r->in.client_major_version, 3, "client_major_version");
+ torture_assert_int_equal(tctx, r->in.client_minor_version, 2, "client_minor_version");
+
+ return true;
+}
+
+static const uint8_t getprinterdriver2_out_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x88, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x58, 0x04, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0xf4, 0x03, 0x00, 0x00,
+ 0xa8, 0x03, 0x00, 0x00, 0x62, 0x03, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00,
+ 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x8c, 0xa3, 0xc5, 0x94, 0xc6, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xb0, 0x1d, 0x01, 0x00, 0x06, 0x00,
+ 0x0c, 0x03, 0x00, 0x00, 0x8a, 0x02, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00,
+ 0x4c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x8c, 0xa3, 0xc5, 0x94, 0xc6, 0x01, 0x01, 0x40, 0xb0, 0x1d,
+ 0x01, 0x00, 0x06, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x48, 0x00,
+ 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00,
+ 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00,
+ 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00, 0x50, 0x00, 0x53, 0x00, 0x43, 0x00,
+ 0x52, 0x00, 0x49, 0x00, 0x50, 0x00, 0x54, 0x00, 0x2e, 0x00, 0x4e, 0x00,
+ 0x54, 0x00, 0x46, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x52, 0x00,
+ 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00,
+ 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00, 0x36, 0x00,
+ 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00, 0x50, 0x00, 0x53, 0x00,
+ 0x5f, 0x00, 0x53, 0x00, 0x43, 0x00, 0x48, 0x00, 0x4d, 0x00, 0x2e, 0x00,
+ 0x47, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00,
+ 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00,
+ 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00, 0x52, 0x00,
+ 0x49, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x48, 0x00, 0x50, 0x00, 0x53, 0x00,
+ 0x37, 0x00, 0x2e, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x49, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00,
+ 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00,
+ 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00,
+ 0x5c, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00,
+ 0x5c, 0x00, 0x52, 0x00, 0x49, 0x00, 0x50, 0x00, 0x53, 0x00, 0x55, 0x00,
+ 0x49, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00,
+ 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00,
+ 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00,
+ 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00,
+ 0x33, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x49, 0x00, 0x50, 0x00, 0x53, 0x00,
+ 0x52, 0x00, 0x45, 0x00, 0x53, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x44, 0x00,
+ 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x52, 0x00,
+ 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00,
+ 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00, 0x36, 0x00,
+ 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x49, 0x00,
+ 0x43, 0x00, 0x46, 0x00, 0x47, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x58, 0x00,
+ 0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x69, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x72, 0x00, 0x69, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x68, 0x00, 0x72, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x6f, 0x00, 0x68, 0x00, 0x5f, 0x00, 0x61, 0x00, 0x66, 0x00, 0x69, 0x00,
+ 0x63, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x5f, 0x00, 0x6d, 0x00, 0x70, 0x00,
+ 0x35, 0x00, 0x30, 0x00, 0x36, 0x00, 0x33, 0x00, 0x00, 0x00, 0x68, 0x00,
+ 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00,
+ 0x67, 0x00, 0x6f, 0x00, 0x2e, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00,
+ 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2f, 0x00, 0x66, 0x00,
+ 0x77, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6b, 0x00, 0x2f, 0x00,
+ 0x3f, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6b, 0x00, 0x49, 0x00,
+ 0x44, 0x00, 0x3d, 0x00, 0x34, 0x00, 0x37, 0x00, 0x26, 0x00, 0x70, 0x00,
+ 0x72, 0x00, 0x64, 0x00, 0x3d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x37, 0x00,
+ 0x39, 0x00, 0x38, 0x00, 0x26, 0x00, 0x73, 0x00, 0x62, 0x00, 0x70, 0x00,
+ 0x3d, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x00, 0x00, 0x52, 0x00, 0x69, 0x00,
+ 0x63, 0x00, 0x6f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00,
+ 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00,
+ 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00, 0x50, 0x00,
+ 0x53, 0x00, 0x43, 0x00, 0x52, 0x00, 0x49, 0x00, 0x50, 0x00, 0x54, 0x00,
+ 0x2e, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x50, 0x00, 0x00, 0x00, 0x5c, 0x00,
+ 0x5c, 0x00, 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00,
+ 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00,
+ 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00,
+ 0x50, 0x00, 0x53, 0x00, 0x35, 0x00, 0x55, 0x00, 0x49, 0x00, 0x2e, 0x00,
+ 0x44, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00,
+ 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x70, 0x00, 0x72, 0x00,
+ 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00, 0x5c, 0x00, 0x78, 0x00,
+ 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00, 0x5c, 0x00, 0x52, 0x00,
+ 0x49, 0x00, 0x31, 0x00, 0x34, 0x00, 0x30, 0x00, 0x33, 0x00, 0x45, 0x00,
+ 0x33, 0x00, 0x2e, 0x00, 0x50, 0x00, 0x50, 0x00, 0x44, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x48, 0x00, 0x2d, 0x00, 0x57, 0x00,
+ 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00, 0x5c, 0x00,
+ 0x70, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x24, 0x00,
+ 0x5c, 0x00, 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x5c, 0x00, 0x33, 0x00,
+ 0x5c, 0x00, 0x50, 0x00, 0x53, 0x00, 0x43, 0x00, 0x52, 0x00, 0x49, 0x00,
+ 0x50, 0x00, 0x54, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x4c, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x78, 0x00, 0x36, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x52, 0x00, 0x69, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x68, 0x00, 0x20, 0x00, 0x41, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
+ 0x69, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x20, 0x00,
+ 0x35, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x20, 0x00, 0x50, 0x00,
+ 0x53, 0x00, 0x00, 0x00, 0x88, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool getprinterdriver2_out_check(struct torture_context *tctx,
+ struct spoolss_GetPrinterDriver2 *r)
+{
+ torture_assert(tctx, r->out.info, "info");
+ torture_assert_int_equal(tctx, r->out.info->info6.version, SPOOLSS_DRIVER_VERSION_200X, "version");
+ torture_assert_str_equal(tctx, r->out.info->info6.driver_name, "Ricoh Aficio MP 5000 PS", "driver_name");
+ torture_assert_str_equal(tctx, r->out.info->info6.architecture, "Windows x64", "architecture");
+ torture_assert_str_equal(tctx, r->out.info->info6.driver_path, "\\\\RH-W2K8R2\\print$\\x64\\3\\PSCRIPT5.DLL", "driver_path");
+ torture_assert_str_equal(tctx, r->out.info->info6.data_file, "\\\\RH-W2K8R2\\print$\\x64\\3\\RI1403E3.PPD", "data_file");
+ torture_assert_str_equal(tctx, r->out.info->info6.config_file, "\\\\RH-W2K8R2\\print$\\x64\\3\\PS5UI.DLL", "config_file");
+ torture_assert_str_equal(tctx, r->out.info->info6.help_file, "\\\\RH-W2K8R2\\print$\\x64\\3\\PSCRIPT.HLP", "help_file");
+ torture_assert_str_equal(tctx, r->out.info->info6.help_file, "\\\\RH-W2K8R2\\print$\\x64\\3\\PSCRIPT.HLP", "help_file");
+ torture_assert_str_equal(tctx, r->out.info->info6.dependent_files[0], "\\\\RH-W2K8R2\\print$\\x64\\3\\PSCRIPT.NTF", "dependent_files[0]");
+ torture_assert_str_equal(tctx, r->out.info->info6.dependent_files[1], "\\\\RH-W2K8R2\\print$\\x64\\3\\PS_SCHM.GDL", "dependent_files[1]");
+ torture_assert_str_equal(tctx, r->out.info->info6.dependent_files[2], "\\\\RH-W2K8R2\\print$\\x64\\3\\RICOHPS7.INI", "dependent_files[2]");
+ torture_assert_str_equal(tctx, r->out.info->info6.dependent_files[3], "\\\\RH-W2K8R2\\print$\\x64\\3\\RIPSUI7.DLL", "dependent_files[3]");
+ torture_assert_str_equal(tctx, r->out.info->info6.dependent_files[4], "\\\\RH-W2K8R2\\print$\\x64\\3\\RIPSRES7.DLL", "dependent_files[4]");
+ torture_assert_str_equal(tctx, r->out.info->info6.dependent_files[5], "\\\\RH-W2K8R2\\print$\\x64\\3\\RICFG7.XML", "dependent_files[5]");
+ torture_assert(tctx, r->out.info->info6.monitor_name == NULL, "monitor_name");
+ torture_assert(tctx, r->out.info->info6.default_datatype == NULL, "default_datatype");
+ torture_assert(tctx, r->out.info->info6.previous_names == NULL, "previous_names");
+ /* driver_date : Wed Jun 21 02:00:00 2006 CEST */
+ torture_assert_u64_equal(tctx, r->out.info->info6.driver_version, 0x000600011db04001ULL, "driver_version");
+ torture_assert_str_equal(tctx, r->out.info->info6.manufacturer_name, "Ricoh", "manufacturer_name");
+ torture_assert_str_equal(tctx, r->out.info->info6.manufacturer_url, "http://go.microsoft.com/fwlink/?LinkID=47&prd=10798&sbp=Printers", "manufacturer_url");
+ torture_assert_str_equal(tctx, r->out.info->info6.hardware_id, "ricohricoh_aficio_mp5063", "hardware_id");
+ torture_assert_str_equal(tctx, r->out.info->info6.provider, "Ricoh", "provider");
+ torture_assert_int_equal(tctx, *r->out.needed, 1160, "needed");
+ torture_assert_int_equal(tctx, *r->out.server_major_version, 0, "server_major_version");
+ torture_assert_int_equal(tctx, *r->out.server_minor_version, 0, "server_minor_version");
+ torture_assert_werr_ok(tctx, r->out.result, "result");
+
+ return true;
+}
+
+static const uint8_t openprinterex_64_req_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00,
+ 0x38, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x35, 0x00,
+ 0x5c, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x23, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00,
+ 0x41, 0x00, 0x5c, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00
+};
+
+static const uint8_t setprinter_64_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x13, 0xbe, 0x52, 0x2a, 0xe4, 0x67, 0xe8, 0x45,
+ 0x8b, 0xb2, 0xd4, 0x15, 0x55, 0xff, 0xbf, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00,
+ 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00,
+ 0x33, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00,
+ 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x2e, 0x00,
+ 0x37, 0x00, 0x35, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x50, 0x00, 0x20, 0x00,
+ 0x43, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00,
+ 0x4c, 0x00, 0x61, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x4a, 0x00,
+ 0x65, 0x00, 0x74, 0x00, 0x20, 0x00, 0x32, 0x00, 0x35, 0x00, 0x30, 0x00,
+ 0x30, 0x00, 0x20, 0x00, 0x50, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x36, 0x00,
+ 0x20, 0x00, 0x43, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00,
+ 0x20, 0x00, 0x44, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x50, 0x00, 0x54, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00,
+ 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, 0x00,
+ 0x65, 0x00, 0x6e, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00,
+ 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x50, 0x00, 0x6f, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x20, 0x00, 0x50, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00,
+ 0x20, 0x00, 0x64, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x65, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x6c, 0x00,
+ 0x61, 0x00, 0x20, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x70, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x41, 0x00, 0x57, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getcoreprinterdrivers_64_req_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00,
+ 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00,
+ 0x38, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x38, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00,
+ 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x78, 0x00, 0x36, 0x00,
+ 0x34, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x44, 0x00,
+ 0x32, 0x00, 0x30, 0x00, 0x45, 0x00, 0x41, 0x00, 0x33, 0x00, 0x37, 0x00,
+ 0x32, 0x00, 0x2d, 0x00, 0x44, 0x00, 0x44, 0x00, 0x33, 0x00, 0x35, 0x00,
+ 0x2d, 0x00, 0x34, 0x00, 0x39, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2d, 0x00,
+ 0x39, 0x00, 0x45, 0x00, 0x44, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x41, 0x00,
+ 0x36, 0x00, 0x33, 0x00, 0x33, 0x00, 0x35, 0x00, 0x41, 0x00, 0x46, 0x00,
+ 0x45, 0x00, 0x37, 0x00, 0x39, 0x00, 0x46, 0x00, 0x30, 0x00, 0x7d, 0x00,
+ 0x00, 0x00, 0x7b, 0x00, 0x44, 0x00, 0x32, 0x00, 0x30, 0x00, 0x45, 0x00,
+ 0x41, 0x00, 0x33, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x44, 0x00,
+ 0x44, 0x00, 0x33, 0x00, 0x35, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x39, 0x00,
+ 0x35, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x39, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x38, 0x00, 0x2d, 0x00, 0x41, 0x00, 0x36, 0x00, 0x33, 0x00, 0x33, 0x00,
+ 0x35, 0x00, 0x41, 0x00, 0x46, 0x00, 0x45, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x46, 0x00, 0x31, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x44, 0x00,
+ 0x32, 0x00, 0x30, 0x00, 0x45, 0x00, 0x41, 0x00, 0x33, 0x00, 0x37, 0x00,
+ 0x32, 0x00, 0x2d, 0x00, 0x44, 0x00, 0x44, 0x00, 0x33, 0x00, 0x35, 0x00,
+ 0x2d, 0x00, 0x34, 0x00, 0x39, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2d, 0x00,
+ 0x39, 0x00, 0x45, 0x00, 0x44, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x41, 0x00,
+ 0x36, 0x00, 0x33, 0x00, 0x33, 0x00, 0x35, 0x00, 0x41, 0x00, 0x46, 0x00,
+ 0x45, 0x00, 0x37, 0x00, 0x39, 0x00, 0x46, 0x00, 0x32, 0x00, 0x7d, 0x00,
+ 0x00, 0x00, 0x7b, 0x00, 0x44, 0x00, 0x32, 0x00, 0x30, 0x00, 0x45, 0x00,
+ 0x41, 0x00, 0x33, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x44, 0x00,
+ 0x44, 0x00, 0x33, 0x00, 0x35, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x39, 0x00,
+ 0x35, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x39, 0x00, 0x45, 0x00, 0x44, 0x00,
+ 0x38, 0x00, 0x2d, 0x00, 0x41, 0x00, 0x36, 0x00, 0x33, 0x00, 0x33, 0x00,
+ 0x35, 0x00, 0x41, 0x00, 0x46, 0x00, 0x45, 0x00, 0x37, 0x00, 0x39, 0x00,
+ 0x46, 0x00, 0x33, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getcoreprinterdrivers_req_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x47, 0x00, 0x44, 0x00,
+ 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00,
+ 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x63, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x6e, 0x00,
+ 0x6f, 0x00, 0x6e, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x65, 0x00, 0x6e, 0x00,
+ 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t getcoreprinterdrivers_rep_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x07, 0x80,
+};
+
+static const uint8_t getcoreprinterdrivers_req_data_unknown_guid[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x47, 0x00, 0x44, 0x00,
+ 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00, 0x52, 0x00, 0x32, 0x00,
+ 0x44, 0x00, 0x43, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00,
+ 0x78, 0x00, 0x36, 0x00, 0x34, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x62, 0x00, 0x38, 0x00, 0x62, 0x00,
+ 0x37, 0x00, 0x33, 0x00, 0x61, 0x00, 0x36, 0x00, 0x34, 0x00, 0x2d, 0x00,
+ 0x65, 0x00, 0x35, 0x00, 0x66, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x34, 0x00,
+ 0x65, 0x00, 0x65, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x61, 0x00, 0x62, 0x00,
+ 0x61, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x66, 0x00, 0x39, 0x00, 0x38, 0x00,
+ 0x64, 0x00, 0x61, 0x00, 0x64, 0x00, 0x32, 0x00, 0x33, 0x00, 0x32, 0x00,
+ 0x37, 0x00, 0x38, 0x00, 0x32, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+static const uint8_t getcoreprinterdrivers_rep_data_unknown_guid[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x07, 0x80
+};
+
+static const uint8_t setjobnamedproperty_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x50, 0xdf, 0xe4, 0xce, 0x1a, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x53, 0x00, 0x70, 0x00,
+ 0x6f, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x46, 0x00, 0x69, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x73, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x59, 0x00, 0x50, 0x00, 0x45, 0x00, 0x5f, 0x00, 0x50, 0x00,
+ 0x44, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x4b, 0x00,
+ 0x4e, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x4e, 0x00, 0x00, 0x00
+};
+
+static bool setjobnamedproperty_req_check(struct torture_context *tctx,
+ struct spoolss_SetJobNamedProperty *r)
+{
+ /* FIXME hPrinter */
+ torture_assert_int_equal(tctx, r->in.JobId, 0x00000005, "JobId");
+ torture_assert(tctx, r->in.pProperty, "pProperty");
+ torture_assert_str_equal(tctx, r->in.pProperty->propertyName, SPLFILE_CONTENT_TYPE_PROP_NAME, "propertyName");
+ torture_assert_int_equal(tctx, r->in.pProperty->propertyValue.ePropertyType, kRpcPropertyTypeString, "ePropertyType");
+ torture_assert_str_equal(tctx, r->in.pProperty->propertyValue.value.propertyString, SPLFILE_CONTENT_TYPE_PDL_UNKNOWN, "propertyString");
+
+ return true;
+}
+
+static const uint8_t setprinter_level_3_xpsp3_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2b, 0x55, 0x94, 0xbe, 0x50, 0x28, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0xd1, 0xe9, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x02, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0xa0, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x00, 0x09, 0x18, 0x00, 0x30, 0x00, 0x0f, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x24, 0x00, 0x08, 0x00, 0x02, 0x00, 0x01, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0xa4, 0xc0, 0x7d, 0x3b,
+ 0xcc, 0xce, 0x29, 0xa7, 0xd1, 0xc7, 0xe9, 0xd4, 0x50, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x0f, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, 0x00,
+ 0x00, 0x09, 0x18, 0x00, 0x30, 0x00, 0x0f, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, 0x02, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool setprinter_level_3_xpsp3_req_check(struct torture_context *tctx,
+ struct spoolss_SetPrinter *r)
+{
+ struct GUID guid;
+
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string("0000053c-0000-0000-2b55-94be50280000", &guid),
+ "failed to parse GUID");
+ torture_assert_int_equal(tctx, r->in.handle->handle_type, 0, "handle_type");
+ torture_assert_guid_equal(tctx, r->in.handle->uuid, guid, "handle.uuid");
+
+ torture_assert(tctx, r->in.info_ctr, "info_ctr");
+ torture_assert_int_equal(tctx, r->in.info_ctr->level, 3, "level");
+ torture_assert_int_equal(tctx, r->in.info_ctr->info.info3->sec_desc_ptr, 0x06e9d108, "sec_desc_ptr");
+
+ torture_assert(tctx, r->in.devmode_ctr, "devmode_ctr");
+ torture_assert_int_equal(tctx, r->in.devmode_ctr->_ndr_size, 0, "_ndr_size");
+ torture_assert(tctx, r->in.devmode_ctr->devmode == NULL, "devmode");
+
+ torture_assert(tctx, r->in.secdesc_ctr, "secdesc_ctr");
+ torture_assert_int_equal(tctx, r->in.secdesc_ctr->sd_size, 0x000000b4, "sd_size");
+ torture_assert_int_equal(tctx, r->in.secdesc_ctr->sd->revision, SECURITY_DESCRIPTOR_REVISION_1, "revision");
+ torture_assert_int_equal(tctx, r->in.secdesc_ctr->sd->type, 0x8004, "type");
+ torture_assert(tctx, r->in.secdesc_ctr->sd, "sd");
+ torture_assert(tctx, r->in.secdesc_ctr->sd->owner_sid == NULL, "owner_sid");
+ torture_assert(tctx, r->in.secdesc_ctr->sd->group_sid == NULL, "group_sid");
+ torture_assert(tctx, r->in.secdesc_ctr->sd->sacl == NULL, "sacl");
+ torture_assert(tctx, r->in.secdesc_ctr->sd->dacl, "dacl");
+
+ return true;
+}
+
+struct torture_suite *ndr_spoolss_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "spoolss");
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_OpenPrinterEx, openprinterex_req_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_OpenPrinterEx, openprinterex_resp_data, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncOpenPrinter, openprinterex_req_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncOpenPrinter, openprinterex_resp_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_OpenPrinterEx, openprinterex_devmode_req_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncOpenPrinter, openprinterex_devmode_req_data, NDR_IN, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_ClosePrinter, closeprinter_req_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_ClosePrinter, closeprinter_resp_data, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncClosePrinter, closeprinter_req_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncClosePrinter, closeprinter_resp_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetPrinter, getprinter_req_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetPrinter, getprinter_resp_data, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetPrinter, getprinter_req_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetPrinter, getprinter_resp_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetPrinterData, getprinterdata_req_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_io_test(suite, spoolss_GetPrinterData, getprinterdata_req_data, getprinterdata_resp_data, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetPrinterData, getprinterdata_req_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, winspool_AsyncGetPrinterData, getprinterdata_req_data, getprinterdata_resp_data, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_ReplyOpenPrinter, replyopenprinter_req_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_ReplyOpenPrinter, replyopenprinter_resp_data, NDR_OUT, NULL );
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_ReplyClosePrinter, replycloseprinter_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_ReplyClosePrinter, replycloseprinter_out_data, NDR_OUT, NULL );
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_RemoteFindFirstPrinterChangeNotifyEx, RFFPCNEX_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_RemoteFindFirstPrinterChangeNotifyEx, RFFPCNEX_out_data, NDR_OUT, NULL );
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_RouterRefreshPrinterChangeNotify, RRPCN_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_RouterRefreshPrinterChangeNotify, RRPCN_out_data, NDR_OUT, NULL );
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumForms, enumforms_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumForms, enumforms_out_data, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumForms, enumforms_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumForms, enumforms_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumPrinterDataEx, enumprinterdataex_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumPrinterDataEx, enumprinterdataex_out_data, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumPrinterDataEx, enumprinterdataex_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumPrinterDataEx, enumprinterdataex_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_io_test(suite, spoolss_EnumPrinterDataEx, enumprinterdataex_w2k8r2_in_data, enumprinterdataex_w2k8r2_out_data, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, winspool_AsyncEnumPrinterDataEx, enumprinterdataex_w2k8r2_in_data, enumprinterdataex_w2k8r2_out_data, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumPrinterKey, enumprinterkey_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumPrinterKey, enumprinterkey_out_data, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumPrinterKey, enumprinterkey_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumPrinterKey, enumprinterkey_out_data, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumPrinterKey, enumprinterkey_in_data2, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_EnumPrinterKey, enumprinterkey_out_data2, NDR_OUT, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumPrinterKey, enumprinterkey_in_data2, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncEnumPrinterKey, enumprinterkey_out_data2, NDR_OUT, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_FindClosePrinterNotify, FCPN_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_FindClosePrinterNotify, FCPN_out_data, NDR_OUT, NULL );
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetPrinterDriverDirectory, getprinterdriverdir_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_io_test(suite, spoolss_GetPrinterDriverDirectory, getprinterdriverdir_in_data, getprinterdriverdir_out_data, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetPrinterDriverDirectory, getprinterdriverdir_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, winspool_AsyncGetPrinterDriverDirectory, getprinterdriverdir_in_data, getprinterdriverdir_out_data, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_AddPrinterDriverEx, addprinterdriverex_in_data, NDR_IN, NULL );
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncAddPrinterDriver, addprinterdriverex_in_data, NDR_IN, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetPrinterDriver2, getprinterdriver2_in_data, NDR_IN, getprinterdriver2_in_check);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetPrinterDriver, getprinterdriver2_in_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, spoolss_GetPrinterDriver2, getprinterdriver2_in_data, getprinterdriver2_out_data, getprinterdriver2_out_check);
+ torture_suite_add_ndr_pull_io_test(suite, winspool_AsyncGetPrinterDriver, getprinterdriver2_in_data, getprinterdriver2_out_data, NULL);
+
+ torture_suite_add_ndr_pull_fn_test_flags(suite, spoolss_OpenPrinterEx, openprinterex_64_req_data, NDR_IN, LIBNDR_FLAG_NDR64, NULL);
+ torture_suite_add_ndr_pull_fn_test_flags(suite, winspool_AsyncOpenPrinter, openprinterex_64_req_data, NDR_IN, LIBNDR_FLAG_NDR64, NULL);
+
+ torture_suite_add_ndr_pull_fn_test_flags(suite, spoolss_SetPrinter, setprinter_64_req_data, NDR_IN, LIBNDR_FLAG_NDR64, NULL);
+ torture_suite_add_ndr_pull_fn_test_flags(suite, winspool_AsyncSetPrinter, setprinter_64_req_data, NDR_IN, LIBNDR_FLAG_NDR64, NULL);
+
+ torture_suite_add_ndr_pull_fn_test_flags(suite, spoolss_GetCorePrinterDrivers, getcoreprinterdrivers_64_req_data, NDR_IN, LIBNDR_FLAG_NDR64, NULL);
+ torture_suite_add_ndr_pull_fn_test_flags(suite, winspool_AsyncGetCorePrinterDrivers, getcoreprinterdrivers_64_req_data, NDR_IN, LIBNDR_FLAG_NDR64, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetCorePrinterDrivers, getcoreprinterdrivers_req_data, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetCorePrinterDrivers, getcoreprinterdrivers_req_data, NDR_IN, NULL);
+
+ torture_suite_add_ndr_pull_io_test(suite, spoolss_GetCorePrinterDrivers, getcoreprinterdrivers_req_data, getcoreprinterdrivers_rep_data, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, winspool_AsyncGetCorePrinterDrivers, getcoreprinterdrivers_req_data, getcoreprinterdrivers_rep_data, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_GetCorePrinterDrivers, getcoreprinterdrivers_req_data_unknown_guid, NDR_IN, NULL);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncGetCorePrinterDrivers, getcoreprinterdrivers_req_data_unknown_guid, NDR_IN, NULL);
+
+ torture_suite_add_ndr_pull_io_test(suite, spoolss_GetCorePrinterDrivers, getcoreprinterdrivers_req_data_unknown_guid, getcoreprinterdrivers_rep_data_unknown_guid, NULL);
+ torture_suite_add_ndr_pull_io_test(suite, winspool_AsyncGetCorePrinterDrivers, getcoreprinterdrivers_req_data_unknown_guid, getcoreprinterdrivers_rep_data_unknown_guid, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_SetJobNamedProperty, setjobnamedproperty_req_data, NDR_IN, setjobnamedproperty_req_check);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncSetJobNamedProperty, setjobnamedproperty_req_data, NDR_IN, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, spoolss_SetPrinter, setprinter_level_3_xpsp3_req_data, NDR_IN, setprinter_level_3_xpsp3_req_check);
+ torture_suite_add_ndr_pull_fn_test(suite, winspool_AsyncSetPrinter, setprinter_level_3_xpsp3_req_data, NDR_IN, NULL);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/string.c b/source4/torture/ndr/string.c
new file mode 100644
index 0000000..16d3fc3
--- /dev/null
+++ b/source4/torture/ndr/string.c
@@ -0,0 +1,223 @@
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "torture/ndr/proto.h"
+#include "../lib/util/dlinklist.h"
+#include "param/param.h"
+
+static const char *ascii = "ascii";
+/* the following is equivalent to "kamelåså öäüÿéèóò" in latin1 */
+static const char latin1[] = { 0x6b, 0x61, 0x6d, 0x65, 0x6c, 0xe5, 0x73,
+ 0xe5, 0x20, 0xF6, 0xE4, 0xFC, 0xFF, 0xE9,
+ 0xE8, 0xF3, 0xF2, 0x00 };
+/* the following is equivalent to "kamelåså ☺☺☺ öäüÿéèóò" in utf8 */
+static const char utf8[] = { 0x6b, 0x61, 0x6d, 0x65, 0x6c, 0xc3, 0xa5,
+ 0x73, 0xc3, 0xa5, 0x20, 0xE2, 0x98, 0xBA,
+ 0xE2, 0x98, 0xBA, 0xE2, 0x98, 0xBA, 0x20,
+ 0xc3, 0xb6, 0xc3, 0xa4, 0xc3, 0xbc, 0xc3,
+ 0xbf, 0xc3, 0xa9, 0xc3, 0xa8, 0xc3, 0xb3,
+ 0xc3, 0xb2, 0x00 };
+
+/* purely for convenience */
+static const libndr_flags fl_ascii_null = LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM;
+static const libndr_flags fl_ascii_noterm = LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING;
+static const libndr_flags fl_utf8_null = LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM;
+static const libndr_flags fl_raw8_null = LIBNDR_FLAG_STR_RAW8|LIBNDR_FLAG_STR_NULLTERM;
+
+static bool
+test_ndr_push_string (struct torture_context *tctx, const char *string,
+ libndr_flags flags, enum ndr_err_code exp_ndr_err,
+ bool strcmp_pass)
+{
+ TALLOC_CTX *mem_ctx;
+ struct ndr_push *ndr;
+ enum ndr_err_code err;
+
+ torture_comment(tctx,
+ "test_ndr_push_string %s flags 0x%"PRI_LIBNDR_FLAGS" expecting "
+ "err 0x%x and strcmp %s\n", string, flags, exp_ndr_err,
+ strcmp_pass?"pass":"fail");
+ if (exp_ndr_err != NDR_ERR_SUCCESS) {
+ torture_comment(tctx, "(ignore any Conversion error) ");
+ }
+
+ mem_ctx = talloc_named (NULL, 0, "test_ndr_push_string");
+ ndr = ndr_push_init_ctx(mem_ctx);
+ ndr_set_flags (&ndr->flags, flags);
+
+ err = ndr_push_string (ndr, NDR_SCALARS, string);
+ torture_assert_ndr_err_equal(tctx, err, exp_ndr_err,
+ "ndr_push_string: unexpected return code");
+
+ if (exp_ndr_err == NDR_ERR_SUCCESS) {
+ uint32_t expected_offset = strlen(string);
+
+ if (flags & LIBNDR_FLAG_STR_NULLTERM) {
+ expected_offset += 1;
+ }
+
+ torture_assert_int_equal(tctx,
+ ndr->offset, expected_offset,
+ "ndr_push_string: invalid length");
+
+ torture_assert(tctx, ndr->data != NULL,
+ "ndr_push_string: succeeded but NULL data");
+
+ torture_assert(tctx,
+ strcmp_pass == !strcmp(string, (char *)ndr->data),
+ "ndr_push_string: post-push strcmp");
+
+ }
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+static bool
+test_ndr_pull_string (struct torture_context *tctx, const char *string,
+ libndr_flags flags, enum ndr_err_code exp_ndr_err,
+ bool strcmp_pass)
+{
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB blob;
+ struct ndr_pull *ndr;
+ enum ndr_err_code err;
+ const char *result = NULL;
+
+ torture_comment(tctx,
+ "test_ndr_pull_string '%s' flags 0x%"PRI_LIBNDR_FLAGS" expecting "
+ "err 0x%x and strcmp %s\n", string, flags, exp_ndr_err,
+ strcmp_pass?"pass":"fail");
+ if (exp_ndr_err != NDR_ERR_SUCCESS) {
+ torture_comment(tctx, "(ignore any Conversion error) ");
+ }
+
+ mem_ctx = talloc_named (NULL, 0, "test_ndr_pull_string");
+
+ blob = data_blob_string_const(string);
+ ndr = ndr_pull_init_blob(&blob, mem_ctx);
+ torture_assert(mem_ctx, ndr, "ndr init failed");
+ ndr_set_flags (&ndr->flags, flags);
+
+ err = ndr_pull_string (ndr, NDR_SCALARS, &result);
+ torture_assert_ndr_err_equal(tctx, err, exp_ndr_err,
+ "ndr_pull_string: unexpected return code");
+
+ if (exp_ndr_err == NDR_ERR_SUCCESS) {
+ torture_assert(tctx, result != NULL,
+ "ndr_pull_string: NULL data");
+ torture_assert(tctx, strcmp_pass == !strcmp(string, result),
+ "ndr_pull_string: post-pull strcmp");
+ torture_assert(tctx, result != NULL,
+ "ndr_pull_string succeeded but result NULL");
+ }
+
+ talloc_free(mem_ctx);
+ return true;
+}
+
+static bool
+torture_ndr_string(struct torture_context *torture)
+{
+ const char *saved_dos_cp = talloc_strdup(torture, lpcfg_dos_charset(torture->lp_ctx));
+
+ torture_assert(torture,
+ test_ndr_push_string (torture, ascii, fl_ascii_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string(ASCII, STR_ASCII|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, ascii, fl_ascii_noterm,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string(ASCII, STR_ASCII|STR_NOTERM|REMAINING)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, "", fl_ascii_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string('', STR_ASCII|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, "", fl_ascii_noterm,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string('', STR_ASCII|STR_NOTERM|REMAINING)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, utf8, fl_utf8_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string(UTF8, STR_UTF8|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, utf8, fl_raw8_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string(UTF8, STR_RAW8|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, latin1, fl_raw8_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_push_string(LATIN1, STR_RAW8|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, utf8, fl_ascii_null,
+ NDR_ERR_CHARCNV, false),
+ "test_ndr_push_string(UTF8, STR_ASCII|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_push_string (torture, latin1, fl_ascii_null,
+ NDR_ERR_CHARCNV, false),
+ "test_ndr_push_string(LATIN1, STR_ASCII|STR_NULL)");
+
+
+ torture_assert(torture,
+ test_ndr_pull_string (torture, ascii, fl_ascii_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_pull_string(ASCII, STR_ASCII|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_pull_string (torture, utf8, fl_utf8_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_pull_string(UTF8, STR_UTF8|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_pull_string (torture, utf8, fl_raw8_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_pull_string(UTF8, STR_RAW8|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_pull_string (torture, latin1, fl_raw8_null,
+ NDR_ERR_SUCCESS, true),
+ "test_ndr_pull_string(LATIN1, STR_RAW8|STR_NULL)");
+
+ /* Depending on runtime config, the behavior of ndr_pull_string on
+ * incorrect combinations of strings and flags (latin1 with ASCII
+ * flags, for example) may differ; it may return NDR_ERR_CHARCNV, or
+ * it may return NDR_ERR_SUCCESS but with a string that has been
+ * mutilated, depending on the value of "dos charset". We test for
+ * both cases here. */
+
+ lpcfg_do_global_parameter(torture->lp_ctx, "dos charset", "ASCII");
+ reload_charcnv(torture->lp_ctx);
+
+ torture_assert(torture,
+ test_ndr_pull_string (torture, latin1, fl_ascii_null,
+ NDR_ERR_CHARCNV, false),
+ "test_ndr_pull_string(LATIN1, STR_ASCII|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_pull_string (torture, utf8, fl_ascii_null,
+ NDR_ERR_CHARCNV, false),
+ "test_ndr_pull_string(UTF8, STR_ASCII|STR_NULL)");
+
+ lpcfg_do_global_parameter(torture->lp_ctx, "dos charset", "CP850");
+ reload_charcnv(torture->lp_ctx);
+
+ torture_assert(torture,
+ test_ndr_pull_string (torture, latin1, fl_ascii_null,
+ NDR_ERR_SUCCESS, false),
+ "test_ndr_pull_string(LATIN1, STR_ASCII|STR_NULL)");
+ torture_assert(torture,
+ test_ndr_pull_string (torture, utf8, fl_ascii_null,
+ NDR_ERR_SUCCESS, false),
+ "test_ndr_pull_string(UTF8, STR_ASCII|STR_NULL)");
+
+ lpcfg_do_global_parameter(torture->lp_ctx, "dos charset", saved_dos_cp);
+ reload_charcnv(torture->lp_ctx);
+
+ return true;
+}
+
+struct torture_suite *ndr_string_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ndr_string");
+
+ torture_suite_add_simple_test(suite, "ndr_string", torture_ndr_string);
+ suite->description = talloc_strdup(suite, "NDR - string-conversion focused push/pull tests");
+
+ return suite;
+}
diff --git a/source4/torture/ndr/svcctl.c b/source4/torture/ndr/svcctl.c
new file mode 100644
index 0000000..6592bed
--- /dev/null
+++ b/source4/torture/ndr/svcctl.c
@@ -0,0 +1,88 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for svcctl ndr operations
+
+ Copyright (C) Guenther Deschner 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+#include "torture/ndr/proto.h"
+#include "param/param.h"
+
+static const uint8_t svcctl_ChangeServiceConfigW_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xcd, 0x94, 0x05, 0x40, 0x30, 0x28, 0x00, 0x49,
+ 0x8d, 0xe4, 0x8e, 0x85, 0xb7, 0x19, 0x5c, 0x83, 0x10, 0x01, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool svcctl_ChangeServiceConfigW_req_check(struct torture_context *tctx,
+ struct svcctl_ChangeServiceConfigW *r)
+{
+ struct policy_handle handle = { 0 };
+ GUID_from_string("400594cd-2830-4900-8de4-8e85b7195c83", &handle.uuid);
+
+ torture_assert_guid_equal(tctx, r->in.handle->uuid, handle.uuid, "handle");
+ torture_assert_u32_equal(tctx, r->in.type, 0x00000110, "type");
+ torture_assert_u32_equal(tctx, r->in.start_type, SVCCTL_AUTO_START, "start_type");
+ torture_assert_u32_equal(tctx, r->in.error_control, SVCCTL_SVC_ERROR_NORMAL, "error_control");
+ torture_assert_str_equal(tctx, r->in.binary_path, NULL, "binary_path");
+ torture_assert_str_equal(tctx, r->in.load_order_group, NULL, "load_order_group");
+ torture_assert(tctx, r->in.tag_id == NULL, "tag_id");
+ torture_assert_str_equal(tctx, r->in.dependencies, NULL, "dependencies");
+ torture_assert_u32_equal(tctx, r->in.dwDependSize, 0, "dwDependSize");
+ torture_assert_str_equal(tctx, r->in.service_start_name, NULL, "service_start_name");
+ torture_assert_str_equal(tctx, r->in.password, NULL, "password");
+ torture_assert_u32_equal(tctx, r->in.dwPwSize, 0, "dwPwSize");
+ torture_assert_str_equal(tctx, r->in.display_name, NULL, "display_name");
+
+ return true;
+}
+
+static const uint8_t svcctl_ChangeServiceConfigW_rep_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool svcctl_ChangeServiceConfigW_rep_check(struct torture_context *tctx,
+ struct svcctl_ChangeServiceConfigW *r)
+{
+ torture_assert(tctx, r->out.tag_id == NULL, "tag_id");
+ torture_assert_werr_ok(tctx, r->out.result, "result");
+
+ return true;
+}
+
+struct torture_suite *ndr_svcctl_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "svcctl");
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ svcctl_ChangeServiceConfigW,
+ svcctl_ChangeServiceConfigW_req_data,
+ NDR_IN,
+ svcctl_ChangeServiceConfigW_req_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ svcctl_ChangeServiceConfigW,
+ svcctl_ChangeServiceConfigW_rep_data,
+ NDR_OUT,
+ svcctl_ChangeServiceConfigW_rep_check);
+ return suite;
+}
diff --git a/source4/torture/ndr/winreg.c b/source4/torture/ndr/winreg.c
new file mode 100644
index 0000000..4eaff8d
--- /dev/null
+++ b/source4/torture/ndr/winreg.c
@@ -0,0 +1,620 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for winreg ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_winreg.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t closekey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x1d, 0xd8, 0xd7, 0xaa, 0x8d, 0x6c, 0x3f, 0x48,
+ 0xa7, 0x1e, 0x02, 0x6a, 0x47, 0xf6, 0x7b, 0xae
+};
+
+static bool closekey_in_check(struct torture_context *tctx,
+ struct winreg_CloseKey *ck)
+{
+ torture_assert(tctx, ck->in.handle != NULL, "handle invalid");
+ torture_assert_int_equal(tctx, ck->in.handle->handle_type, 0, "handle type");
+ return true;
+}
+
+const static uint8_t closekey_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool closekey_out_check(struct torture_context *tctx,
+ struct winreg_CloseKey *ck)
+{
+ torture_assert_int_equal(tctx, ck->out.handle->handle_type, 0, "handle type");
+ torture_assert_werr_ok(tctx, ck->out.result, "return code");
+ return true;
+}
+
+static const uint8_t OpenHKLM_In[] = {
+ 0x01, 0x00, 0x00, 0x00, 0xe0, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool openhklm_in_check(struct torture_context *tctx,
+ struct winreg_OpenHKLM *r)
+{
+ torture_assert(tctx, r->in.system_name != NULL, "system name pointer");
+ torture_assert_int_equal(tctx, *r->in.system_name, 34016, "system name");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x02000000, "access mask");
+ return true;
+}
+
+static const uint8_t openhklm_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool openhklm_out_check(struct torture_context *tctx,
+ struct winreg_OpenHKLM *r)
+{
+ torture_assert(tctx, r->out.handle != NULL, "handle pointer");
+ torture_assert_int_equal(tctx, r->out.handle->handle_type, 0, "handle_type");
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t createkey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3, 0x16, 0x00, 0x16, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x73, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool createkey_in_check(struct torture_context *tctx,
+ struct winreg_CreateKey *r)
+{
+ torture_assert_str_equal(tctx, r->in.name.name, "spottyfoot", "name");
+ torture_assert(tctx, r->in.keyclass.name == NULL, "keyclass");
+ torture_assert_int_equal(tctx, r->in.options, 0, "option");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x2000000, "access mask");
+ torture_assert(tctx, r->in.secdesc == NULL, "secdesc");
+ torture_assert(tctx, r->in.action_taken == NULL, "action_taken");
+
+ return true;
+}
+
+static const uint8_t createkey_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0x00, 0x00, 0x00
+};
+
+static bool createkey_out_check(struct torture_context *tctx,
+ struct winreg_CreateKey *r)
+{
+ torture_assert(tctx, GUID_all_zero(&r->out.new_handle->uuid), "new_handle");
+ torture_assert(tctx, r->out.action_taken == NULL, "action_taken pointer");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAMETER,
+ "return code");
+
+ return true;
+}
+
+static const uint8_t enumvalue_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xae, 0x1a, 0xbd, 0xbe, 0xbb, 0x94, 0xce, 0x4e,
+ 0xba, 0xcf, 0x56, 0xeb, 0xe5, 0xb3, 0x6c, 0xa3, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool enumvalue_in_check(struct torture_context *tctx,
+ struct winreg_EnumValue *r)
+{
+ torture_assert_int_equal(tctx, r->in.enum_index, 5, "enum index");
+ torture_assert(tctx, r->in.type != NULL, "type pointer");
+ torture_assert_int_equal(tctx, *r->in.type, 0, "type");
+ torture_assert_int_equal(tctx, *r->in.size, 65535, "size");
+ torture_assert_int_equal(tctx, *r->in.length, 0, "length");
+ torture_assert_int_equal(tctx, r->in.name->size, 512, "name size");
+ torture_assert_int_equal(tctx, r->in.name->length, 0, "name length");
+
+ return true;
+}
+
+static const uint8_t enumvalue_out_data[] = {
+ 0x12, 0x00, 0x00, 0x02, 0x28, 0x91, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4f, 0x00,
+ 0x4d, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00, 0x54, 0x00, 0x48, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x8c, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xe0, 0x00, 0x0c, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x63, 0x00,
+ 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x73, 0x00,
+ 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x53, 0x00,
+ 0x65, 0x00, 0x74, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00,
+ 0x73, 0x00, 0x5c, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6d, 0x00, 0x69, 0x00,
+ 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00,
+ 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00, 0xf0, 0x8c, 0x07, 0x00,
+ 0x4c, 0x00, 0x00, 0x00, 0xf8, 0x8c, 0x07, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool enumvalue_out_check(struct torture_context *tctx,
+ struct winreg_EnumValue *r)
+{
+ torture_assert_int_equal(tctx, r->out.name->size, 512, "name size");
+ torture_assert_int_equal(tctx, r->out.name->length, 18, "name length");
+ torture_assert_str_equal(tctx, r->out.name->name, "HOMEPATH", "name");
+ torture_assert_int_equal(tctx, *r->out.type, 1, "type");
+ torture_assert_int_equal(tctx, *r->out.size, 76, "size");
+ torture_assert_int_equal(tctx, *r->out.length, 76, "length");
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+
+ return true;
+}
+
+unsigned char enumvalue_in_data2[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xda, 0x45, 0x9c, 0xed, 0xe2, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0xcc, 0xf9, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xf9, 0x06, 0x00,
+ 0x39, 0xa6, 0x07, 0x00, 0x00, 0xc4, 0x04, 0x01, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xf9, 0x06, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x94, 0xf9, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t queryvalue_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xae, 0x1a, 0xbd, 0xbe, 0xbb, 0x94, 0xce, 0x4e,
+ 0xba, 0xcf, 0x56, 0xeb, 0xe5, 0xb3, 0x6c, 0xa3, 0x12, 0x00, 0x12, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x45, 0x00,
+ 0x50, 0x00, 0x41, 0x00, 0x54, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool queryvalue_in_check(struct torture_context *tctx,
+ struct winreg_QueryValue *r)
+{
+ torture_assert_str_equal(tctx, r->in.value_name->name, "HOMEPATH", "name");
+ torture_assert_int_equal(tctx, *r->in.type, 0, "type");
+ torture_assert_int_equal(tctx, *r->in.data_size, 4095, "size");
+ torture_assert_int_equal(tctx, *r->in.data_length, 0, "length");
+ torture_assert(tctx, r->in.data == NULL, "data pointer");
+
+ return true;
+}
+
+static const uint8_t queryvalue_out_data[] = {
+ 0xd8, 0xf5, 0x0b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe4, 0xf5, 0x0b, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xec, 0xf5, 0x0b, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool queryvalue_out_check(struct torture_context *tctx,
+ struct winreg_QueryValue *r)
+{
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ torture_assert_int_equal(tctx, *r->out.type, 1, "type");
+ torture_assert(tctx, r->out.data == NULL, "data pointer");
+ torture_assert_int_equal(tctx, *r->out.data_size, 76, "size");
+ torture_assert_int_equal(tctx, *r->out.data_length, 0, "length");
+
+ return true;
+}
+
+static const uint8_t querymultiplevalues_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xae, 0x1a, 0xbd, 0xbe, 0xbb, 0x94, 0xce, 0x4e,
+ 0xba, 0xcf, 0x56, 0xeb, 0xe5, 0xb3, 0x6c, 0xa3, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4f, 0x00,
+ 0x4d, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00, 0x54, 0x00, 0x48, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
+};
+
+static bool querymultiplevalues_in_check(struct torture_context *tctx,
+ struct winreg_QueryMultipleValues *r)
+{
+ torture_assert_int_equal(tctx, r->in.num_values, 1, "num values");
+ torture_assert_str_equal(tctx, r->in.values_in[0].ve_valuename->name, "HOMEPATH", "name");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valuename->length, 18, "name len");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valuename->size, 18, "name size");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valuelen, 0, "length");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valueptr, 0, "ve_valueptr");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_type, 0, "type");
+ torture_assert_int_equal(tctx, *r->in.buffer_size, 32, "buffer size");
+
+ return true;
+}
+
+static const uint8_t querymultiplevalues_out_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0xd8, 0x8c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, 0x00, 0x38, 0x87, 0x07, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00,
+ 0x54, 0x00, 0x48, 0x00, 0xc8, 0x95, 0x08, 0x00, 0x4c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x4d, 0x45, 0x4d, 0xc8, 0x95, 0x08, 0x00,
+ 0x50, 0x87, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x07, 0x00,
+ 0x00, 0x01, 0x0c, 0x00, 0x50, 0x95, 0x08, 0x00, 0x48, 0x96, 0x08, 0x00,
+ 0xdc, 0x00, 0x00, 0x00, 0xc0, 0x83, 0x00, 0x01, 0x0d, 0xf0, 0xff, 0xff,
+ 0x4c, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00
+};
+
+static bool querymultiplevalues_out_check(struct torture_context *tctx,
+ struct winreg_QueryMultipleValues *r)
+{
+ torture_assert_str_equal(tctx, r->out.values_out[0].ve_valuename->name, "HOMEPATH", "name");
+ torture_assert_int_equal(tctx, r->out.values_out[0].ve_type, 0, "type");
+ torture_assert_int_equal(tctx, r->out.values_out[0].ve_valuelen, 0, "length");
+ /* FIXME: r->out.buffer */
+ torture_assert_int_equal(tctx, *r->out.buffer_size, 76, "buffer size");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_MORE_DATA, "return code");
+
+ return true;
+}
+
+const uint8_t querymultiplevalues2_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0xe4, 0xdf, 0x3c, 0x70, 0xde, 0x69, 0x4a,
+ 0x90, 0xb4, 0x85, 0x36, 0x33, 0x79, 0x89, 0x32, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x54, 0x00, 0x45, 0x00,
+ 0x4d, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool querymultiplevalues2_in_check(struct torture_context *tctx,
+ struct winreg_QueryMultipleValues2 *r)
+{
+ torture_assert_int_equal(tctx, r->in.num_values, 1, "num values");
+ torture_assert_str_equal(tctx, r->in.values_in[0].ve_valuename->name, "TEMP", "name");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valuename->length, 10, "name len");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valuename->size, 10, "name size");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valuelen, 0, "length");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_valueptr, 0, "ve_valueptr");
+ torture_assert_int_equal(tctx, r->in.values_in[0].ve_type, 0, "type");
+ torture_assert_int_equal(tctx, *r->in.offered, 0, "buffer size");
+
+ return true;
+}
+
+const uint8_t querymultiplevalues2_out_data[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x45, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00
+};
+
+static bool querymultiplevalues2_out_check(struct torture_context *tctx,
+ struct winreg_QueryMultipleValues2 *r)
+{
+ return true;
+}
+
+static const uint8_t flushkey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3
+};
+
+static bool flushkey_in_check(struct torture_context *tctx,
+ struct winreg_FlushKey *r)
+{
+ torture_assert_int_equal(tctx, r->in.handle->handle_type, 0, "handle type");
+ return true;
+}
+
+static const uint8_t flushkey_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool flushkey_out_check(struct torture_context *tctx,
+ struct winreg_FlushKey *r)
+{
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+
+static const uint8_t openkey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3, 0x16, 0x00, 0x16, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x73, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
+};
+
+static bool openkey_in_check(struct torture_context *tctx, struct winreg_OpenKey *r)
+{
+ torture_assert_int_equal(tctx, r->in.options, 0, "unknown");
+ torture_assert_int_equal(tctx, r->in.access_mask, 0x02000000, "access mask");
+ torture_assert_str_equal(tctx, r->in.keyname.name, "spottyfoot", "keyname");
+ /* FIXME: parent handle */
+ return true;
+}
+
+static const uint8_t openkey_out_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
+};
+
+static bool openkey_out_check(struct torture_context *tctx, struct winreg_OpenKey *r)
+{
+ torture_assert(tctx, GUID_all_zero(&r->out.handle->uuid), "handle");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_FILE_NOT_FOUND, "return code");
+ return true;
+}
+
+static const uint8_t deletekey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3, 0x16, 0x00, 0x16, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x00, 0x00, 0x00, 0x73, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x74, 0x00, 0x79, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x00, 0x00
+};
+
+static bool deletekey_in_check(struct torture_context *tctx, struct winreg_DeleteKey *r)
+{
+ /* FIXME: Handle */
+ torture_assert_str_equal(tctx, r->in.key.name, "spottyfoot", "key name");
+ return true;
+}
+
+static const uint8_t deletekey_out_data[] = {
+ 0x02, 0x00, 0x00, 0x00
+};
+
+static bool deletekey_out_check(struct torture_context *tctx, struct winreg_DeleteKey *r)
+{
+ torture_assert_werr_equal(tctx, r->out.result, WERR_FILE_NOT_FOUND, "return code");
+ return true;
+}
+
+static const uint8_t getversion_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3
+};
+
+static bool getversion_in_check(struct torture_context *tctx, struct winreg_GetVersion *r)
+{
+ /* FIXME: Handle */
+ return true;
+}
+
+static const uint8_t getversion_out_data[] = {
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool getversion_out_check(struct torture_context *tctx, struct winreg_GetVersion *r)
+{
+ torture_assert_int_equal(tctx, *r->out.version, 5, "version");
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ return true;
+}
+
+static const uint8_t queryinfokey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool queryinfokey_in_check(struct torture_context *tctx, struct winreg_QueryInfoKey *r)
+{
+ /* FIXME: Handle */
+ torture_assert(tctx, r->in.classname->name == NULL, "class in");
+ return true;
+}
+
+#if 0
+static const uint8_t queryinfokey_out_data[] = {
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00,
+ 0x10, 0x48, 0x02, 0x3a, 0xcf, 0xfd, 0xc4, 0x01, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool queryinfokey_out_check(struct torture_context *tctx, struct winreg_QueryInfoKey *r)
+{
+ torture_assert(tctx, r->out.classname != NULL, "class out");
+ torture_assert(tctx, r->out.classname->name != NULL, "class out name");
+ torture_assert_str_equal(tctx, r->out.classname->name, "", "class out name");
+ torture_assert_int_equal(tctx, *r->out.num_subkeys, 0, "num subkeys");
+ torture_assert_int_equal(tctx, *r->out.max_subkeylen, 0, "subkey length");
+ torture_assert_int_equal(tctx, *r->out.max_classlen, 140, "subkey size");
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ return true;
+}
+#endif
+
+static const uint8_t notifychangekeyvalue_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xb2, 0x64, 0xbc, 0xb3, 0x7f, 0x90, 0x29, 0x4a,
+ 0xb4, 0xb3, 0x91, 0xe7, 0xe4, 0x4a, 0x58, 0xe3, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool notifychangekeyvalue_in_check(struct torture_context *tctx, struct winreg_NotifyChangeKeyValue *r)
+{
+ torture_assert_int_equal(tctx, r->in.watch_subtree, 1, "watch subtree");
+ torture_assert_int_equal(tctx, r->in.notify_filter, 0, "notify filter");
+ torture_assert_int_equal(tctx, r->in.unknown, 0, "unknown");
+ torture_assert(tctx, r->in.string1.name == NULL, "string1");
+ torture_assert(tctx, r->in.string2.name == NULL, "string2");
+ torture_assert_int_equal(tctx, r->in.unknown2, 0, "unknown2");
+ return true;
+}
+
+static const uint8_t notifychangekeyvalue_out_data[] = {
+ 0x57, 0x00, 0x00, 0x00
+};
+
+static bool notifychangekeyvalue_out_check(struct torture_context *tctx, struct winreg_NotifyChangeKeyValue *r)
+{
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAMETER, "notify change key value");
+ return true;
+}
+
+#if 0
+static const uint8_t getkeysecurity_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xbd, 0xaa, 0xf6, 0x59, 0xc1, 0x82, 0x1f, 0x4d,
+ 0x84, 0xa9, 0xdd, 0xae, 0x60, 0x77, 0x1e, 0x45, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool getkeysecurity_in_check(struct torture_context *tctx,
+ struct winreg_GetKeySecurity *r)
+{
+ /* FIXME: Handle */
+ torture_assert_int_equal(tctx, r->in.sec_info, 2, "sec info");
+ torture_assert_int_equal(tctx, r->in.sd->size, 65536, "sd size");
+ torture_assert_int_equal(tctx, r->in.sd->len, 0, "sd len");
+ torture_assert(tctx, r->in.sd->data == NULL, "sd data");
+ return true;
+}
+
+static const uint8_t getkeysecurity_out_data[] = {
+ 0x08, 0x91, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool getkeysecurity_out_check(struct torture_context *tctx,
+ struct winreg_GetKeySecurity *r)
+{
+ torture_assert_int_equal(tctx, r->in.sd->size, 20, "sd size");
+ torture_assert_int_equal(tctx, r->in.sd->len, 20, "sd len");
+ torture_assert_werr_ok(tctx, r->out.result, "return code");
+ return true;
+}
+#endif
+
+static const uint8_t enumkey_in_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x85, 0xb8, 0x41, 0xb0, 0x17, 0xe4, 0x28, 0x45,
+ 0x8a, 0x69, 0xbf, 0x40, 0x79, 0x82, 0x8b, 0xcb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x14, 0x04, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f
+};
+
+static bool enumkey_in_check(struct torture_context *tctx, struct winreg_EnumKey *r)
+{
+ torture_assert_int_equal(tctx, r->in.enum_index, 0, "enum index");
+ torture_assert_int_equal(tctx, r->in.name->size, 1044, "name size");
+ torture_assert_int_equal(tctx, r->in.name->length, 0, "name len");
+ torture_assert(tctx, r->in.keyclass != NULL, "keyclass pointer");
+ torture_assert(tctx, r->in.keyclass->name == NULL, "keyclass");
+ torture_assert(tctx, r->in.last_changed_time != NULL, "last_changed_time != NULL");
+ return true;
+}
+
+static const uint8_t enumkey_out_data[] = {
+ 0x08, 0x00, 0x14, 0x04, 0x18, 0xe8, 0x07, 0x00, 0x0a, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x53, 0x00, 0x41, 0x00,
+ 0x4d, 0x00, 0x00, 0x00, 0xd0, 0x62, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x62, 0x07, 0x00, 0x50, 0x67, 0xd0, 0x8b,
+ 0x16, 0x06, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool enumkey_out_check(struct torture_context *tctx, struct winreg_EnumKey *r)
+{
+ torture_assert_int_equal(tctx, r->out.name->size, 1044, "name size");
+ torture_assert_int_equal(tctx, r->out.name->length, 8, "name len");
+ torture_assert(tctx, r->out.keyclass != NULL, "keyclass pointer");
+ torture_assert(tctx, r->out.keyclass->name == NULL, "keyclass");
+ torture_assert(tctx, r->out.last_changed_time != NULL, "last_changed_time pointer");
+ /* FIXME: *last_changed_time */
+ return true;
+}
+
+struct torture_suite *ndr_winreg_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "winreg");
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_CloseKey, closekey_in_data, NDR_IN, closekey_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_CloseKey, closekey_out_data, NDR_OUT, closekey_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_OpenHKLM, OpenHKLM_In, NDR_IN, openhklm_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_OpenHKLM, openhklm_out_data, NDR_OUT, openhklm_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_CreateKey, createkey_in_data, NDR_IN, createkey_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_CreateKey, createkey_out_data, NDR_OUT, createkey_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_EnumValue, enumvalue_in_data, NDR_IN, enumvalue_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_EnumValue, enumvalue_out_data, NDR_OUT, enumvalue_out_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_EnumValue, enumvalue_in_data2, NDR_IN, NULL);
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_QueryValue, queryvalue_in_data, NDR_IN, queryvalue_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_QueryValue, queryvalue_out_data, NDR_OUT, queryvalue_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_QueryMultipleValues, querymultiplevalues_in_data, NDR_IN, querymultiplevalues_in_check );
+ torture_suite_add_ndr_pull_io_test(suite, winreg_QueryMultipleValues, querymultiplevalues_in_data, querymultiplevalues_out_data, querymultiplevalues_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_QueryMultipleValues2, querymultiplevalues2_in_data, NDR_IN, querymultiplevalues2_in_check );
+ torture_suite_add_ndr_pull_io_test(suite, winreg_QueryMultipleValues2, querymultiplevalues2_in_data, querymultiplevalues2_out_data, querymultiplevalues2_out_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_FlushKey, flushkey_in_data, NDR_IN, flushkey_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_FlushKey, flushkey_out_data, NDR_OUT, flushkey_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_OpenKey, openkey_in_data, NDR_IN, openkey_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_OpenKey, openkey_out_data, NDR_OUT, openkey_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_DeleteKey, deletekey_in_data, NDR_IN, deletekey_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_DeleteKey, deletekey_out_data, NDR_OUT, deletekey_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_GetVersion, getversion_in_data, NDR_IN, getversion_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_GetVersion, getversion_out_data, NDR_OUT, getversion_out_check );
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_QueryInfoKey, queryinfokey_in_data, NDR_IN, queryinfokey_in_check );
+ /*torture_suite_add_ndr_pull_fn_test(suite, winreg_QueryInfoKey, queryinfokey_out_data, NDR_OUT, queryinfokey_out_check );*/
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_NotifyChangeKeyValue, notifychangekeyvalue_in_data, NDR_IN, notifychangekeyvalue_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_NotifyChangeKeyValue, notifychangekeyvalue_out_data, NDR_OUT, notifychangekeyvalue_out_check );
+
+ /*torture_suite_add_ndr_pull_fn_test(suite, winreg_GetKeySecurity, getkeysecurity_in_data, NDR_IN, getkeysecurity_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_GetKeySecurity, getkeysecurity_out_data, NDR_OUT, getkeysecurity_out_check );*/
+
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_EnumKey, enumkey_in_data, NDR_IN, enumkey_in_check );
+ torture_suite_add_ndr_pull_fn_test(suite, winreg_EnumKey, enumkey_out_data, NDR_OUT, enumkey_out_check );
+
+ return suite;
+}
+
diff --git a/source4/torture/ndr/winspool.c b/source4/torture/ndr/winspool.c
new file mode 100644
index 0000000..e5242b9
--- /dev/null
+++ b/source4/torture/ndr/winspool.c
@@ -0,0 +1,173 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for spoolss ndr operations
+
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_winspool.h"
+#include "torture/ndr/proto.h"
+
+static const uint8_t registerforremotenotifications_req_data[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61, 0x4c, 0x7b, 0xc1, 0x46, 0xde, 0x4b,
+ 0x81, 0x29, 0xcb, 0xa4, 0xd2, 0xf4, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00,
+ 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x79, 0x00, 0x46, 0x00, 0x69, 0x00,
+ 0x6c, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x46, 0x00,
+ 0x6c, 0x00, 0x61, 0x00, 0x67, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00,
+ 0x74, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x69, 0x00,
+ 0x66, 0x00, 0x79, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x74, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4f, 0x00, 0x70, 0x00, 0x74, 0x00,
+ 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x52, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x4e, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x79, 0x00,
+ 0x46, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00,
+ 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x6f, 0x00,
+ 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x79, 0x00, 0x46, 0x00, 0x69, 0x00,
+ 0x6c, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4e, 0x00,
+ 0x6f, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x79, 0x00, 0x4f, 0x00,
+ 0x70, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00,
+ 0x06, 0x00, 0x0d, 0x00, 0x12, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0b, 0x00,
+ 0x0d, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00,
+ 0x16, 0x00, 0x17, 0x00
+};
+
+static bool registerforremotenotifications_req_check(struct torture_context *tctx,
+ struct winspool_SyncRegisterForRemoteNotifications *r)
+{
+ struct winspool_PrintNamedProperty *p = r->in.pNotifyFilter->propertiesCollection;
+ struct spoolss_NotifyOption *o;
+
+ /* r->in.hPrinter */
+ torture_assert(tctx, r->in.pNotifyFilter, "pNotifyFilter NULL");
+
+ torture_assert_int_equal(tctx, r->in.pNotifyFilter->numberOfProperties, 4, "numberOfProperties");
+
+ torture_assert_str_equal(tctx, p[0].propertyName, "RemoteNotifyFilter Flags", "propertyName");
+ torture_assert_int_equal(tctx, p[0].propertyValue.PropertyType, winspool_PropertyTypeInt32, "PropertyType");
+ torture_assert_int_equal(tctx, p[0].propertyValue.value.propertyInt32, 255, "propertyInt32");
+
+ torture_assert_str_equal(tctx, p[1].propertyName, "RemoteNotifyFilter Options", "propertyName");
+ torture_assert_int_equal(tctx, p[1].propertyValue.PropertyType, winspool_PropertyTypeInt32, "PropertyType");
+ torture_assert_int_equal(tctx, p[1].propertyValue.value.propertyInt32, 0, "propertyInt32");
+
+ torture_assert_str_equal(tctx, p[2].propertyName, "RemoteNotifyFilter Color", "propertyName");
+ torture_assert_int_equal(tctx, p[2].propertyValue.PropertyType, winspool_PropertyTypeInt32, "PropertyType");
+ torture_assert_int_equal(tctx, p[2].propertyValue.value.propertyInt32, 0, "propertyInt32");
+
+ torture_assert_str_equal(tctx, p[3].propertyName, "RemoteNotifyFilter NotifyOptions", "propertyName");
+ torture_assert_int_equal(tctx, p[3].propertyValue.PropertyType, winspool_PropertyTypeNotificationOptions, "PropertyType");
+
+ o = p[3].propertyValue.value.propertyOptionsContainer.pOptions;
+
+ torture_assert_int_equal(tctx, o->version, 2, "version");
+ torture_assert_int_equal(tctx, o->flags, 0, "flags");
+ torture_assert_int_equal(tctx, o->count, 2, "count");
+
+ torture_assert_int_equal(tctx, o->types[0].type, PRINTER_NOTIFY_TYPE, "type");
+ torture_assert_int_equal(tctx, o->types[0].u1, 0, "u1");
+ torture_assert_int_equal(tctx, o->types[0].u2, 0, "u2");
+ torture_assert_int_equal(tctx, o->types[0].u3, 0, "u3");
+ torture_assert_int_equal(tctx, o->types[0].count, 10, "count");
+
+ torture_assert_int_equal(tctx, o->types[0].fields[0].field, PRINTER_NOTIFY_FIELD_SERVER_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[1].field, PRINTER_NOTIFY_FIELD_PRINTER_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[2].field, PRINTER_NOTIFY_FIELD_SHARE_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[3].field, PRINTER_NOTIFY_FIELD_PORT_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[4].field, PRINTER_NOTIFY_FIELD_DRIVER_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[5].field, PRINTER_NOTIFY_FIELD_COMMENT, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[6].field, PRINTER_NOTIFY_FIELD_LOCATION, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[7].field, PRINTER_NOTIFY_FIELD_ATTRIBUTES, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[8].field, PRINTER_NOTIFY_FIELD_STATUS, "field");
+ torture_assert_int_equal(tctx, o->types[0].fields[9].field, PRINTER_NOTIFY_FIELD_CJOBS, "field");
+
+ torture_assert_int_equal(tctx, o->types[1].type, JOB_NOTIFY_TYPE, "type");
+ torture_assert_int_equal(tctx, o->types[1].u1, 0, "u1");
+ torture_assert_int_equal(tctx, o->types[1].u2, 0, "u2");
+ torture_assert_int_equal(tctx, o->types[1].u3, 0, "u3");
+ torture_assert_int_equal(tctx, o->types[1].count, 16, "count");
+
+ torture_assert_int_equal(tctx, o->types[1].fields[0].field, JOB_NOTIFY_FIELD_PRINTER_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[1].field, JOB_NOTIFY_FIELD_MACHINE_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[2].field, JOB_NOTIFY_FIELD_PORT_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[3].field, JOB_NOTIFY_FIELD_USER_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[4].field, JOB_NOTIFY_FIELD_NOTIFY_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[5].field, JOB_NOTIFY_FIELD_DRIVER_NAME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[6].field, JOB_NOTIFY_FIELD_STATUS, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[7].field, JOB_NOTIFY_FIELD_STATUS_STRING, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[8].field, JOB_NOTIFY_FIELD_DOCUMENT, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[9].field, JOB_NOTIFY_FIELD_POSITION, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[10].field, JOB_NOTIFY_FIELD_SUBMITTED, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[11].field, JOB_NOTIFY_FIELD_TIME, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[12].field, JOB_NOTIFY_FIELD_TOTAL_PAGES, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[13].field, JOB_NOTIFY_FIELD_PAGES_PRINTED, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[14].field, JOB_NOTIFY_FIELD_TOTAL_BYTES, "field");
+ torture_assert_int_equal(tctx, o->types[1].fields[15].field, JOB_NOTIFY_FIELD_BYTES_PRINTED, "field");
+
+ return true;
+}
+
+struct torture_suite *ndr_winspool_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "winspool");
+
+ torture_suite_add_ndr_pull_fn_test_flags(suite,
+ winspool_SyncRegisterForRemoteNotifications,
+ registerforremotenotifications_req_data,
+ NDR_IN,
+ LIBNDR_FLAG_NDR64,
+ registerforremotenotifications_req_check);
+
+ return suite;
+}
diff --git a/source4/torture/ndr/witness.c b/source4/torture/ndr/witness.c
new file mode 100644
index 0000000..496d045
--- /dev/null
+++ b/source4/torture/ndr/witness.c
@@ -0,0 +1,411 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for witness ndr operations
+
+ Copyright (C) Guenther Deschner 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/ndr/ndr.h"
+#include "librpc/gen_ndr/ndr_witness.h"
+#include "torture/ndr/proto.h"
+#include "param/param.h"
+
+static const uint8_t witness_GetInterfaceList_data[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x45, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x01, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x2c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x45, 0x00,
+ 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x01, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x2d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool witness_GetInterfaceList_check(struct torture_context *tctx,
+ struct witness_GetInterfaceList *r)
+{
+ struct witness_interfaceList *l;
+
+ torture_assert(tctx, r->out.interface_list, "r->out.interface_list");
+
+ l = *(r->out.interface_list);
+
+ torture_assert_int_equal(tctx, l->num_interfaces, 2, "l->num_interfaces");
+ torture_assert(tctx, l->interfaces, "l->interfaces");
+
+ torture_assert_str_equal(tctx, l->interfaces[0].group_name, "NODE2", "l->interfaces[0].group_name");
+ torture_assert_int_equal(tctx, l->interfaces[0].version, -1, "l->interfaces[0].version");
+ torture_assert_int_equal(tctx, l->interfaces[0].state, 1, "l->interfaces[0].state");
+ torture_assert_str_equal(tctx, l->interfaces[0].ipv4, "192.168.3.44", "l->interfaces[0].state");
+ torture_assert_int_equal(tctx, l->interfaces[0].flags, 5, "l->interfaces[0].flags");
+
+ torture_assert_str_equal(tctx, l->interfaces[1].group_name, "NODE1", "l->interfaces[0].group_name");
+ torture_assert_int_equal(tctx, l->interfaces[1].version, -1, "l->interfaces[0].version");
+ torture_assert_int_equal(tctx, l->interfaces[1].state, 1, "l->interfaces[0].state");
+ torture_assert_str_equal(tctx, l->interfaces[1].ipv4, "192.168.3.45", "l->interfaces[0].state");
+ torture_assert_int_equal(tctx, l->interfaces[1].flags, 1, "l->interfaces[0].flags");
+ torture_assert_werr_ok(tctx, r->out.result, "r->out.result");
+
+ return true;
+}
+
+static const uint8_t witness_Register_data_IN[] = {
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x73, 0x00, 0x6f, 0x00,
+ 0x66, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+ 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00,
+ 0x38, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x35, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x54, 0x00,
+ 0x48, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x45, 0x00, 0x4e, 0x00, 0x41, 0x00,
+ 0x00, 0x00
+};
+
+static bool witness_Register_check_IN(struct torture_context *tctx,
+ struct witness_Register *r)
+{
+ torture_assert_int_equal(tctx, r->in.version, 65537, "r->in.version");
+ torture_assert_str_equal(tctx, r->in.net_name, "sofs", "r->in.net_name");
+ torture_assert_str_equal(tctx, r->in.ip_address, "192.168.3.45", "r->in.ip_address");
+ torture_assert_str_equal(tctx, r->in.client_computer_name, "MTHELENA", "r->in.client_computer_name");
+
+ return true;
+}
+
+static const uint8_t witness_Register_data_OUT[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x33, 0x86, 0xb8, 0x3a, 0x57, 0x1e, 0x1a, 0x4c,
+ 0x85, 0x6c, 0xd1, 0xbc, 0x4b, 0x15, 0xbb, 0xb1, 0x00, 0x00, 0x00, 0x00
+};
+
+static bool witness_Register_check_OUT(struct torture_context *tctx,
+ struct witness_Register *r)
+{
+ struct GUID guid;
+
+ torture_assert(tctx, r->out.context_handle, "r->out.context_handle");
+ torture_assert_int_equal(tctx, r->out.context_handle->handle_type, 0, "r->out.context_handle->handle_type");
+ torture_assert_ntstatus_ok(tctx, GUID_from_string("3ab88633-1e57-4c1a-856c-d1bc4b15bbb1", &guid), "");
+ torture_assert_mem_equal(tctx, &r->out.context_handle->uuid, &guid, sizeof(guid), "r->out.context_handle->uuid");
+ torture_assert_werr_ok(tctx, r->out.result, "r->out.result");
+
+ return true;
+}
+
+static const uint8_t witness_UnRegister_data_IN[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x33, 0x86, 0xb8, 0x3a, 0x57, 0x1e, 0x1a, 0x4c,
+ 0x85, 0x6c, 0xd1, 0xbc, 0x4b, 0x15, 0xbb, 0xb1
+};
+
+static bool witness_UnRegister_check_IN(struct torture_context *tctx,
+ struct witness_UnRegister *r)
+{
+ struct GUID guid;
+
+ torture_assert_int_equal(tctx, r->in.context_handle.handle_type, 0, "r->in.context_handle.handle_type");
+ torture_assert_ntstatus_ok(tctx, GUID_from_string("3ab88633-1e57-4c1a-856c-d1bc4b15bbb1", &guid), "");
+ torture_assert_mem_equal(tctx, &r->in.context_handle.uuid, &guid, sizeof(guid), "r->in.context_handle.uuid");
+
+ return true;
+}
+
+static const uint8_t witness_UnRegister_data_OUT[] = {
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool witness_UnRegister_check_OUT(struct torture_context *tctx,
+ struct witness_UnRegister *r)
+{
+ torture_assert_werr_ok(tctx, r->out.result, "r->out.result");
+
+ return true;
+}
+
+static const uint8_t witness_AsyncNotify_data_IN[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xee, 0xf2, 0xb9, 0x1f, 0x4d, 0x2a, 0xf8, 0x4b,
+ 0xaf, 0x8b, 0xcb, 0x9d, 0x45, 0x29, 0xa9, 0xab
+};
+
+static bool witness_AsyncNotify_check_IN(struct torture_context *tctx,
+ struct witness_AsyncNotify *r)
+{
+ struct GUID guid;
+
+ torture_assert_int_equal(tctx, r->in.context_handle.handle_type, 0, "r->in.context_handle.handle_type");
+ torture_assert_ntstatus_ok(tctx, GUID_from_string("1fb9f2ee-2a4d-4bf8-af8b-cb9d4529a9ab", &guid), "");
+ torture_assert_mem_equal(tctx, &r->in.context_handle.uuid, &guid, sizeof(guid), "r->in.context_handle.uuid");
+
+ return true;
+}
+
+static const uint8_t witness_AsyncNotify_data_OUT[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00,
+ 0x12, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x53, 0x00, 0x4f, 0x00,
+ 0x46, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static bool witness_AsyncNotify_check_OUT(struct torture_context *tctx,
+ struct witness_AsyncNotify *r)
+{
+ struct witness_notifyResponse *n;
+ struct witness_ResourceChange *c;
+
+ torture_assert(tctx, r->out.response, "r->out.response");
+
+ n = *(r->out.response);
+
+ torture_assert_int_equal(tctx, n->type, WITNESS_NOTIFY_RESOURCE_CHANGE, "type");
+ torture_assert_int_equal(tctx, n->length, 18, "length");
+ torture_assert_int_equal(tctx, n->num, 1, "num");
+
+ c = &n->messages[0].resource_change;
+
+ torture_assert_int_equal(tctx, c->length, 18, "c->length");
+ torture_assert_int_equal(tctx, c->type, WITNESS_RESOURCE_STATE_UNAVAILABLE, "c->type");
+ torture_assert_str_equal(tctx, c->name, "SOFS", "c->name");
+
+ return true;
+}
+
+static const uint8_t witness_AsyncNotify_data_move_OUT[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x2d, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0xe8, 0xeb, 0x26, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x60, 0x26,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool witness_AsyncNotify_check_move_OUT(struct torture_context *tctx,
+ struct witness_AsyncNotify *r)
+{
+ struct witness_notifyResponse *n;
+ struct witness_IPaddrInfoList *i;
+
+ torture_assert(tctx, r->out.response, "r->out.response");
+
+ n = *(r->out.response);
+
+ torture_assert_int_equal(tctx, n->type, WITNESS_NOTIFY_CLIENT_MOVE, "type");
+ torture_assert_int_equal(tctx, n->length, 36, "length");
+ torture_assert_int_equal(tctx, n->num, 1, "num");
+
+ i = &n->messages[0].client_move;
+
+ torture_assert_int_equal(tctx, i->length, 36, "i->length");
+ torture_assert_int_equal(tctx, i->reserved, 0, "i->reserved");
+ torture_assert_int_equal(tctx, i->num, 1, "i->num");
+
+ torture_assert_int_equal(tctx, i->addr[0].flags, WITNESS_IPADDR_V4, "i->addr[0].flags");
+ torture_assert_str_equal(tctx, i->addr[0].ipv4, "192.168.3.45", "i->addr[0].ipv4");
+ torture_assert_str_equal(tctx, i->addr[0].ipv6, "0000:0000:38e8:eb26:8e00:0000:009e:6026", "i->addr[0].ipv6");
+
+ return true;
+}
+
+static const uint8_t witness_AsyncNotify_data_fuzz1_OUT[] = {
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00,
+ 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+static bool witness_AsyncNotify_check_fuzz1_OUT(struct torture_context *tctx,
+ struct witness_AsyncNotify *r)
+{
+ struct witness_notifyResponse *n;
+ struct witness_IPaddrInfoList *i;
+
+ torture_assert(tctx, r->out.response, "r->out.response");
+
+ n = *(r->out.response);
+
+ torture_assert_int_equal(tctx, n->type, WITNESS_NOTIFY_CLIENT_MOVE, "type");
+ torture_assert_int_equal(tctx, n->length, 12, "length");
+ torture_assert_int_equal(tctx, n->num, 1, "num");
+
+ i = &n->messages[0].client_move;
+
+ torture_assert_int_equal(tctx, i->length, 12, "i->length");
+ torture_assert_int_equal(tctx, i->reserved, 0, "i->reserved");
+ torture_assert_int_equal(tctx, i->num, 0, "i->num");
+
+ return true;
+}
+
+struct torture_suite *ndr_witness_suite(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "witness");
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_GetInterfaceList,
+ witness_GetInterfaceList_data,
+ NDR_OUT,
+ witness_GetInterfaceList_check);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_Register,
+ witness_Register_data_IN,
+ NDR_IN,
+ witness_Register_check_IN);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_Register,
+ witness_Register_data_OUT,
+ NDR_OUT,
+ witness_Register_check_OUT);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_UnRegister,
+ witness_UnRegister_data_IN,
+ NDR_IN,
+ witness_UnRegister_check_IN);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_UnRegister,
+ witness_UnRegister_data_OUT,
+ NDR_OUT,
+ witness_UnRegister_check_OUT);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_AsyncNotify,
+ witness_AsyncNotify_data_IN,
+ NDR_IN,
+ witness_AsyncNotify_check_IN);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_AsyncNotify,
+ witness_AsyncNotify_data_OUT,
+ NDR_OUT,
+ witness_AsyncNotify_check_OUT);
+
+ torture_suite_add_ndr_pullpush_fn_test_flags(suite,
+ witness_AsyncNotify,
+ witness_AsyncNotify_data_OUT,
+ NDR_OUT,
+ 0,
+ witness_AsyncNotify_check_OUT);
+
+ torture_suite_add_ndr_pullpush_fn_test_flags(suite,
+ witness_AsyncNotify,
+ witness_AsyncNotify_data_move_OUT,
+ NDR_OUT,
+ 0,
+ witness_AsyncNotify_check_move_OUT);
+
+ torture_suite_add_ndr_pull_fn_test(suite,
+ witness_AsyncNotify,
+ witness_AsyncNotify_data_fuzz1_OUT,
+ NDR_OUT,
+ witness_AsyncNotify_check_fuzz1_OUT);
+
+ torture_suite_add_ndr_pullpush_fn_test_flags(suite,
+ witness_AsyncNotify,
+ witness_AsyncNotify_data_fuzz1_OUT,
+ NDR_OUT,
+ 0,
+ witness_AsyncNotify_check_fuzz1_OUT);
+
+ return suite;
+}
diff --git a/source4/torture/ntp/ntp_signd.c b/source4/torture/ntp/ntp_signd.c
new file mode 100644
index 0000000..fd7da67
--- /dev/null
+++ b/source4/torture/ntp/ntp_signd.c
@@ -0,0 +1,306 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Test NTP authentication support
+
+ Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include <tevent.h>
+#include "lib/stream/packet.h"
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/tstream.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_ntp_signd.h"
+#include "param/param.h"
+#include "system/network.h"
+#include "torture/ntp/proto.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#define TEST_MACHINE_NAME "ntpsigndtest"
+
+struct signd_client_state {
+ struct tsocket_address *local_address;
+ struct tsocket_address *remote_address;
+
+ struct tstream_context *tstream;
+ struct tevent_queue *send_queue;
+
+ uint8_t request_hdr[4];
+ struct iovec request_iov[2];
+
+ DATA_BLOB reply;
+
+ NTSTATUS status;
+};
+
+/*
+ * A torture test to show that the unix domain socket protocol is
+ * operating correctly, and the signatures are as expected
+ */
+static bool test_ntp_signd(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netlogon_creds_CredentialState *creds;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ uint32_t rid;
+ const char *machine_name;
+ const struct samr_Password *pwhash = cli_credentials_get_nt_hash(credentials, mem_ctx);
+ uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+
+ struct sign_request sign_req;
+ struct signed_reply signed_reply;
+ DATA_BLOB sign_req_blob;
+
+ struct signd_client_state *signd_client;
+ struct tevent_req *req;
+ char *unix_address;
+ int sys_errno;
+
+ gnutls_hash_hd_t hash_hnd;
+ uint8_t sig[16];
+ enum ndr_err_code ndr_err;
+ bool ok;
+ int rc;
+
+ machine_name = cli_credentials_get_workstation(credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ generate_random_buffer(credentials1.data, sizeof(credentials1.data));
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_ServerReqChallenge_r(p->binding_handle, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "ServerReqChallenge failed");
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = SEC_CHAN_WKSTA;
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ pwhash, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_ServerAuthenticate3_r(p->binding_handle, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_ok(tctx, a.out.result,
+ "ServerAuthenticate3 failed");
+ torture_assert(tctx,
+ netlogon_creds_client_check(creds, &credentials3),
+ "Credential chaining failed");
+
+ sign_req.op = SIGN_TO_CLIENT;
+ sign_req.packet_id = 1;
+ sign_req.key_id = rid;
+ sign_req.packet_to_sign = data_blob_string_const("I am a tea pot");
+
+ ndr_err = ndr_push_struct_blob(&sign_req_blob,
+ mem_ctx,
+ &sign_req,
+ (ndr_push_flags_fn_t)ndr_push_sign_request);
+ torture_assert(tctx,
+ NDR_ERR_CODE_IS_SUCCESS(ndr_err),
+ "Failed to push sign_req");
+
+ signd_client = talloc(mem_ctx, struct signd_client_state);
+
+ /* Create socket addresses */
+ torture_comment(tctx, "Creating the socket addresses\n");
+ rc = tsocket_address_unix_from_path(signd_client, "",
+ &signd_client->local_address);
+ torture_assert(tctx, rc == 0,
+ "Failed to create local address from unix path.");
+
+ unix_address = talloc_asprintf(signd_client,
+ "%s/socket",
+ lpcfg_ntp_signd_socket_directory(tctx->lp_ctx));
+ rc = tsocket_address_unix_from_path(mem_ctx,
+ unix_address,
+ &signd_client->remote_address);
+ torture_assert(tctx, rc == 0,
+ "Failed to create remote address from unix path.");
+
+ /* Connect to the unix socket */
+ torture_comment(tctx, "Connecting to the unix socket\n");
+ req = tstream_unix_connect_send(signd_client,
+ tctx->ev,
+ signd_client->local_address,
+ signd_client->remote_address);
+ torture_assert(tctx, req != NULL,
+ "Failed to create a tstream unix connect request.");
+
+ ok = tevent_req_poll(req, tctx->ev);
+ torture_assert(tctx, ok == true,
+ "Failed to poll for tstream_unix_connect_send.");
+
+ rc = tstream_unix_connect_recv(req,
+ &sys_errno,
+ signd_client,
+ &signd_client->tstream);
+ TALLOC_FREE(req);
+ torture_assert(tctx, rc == 0, "Failed to connect to signd!");
+
+ /* Allocate the send queue */
+ signd_client->send_queue = tevent_queue_create(signd_client,
+ "signd_client_queue");
+ torture_assert(tctx, signd_client->send_queue != NULL,
+ "Failed to create send queue!");
+
+ /*
+ * Create the request buffer.
+ * First add the length of the request buffer
+ */
+ RSIVAL(signd_client->request_hdr, 0, sign_req_blob.length);
+ signd_client->request_iov[0].iov_base = (char *) signd_client->request_hdr;
+ signd_client->request_iov[0].iov_len = 4;
+
+ signd_client->request_iov[1].iov_base = (char *) sign_req_blob.data;
+ signd_client->request_iov[1].iov_len = sign_req_blob.length;
+
+ /* Fire the request buffer */
+ torture_comment(tctx, "Sending the request\n");
+ req = tstream_writev_queue_send(signd_client,
+ tctx->ev,
+ signd_client->tstream,
+ signd_client->send_queue,
+ signd_client->request_iov, 2);
+ torture_assert(tctx, req != NULL,
+ "Failed to send the signd request.");
+
+ ok = tevent_req_poll(req, tctx->ev);
+ torture_assert(tctx, ok == true,
+ "Failed to poll for tstream_writev_queue_send.");
+
+ rc = tstream_writev_queue_recv(req, &sys_errno);
+ TALLOC_FREE(req);
+ torture_assert(tctx, rc > 0, "Failed to send data");
+
+ /* Wait for a reply */
+ torture_comment(tctx, "Waiting for the reply\n");
+ req = tstream_read_pdu_blob_send(signd_client,
+ tctx->ev,
+ signd_client->tstream,
+ 4, /*initial_read_size */
+ tstream_full_request_u32,
+ NULL);
+ torture_assert(tctx, req != NULL,
+ "Failed to setup a read for pdu_blob.");
+
+ ok = tevent_req_poll(req, tctx->ev);
+ torture_assert(tctx, ok == true,
+ "Failed to poll for tstream_read_pdu_blob_send.");
+
+ signd_client->status = tstream_read_pdu_blob_recv(req,
+ signd_client,
+ &signd_client->reply);
+ torture_assert_ntstatus_ok(tctx, signd_client->status,
+ "Error reading signd_client reply packet");
+
+ /* Skip length header */
+ signd_client->reply.data += 4;
+ signd_client->reply.length -= 4;
+
+ /* Check if the reply buffer is valid */
+ torture_comment(tctx, "Validating the reply buffer\n");
+ ndr_err = ndr_pull_struct_blob_all(&signd_client->reply,
+ mem_ctx,
+ &signed_reply,
+ (ndr_pull_flags_fn_t)ndr_pull_signed_reply);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err),
+ ndr_map_error2string(ndr_err));
+
+ torture_assert_u64_equal(tctx, signed_reply.version,
+ NTP_SIGND_PROTOCOL_VERSION_0,
+ "Invalid Version");
+ torture_assert_u64_equal(tctx, signed_reply.packet_id,
+ sign_req.packet_id, "Invalid Packet ID");
+ torture_assert_u64_equal(tctx, signed_reply.op,
+ SIGNING_SUCCESS,
+ "Should have replied with signing success");
+ torture_assert_u64_equal(tctx, signed_reply.signed_packet.length,
+ sign_req.packet_to_sign.length + 20,
+ "Invalid reply length from signd");
+ torture_assert_u64_equal(tctx, rid,
+ IVAL(signed_reply.signed_packet.data,
+ sign_req.packet_to_sign.length),
+ "Incorrect RID in reply");
+
+ /* Check computed signature */
+ gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ gnutls_hash(hash_hnd, pwhash->hash, sizeof(pwhash->hash));
+ gnutls_hash(hash_hnd,
+ sign_req.packet_to_sign.data,
+ sign_req.packet_to_sign.length);
+ gnutls_hash_deinit(hash_hnd, sig);
+
+ torture_assert_mem_equal(tctx,
+ &signed_reply.signed_packet.data[sign_req.packet_to_sign.length + 4],
+ sig, 16, "Signature on reply was incorrect!");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+NTSTATUS torture_ntp_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ntp");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite,
+ "signd", &ndr_table_netlogon, TEST_MACHINE_NAME);
+
+ torture_rpc_tcase_add_test_creds(tcase, "ntp_signd", test_ntp_signd);
+
+ suite->description = talloc_strdup(suite, "NTP tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/torture/rap/printing.c b/source4/torture/rap/printing.c
new file mode 100644
index 0000000..af76b26
--- /dev/null
+++ b/source4/torture/rap/printing.c
@@ -0,0 +1,711 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for SMB printing operations
+
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "system/filesys.h"
+
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "libcli/rap/rap.h"
+#include "torture/rap/proto.h"
+#include "param/param.h"
+
+/* TODO:
+
+ printing half the file,
+ finding job
+ delete job
+ try writing 2nd half
+
+ SMBsplretq
+
+*/
+
+#define TORTURE_PRINT_FILE "torture_print_file"
+
+static bool print_printjob(struct torture_context *tctx,
+ struct smbcli_tree *tree)
+{
+ int fnum;
+ DATA_BLOB data;
+ ssize_t size_written;
+ const char *str;
+
+ torture_comment(tctx, "creating printjob %s\n", TORTURE_PRINT_FILE);
+
+ fnum = smbcli_open(tree, TORTURE_PRINT_FILE, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ torture_fail(tctx, "failed to open file");
+ }
+
+ str = talloc_asprintf(tctx, "TortureTestPage: %d\nData\n",0);
+
+ data = data_blob_string_const(str);
+
+ size_written = smbcli_write(tree, fnum, 0, data.data, 0, data.length);
+ if (size_written != data.length) {
+ torture_fail(tctx, "failed to write file");
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(tree, fnum),
+ "failed to close file");
+
+ return true;
+}
+
+static bool test_raw_print(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ return print_printjob(tctx, cli->tree);
+}
+
+static bool test_netprintqenum(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQEnum r;
+ int i, q;
+ uint16_t levels[] = { 0, 1, 2, 3, 4, 5 };
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+
+ torture_comment(tctx,
+ "Testing rap_NetPrintQEnum level %d\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r),
+ "smbcli_rap_netprintqenum failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "failed to enum printq");
+
+ for (q=0; q<r.out.count; q++) {
+ switch (r.in.level) {
+ case 0:
+ printf("%s\n", r.out.info[q].info0.PrintQName);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_netprintqgetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQGetInfo r;
+ struct rap_NetPrintQEnum r_enum;
+ int i, p;
+ uint16_t levels[] = { 0, 1, 2, 3, 4, 5 };
+
+ r.in.level = 0;
+ r.in.bufsize = 0;
+ r.in.PrintQueueName = "";
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqgetinfo(cli->tree, tctx, &r),
+ "smbcli_rap_netprintqgetinfo failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(r.out.status),
+ WERR_INVALID_PARAMETER,
+ "smbcli_rap_netprintqgetinfo failed");
+
+ r_enum.in.level = 5;
+ r_enum.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r_enum),
+ "failed to enum printq");
+ torture_assert_werr_ok(tctx, W_ERROR(r_enum.out.status),
+ "failed to enum printq");
+
+ for (p=0; p < r_enum.out.count; p++) {
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+ r.in.PrintQueueName = r_enum.out.info[p].info5.PrintQueueName;
+
+ torture_comment(tctx, "Testing rap_NetPrintQGetInfo(%s) level %d\n",
+ r.in.PrintQueueName, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqgetinfo(cli->tree, tctx, &r),
+ "smbcli_rap_netprintqgetinfo failed");
+ torture_assert_werr_ok(tctx,
+ W_ERROR(r.out.status),
+ "smbcli_rap_netprintqgetinfo failed");
+
+ switch (r.in.level) {
+ case 0:
+ printf("%s\n", r.out.info.info0.PrintQName);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_netprintjob_pause(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ uint16_t job_id)
+{
+ struct rap_NetPrintJobPause r;
+
+ r.in.JobID = job_id;
+
+ torture_comment(tctx, "Testing rap_NetPrintJobPause(%d)\n", r.in.JobID);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobpause(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobpause failed");
+
+ return true;
+}
+
+static bool test_netprintjob_continue(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ uint16_t job_id)
+{
+ struct rap_NetPrintJobContinue r;
+
+ r.in.JobID = job_id;
+
+ torture_comment(tctx, "Testing rap_NetPrintJobContinue(%d)\n", r.in.JobID);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobcontinue(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobcontinue failed");
+
+ return true;
+}
+
+static bool test_netprintjob_delete(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ uint16_t job_id)
+{
+ struct rap_NetPrintJobDelete r;
+
+ r.in.JobID = job_id;
+
+ torture_comment(tctx, "Testing rap_NetPrintJobDelete(%d)\n", r.in.JobID);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobdelete(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobdelete failed");
+
+ return true;
+}
+
+static bool test_netprintjob(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ uint16_t job_id = 400;
+
+ torture_assert(tctx,
+ test_netprintjob_pause(tctx, cli, job_id),
+ "failed to pause job");
+ torture_assert(tctx,
+ test_netprintjob_continue(tctx, cli, job_id),
+ "failed to continue job");
+ torture_assert(tctx,
+ test_netprintjob_delete(tctx, cli, job_id),
+ "failed to delete job");
+
+ return true;
+}
+
+static bool test_netprintq_pause(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintQueueName)
+{
+ struct rap_NetPrintQueuePause r;
+
+ r.in.PrintQueueName = PrintQueueName;
+
+ torture_comment(tctx, "Testing rap_NetPrintQueuePause(%s)\n", r.in.PrintQueueName);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqueuepause(cli->tree, tctx, &r),
+ "smbcli_rap_netprintqueuepause failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netprintqueuepause failed");
+
+ return true;
+}
+
+static bool test_netprintq_resume(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintQueueName)
+{
+ struct rap_NetPrintQueueResume r;
+
+ r.in.PrintQueueName = PrintQueueName;
+
+ torture_comment(tctx, "Testing rap_NetPrintQueueResume(%s)\n", r.in.PrintQueueName);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqueueresume(cli->tree, tctx, &r),
+ "smbcli_rap_netprintqueueresume failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netprintqueueresume failed");
+
+ return true;
+}
+
+static bool test_netprintq(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQEnum r;
+ int i;
+
+ r.in.level = 5;
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r),
+ "failed to enum printq");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "failed to enum printq");
+
+ for (i=0; i < r.out.count; i++) {
+
+ const char *printqname = r.out.info[i].info5.PrintQueueName;
+
+ torture_assert(tctx,
+ test_netprintq_pause(tctx, cli, printqname),
+ "failed to pause print queue");
+
+ torture_assert(tctx,
+ test_netprintq_resume(tctx, cli, printqname),
+ "failed to resume print queue");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobenum_args(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintQueueName,
+ uint16_t level,
+ uint16_t *count_p,
+ union rap_printj_info **info_p)
+{
+ struct rap_NetPrintJobEnum r;
+
+ r.in.PrintQueueName = PrintQueueName;
+ r.in.bufsize = 8192;
+ r.in.level = level;
+
+ torture_comment(tctx,
+ "Testing rap_NetPrintJobEnum(%s) level %d\n", r.in.PrintQueueName, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobenum(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobenum failed");
+
+ if (count_p) {
+ *count_p = r.out.count;
+ }
+ if (info_p) {
+ *info_p = r.out.info;
+ }
+
+ return true;
+}
+
+static bool test_netprintjobenum_one(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintQueueName)
+{
+ struct rap_NetPrintJobEnum r;
+ int i;
+ uint16_t levels[] = { 0, 1, 2 };
+
+ r.in.PrintQueueName = PrintQueueName;
+ r.in.bufsize = 8192;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+
+ torture_comment(tctx,
+ "Testing rap_NetPrintJobEnum(%s) level %d\n", r.in.PrintQueueName, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobenum(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobenum failed");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobgetinfo_byid(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ uint16_t JobID)
+{
+ struct rap_NetPrintJobGetInfo r;
+ uint16_t levels[] = { 0, 1, 2 };
+ int i;
+
+ r.in.JobID = JobID;
+ r.in.bufsize = 8192;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+
+ torture_comment(tctx, "Testing rap_NetPrintJobGetInfo(%d) level %d\n", r.in.JobID, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobgetinfo(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobgetinfo failed");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobsetinfo_byid(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ uint16_t JobID)
+{
+ struct rap_NetPrintJobSetInfo r;
+ uint16_t levels[] = { 0, 1, 2 };
+ int i;
+ const char *comment = "tortured by samba";
+
+ r.in.JobID = JobID;
+ r.in.bufsize = strlen(comment);
+ r.in.ParamNum = RAP_PARAM_JOBCOMMENT;
+ r.in.Param.string = comment;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+
+ torture_comment(tctx, "Testing rap_NetPrintJobSetInfo(%d) level %d\n", r.in.JobID, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobsetinfo(cli->tree, tctx, &r),
+ "smbcli_rap_netprintjobsetinfo failed");
+ }
+
+ return true;
+}
+
+
+static bool test_netprintjobgetinfo_byqueue(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintQueueName)
+{
+ struct rap_NetPrintJobEnum r;
+ int i;
+
+ r.in.PrintQueueName = PrintQueueName;
+ r.in.bufsize = 8192;
+ r.in.level = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobenum(cli->tree, tctx, &r),
+ "failed to enumerate jobs");
+
+ for (i=0; i < r.out.count; i++) {
+
+ torture_assert(tctx,
+ test_netprintjobgetinfo_byid(tctx, cli, r.out.info[i].info0.JobID),
+ "failed to get job info");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobsetinfo_byqueue(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintQueueName)
+{
+ struct rap_NetPrintJobEnum r;
+ int i;
+
+ r.in.PrintQueueName = PrintQueueName;
+ r.in.bufsize = 8192;
+ r.in.level = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintjobenum(cli->tree, tctx, &r),
+ "failed to enumerate jobs");
+
+ for (i=0; i < r.out.count; i++) {
+
+ torture_assert(tctx,
+ test_netprintjobsetinfo_byid(tctx, cli, r.out.info[i].info0.JobID),
+ "failed to set job info");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobenum(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQEnum r;
+ int i;
+
+ r.in.level = 5;
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r),
+ "failed to enum printq");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "failed to enum printq");
+
+ for (i=0; i < r.out.count; i++) {
+
+ const char *printqname = r.out.info[i].info5.PrintQueueName;
+
+ torture_assert(tctx,
+ test_netprintjobenum_one(tctx, cli, printqname),
+ "failed to enumerate printjobs on print queue");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobgetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQEnum r;
+ int i;
+
+ r.in.level = 5;
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r),
+ "failed to enum printq");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "failed to enum printq");
+
+ for (i=0; i < r.out.count; i++) {
+
+ const char *printqname = r.out.info[i].info5.PrintQueueName;
+
+ torture_assert(tctx,
+ test_netprintjobgetinfo_byqueue(tctx, cli, printqname),
+ "failed to enumerate printjobs on print queue");
+ }
+
+ return true;
+}
+
+static bool test_netprintjobsetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQEnum r;
+ int i;
+
+ r.in.level = 5;
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r),
+ "failed to enum printq");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "failed to enum printq");
+
+ for (i=0; i < r.out.count; i++) {
+
+ const char *printqname = r.out.info[i].info5.PrintQueueName;
+
+ torture_assert(tctx,
+ test_netprintjobsetinfo_byqueue(tctx, cli, printqname),
+ "failed to set printjobs on print queue");
+ }
+
+ return true;
+}
+
+static bool test_netprintdestenum(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintDestEnum r;
+ int i;
+ uint16_t levels[] = { 0, 1, 2, 3 };
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+
+ torture_comment(tctx,
+ "Testing rap_NetPrintDestEnum level %d\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintdestenum(cli->tree, tctx, &r),
+ "smbcli_rap_netprintdestenum failed");
+ }
+
+ return true;
+}
+
+static bool test_netprintdestgetinfo_bydest(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *PrintDestName)
+{
+ struct rap_NetPrintDestGetInfo r;
+ int i;
+ uint16_t levels[] = { 0, 1, 2, 3 };
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.PrintDestName = PrintDestName;
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+
+ torture_comment(tctx,
+ "Testing rap_NetPrintDestGetInfo(%s) level %d\n", r.in.PrintDestName, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintdestgetinfo(cli->tree, tctx, &r),
+ "smbcli_rap_netprintdestgetinfo failed");
+ }
+
+ return true;
+}
+
+
+static bool test_netprintdestgetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintDestEnum r;
+ int i;
+
+ r.in.level = 2;
+ r.in.bufsize = 8192;
+
+ torture_comment(tctx,
+ "Testing rap_NetPrintDestEnum level %d\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintdestenum(cli->tree, tctx, &r),
+ "smbcli_rap_netprintdestenum failed");
+
+ for (i=0; i < r.out.count; i++) {
+
+ torture_assert(tctx,
+ test_netprintdestgetinfo_bydest(tctx, cli, r.out.info[i].info2.PrinterName),
+ "failed to get printdest info");
+
+ }
+
+ return true;
+}
+
+static bool test_rap_print(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetPrintQEnum r;
+ int i;
+
+ r.in.level = 5;
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netprintqenum(cli->tree, tctx, &r),
+ "failed to enum printq");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "failed to enum printq");
+
+ for (i=0; i < r.out.count; i++) {
+
+ const char *printqname = r.out.info[i].info5.PrintQueueName;
+ struct smbcli_tree *res_queue = NULL;
+ uint16_t num_jobs;
+ union rap_printj_info *job_info;
+ int j;
+
+ torture_assert(tctx,
+ test_netprintq_pause(tctx, cli, printqname),
+ "failed to set printjobs on print queue");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_second_tcon(tctx, cli->session, printqname, &res_queue),
+ "failed to open 2nd connection");
+
+ torture_assert(tctx,
+ print_printjob(tctx, res_queue),
+ "failed to print job on 2nd connection");
+
+ talloc_free(res_queue);
+
+ torture_assert(tctx,
+ test_netprintjobenum_args(tctx, cli, printqname, 1,
+ &num_jobs, &job_info),
+ "failed to enum printjobs on print queue");
+
+ for (j=0; j < num_jobs; j++) {
+
+ uint16_t job_id = job_info[j].info1.JobID;
+
+ torture_assert(tctx,
+ test_netprintjobgetinfo_byid(tctx, cli, job_id),
+ "failed to getinfo on new printjob");
+
+ torture_assert(tctx,
+ test_netprintjob_delete(tctx, cli, job_id),
+ "failed to delete job");
+ }
+
+ torture_assert(tctx,
+ test_netprintq_resume(tctx, cli, printqname),
+ "failed to resume print queue");
+
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rap_printing(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "printing");
+
+ torture_suite_add_1smb_test(suite, "raw_print", test_raw_print);
+ torture_suite_add_1smb_test(suite, "rap_print", test_rap_print);
+ torture_suite_add_1smb_test(suite, "rap_printq_enum", test_netprintqenum);
+ torture_suite_add_1smb_test(suite, "rap_printq_getinfo", test_netprintqgetinfo);
+ torture_suite_add_1smb_test(suite, "rap_printq", test_netprintq);
+ torture_suite_add_1smb_test(suite, "rap_printjob_enum", test_netprintjobenum);
+ torture_suite_add_1smb_test(suite, "rap_printjob_getinfo", test_netprintjobgetinfo);
+ torture_suite_add_1smb_test(suite, "rap_printjob_setinfo", test_netprintjobsetinfo);
+ torture_suite_add_1smb_test(suite, "rap_printjob", test_netprintjob);
+ torture_suite_add_1smb_test(suite, "rap_printdest_enum", test_netprintdestenum);
+ torture_suite_add_1smb_test(suite, "rap_printdest_getinfo", test_netprintdestgetinfo);
+
+ return suite;
+}
diff --git a/source4/torture/rap/rap.c b/source4/torture/rap/rap.c
new file mode 100644
index 0000000..054e011
--- /dev/null
+++ b/source4/torture/rap/rap.c
@@ -0,0 +1,275 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various RAP operations
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Tim Potter 2005
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "param/param.h"
+#include "libcli/rap/rap.h"
+#include "torture/rap/proto.h"
+
+static bool test_netshareenum(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetShareEnum r;
+ int i;
+
+ r.in.level = 1;
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netshareenum(cli->tree, tctx, &r), "");
+
+ for (i=0; i<r.out.count; i++) {
+ printf("%s %d %s\n", r.out.info[i].info1.share_name,
+ r.out.info[i].info1.share_type,
+ r.out.info[i].info1.comment);
+ }
+
+ return true;
+}
+
+static bool test_netserverenum(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetServerEnum2 r;
+ int i;
+
+ r.in.level = 0;
+ r.in.bufsize = 8192;
+ r.in.servertype = 0xffffffff;
+ r.in.servertype = 0x80000000;
+ r.in.domain = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netserverenum2(cli->tree, tctx, &r), "");
+
+ for (i=0; i<r.out.count; i++) {
+ switch (r.in.level) {
+ case 0:
+ printf("%s\n", r.out.info[i].info0.name);
+ break;
+ case 1:
+ printf("%s %x %s\n", r.out.info[i].info1.name,
+ r.out.info[i].info1.servertype,
+ r.out.info[i].info1.comment);
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool test_netservergetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_WserverGetInfo r;
+ bool res = true;
+
+ r.in.bufsize = 0xffff;
+
+ r.in.level = 0;
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netservergetinfo(cli->tree, tctx, &r),
+ "rap_netservergetinfo level 0 failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "rap_netservergetinfo level 0 failed");
+
+ r.in.level = 1;
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netservergetinfo(cli->tree, tctx, &r),
+ "rap_netservergetinfo level 1 failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "rap_netservergetinfo level 1 failed");
+
+ return res;
+}
+
+static bool test_netsessionenum(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetSessionEnum r;
+ int i,n;
+ uint16_t levels[] = { 2 };
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+
+ torture_comment(tctx,
+ "Testing rap_NetSessionEnum level %d\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netsessionenum(cli->tree, tctx, &r),
+ "smbcli_rap_netsessionenum failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netsessionenum failed");
+
+ for (n=0; n < r.out.count; n++) {
+ switch (r.in.level) {
+ case 2:
+ torture_comment(tctx, "ComputerName: %s\n",
+ r.out.info[n].info2.ComputerName);
+
+ torture_comment(tctx, "UserName: %s\n",
+ r.out.info[n].info2.UserName);
+
+ torture_assert(tctx, r.out.info[n].info2.ComputerName,
+ "ComputerName empty");
+ torture_assert(tctx, r.out.info[n].info2.UserName,
+ "UserName empty");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_netsessiongetinfo_bysession(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *session)
+{
+ struct rap_NetSessionGetInfo r;
+ int i;
+ uint16_t levels[] = { 2 };
+
+ if (session && session[0] == '\\' && session[1] == '\\') {
+ r.in.SessionName = session;
+ } else {
+ r.in.SessionName = talloc_asprintf(tctx, "\\\\%s", session);
+ }
+ r.in.bufsize = 0xffff;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netsessiongetinfo(cli->tree, tctx, &r),
+ "rap_netsessiongetinfo failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "rap_netsessiongetinfo failed");
+ }
+
+ return true;
+}
+
+static bool test_netsessiongetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetSessionEnum r;
+ int i,n;
+ uint16_t levels[] = { 2 };
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netsessionenum(cli->tree, tctx, &r),
+ "smbcli_rap_netsessionenum failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netsessionenum failed");
+
+ for (n=0; n < r.out.count; n++) {
+ torture_assert(tctx,
+ test_netsessiongetinfo_bysession(tctx, cli, r.out.info[n].info2.ComputerName),
+ "failed to query sessioninfo");
+ }
+ }
+
+ return true;
+}
+
+static bool test_netremotetod(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_NetRemoteTOD r;
+
+ r.in.bufsize = 8192;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netremotetod(cli->tree, tctx, &r),
+ "smbcli_rap_netremotetod failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netremotetod failed");
+
+ return true;
+}
+
+bool torture_rap_scan(struct torture_context *torture, struct smbcli_state *cli)
+{
+ int callno;
+
+ for (callno = 0; callno < 0xffff; callno++) {
+ struct rap_call *call = new_rap_cli_call(torture, callno);
+ NTSTATUS result;
+
+ result = rap_cli_do_call(cli->tree, call);
+
+ if (!NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER))
+ continue;
+
+ printf("callno %d is RAP call\n", callno);
+ }
+
+ return true;
+}
+
+NTSTATUS torture_rap_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "rap");
+ struct torture_suite *suite_basic = torture_suite_create(suite, "basic");
+
+ torture_suite_add_suite(suite, suite_basic);
+ torture_suite_add_suite(suite, torture_rap_rpc(suite));
+ torture_suite_add_suite(suite, torture_rap_printing(suite));
+ torture_suite_add_suite(suite, torture_rap_sam(suite));
+
+ torture_suite_add_1smb_test(suite_basic, "netserverenum",
+ test_netserverenum);
+ torture_suite_add_1smb_test(suite_basic, "netshareenum",
+ test_netshareenum);
+ torture_suite_add_1smb_test(suite_basic, "netservergetinfo",
+ test_netservergetinfo);
+ torture_suite_add_1smb_test(suite_basic, "netsessionenum",
+ test_netsessionenum);
+ torture_suite_add_1smb_test(suite_basic, "netsessiongetinfo",
+ test_netsessiongetinfo);
+ torture_suite_add_1smb_test(suite_basic, "netremotetod",
+ test_netremotetod);
+
+ torture_suite_add_1smb_test(suite, "scan", torture_rap_scan);
+
+ suite->description = talloc_strdup(suite,
+ "Remote Administration Protocol tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/rap/rpc.c b/source4/torture/rap/rpc.c
new file mode 100644
index 0000000..6c8c86c
--- /dev/null
+++ b/source4/torture/rap/rpc.c
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for RAP / DCERPC consistency
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "libcli/rap/rap.h"
+#include "torture/rap/proto.h"
+#include "param/param.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+
+static bool test_rpc_netservergetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct rap_WserverGetInfo r;
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ struct srvsvc_NetSrvGetInfo s;
+ union srvsvc_NetSrvInfo info;
+
+ const char *server_name;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p, &ndr_table_srvsvc),
+ "failed to open srvsvc");
+
+ b = p->binding_handle;
+
+ s.in.server_unc = NULL;
+ s.in.level = 101;
+ s.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_srvsvc_NetSrvGetInfo_r(b, tctx, &s),
+ "srvsvc_NetSrvGetInfo level 101 failed");
+ torture_assert_werr_ok(tctx, s.out.result,
+ "srvsvc_NetSrvGetInfo level 101 failed");
+
+ r.in.bufsize = 0xffff;
+ r.in.level = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netservergetinfo(cli->tree, tctx, &r),
+ "rap_netservergetinfo level 0 failed");
+ torture_assert_int_equal(tctx, r.out.status, 0,
+ "rap_netservergetinfo level 0 failed");
+
+ server_name = talloc_strndup(tctx, info.info101->server_name, 16);
+
+ torture_assert_str_equal(tctx, (const char *)r.out.info.info0.name, server_name, "server name");
+
+ r.in.level = 1;
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netservergetinfo(cli->tree, tctx, &r),
+ "rap_netservergetinfo level 1 failed");
+ torture_assert_int_equal(tctx, r.out.status, 0,
+ "rap_netservergetinfo level 1 failed");
+
+ torture_assert_str_equal(tctx, (const char *)r.out.info.info1.name, server_name, "server name");
+ torture_assert_int_equal(tctx, r.out.info.info1.version_major, info.info101->version_major, "version major");
+ torture_assert_int_equal(tctx, r.out.info.info1.version_minor, info.info101->version_minor, "version minor");
+ torture_assert_int_equal(tctx, r.out.info.info1.servertype, info.info101->server_type, "server_type");
+ torture_assert_str_equal(tctx, r.out.info.info1.comment, info.info101->comment, "comment");
+
+ talloc_free(p);
+
+ return true;
+}
+
+struct torture_suite *torture_rap_rpc(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "rpc");
+
+ torture_suite_add_1smb_test(suite, "netservergetinfo",
+ test_rpc_netservergetinfo);
+
+ suite->description = talloc_strdup(suite,
+ "RAP / DCERPC consistency tests");
+
+ return suite;
+}
diff --git a/source4/torture/rap/sam.c b/source4/torture/rap/sam.c
new file mode 100644
index 0000000..3c13849
--- /dev/null
+++ b/source4/torture/rap/sam.c
@@ -0,0 +1,376 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for RAP sam operations
+
+ Copyright (C) Guenther Deschner 2010-2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smbtorture.h"
+#include "torture/util.h"
+#include "libcli/rap/rap.h"
+#include "torture/rap/proto.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "torture/rpc/torture_rpc.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#define TEST_RAP_USER "torture_rap_user"
+
+static char *samr_rand_pass(TALLOC_CTX *mem_ctx, int min_len)
+{
+ size_t len = MAX(8, min_len);
+ char *s = generate_random_password(mem_ctx, len, len+6);
+ printf("Generated password '%s'\n", s);
+ return s;
+}
+
+static bool test_userpasswordset2_args(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *username,
+ const char **password)
+{
+ struct rap_NetUserPasswordSet2 r;
+ char *newpass = samr_rand_pass(tctx, 8);
+
+ ZERO_STRUCT(r);
+
+ r.in.UserName = username;
+
+ memcpy(r.in.OldPassword, *password, MIN(strlen(*password), 16));
+ memcpy(r.in.NewPassword, newpass, MIN(strlen(newpass), 16));
+ r.in.EncryptedPassword = 0;
+ r.in.RealPasswordLength = strlen(newpass);
+
+ torture_comment(tctx, "Testing rap_NetUserPasswordSet2(%s)\n", r.in.UserName);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuserpasswordset2(cli->tree, tctx, &r),
+ "smbcli_rap_netuserpasswordset2 failed");
+ if (!W_ERROR_IS_OK(W_ERROR(r.out.status))) {
+ torture_warning(tctx, "RAP NetUserPasswordSet2 gave: %s\n",
+ win_errstr(W_ERROR(r.out.status)));
+ } else {
+ *password = newpass;
+ }
+
+ return true;
+}
+
+static bool test_userpasswordset2_crypt_args(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *username,
+ const char **password)
+{
+ struct rap_NetUserPasswordSet2 r;
+ char *newpass = samr_rand_pass(tctx, 8);
+
+ r.in.UserName = username;
+
+ E_deshash(*password, r.in.OldPassword);
+ E_deshash(newpass, r.in.NewPassword);
+
+ r.in.RealPasswordLength = strlen(newpass);
+ r.in.EncryptedPassword = 1;
+
+ torture_comment(tctx, "Testing rap_NetUserPasswordSet2(%s)\n", r.in.UserName);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuserpasswordset2(cli->tree, tctx, &r),
+ "smbcli_rap_netuserpasswordset2 failed");
+ if (!W_ERROR_IS_OK(W_ERROR(r.out.status))) {
+ torture_warning(tctx, "RAP NetUserPasswordSet2 gave: %s\n",
+ win_errstr(W_ERROR(r.out.status)));
+ } else {
+ *password = newpass;
+ }
+
+ return true;
+}
+
+static bool test_userpasswordset2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct test_join *join_ctx;
+ const char *password;
+ bool ret = true;
+
+ join_ctx = torture_create_testuser_max_pwlen(tctx, TEST_RAP_USER,
+ torture_setting_string(tctx, "workgroup", NULL),
+ ACB_NORMAL,
+ &password, 14);
+ if (join_ctx == NULL) {
+ torture_fail(tctx, "failed to create user\n");
+ }
+
+ ret &= test_userpasswordset2_args(tctx, cli, TEST_RAP_USER, &password);
+ ret &= test_userpasswordset2_crypt_args(tctx, cli, TEST_RAP_USER, &password);
+
+ torture_leave_domain(tctx, join_ctx);
+
+ return ret;
+}
+
+static bool test_oemchangepassword_args(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *username,
+ const char **password)
+{
+ struct rap_NetOEMChangePassword r;
+
+ const char *oldpass = *password;
+ char *newpass = samr_rand_pass(tctx, 9);
+ uint8_t old_pw_hash[16];
+ uint8_t new_pw_hash[16];
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t pw_key = {
+ .data = old_pw_hash,
+ .size = sizeof(old_pw_hash),
+ };
+
+ r.in.UserName = username;
+
+ E_deshash(oldpass, old_pw_hash);
+ E_deshash(newpass, new_pw_hash);
+
+ encode_pw_buffer(r.in.crypt_password, newpass, STR_ASCII);
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &pw_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd,
+ r.in.crypt_password,
+ 516);
+ gnutls_cipher_deinit(cipher_hnd);
+ E_old_pw_hash(new_pw_hash, old_pw_hash, r.in.password_hash);
+
+ torture_comment(tctx, "Testing rap_NetOEMChangePassword(%s)\n", r.in.UserName);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netoemchangepassword(cli->tree, tctx, &r),
+ "smbcli_rap_netoemchangepassword failed");
+ if (!W_ERROR_IS_OK(W_ERROR(r.out.status))) {
+ torture_warning(tctx, "RAP NetOEMChangePassword gave: %s\n",
+ win_errstr(W_ERROR(r.out.status)));
+ } else {
+ *password = newpass;
+ }
+
+ return true;
+}
+
+static bool test_oemchangepassword(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+
+ struct test_join *join_ctx;
+ const char *password;
+ bool ret;
+
+ join_ctx = torture_create_testuser_max_pwlen(tctx, TEST_RAP_USER,
+ torture_setting_string(tctx, "workgroup", NULL),
+ ACB_NORMAL,
+ &password, 14);
+ if (join_ctx == NULL) {
+ torture_fail(tctx, "failed to create user\n");
+ }
+
+ ret = test_oemchangepassword_args(tctx, cli, TEST_RAP_USER, &password);
+
+ torture_leave_domain(tctx, join_ctx);
+
+ return ret;
+}
+
+static bool test_usergetinfo_byname(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *UserName)
+{
+ struct rap_NetUserGetInfo r;
+ int i;
+ uint16_t levels[] = { 0, 1, 2, 10, 11 };
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.UserName = UserName;
+ r.in.level = levels[i];
+ r.in.bufsize = 8192;
+
+ torture_comment(tctx,
+ "Testing rap_NetUserGetInfo(%s) level %d\n", r.in.UserName, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netusergetinfo(cli->tree, tctx, &r),
+ "smbcli_rap_netusergetinfo failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netusergetinfo failed");
+ }
+
+ return true;
+}
+
+static bool test_usergetinfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+
+ struct test_join *join_ctx;
+ const char *password;
+ bool ret;
+
+ join_ctx = torture_create_testuser_max_pwlen(tctx, TEST_RAP_USER,
+ torture_setting_string(tctx, "workgroup", NULL),
+ ACB_NORMAL,
+ &password, 14);
+ if (join_ctx == NULL) {
+ torture_fail(tctx, "failed to create user\n");
+ }
+
+ ret = test_usergetinfo_byname(tctx, cli, TEST_RAP_USER);
+
+ torture_leave_domain(tctx, join_ctx);
+
+ return ret;
+}
+
+static bool test_useradd(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+
+ struct rap_NetUserAdd r;
+ struct rap_NetUserInfo1 info1;
+ int i;
+ uint16_t levels[] = { 1 };
+ const char *username = TEST_RAP_USER;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ const char *pwd;
+
+ pwd = generate_random_password(tctx, 9, 16);
+
+ r.in.level = levels[i];
+ r.in.bufsize = 0xffff;
+ r.in.pwdlength = strlen(pwd);
+ r.in.unknown = 0;
+
+ switch (r.in.level) {
+ case 1:
+ ZERO_STRUCT(info1);
+
+ info1.Name = username;
+ memcpy(info1.Password, pwd, MIN(strlen(pwd), 16));
+ info1.Priv = USER_PRIV_USER;
+ info1.Flags = 0x21;
+ info1.HomeDir = "home_dir";
+ info1.Comment = "comment";
+ info1.ScriptPath = "logon_script";
+
+ r.in.info.info1 = info1;
+ break;
+ }
+
+ torture_comment(tctx,
+ "Testing rap_NetUserAdd(%s) level %d\n", username, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuseradd(cli->tree, tctx, &r),
+ "smbcli_rap_netuseradd failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netuseradd failed");
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuseradd(cli->tree, tctx, &r),
+ "2nd smbcli_rap_netuseradd failed");
+ torture_assert_werr_equal(tctx, W_ERROR(r.out.status), WERR_NERR_USEREXISTS,
+ "2nd smbcli_rap_netuseradd failed");
+
+ {
+ struct rap_NetUserDelete d;
+
+ d.in.UserName = username;
+
+ smbcli_rap_netuserdelete(cli->tree, tctx, &d);
+ }
+ }
+
+ return true;
+}
+
+static bool test_userdelete(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+
+ struct rap_NetUserDelete r;
+
+ {
+ struct rap_NetUserAdd a;
+ const char *pwd;
+
+ ZERO_STRUCT(a.in.info.info1);
+
+ pwd = generate_random_password(tctx, 9, 16);
+
+ a.in.level = 1;
+ a.in.bufsize = 0xffff;
+ a.in.pwdlength = strlen(pwd);
+ a.in.unknown = 0;
+ a.in.info.info1.Name = TEST_RAP_USER;
+ a.in.info.info1.Priv = USER_PRIV_USER;
+
+ memcpy(a.in.info.info1.Password, pwd, MIN(strlen(pwd), 16));
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuseradd(cli->tree, tctx, &a),
+ "smbcli_rap_netuseradd failed");
+ }
+
+ r.in.UserName = TEST_RAP_USER;
+
+ torture_comment(tctx,
+ "Testing rap_NetUserDelete(%s)\n", r.in.UserName);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuserdelete(cli->tree, tctx, &r),
+ "smbcli_rap_netuserdelete failed");
+ torture_assert_werr_ok(tctx, W_ERROR(r.out.status),
+ "smbcli_rap_netuserdelete failed");
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_rap_netuserdelete(cli->tree, tctx, &r),
+ "2nd smbcli_rap_netuserdelete failed");
+ torture_assert_werr_equal(tctx, W_ERROR(r.out.status), WERR_NERR_USERNOTFOUND,
+ "2nd smbcli_rap_netuserdelete failed");
+
+ return true;
+}
+
+struct torture_suite *torture_rap_sam(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "sam");
+
+ torture_suite_add_1smb_test(suite, "userpasswordset2", test_userpasswordset2);
+ torture_suite_add_1smb_test(suite, "oemchangepassword", test_oemchangepassword);
+ torture_suite_add_1smb_test(suite, "usergetinfo", test_usergetinfo);
+ torture_suite_add_1smb_test(suite, "useradd", test_useradd);
+ torture_suite_add_1smb_test(suite, "userdelete", test_userdelete);
+
+ return suite;
+}
diff --git a/source4/torture/raw/acls.c b/source4/torture/raw/acls.c
new file mode 100644
index 0000000..6a56514
--- /dev/null
+++ b/source4/torture/raw/acls.c
@@ -0,0 +1,2556 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test security descriptor operations
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/util/clilsa.h"
+#include "libcli/security/security.h"
+#include "torture/util.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\testsd"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ goto done; \
+ }} while (0)
+
+#define FAIL_UNLESS(__cond) \
+ do { \
+ if (__cond) {} else { \
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
+ __location__, #__cond); \
+ goto done; \
+ } \
+ } while(0)
+
+#define CHECK_SECURITY_DESCRIPTOR(_sd1, _sd2) do { \
+ if (!security_descriptor_equal(_sd1, _sd2)) { \
+ torture_warning(tctx, "%s: security descriptors don't match!\n", __location__); \
+ torture_warning(tctx, "got:\n"); \
+ NDR_PRINT_DEBUG(security_descriptor, _sd1); \
+ torture_warning(tctx, "expected:\n"); \
+ NDR_PRINT_DEBUG(security_descriptor, _sd2); \
+ ret = false; \
+ } \
+} while (0)
+
+/*
+ * Helper function to verify a security descriptor, by querying
+ * and comparing against the passed in sd.
+ * Copied to smb2_util_verify_sd() for SMB2.
+ */
+static bool verify_sd(TALLOC_CTX *tctx, struct smbcli_state *cli,
+ int fnum, struct security_descriptor *sd)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_fileinfo q = {};
+
+ if (sd) {
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* More work is needed if we're going to check this bit. */
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+ }
+
+ done:
+ return ret;
+}
+
+/*
+ * Helper function to verify attributes, by querying
+ * and comparing against the passed attrib.
+ * Copied to smb2_util_verify_attrib() for SMB2.
+ */
+static bool verify_attrib(TALLOC_CTX *tctx, struct smbcli_state *cli,
+ int fnum, uint32_t attrib)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_fileinfo q2 = {};
+
+ if (attrib) {
+ q2.standard.level = RAW_FILEINFO_STANDARD;
+ q2.standard.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ q2.standard.out.attrib &= ~FILE_ATTRIBUTE_ARCHIVE;
+
+ if (q2.standard.out.attrib != attrib) {
+ torture_warning(tctx, "%s: attributes don't match! "
+ "got %x, expected %x\n", __location__,
+ (uint32_t)q2.standard.out.attrib,
+ (uint32_t)attrib);
+ ret = false;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+/**
+ * Test setting and removing a DACL.
+ * Test copied to torture_smb2_setinfo() for SMB2.
+ */
+static bool test_sd(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\sd.txt";
+ bool ret = true;
+ int fnum = -1;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_ace ace = {};
+ struct security_descriptor *sd;
+ const struct dom_sid *test_sid;
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING SETFILEINFO EA_SET\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd = q.query_secdesc.out.sd;
+
+ torture_comment(tctx, "add a new ACE to the DACL\n");
+
+ test_sid = &global_sid_Authenticated_Users;
+
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_STD_ALL;
+ ace.trustee = *test_sid;
+
+ status = security_descriptor_dacl_add(sd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = q.query_secdesc.in.secinfo_flags;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ FAIL_UNLESS(verify_sd(tctx, cli, fnum, sd));
+
+ torture_comment(tctx, "remove it again\n");
+
+ status = security_descriptor_dacl_del(sd, test_sid);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ FAIL_UNLESS(verify_sd(tctx, cli, fnum, sd));
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test using nttrans create to create a file with an initial acl set
+ Test copied to test_create_acl() for SMB2.
+*/
+static bool test_nttrans_create_ext(struct torture_context *tctx,
+ struct smbcli_state *cli, bool test_dir)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\acl2.txt";
+ bool ret = true;
+ int fnum = -1;
+ union smb_fileinfo q = {};
+ struct security_ace ace;
+ struct security_descriptor *sd;
+ const struct dom_sid *test_sid;
+ uint32_t attrib =
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM |
+ (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
+ NTSTATUS (*delete_func)(struct smbcli_tree *, const char *) =
+ test_dir ? smbcli_rmdir : smbcli_unlink;
+
+ ZERO_STRUCT(ace);
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options =
+ test_dir ? NTCREATEX_OPTIONS_DIRECTORY : 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.sec_desc = NULL;
+ io.ntcreatex.in.ea_list = NULL;
+
+ torture_comment(tctx, "basic create\n");
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "querying ACL\n");
+
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd = q.query_secdesc.out.sd;
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = delete_func(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "adding a new ACE\n");
+ test_sid = &global_sid_Authenticated_Users;
+
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_STD_ALL;
+ ace.trustee = *test_sid;
+
+ status = security_descriptor_dacl_add(sd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating with an initial ACL\n");
+
+ io.ntcreatex.in.sec_desc = sd;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ FAIL_UNLESS(verify_sd(tctx, cli, fnum, sd));
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating with attributes\n");
+
+ io.ntcreatex.in.sec_desc = NULL;
+ io.ntcreatex.in.file_attr = attrib;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ FAIL_UNLESS(verify_attrib(tctx, cli, fnum, attrib));
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = delete_func(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating with attributes and ACL\n");
+
+ io.ntcreatex.in.sec_desc = sd;
+ io.ntcreatex.in.file_attr = attrib;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ FAIL_UNLESS(verify_sd(tctx, cli, fnum, sd));
+ FAIL_UNLESS(verify_attrib(tctx, cli, fnum, attrib));
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test using nttrans create to create a file and directory with an initial acl
+ and owner.
+*/
+static bool test_nttrans_create_ext_owner(
+ struct torture_context *tctx,
+ struct smbcli_state *cli, bool test_dir)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\foo.txt";
+ bool ret = true;
+ int fnum = -1;
+ struct security_ace ace;
+ struct security_descriptor *sd;
+ uint32_t attrib =
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM |
+ (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
+ NTSTATUS (*delete_func)(struct smbcli_tree *, const char *) =
+ test_dir ? smbcli_rmdir : smbcli_unlink;
+
+ ZERO_STRUCT(ace);
+
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options =
+ test_dir ? NTCREATEX_OPTIONS_DIRECTORY : 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.sec_desc = NULL;
+ io.ntcreatex.in.ea_list = NULL;
+
+ torture_comment(tctx, "creating with attributes, ACL and owner\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_WORLD, SID_BUILTIN_USERS,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ io.ntcreatex.in.sec_desc = sd;
+ io.ntcreatex.in.file_attr = attrib;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ FAIL_UNLESS(verify_sd(tctx, cli, fnum, sd));
+ FAIL_UNLESS(verify_attrib(tctx, cli, fnum, attrib));
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_nttrans_create_file(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ torture_comment(tctx, "Testing nttrans create with sec_desc on files\n");
+
+ return test_nttrans_create_ext(tctx, cli, false);
+}
+
+static bool test_nttrans_create_dir(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ torture_comment(tctx, "Testing nttrans create with sec_desc on directories\n");
+
+ return test_nttrans_create_ext(tctx, cli, true);
+}
+
+static bool test_nttrans_create_owner_file(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ torture_comment(tctx, "Testing nttrans create with sec_desc with owner on file\n");
+
+ return test_nttrans_create_ext_owner(tctx, cli, false);
+}
+
+static bool test_nttrans_create_owner_dir(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ torture_comment(tctx, "Testing nttrans create with sec_desc with owner on directory\n");
+
+ return test_nttrans_create_ext_owner(tctx, cli, true);
+}
+
+#define CHECK_ACCESS_FLAGS(_fnum, flags) do { \
+ union smb_fileinfo _q; \
+ _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
+ _q.access_information.in.file.fnum = (_fnum); \
+ status = smb_raw_fileinfo(cli->tree, tctx, &_q); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if (_q.access_information.out.access_flags != (flags)) { \
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
+ __location__, _q.access_information.out.access_flags, (flags)); \
+ goto done; \
+ } \
+} while (0)
+
+/*
+ test using NTTRANS CREATE to create a file with a null ACL set
+ Test copied to test_create_null_dacl() for SMB2.
+*/
+static bool test_nttrans_create_null_dacl(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\nulldacl.txt";
+ bool ret = true;
+ int fnum = -1;
+ union smb_fileinfo q;
+ union smb_setfileinfo s;
+ struct security_descriptor *sd = security_descriptor_initialise(tctx);
+ struct security_acl dacl;
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n");
+
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC
+ | SEC_STD_WRITE_OWNER;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.sec_desc = sd;
+ io.ntcreatex.in.ea_list = NULL;
+
+ torture_comment(tctx, "creating a file with a empty sd\n");
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Testing the created DACL,
+ * the server should add the inherited DACL
+ * when SEC_DESC_DACL_PRESENT isn't specified
+ */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL_PRESENT flag not set by the server!\n");
+ goto done;
+ }
+ if (q.query_secdesc.out.sd->dacl == NULL) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "no DACL has been created on the server!\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "set NULL DACL\n");
+ sd->type |= SEC_DESC_DACL_PRESENT;
+
+ s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ s.set_secdesc.in.file.fnum = fnum;
+ s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ s.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &s);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "get the sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Testing the modified DACL */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL_PRESENT flag not set by the server!\n");
+ goto done;
+ }
+ if (q.query_secdesc.out.sd->dacl != NULL) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL has been created on the server!\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "try open for read control\n");
+ io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_STD_READ_CONTROL | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for write\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_FILE_WRITE_DATA | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for read\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_RIGHTS_FILE_WRITE | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_RIGHTS_FILE_READ | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "set DACL with 0 aces\n");
+ ZERO_STRUCT(dacl);
+ dacl.revision = SECURITY_ACL_REVISION_NT4;
+ dacl.num_aces = 0;
+ sd->dacl = &dacl;
+
+ s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ s.set_secdesc.in.file.fnum = fnum;
+ s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ s.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &s);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "get the sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Testing the modified DACL */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL_PRESENT flag not set by the server!\n");
+ goto done;
+ }
+ if (q.query_secdesc.out.sd->dacl == NULL) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "no DACL has been created on the server!\n");
+ goto done;
+ }
+ if (q.query_secdesc.out.sd->dacl->num_aces != 0) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n",
+ q.query_secdesc.out.sd->dacl->num_aces);
+ goto done;
+ }
+
+ torture_comment(tctx, "try open for read control\n");
+ io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_STD_READ_CONTROL | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for write => access_denied\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read => access_denied\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic write => access_denied\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read => access_denied\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "set empty sd\n");
+ sd->type &= ~SEC_DESC_DACL_PRESENT;
+ sd->dacl = NULL;
+
+ s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ s.set_secdesc.in.file.fnum = fnum;
+ s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ s.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &s);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "get the sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Testing the modified DACL */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL_PRESENT flag not set by the server!\n");
+ goto done;
+ }
+ if (q.query_secdesc.out.sd->dacl != NULL) {
+ ret = false;
+ torture_result(tctx, TORTURE_FAIL, "DACL has been created on the server!\n");
+ goto done;
+ }
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test the behaviour of the well known SID_CREATOR_OWNER sid, and some generic
+ mapping bits
+ Test copied to smb2/acls.c for SMB2.
+*/
+static bool test_creator_sid(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\creator.txt";
+ bool ret = true;
+ int fnum = -1;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig, *sd2;
+ const char *owner_sid;
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING SID_CREATOR_OWNER\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "try open for write\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "set a sec desc allowing no write by owner\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "check that sd has been mapped correctly\n");
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ torture_comment(tctx, "try open for write\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_FILE_READ_DATA|
+ SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_RIGHTS_FILE_READ);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "set a sec desc allowing generic read by owner\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "check that generic read has been mapped correctly\n");
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ torture_comment(tctx, "try open for write\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ SEC_FILE_READ_DATA |
+ SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.ntcreatex.in.access_mask = SEC_GENERIC_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum, SEC_RIGHTS_FILE_READ);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test the mapping of the SEC_GENERIC_xx bits to SEC_STD_xx and
+ SEC_FILE_xx bits
+ Test copied to smb2/acls.c for SMB2.
+*/
+static bool test_generic_bits(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\generic.txt";
+ bool ret = true;
+ int fnum = -1, i;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig, *sd2;
+ const char *owner_sid;
+ const struct {
+ uint32_t gen_bits;
+ uint32_t specific_bits;
+ } file_mappings[] = {
+ { 0, 0 },
+ { SEC_GENERIC_READ, SEC_RIGHTS_FILE_READ },
+ { SEC_GENERIC_WRITE, SEC_RIGHTS_FILE_WRITE },
+ { SEC_GENERIC_EXECUTE, SEC_RIGHTS_FILE_EXECUTE },
+ { SEC_GENERIC_ALL, SEC_RIGHTS_FILE_ALL },
+ { SEC_FILE_READ_DATA, SEC_FILE_READ_DATA },
+ { SEC_FILE_READ_ATTRIBUTE, SEC_FILE_READ_ATTRIBUTE }
+ };
+ const struct {
+ uint32_t gen_bits;
+ uint32_t specific_bits;
+ } dir_mappings[] = {
+ { 0, 0 },
+ { SEC_GENERIC_READ, SEC_RIGHTS_DIR_READ },
+ { SEC_GENERIC_WRITE, SEC_RIGHTS_DIR_WRITE },
+ { SEC_GENERIC_EXECUTE, SEC_RIGHTS_DIR_EXECUTE },
+ { SEC_GENERIC_ALL, SEC_RIGHTS_DIR_ALL }
+ };
+ bool has_restore_privilege;
+ bool has_take_ownership_privilege;
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING FILE GENERIC BITS\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "torture_check_privilege - %s\n",
+ nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_RESTORE - %s\n", has_restore_privilege?"Yes":"No");
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_TAKE_OWNERSHIP));
+ has_take_ownership_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "torture_check_privilege - %s\n",
+ nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_TAKE_OWNERSHIP - %s\n", has_take_ownership_privilege?"Yes":"No");
+
+ for (i=0;i<ARRAY_SIZE(file_mappings);i++) {
+ uint32_t expected_mask =
+ SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_STD_DELETE;
+ uint32_t expected_mask_anon = SEC_FILE_READ_ATTRIBUTE;
+
+ if (has_restore_privilege) {
+ expected_mask_anon |= SEC_STD_DELETE;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ expected_mask | file_mappings[i].specific_bits);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ if (!has_take_ownership_privilege) {
+ continue;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x (anonymous)\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ expected_mask_anon | file_mappings[i].specific_bits);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ }
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+
+ torture_comment(tctx, "TESTING DIR GENERIC BITS\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "torture_check_privilege - %s\n",
+ nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_RESTORE - %s\n", has_restore_privilege?"Yes":"No");
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_TAKE_OWNERSHIP));
+ has_take_ownership_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "torture_check_privilege - %s\n",
+ nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_TAKE_OWNERSHIP - %s\n", has_take_ownership_privilege?"Yes":"No");
+
+ for (i=0;i<ARRAY_SIZE(dir_mappings);i++) {
+ uint32_t expected_mask =
+ SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_STD_DELETE;
+ uint32_t expected_mask_anon = SEC_FILE_READ_ATTRIBUTE;
+
+ if (has_restore_privilege) {
+ expected_mask_anon |= SEC_STD_DELETE;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ dir_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ dir_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ expected_mask | dir_mappings[i].specific_bits);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ if (!has_take_ownership_privilege) {
+ continue;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x (anonymous)\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum,
+ expected_mask_anon | dir_mappings[i].specific_bits);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ }
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ see what access bits the owner of a file always gets
+ Test copied to smb2/acls.c for SMB2.
+*/
+static bool test_owner_bits(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\test_owner_bits.txt";
+ bool ret = true;
+ int fnum = -1, i;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig;
+ const char *owner_sid;
+ bool has_restore_privilege;
+ bool has_take_ownership_privilege;
+ uint32_t expected_bits;
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING FILE OWNER BITS\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "torture_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_RESTORE - %s\n", has_restore_privilege?"Yes":"No");
+
+ status = torture_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_TAKE_OWNERSHIP));
+ has_take_ownership_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "torture_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_TAKE_OWNERSHIP - %s\n", has_take_ownership_privilege?"Yes":"No");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ expected_bits = SEC_FILE_WRITE_DATA | SEC_FILE_READ_ATTRIBUTE;
+
+ for (i=0;i<16;i++) {
+ uint32_t bit = (1<<i);
+ io.ntcreatex.in.access_mask = bit;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (expected_bits & bit) {
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "failed with access mask 0x%08x of expected 0x%08x\n",
+ bit, expected_bits);
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.ntcreatex.out.file.fnum, bit | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ } else {
+ if (NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "open succeeded with access mask 0x%08x of "
+ "expected 0x%08x - should fail\n",
+ bit, expected_bits);
+ }
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+
+/*
+ test the inheritance of ACL flags onto new files and directories
+ Test copied to smb2/acls.c for SMB2.
+*/
+static bool test_inheritance(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *dname = BASEDIR "\\inheritance";
+ const char *fname1 = BASEDIR "\\inheritance\\testfile";
+ const char *fname2 = BASEDIR "\\inheritance\\testdir";
+ bool ret = true;
+ int fnum=0, fnum2, i;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd2, *sd_orig=NULL, *sd_def1, *sd_def2;
+ const char *owner_sid, *group_sid;
+ const struct dom_sid *creator_owner;
+ const struct {
+ uint32_t parent_flags;
+ uint32_t file_flags;
+ uint32_t dir_flags;
+ } test_flags[] = {
+ {
+ 0,
+ 0,
+ 0
+ },
+ {
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY,
+ },
+ {
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ }
+ };
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACL INHERITANCE\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+ group_sid = dom_sid_string(tctx, sd_orig->group_sid);
+
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+ torture_comment(tctx, "group_sid is %s\n", group_sid);
+
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ /* the default ACL in Samba4 includes the group and
+ other permissions */
+ sd_def1 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ group_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE,
+ 0,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE,
+ 0,
+ SID_NT_SYSTEM,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ NULL);
+ } else {
+ /*
+ * The Windows Default ACL for a new file, when there is no ACL to be
+ * inherited: FullControl for the owner and SYSTEM.
+ */
+ sd_def1 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ SID_NT_SYSTEM,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ NULL);
+ }
+
+ /*
+ * Use this in the case the system being tested does not add an ACE for
+ * the SYSTEM SID.
+ */
+ sd_def2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ NULL);
+
+ creator_owner = dom_sid_parse_talloc(tctx, SID_CREATOR_OWNER);
+
+ for (i=0;i<ARRAY_SIZE(test_flags);i++) {
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ test_flags[i].parent_flags,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.ntcreatex.in.fname = fname1;
+ io.ntcreatex.in.create_options = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ q.query_secdesc.in.file.fnum = fnum2;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum2);
+ smbcli_unlink(cli->tree, fname1);
+
+ if (!(test_flags[i].parent_flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ if (!security_descriptor_equal(q.query_secdesc.out.sd, sd_def1) &&
+ !security_descriptor_equal(q.query_secdesc.out.sd, sd_def2)) {
+ torture_warning(tctx, "Expected default sd "
+ "for i=%d:\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, sd_def1);
+ torture_warning(tctx, "at %d - got:\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ }
+ goto check_dir;
+ }
+
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 1 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ sd_orig->owner_sid)) {
+ ret = false;
+ torture_warning(tctx, "Bad sd in child file at %d\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ goto check_dir;
+ }
+
+ if (q.query_secdesc.out.sd->dacl->aces[0].flags !=
+ test_flags[i].file_flags) {
+ torture_warning(tctx, "incorrect file_flags 0x%x - expected 0x%x for parent 0x%x with (i=%d)\n",
+ q.query_secdesc.out.sd->dacl->aces[0].flags,
+ test_flags[i].file_flags,
+ test_flags[i].parent_flags,
+ i);
+ ret = false;
+ }
+
+ check_dir:
+ io.ntcreatex.in.fname = fname2;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ q.query_secdesc.in.file.fnum = fnum2;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum2);
+ smbcli_rmdir(cli->tree, fname2);
+
+ if (!(test_flags[i].parent_flags & SEC_ACE_FLAG_CONTAINER_INHERIT) &&
+ (!(test_flags[i].parent_flags & SEC_ACE_FLAG_OBJECT_INHERIT) ||
+ (test_flags[i].parent_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT))) {
+ if (!security_descriptor_equal(q.query_secdesc.out.sd, sd_def1) &&
+ !security_descriptor_equal(q.query_secdesc.out.sd, sd_def2)) {
+ torture_warning(tctx, "Expected default sd for dir at %d:\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, sd_def1);
+ torture_warning(tctx, "got:\n");
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ }
+ continue;
+ }
+
+ if ((test_flags[i].parent_flags & SEC_ACE_FLAG_CONTAINER_INHERIT) &&
+ (test_flags[i].parent_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 1 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ sd_orig->owner_sid) ||
+ q.query_secdesc.out.sd->dacl->aces[0].flags != test_flags[i].dir_flags) {
+ torture_warning(tctx, "(CI & NP) Bad sd in child dir - expected 0x%x for parent 0x%x (i=%d)\n",
+ test_flags[i].dir_flags,
+ test_flags[i].parent_flags, i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ torture_comment(tctx, "FYI, here is the parent sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ continue;
+ }
+ } else if (test_flags[i].parent_flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 2 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ sd_orig->owner_sid) ||
+ q.query_secdesc.out.sd->dacl->aces[1].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[1].trustee,
+ creator_owner) ||
+ q.query_secdesc.out.sd->dacl->aces[0].flags != 0 ||
+ q.query_secdesc.out.sd->dacl->aces[1].flags !=
+ (test_flags[i].dir_flags | SEC_ACE_FLAG_INHERIT_ONLY)) {
+ torture_warning(tctx, "(CI) Bad sd in child dir - expected 0x%x for parent 0x%x (i=%d)\n",
+ test_flags[i].dir_flags,
+ test_flags[i].parent_flags, i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ torture_comment(tctx, "FYI, here is the parent sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ continue;
+ }
+ } else {
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 1 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ creator_owner) ||
+ q.query_secdesc.out.sd->dacl->aces[0].flags != test_flags[i].dir_flags) {
+ torture_warning(tctx, "(0) Bad sd in child dir - expected 0x%x for parent 0x%x (i=%d)\n",
+ test_flags[i].dir_flags,
+ test_flags[i].parent_flags, i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ torture_comment(tctx, "FYI, here is the parent sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ continue;
+ }
+ }
+ }
+
+ torture_comment(tctx, "Testing access checks on inherited create with %s\n", fname1);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Check DACL we just set. */
+ torture_comment(tctx, "checking new sd\n");
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ io.ntcreatex.in.fname = fname1;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_ACCESS_FLAGS(fnum2, SEC_RIGHTS_FILE_ALL);
+
+ q.query_secdesc.in.file.fnum = fnum2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, fnum2);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ 0,
+ NULL);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "failed: w2k3 ACL bug (allowed open when ACL should deny)\n");
+ ret = false;
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_ACCESS_FLAGS(fnum2, SEC_RIGHTS_FILE_ALL);
+ smbcli_close(cli->tree, fnum2);
+ } else {
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ torture_comment(tctx, "trying without execute\n");
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL & ~SEC_FILE_EXECUTE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "and with full permissions again\n");
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_ACCESS_FLAGS(fnum2, SEC_FILE_WRITE_DATA | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, fnum2);
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_ACCESS_FLAGS(fnum2, SEC_FILE_WRITE_DATA | SEC_FILE_READ_ATTRIBUTE);
+ smbcli_close(cli->tree, fnum2);
+
+done:
+ if (sd_orig != NULL) {
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ }
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname1);
+ smbcli_rmdir(cli->tree, dname);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ if (!ret) {
+ torture_result(tctx,
+ TORTURE_FAIL, "(%s) test_inheritance\n",
+ __location__);
+ }
+
+ return ret;
+}
+
+static bool test_inheritance_flags(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *dname = BASEDIR "\\inheritance";
+ const char *fname1 = BASEDIR "\\inheritance\\testfile";
+ bool ret = true;
+ int fnum=0, fnum2, i, j;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd2, *sd_orig=NULL;
+ const char *owner_sid;
+ struct {
+ uint32_t parent_set_sd_type; /* 3 options */
+ uint32_t parent_set_ace_inherit; /* 1 option */
+ uint32_t parent_get_sd_type;
+ uint32_t parent_get_ace_inherit;
+ uint32_t child_get_sd_type;
+ uint32_t child_get_ace_inherit;
+ } tflags[16] = {{0}}; /* 2^4 */
+
+ for (i = 0; i < 15; i++) {
+ torture_comment(tctx, "i=%d:", i);
+
+ ZERO_STRUCT(tflags[i]);
+
+ if (i & 1) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ torture_comment(tctx, "AUTO_INHERITED, ");
+ }
+ if (i & 2) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERIT_REQ;
+ torture_comment(tctx, "AUTO_INHERIT_REQ, ");
+ }
+ if (i & 4) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_PROTECTED;
+ tflags[i].parent_get_sd_type |=
+ SEC_DESC_DACL_PROTECTED;
+ torture_comment(tctx, "PROTECTED, ");
+ }
+ if (i & 8) {
+ tflags[i].parent_set_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ tflags[i].parent_get_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, "INHERITED, ");
+ }
+
+ if ((tflags[i].parent_set_sd_type &
+ (SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ)) ==
+ (SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ)) {
+ tflags[i].parent_get_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ tflags[i].child_get_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ tflags[i].child_get_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, " ... parent is AUTO INHERITED");
+ }
+
+ if (tflags[i].parent_set_ace_inherit &
+ SEC_ACE_FLAG_INHERITED_ACE) {
+ tflags[i].parent_get_ace_inherit =
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, " ... parent ACE is INHERITED");
+ }
+
+ torture_comment(tctx, "\n");
+ }
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACL INHERITANCE FLAGS\n");
+
+ ZERO_STRUCT(io);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = dname;
+
+ torture_comment(tctx, "creating initial directory %s\n", dname);
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "getting original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+
+ for (i=0; i < ARRAY_SIZE(tflags); i++) {
+ torture_comment(tctx, "setting a new sd on directory, pass #%d\n", i);
+
+ sd = security_descriptor_dacl_create(tctx,
+ tflags[i].parent_set_sd_type,
+ NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ tflags[i].parent_set_ace_inherit,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Check DACL we just set, except change the bits to what they
+ * should be.
+ */
+ torture_comment(tctx, " checking new sd\n");
+
+ /* REQ bit should always be false. */
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ if ((tflags[i].parent_get_sd_type & SEC_DESC_DACL_AUTO_INHERITED) == 0)
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ /* Create file. */
+ torture_comment(tctx, " creating file %s\n", fname1);
+ io.ntcreatex.in.fname = fname1;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_ACCESS_FLAGS(fnum2, SEC_RIGHTS_FILE_ALL);
+
+ q.query_secdesc.in.file.fnum = fnum2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, " checking sd on file %s\n", fname1);
+ sd2 = security_descriptor_dacl_create(tctx,
+ tflags[i].child_get_sd_type,
+ owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ tflags[i].child_get_ace_inherit,
+ NULL);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ /*
+ * Set new sd on file ... prove that the bits have nothing to
+ * do with the parents bits when manually setting an ACL. The
+ * _AUTO_INHERITED bit comes directly from the ACL set.
+ */
+ for (j = 0; j < ARRAY_SIZE(tflags); j++) {
+ torture_comment(tctx, " setting new file sd, pass #%d\n", j);
+
+ /* Change sd type. */
+ sd2->type &= ~(SEC_DESC_DACL_AUTO_INHERITED |
+ SEC_DESC_DACL_AUTO_INHERIT_REQ |
+ SEC_DESC_DACL_PROTECTED);
+ sd2->type |= tflags[j].parent_set_sd_type;
+
+ sd2->dacl->aces[0].flags &=
+ ~SEC_ACE_FLAG_INHERITED_ACE;
+ sd2->dacl->aces[0].flags |=
+ tflags[j].parent_set_ace_inherit;
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum2;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd2;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Check DACL we just set. */
+ sd2->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
+ if ((tflags[j].parent_get_sd_type & SEC_DESC_DACL_AUTO_INHERITED) == 0)
+ sd2->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ q.query_secdesc.in.file.fnum = fnum2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+ }
+
+ smbcli_close(cli->tree, fnum2);
+ smbcli_unlink(cli->tree, fname1);
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ if (!ret) {
+ torture_result(tctx,
+ TORTURE_FAIL, "(%s) test_inheritance_flags\n",
+ __location__);
+ }
+
+ return ret;
+}
+
+/*
+ test dynamic acl inheritance
+ Test copied to smb2/acls.c for SMB2.
+*/
+static bool test_inheritance_dynamic(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *dname = BASEDIR "\\inheritance2";
+ const char *fname1 = BASEDIR "\\inheritance2\\testfile";
+ bool ret = true;
+ int fnum=0, fnum2;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig=NULL;
+ const char *owner_sid;
+
+ torture_comment(tctx, "TESTING DYNAMIC ACL INHERITANCE\n");
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_DELETE | SEC_FILE_READ_ATTRIBUTE,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+ sd->type |= SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "create a file with an inherited acl\n");
+ io.ntcreatex.in.fname = fname1;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ smbcli_close(cli->tree, fnum2);
+
+ torture_comment(tctx, "try and access file with base rights - should be OK\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ smbcli_close(cli->tree, fnum2);
+
+ torture_comment(tctx, "try and access file with extra rights - should be denied\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA | SEC_FILE_EXECUTE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "update parent sd\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_DELETE | SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+ sd->type |= SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ set.set_secdesc.in.sd = sd;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "try and access file with base rights - should be OK\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ smbcli_close(cli->tree, fnum2);
+
+
+ torture_comment(tctx, "try and access now - should be OK if dynamic inheritance works\n");
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA | SEC_FILE_EXECUTE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "Server does not have dynamic inheritance\n");
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Server does have dynamic inheritance\n");
+ }
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ smbcli_unlink(cli->tree, fname1);
+
+done:
+ if (sd_orig != NULL) {
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ }
+ smbcli_close(cli->tree, fnum);
+ smbcli_rmdir(cli->tree, dname);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+#define CHECK_STATUS_FOR_BIT_ACTION(status, bits, action) do { \
+ if (!(bits & desired_64)) {\
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); \
+ action; \
+ } else { \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ } \
+} while (0)
+
+#define CHECK_STATUS_FOR_BIT(status, bits, access) do { \
+ if (NT_STATUS_IS_OK(status)) { \
+ if (!(granted & access)) {\
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s but flags 0x%08X are not granted! granted[0x%08X] desired[0x%08X]\n", \
+ __location__, nt_errstr(status), access, granted, desired); \
+ goto done; \
+ } \
+ } else { \
+ if (granted & access) {\
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s but flags 0x%08X are granted! granted[0x%08X] desired[0x%08X]\n", \
+ __location__, nt_errstr(status), access, granted, desired); \
+ goto done; \
+ } \
+ } \
+ CHECK_STATUS_FOR_BIT_ACTION(status, bits, do {} while (0)); \
+} while (0)
+
+#if 0
+
+/* test what access mask is needed for getting and setting security_descriptors
+ Test copied to smb2/acls.c for SMB2. */
+static bool test_sd_get_set(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo fi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd;
+ struct security_descriptor *sd_owner = NULL;
+ struct security_descriptor *sd_group = NULL;
+ struct security_descriptor *sd_dacl = NULL;
+ struct security_descriptor *sd_sacl = NULL;
+ int fnum=0;
+ const char *fname = BASEDIR "\\sd_get_set.txt";
+ uint64_t desired_64;
+ uint32_t desired = 0, granted;
+ int i = 0;
+#define NO_BITS_HACK (((uint64_t)1)<<32)
+ uint64_t open_bits =
+ SEC_MASK_GENERIC |
+ SEC_FLAG_SYSTEM_SECURITY |
+ SEC_FLAG_MAXIMUM_ALLOWED |
+ SEC_STD_ALL |
+ SEC_FILE_ALL |
+ NO_BITS_HACK;
+ uint64_t get_owner_bits = SEC_MASK_GENERIC | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_READ_CONTROL;
+ uint64_t set_owner_bits = SEC_GENERIC_ALL | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_WRITE_OWNER;
+ uint64_t get_group_bits = SEC_MASK_GENERIC | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_READ_CONTROL;
+ uint64_t set_group_bits = SEC_GENERIC_ALL | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_WRITE_OWNER;
+ uint64_t get_dacl_bits = SEC_MASK_GENERIC | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_READ_CONTROL;
+ uint64_t set_dacl_bits = SEC_GENERIC_ALL | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_WRITE_DAC;
+ uint64_t get_sacl_bits = SEC_FLAG_SYSTEM_SECURITY;
+ uint64_t set_sacl_bits = SEC_FLAG_SYSTEM_SECURITY;
+
+ if (!torture_setup_dir(cli, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACCESS MASKS FOR SD GET/SET\n");
+
+ /* first create a file with full access for everyone */
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, SID_BUILTIN_USERS,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_ALL,
+ 0,
+ NULL);
+ sd->type |= SEC_DESC_SACL_PRESENT;
+ sd->sacl = NULL;
+ io.ntcreatex.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_GENERIC_ALL;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.sec_desc = sd;
+ io.ntcreatex.in.ea_list = NULL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * now try each access_mask bit and no bit at all in a loop
+ * and see what's allowed
+ * NOTE: if i == 32 it means access_mask = 0 (see NO_BITS_HACK above)
+ */
+ for (i=0; i <= 32; i++) {
+ desired_64 = ((uint64_t)1) << i;
+ desired = (uint32_t)desired_64;
+
+ /* first open the file with the desired access */
+ io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.access_mask = desired;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS_FOR_BIT_ACTION(status, open_bits, goto next);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* then check what access was granted */
+ fi.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ fi.access_information.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &fi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ granted = fi.access_information.out.access_flags;
+
+ /* test the owner */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.fnum = fnum;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_owner_bits, SEC_STD_READ_CONTROL);
+ if (fi.query_secdesc.out.sd) {
+ sd_owner = fi.query_secdesc.out.sd;
+ } else if (!sd_owner) {
+ sd_owner = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.fnum = fnum;
+ si.set_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ si.set_secdesc.in.sd = sd_owner;
+ status = smb_raw_setfileinfo(cli->tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_owner_bits, SEC_STD_WRITE_OWNER);
+
+ /* test the group */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.fnum = fnum;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_GROUP;
+ status = smb_raw_fileinfo(cli->tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_group_bits, SEC_STD_READ_CONTROL);
+ if (fi.query_secdesc.out.sd) {
+ sd_group = fi.query_secdesc.out.sd;
+ } else if (!sd_group) {
+ sd_group = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.fnum = fnum;
+ si.set_secdesc.in.secinfo_flags = SECINFO_GROUP;
+ si.set_secdesc.in.sd = sd_group;
+ status = smb_raw_setfileinfo(cli->tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_group_bits, SEC_STD_WRITE_OWNER);
+
+ /* test the DACL */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.fnum = fnum;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_dacl_bits, SEC_STD_READ_CONTROL);
+ if (fi.query_secdesc.out.sd) {
+ sd_dacl = fi.query_secdesc.out.sd;
+ } else if (!sd_dacl) {
+ sd_dacl = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.fnum = fnum;
+ si.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ si.set_secdesc.in.sd = sd_dacl;
+ status = smb_raw_setfileinfo(cli->tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_dacl_bits, SEC_STD_WRITE_DAC);
+
+ /* test the SACL */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.fnum = fnum;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_SACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_sacl_bits, SEC_FLAG_SYSTEM_SECURITY);
+ if (fi.query_secdesc.out.sd) {
+ sd_sacl = fi.query_secdesc.out.sd;
+ } else if (!sd_sacl) {
+ sd_sacl = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.fnum = fnum;
+ si.set_secdesc.in.secinfo_flags = SECINFO_SACL;
+ si.set_secdesc.in.sd = sd_sacl;
+ status = smb_raw_setfileinfo(cli->tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_sacl_bits, SEC_FLAG_SYSTEM_SECURITY);
+
+ /* close the handle */
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+next:
+ continue;
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+#endif
+
+/*
+ basic testing of security descriptor calls
+*/
+struct torture_suite *torture_raw_acls(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "acls");
+
+ torture_suite_add_1smb_test(suite, "sd", test_sd);
+ torture_suite_add_1smb_test(suite, "create_file", test_nttrans_create_file);
+ torture_suite_add_1smb_test(suite, "create_dir", test_nttrans_create_dir);
+ torture_suite_add_1smb_test(suite, "create_owner_file", test_nttrans_create_owner_file);
+ torture_suite_add_1smb_test(suite, "create_owner_dir", test_nttrans_create_owner_dir);
+ torture_suite_add_1smb_test(suite, "nulldacl", test_nttrans_create_null_dacl);
+ torture_suite_add_1smb_test(suite, "creator", test_creator_sid);
+ torture_suite_add_1smb_test(suite, "generic", test_generic_bits);
+ torture_suite_add_1smb_test(suite, "owner", test_owner_bits);
+ torture_suite_add_1smb_test(suite, "inheritance", test_inheritance);
+
+ torture_suite_add_1smb_test(suite, "INHERITFLAGS", test_inheritance_flags);
+ torture_suite_add_1smb_test(suite, "dynamic", test_inheritance_dynamic);
+#if 0
+ /* XXX This test does not work against XP or Vista. */
+ torture_suite_add_1smb_test(suite, "GETSET", test_sd_get_set);
+#endif
+
+ return suite;
+}
diff --git a/source4/torture/raw/chkpath.c b/source4/torture/raw/chkpath.c
new file mode 100644
index 0000000..2afd7ea
--- /dev/null
+++ b/source4/torture/raw/chkpath.c
@@ -0,0 +1,390 @@
+/*
+ Unix SMB/CIFS implementation.
+ chkpath individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/locale.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\rawchkpath"
+
+#define CHECK_STATUS(status, correct, dos_correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct) && !NT_STATUS_EQUAL(status, dos_correct)) { \
+ printf("(%d) Incorrect status %s - should be %s\n", \
+ __LINE__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+
+static NTSTATUS single_search(struct smbcli_state *cli,
+ TALLOC_CTX *mem_ctx, const char *pattern)
+{
+ union smb_search_first io;
+ NTSTATUS status;
+
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = RAW_SEARCH_DATA_STANDARD;
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = 1;
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = pattern;
+
+ status = smb_raw_search_first(cli->tree, mem_ctx,
+ &io, NULL, NULL);
+
+ return status;
+}
+
+static bool test_path_ex(struct smbcli_state *cli, struct torture_context *tctx,
+ const char *path, const char *path_expected,
+ NTSTATUS expected, NTSTATUS dos_expected)
+{
+ union smb_chkpath io;
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+
+ io.chkpath.in.path = path;
+ status = smb_raw_chkpath(cli->tree, &io);
+ if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) {
+ printf("FAILED %-30s chkpath %s should be %s or %s\n",
+ path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected));
+ return false;
+ } else {
+ printf("%-30s chkpath correct (%s)\n", path, nt_errstr(status));
+ }
+
+ if (NT_STATUS_EQUAL(expected, NT_STATUS_NOT_A_DIRECTORY)) {
+ expected = NT_STATUS_OK;
+ }
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_NAME_INFO;
+ finfo.generic.in.file.path = path;
+ status = smb_raw_pathinfo(cli->tree, cli, &finfo);
+ if (!NT_STATUS_EQUAL(status, expected) && !NT_STATUS_EQUAL(status, dos_expected)) {
+ printf("FAILED: %-30s pathinfo %s should be %s or %s\n",
+ path, nt_errstr(status), nt_errstr(expected), nt_errstr(dos_expected));
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%-30s chkpath correct (%s)\n", path, nt_errstr(status));
+ return true;
+ }
+
+ if (path_expected &&
+ (!finfo.name_info.out.fname.s ||
+ strcmp(finfo.name_info.out.fname.s, path_expected) != 0)) {
+ if (tctx && torture_setting_bool(tctx, "samba4", false)) {
+ printf("IGNORE: %-30s => %-20s should be %s\n",
+ path, finfo.name_info.out.fname.s, path_expected);
+ return true;
+ }
+ printf("FAILED: %-30s => %-20s should be %s\n",
+ path, finfo.name_info.out.fname.s, path_expected);
+ return false;
+ }
+ printf("%-30s => %-20s correct\n",
+ path, finfo.name_info.out.fname.s);
+
+ return true;
+}
+
+static bool test_path(struct smbcli_state *cli, const char *path,
+ NTSTATUS expected, NTSTATUS dos_expected)
+{
+ return test_path_ex(cli, NULL, path, path, expected, dos_expected);
+}
+
+static bool test_chkpath(struct smbcli_state *cli, struct torture_context *tctx)
+{
+ union smb_chkpath io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum = -1;
+
+ io.chkpath.in.path = BASEDIR;
+
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK, NT_STATUS_OK);
+
+ ret &= test_path(cli, BASEDIR "\\nodir", NT_STATUS_OBJECT_NAME_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ fnum = create_complex_file(cli, tctx, BASEDIR "\\test.txt..");
+ if (fnum == -1) {
+ printf("failed to open test.txt - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ ret &= test_path(cli, BASEDIR "\\test.txt..", NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ if (!torture_set_file_attribute(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN)) {
+ printf("failed to set basedir hidden\n");
+ ret = false;
+ goto done;
+ }
+
+ ret &= test_path_ex(cli, tctx, BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, ((const char *)BASEDIR) + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, ((const char *)BASEDIR"\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, ((const char *)BASEDIR"\\foo\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, ((const char *)BASEDIR"\\f\\o\\o\\..\\..\\..") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, ((const char *)BASEDIR"\\foo\\\\..\\\\") + 1, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, BASEDIR"\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, BASEDIR"\\\\..\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, BASEDIR"\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, "\\\\\\\\"BASEDIR"\\\\\\\\", BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, "\\\\\\\\"BASEDIR, BASEDIR, NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path_ex(cli, tctx, BASEDIR "\\foo\\..\\test.txt..", BASEDIR "\\test.txt..",
+ NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path_ex(cli, tctx, "", "\\", NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path(cli, ".", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "\\\\\\.\\", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "." BASEDIR, NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\.\\test.txt..", NT_STATUS_OBJECT_PATH_NOT_FOUND, NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\.\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\.\\.aaaaa", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "\\.\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "\\.\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "\\.\\\\\\\\\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ /* Note that the two following paths are identical but
+ give different NT status returns for chkpth and findfirst. */
+
+ printf("Testing findfirst on %s\n", "\\.\\\\\\\\\\\\.");
+ status = single_search(cli, tctx, "\\.\\\\\\\\\\\\.");
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRinvalidname));
+
+ ret &= test_path(cli, "\\.\\\\\\\\\\\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ /* We expect this open to fail with the same error code as the chkpath below. */
+ printf("Testing Open on %s\n", "\\.\\\\\\\\\\\\.");
+ /* findfirst seems to fail with a different error. */
+ (void)smbcli_nt_create_full(cli->tree, "\\.\\\\\\\\\\\\.",
+ 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+ status = smbcli_nt_error(cli->tree);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+
+ ret &= test_path(cli, "\\.\\\\xxx", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "..\\..\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
+ ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
+ ret &= test_path(cli, "\\.\\\\\\\\\\\\xxx", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR"\\.\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR"\\.\\\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR"\\.\\nt", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR"\\.\\.\\nt", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR"\\nt", NT_STATUS_OK, NT_STATUS_OK);
+ ret &= test_path(cli, BASEDIR".\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR"xx\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\.", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, ".\\.\\.\\.\\foo\\.\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR".\\.\\.\\.\\foo\\.\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR".\\.\\.\\.\\foo\\..\\.\\", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR".", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "\\", NT_STATUS_OK,NT_STATUS_OK);
+ ret &= test_path(cli, "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, "\\..\\", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
+ ret &= test_path(cli, "\\..", NT_STATUS_OBJECT_PATH_SYNTAX_BAD,NT_STATUS_DOS(ERRDOS,ERRinvalidpath));
+ ret &= test_path(cli, BASEDIR "\\.", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path_ex(cli, tctx, BASEDIR "\\..", "\\", NT_STATUS_OK,NT_STATUS_OK);
+ ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb600", NT_STATUS_OBJECT_NAME_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe", NT_STATUS_NOT_A_DIRECTORY,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ /* We expect this open to fail with the same error code as the chkpath below. */
+ printf("Testing Open on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
+ /* findfirst seems to fail with a different error. */
+ (void)smbcli_nt_create_full(cli->tree, BASEDIR".\\.\\.\\.\\foo\\..\\.\\",
+ 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+ status = smbcli_nt_error(cli->tree);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ printf("Testing findfirst on %s\n", BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
+ status = single_search(cli, tctx, BASEDIR".\\.\\.\\.\\foo\\..\\.\\");
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ /* We expect this open to fail with the same error code as the chkpath below. */
+ /* findfirst seems to fail with a different error. */
+ printf("Testing Open on %s\n", BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3");
+ (void)smbcli_nt_create_full(cli->tree, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3",
+ 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+ status = smbcli_nt_error(cli->tree);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+ ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\nt\\V S\\VB98\\vb6.exe\\3\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\nt\\3\\foo", NT_STATUS_OBJECT_PATH_NOT_FOUND,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\nt\\V S\\*\\vb6.exe\\3", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+ ret &= test_path(cli, BASEDIR "\\nt\\V S\\*\\*\\vb6.exe\\3", NT_STATUS_OBJECT_NAME_INVALID,NT_STATUS_DOS(ERRDOS,ERRbadpath));
+
+done:
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
+
+static bool test_chkpath_names(struct smbcli_state *cli, struct torture_context *tctx)
+{
+ union smb_chkpath io;
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ bool ret = true;
+ uint8_t i;
+
+ /*
+ * we don't test characters >= 0x80 yet,
+ * as somehow our client libraries can't do that
+ */
+ for (i=0x01; i <= 0x7F; i++) {
+ /*
+ * it's important that we test the last character
+ * because of the error code with ':' 0x3A
+ * and servers without stream support
+ */
+ char *path = talloc_asprintf(tctx, "%s\\File0x%02X%c",
+ BASEDIR, i, i);
+ NTSTATUS expected;
+ NTSTATUS expected_dos1;
+ NTSTATUS expected_dos2;
+
+ expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ expected_dos1 = NT_STATUS_DOS(ERRDOS,ERRbadpath);
+ expected_dos2 = NT_STATUS_DOS(ERRDOS,ERRbadfile);
+
+ switch (i) {
+ case '"':/*0x22*/
+ case '*':/*0x2A*/
+ case '/':/*0x2F*/
+ case ':':/*0x3A*/
+ case '<':/*0x3C*/
+ case '>':/*0x3E*/
+ case '?':/*0x3F*/
+ case '|':/*0x7C*/
+ if (i == '/' &&
+ torture_setting_bool(tctx, "samba3", false)) {
+ /* samba 3 handles '/' as '\\' */
+ break;
+ }
+ expected = NT_STATUS_OBJECT_NAME_INVALID;
+ expected_dos1 = NT_STATUS_DOS(ERRDOS,ERRbadpath);
+ expected_dos2 = NT_STATUS_DOS(ERRDOS,ERRinvalidname);
+ break;
+ default:
+ if (i <= 0x1F) {
+ expected = NT_STATUS_OBJECT_NAME_INVALID;
+ expected_dos1 = NT_STATUS_DOS(ERRDOS,ERRbadpath);
+ expected_dos2 = NT_STATUS_DOS(ERRDOS,ERRinvalidname);
+ }
+ break;
+ }
+
+ printf("Checking File0x%02X%c%s expected[%s|%s|%s]\n",
+ i, isprint(i)?(char)i:' ',
+ isprint(i)?"":"(not printable)",
+ nt_errstr(expected),
+ nt_errstr(expected_dos1),
+ nt_errstr(expected_dos2));
+
+ io.chkpath.in.path = path;
+ status = smb_raw_chkpath(cli->tree, &io);
+ CHECK_STATUS(status, expected, expected_dos1);
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_NAME_INFO;
+ finfo.generic.in.file.path = path;
+ status = smb_raw_pathinfo(cli->tree, cli, &finfo);
+ CHECK_STATUS(status, expected, expected_dos2);
+
+ talloc_free(path);
+ }
+
+done:
+ return ret;
+}
+
+/*
+ basic testing of chkpath calls
+*/
+bool torture_raw_chkpath(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ int fnum;
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt"))) {
+ printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt\\V S"))) {
+ printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR "\\nt\\V S\\VB98"))) {
+ printf("Failed to create " BASEDIR " - %s\n", smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ fnum = create_complex_file(cli, torture, BASEDIR "\\nt\\V S\\VB98\\vb6.exe");
+ if (fnum == -1) {
+ printf("failed to open \\nt\\V S\\VB98\\vb6.exe - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ ret &= test_chkpath(cli, torture);
+ ret &= test_chkpath_names(cli, torture);
+
+ done:
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
diff --git a/source4/torture/raw/close.c b/source4/torture/raw/close.c
new file mode 100644
index 0000000..56b63c6
--- /dev/null
+++ b/source4/torture/raw/close.c
@@ -0,0 +1,178 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_CLOSE_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "system/time.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+/**
+ * basic testing of all RAW_CLOSE_* calls
+*/
+bool torture_raw_close(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ union smb_close io;
+ union smb_flush io_flush;
+ int fnum;
+ const char *fname = "\\torture_close.txt";
+ time_t basetime = (time(NULL) + 3*86400) & ~1;
+ union smb_fileinfo finfo, finfo2;
+ NTSTATUS status;
+
+#define REOPEN do { \
+ fnum = create_complex_file(cli, torture, fname); \
+ if (fnum == -1) { \
+ printf("(%d) Failed to create %s\n", __LINE__, fname); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%d) Incorrect status %s - should be %s\n", \
+ __LINE__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+ REOPEN;
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.file.fnum = fnum;
+ io.close.in.write_time = basetime;
+ status = smb_raw_close(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_close(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ printf("Testing close.in.write_time\n");
+
+ /* the file should have the write time set */
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, torture, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (basetime != nt_time_to_unix(finfo.all_info.out.write_time)) {
+ printf("Incorrect write time on file - %s - %s\n",
+ timestring(torture, basetime),
+ nt_time_string(torture, finfo.all_info.out.write_time));
+ dump_all_info(torture, &finfo);
+ ret = false;
+ }
+
+ printf("Testing other times\n");
+
+ /* none of the other times should be set to that time */
+ if (nt_time_equal(&finfo.all_info.out.write_time,
+ &finfo.all_info.out.access_time) ||
+ nt_time_equal(&finfo.all_info.out.write_time,
+ &finfo.all_info.out.create_time) ||
+ nt_time_equal(&finfo.all_info.out.write_time,
+ &finfo.all_info.out.change_time)) {
+ printf("Incorrect times after close - only write time should be set\n");
+ dump_all_info(torture, &finfo);
+
+ if (!torture_setting_bool(torture, "samba3", false)) {
+ /*
+ * In Samba3 as of 3.0.23d we don't yet support all
+ * file times, so don't mark this as a critical
+ * failure
+ */
+ ret = false;
+ }
+ }
+
+
+ smbcli_unlink(cli->tree, fname);
+ REOPEN;
+
+ finfo2.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo2.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, torture, &finfo2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.file.fnum = fnum;
+ io.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* the file should have the write time set equal to access time */
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, torture, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!nt_time_equal(&finfo.all_info.out.write_time,
+ &finfo2.all_info.out.write_time)) {
+ printf("Incorrect write time on file - 0 time should be ignored\n");
+ dump_all_info(torture, &finfo);
+ ret = false;
+ }
+
+ printf("Testing splclose\n");
+
+ /* check splclose on a file */
+ REOPEN;
+ io.splclose.level = RAW_CLOSE_SPLCLOSE;
+ io.splclose.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
+
+ printf("Testing flush\n");
+ smbcli_close(cli->tree, fnum);
+
+ io_flush.flush.level = RAW_FLUSH_FLUSH;
+ io_flush.flush.in.file.fnum = fnum;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ io_flush.flush_all.level = RAW_FLUSH_ALL;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ REOPEN;
+
+ io_flush.flush.level = RAW_FLUSH_FLUSH;
+ io_flush.flush.in.file.fnum = fnum;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Testing SMBexit\n");
+ smb_raw_exit(cli->session);
+
+ io_flush.flush.level = RAW_FLUSH_FLUSH;
+ io_flush.flush.in.file.fnum = fnum;
+ status = smb_raw_flush(cli->tree, &io_flush);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ return ret;
+}
diff --git a/source4/torture/raw/composite.c b/source4/torture/raw/composite.c
new file mode 100644
index 0000000..7eb682c
--- /dev/null
+++ b/source4/torture/raw/composite.c
@@ -0,0 +1,417 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libcli composite function testing
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "lib/events/events.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "libcli/security/security.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/util.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\composite"
+
+static void loadfile_complete(struct composite_context *c)
+{
+ int *count = talloc_get_type(c->async.private_data, int);
+ (*count)++;
+}
+
+/*
+ test a simple savefile/loadfile combination
+*/
+static bool test_loadfile(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ const char *fname = BASEDIR "\\test.txt";
+ NTSTATUS status;
+ struct smb_composite_savefile io1;
+ struct smb_composite_loadfile *io2;
+ struct composite_context **c;
+ uint8_t *data;
+ size_t len = random() % 100000;
+ const int num_ops = 50;
+ int i;
+ int *count = talloc_zero(tctx, int);
+
+ data = talloc_array(tctx, uint8_t, len);
+
+ generate_random_buffer(data, len);
+
+ io1.in.fname = fname;
+ io1.in.data = data;
+ io1.in.size = len;
+
+ torture_comment(tctx, "Testing savefile\n");
+
+ status = smb_composite_savefile(cli->tree, &io1);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "savefile failed");
+
+ torture_comment(tctx, "Testing parallel loadfile with %d ops\n", num_ops);
+
+ c = talloc_array(tctx, struct composite_context *, num_ops);
+ io2 = talloc_zero_array(tctx, struct smb_composite_loadfile, num_ops);
+
+ for (i=0;i<num_ops;i++) {
+ io2[i].in.fname = fname;
+ c[i] = smb_composite_loadfile_send(cli->tree, &io2[i]);
+ c[i]->async.fn = loadfile_complete;
+ c[i]->async.private_data = count;
+ }
+
+ torture_comment(tctx, "waiting for completion\n");
+ while (*count != num_ops) {
+ tevent_loop_once(tctx->ev);
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "(%s) count=%d\r", __location__, *count);
+ fflush(stdout);
+ }
+ }
+ torture_comment(tctx, "count=%d\n", *count);
+
+ for (i=0;i<num_ops;i++) {
+ status = smb_composite_loadfile_recv(c[i], tctx);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "loadfile failed");
+
+ torture_assert_int_equal(tctx, io2[i].out.size, len, "wrong length in returned data");
+ torture_assert_mem_equal(tctx, io2[i].out.data, data, len, "wrong data in loadfile");
+ }
+
+ talloc_free(data);
+
+ return true;
+}
+
+static bool test_loadfile_t(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ int ret;
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "failed to setup " BASEDIR);
+
+ ret = test_loadfile(tctx, cli);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ test a simple savefile/loadfile combination
+*/
+static bool test_fetchfile(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ const char *fname = BASEDIR "\\test.txt";
+ NTSTATUS status;
+ struct smb_composite_savefile io1;
+ struct smb_composite_fetchfile io2;
+ struct composite_context **c;
+ uint8_t *data;
+ int i;
+ size_t len = random() % 10000;
+ extern int torture_numops;
+ struct tevent_context *event_ctx;
+ int *count = talloc_zero(tctx, int);
+ bool ret = true;
+
+ data = talloc_array(tctx, uint8_t, len);
+
+ generate_random_buffer(data, len);
+
+ ZERO_STRUCT(io1);
+ io1.in.fname = fname;
+ io1.in.data = data;
+ io1.in.size = len;
+
+ torture_comment(tctx, "Testing savefile\n");
+
+ status = smb_composite_savefile(cli->tree, &io1);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "savefile failed");
+
+ ZERO_STRUCT(io2);
+
+ io2.in.dest_host = torture_setting_string(tctx, "host", NULL);
+ io2.in.ports = lpcfg_smb_ports(tctx->lp_ctx);
+ io2.in.called_name = torture_setting_string(tctx, "host", NULL);
+ io2.in.service = torture_setting_string(tctx, "share", NULL);
+ io2.in.service_type = "A:";
+ io2.in.socket_options = lpcfg_socket_options(tctx->lp_ctx);
+
+ io2.in.credentials = samba_cmdline_get_creds();
+ io2.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ io2.in.filename = fname;
+ lpcfg_smbcli_options(tctx->lp_ctx, &io2.in.options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &io2.in.session_options);
+ io2.in.resolve_ctx = lpcfg_resolve_context(tctx->lp_ctx);
+ io2.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+
+ torture_comment(tctx, "Testing parallel fetchfile with %d ops\n", torture_numops);
+
+ event_ctx = tctx->ev;
+ c = talloc_array(tctx, struct composite_context *, torture_numops);
+
+ for (i=0; i<torture_numops; i++) {
+ c[i] = smb_composite_fetchfile_send(&io2, event_ctx);
+ c[i]->async.fn = loadfile_complete;
+ c[i]->async.private_data = count;
+ }
+
+ torture_comment(tctx, "waiting for completion\n");
+
+ while (*count != torture_numops) {
+ tevent_loop_once(event_ctx);
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "(%s) count=%d\r", __location__, *count);
+ fflush(stdout);
+ }
+ }
+ torture_comment(tctx, "count=%d\n", *count);
+
+ for (i=0;i<torture_numops;i++) {
+ status = smb_composite_fetchfile_recv(c[i], tctx);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "loadfile failed");
+
+ torture_assert_int_equal(tctx, io2.out.size, len, "wrong length in returned data");
+ torture_assert_mem_equal(tctx, io2.out.data, data, len, "wrong data in loadfile");
+ }
+
+ return ret;
+}
+
+static bool test_fetchfile_t(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ int ret;
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "failed to setup " BASEDIR);
+ ret = test_fetchfile(tctx, cli);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ test setfileacl
+*/
+static bool test_appendacl(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ struct smb_composite_appendacl **io;
+ struct smb_composite_appendacl **io_orig;
+ struct composite_context **c;
+ struct tevent_context *event_ctx;
+
+ struct security_descriptor *test_sd;
+ struct security_ace *ace;
+ struct dom_sid *test_sid;
+
+ const int num_ops = 50;
+ int *count = talloc_zero(tctx, int);
+ struct smb_composite_savefile io1;
+
+ NTSTATUS status;
+ int i;
+
+ io_orig = talloc_array(tctx, struct smb_composite_appendacl *, num_ops);
+
+ printf ("creating %d empty files and getting their acls with appendacl\n", num_ops);
+
+ for (i = 0; i < num_ops; i++) {
+ io1.in.fname = talloc_asprintf(io_orig, BASEDIR "\\test%d.txt", i);
+ io1.in.data = NULL;
+ io1.in.size = 0;
+
+ status = smb_composite_savefile(cli->tree, &io1);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "savefile failed");
+
+ io_orig[i] = talloc (io_orig, struct smb_composite_appendacl);
+ io_orig[i]->in.fname = talloc_steal(io_orig[i], io1.in.fname);
+ io_orig[i]->in.sd = security_descriptor_initialise(io_orig[i]);
+ status = smb_composite_appendacl(cli->tree, io_orig[i], io_orig[i]);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "appendacl failed");
+ }
+
+
+ /* fill Security Descriptor with aces to be added */
+
+ test_sd = security_descriptor_initialise(tctx);
+ test_sid = dom_sid_parse_talloc (tctx, "S-1-5-32-1234-5432");
+
+ ace = talloc_zero(tctx, struct security_ace);
+
+ ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace->flags = 0;
+ ace->access_mask = SEC_STD_ALL;
+ ace->trustee = *test_sid;
+
+ status = security_descriptor_dacl_add(test_sd, ace);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "appendacl failed");
+
+ /* set parameters for appendacl async call */
+
+ torture_comment(tctx, "Testing parallel appendacl with %d ops\n", num_ops);
+
+ c = talloc_array(tctx, struct composite_context *, num_ops);
+ io = talloc_array(tctx, struct smb_composite_appendacl *, num_ops);
+
+ for (i=0; i < num_ops; i++) {
+ io[i] = talloc (io, struct smb_composite_appendacl);
+ io[i]->in.sd = test_sd;
+ io[i]->in.fname = talloc_asprintf(io[i], BASEDIR "\\test%d.txt", i);
+
+ c[i] = smb_composite_appendacl_send(cli->tree, io[i]);
+ c[i]->async.fn = loadfile_complete;
+ c[i]->async.private_data = count;
+ }
+
+ event_ctx = tctx->ev;
+ torture_comment(tctx, "waiting for completion\n");
+ while (*count != num_ops) {
+ tevent_loop_once(event_ctx);
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "(%s) count=%d\r", __location__, *count);
+ fflush(stdout);
+ }
+ }
+ torture_comment(tctx, "count=%d\n", *count);
+
+ for (i=0; i < num_ops; i++) {
+ status = smb_composite_appendacl_recv(c[i], io[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "(%s) appendacl[%d] failed - %s\n", __location__, i, nt_errstr(status));
+ return false;
+ }
+
+ security_descriptor_dacl_add(io_orig[i]->out.sd, ace);
+ torture_assert(tctx,
+ security_acl_equal(io_orig[i]->out.sd->dacl,
+ io[i]->out.sd->dacl),
+ "appendacl failed - needed acl isn't set");
+ }
+
+
+ talloc_free (ace);
+ talloc_free (test_sid);
+ talloc_free (test_sd);
+
+ return true;
+}
+
+static bool test_appendacl_t(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ int ret;
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "failed to setup " BASEDIR);
+ ret = test_appendacl(tctx, cli);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/* test a query FS info by asking for share's GUID */
+static bool test_fsinfo(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ char *guid = NULL;
+ NTSTATUS status;
+ struct smb_composite_fsinfo io1;
+ struct composite_context **c;
+
+ int i;
+ extern int torture_numops;
+ struct tevent_context *event_ctx;
+ int *count = talloc_zero(tctx, int);
+ bool ret = true;
+
+ io1.in.dest_host = torture_setting_string(tctx, "host", NULL);
+ io1.in.dest_ports = lpcfg_smb_ports(tctx->lp_ctx);
+ io1.in.socket_options = lpcfg_socket_options(tctx->lp_ctx);
+ io1.in.called_name = torture_setting_string(tctx, "host", NULL);
+ io1.in.service = torture_setting_string(tctx, "share", NULL);
+ io1.in.service_type = "A:";
+ io1.in.credentials = samba_cmdline_get_creds();
+ io1.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ io1.in.level = RAW_QFS_OBJECTID_INFORMATION;
+ io1.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+
+ torture_comment(tctx, "Testing parallel queryfsinfo [Object ID] with %d ops\n",
+ torture_numops);
+
+ event_ctx = tctx->ev;
+ c = talloc_array(tctx, struct composite_context *, torture_numops);
+
+ for (i=0; i<torture_numops; i++) {
+ c[i] = smb_composite_fsinfo_send(cli->tree, &io1, lpcfg_resolve_context(tctx->lp_ctx), event_ctx);
+ torture_assert(tctx, c[i], "smb_composite_fsinfo_send failed!");
+ c[i]->async.fn = loadfile_complete;
+ c[i]->async.private_data = count;
+ }
+
+ torture_comment(tctx, "waiting for completion\n");
+
+ while (*count < torture_numops) {
+ tevent_loop_once(event_ctx);
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "(%s) count=%d\r", __location__, *count);
+ fflush(stdout);
+ }
+ }
+ torture_comment(tctx, "count=%d\n", *count);
+
+ for (i=0;i<torture_numops;i++) {
+ status = smb_composite_fsinfo_recv(c[i], tctx);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "smb_composite_fsinfo_recv failed");
+
+ torture_assert_int_equal(tctx, io1.out.fsinfo->generic.level, RAW_QFS_OBJECTID_INFORMATION, "wrong level in returned info");
+
+ guid=GUID_string(tctx, &io1.out.fsinfo->objectid_information.out.guid);
+ torture_comment(tctx, "[%d] GUID: %s\n", i, guid);
+ }
+
+ return ret;
+}
+
+static bool test_fsinfo_t(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ int ret;
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "failed to setup " BASEDIR);
+ ret = test_fsinfo(tctx, cli);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ basic testing of all RAW_SEARCH_* calls using a single file
+*/
+struct torture_suite *torture_raw_composite(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "composite");
+
+ torture_suite_add_1smb_test(suite, "fetchfile", test_fetchfile_t);
+ torture_suite_add_1smb_test(suite, "loadfile", test_loadfile_t);
+ torture_suite_add_1smb_test(suite, "appendacl", test_appendacl_t);
+ torture_suite_add_1smb_test(suite, "fsinfo", test_fsinfo_t);
+
+ return suite;
+}
diff --git a/source4/torture/raw/context.c b/source4/torture/raw/context.c
new file mode 100644
index 0000000..b984ffe
--- /dev/null
+++ b/source4/torture/raw/context.c
@@ -0,0 +1,893 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for session setup operations
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\rawcontext"
+
+#define CHECK_STATUS(status, correct) \
+ torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, __location__)
+
+#define CHECK_VALUE(v, correct) \
+ torture_assert_int_equal_goto(tctx, v, correct, ret, done, __location__)
+
+#define CHECK_NOT_VALUE(v, correct) \
+ torture_assert_goto(tctx, ((v) != (correct)), ret, done, \
+ talloc_asprintf(tctx, "(%s) Incorrect value %s=%d - should not be %d\n", \
+ __location__, #v, v, correct));
+
+
+/*
+ test session ops
+*/
+static bool test_session(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smbcli_session *session;
+ struct smbcli_session *session2;
+ uint16_t vuid3;
+ struct smbcli_session *session3;
+ struct smbcli_session *session4;
+ struct cli_credentials *anon_creds;
+ struct smbcli_session *sessions[15];
+ struct composite_context *composite_contexts[15];
+ struct smbcli_tree *tree;
+ struct smb_composite_sesssetup setup;
+ struct smb_composite_sesssetup setups[15];
+ struct gensec_settings *gensec_settings;
+ union smb_open io;
+ union smb_write wr;
+ union smb_close cl;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ uint8_t c = 1;
+ int i;
+ struct smbcli_session_options options;
+
+ torture_comment(tctx, "TESTING SESSION HANDLING\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "create a second security context on the same transport\n");
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+ gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+
+ session = smbcli_session_init(cli->transport, tctx, false, options);
+
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+
+ setup.in.credentials = samba_cmdline_get_creds();
+ setup.in.gensec_settings = gensec_settings;
+
+ status = smb_composite_sesssetup(session, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ session->vuid = setup.out.vuid;
+
+ torture_comment(tctx, "create a third security context on the same transport, with given vuid\n");
+ session2 = smbcli_session_init(cli->transport, tctx, false, options);
+
+ if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
+ vuid3 = session->vuid+1;
+ if (vuid3 == cli->session->vuid) {
+ vuid3 += 1;
+ }
+ if (vuid3 == UINT16_MAX) {
+ vuid3 += 2;
+ }
+ } else {
+ vuid3 = session->vuid;
+ }
+ session2->vuid = vuid3;
+
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+
+ setup.in.credentials = samba_cmdline_get_creds();
+
+ torture_comment(tctx, "vuid1=%d vuid2=%d vuid3=%d\n", cli->session->vuid, session->vuid, vuid3);
+
+ status = smb_composite_sesssetup(session2, &setup);
+ if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ session2->vuid = setup.out.vuid;
+ CHECK_NOT_VALUE(session2->vuid, vuid3);
+ }
+
+ torture_comment(tctx, "vuid1=%d vuid2=%d vuid3=%d=>%d (%s)\n",
+ cli->session->vuid, session->vuid,
+ vuid3, session2->vuid, nt_errstr(status));
+
+ talloc_free(session2);
+
+ if (cli->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) {
+ torture_comment(tctx, "create a fourth security context on the same transport, without extended security\n");
+ session3 = smbcli_session_init(cli->transport, tctx, false, options);
+
+ session3->vuid = vuid3;
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+
+ setup.in.credentials = samba_cmdline_get_creds();
+
+ status = smb_composite_sesssetup(session3, &setup);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)) {
+ /*
+ * Windows 2008 R2 returns INVALID_PARAMETER
+ * while Windows 2000 sp4 returns LOGON_FAILURE...
+ */
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ torture_comment(tctx, "create a fourth anonymous security context on the same transport, without extended security\n");
+ session4 = smbcli_session_init(cli->transport, tctx, false, options);
+
+ session4->vuid = vuid3;
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities &= ~CAP_EXTENDED_SECURITY; /* force a non extended security login (should fail) */
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+
+ anon_creds = cli_credentials_init(tctx);
+ cli_credentials_set_conf(anon_creds, tctx->lp_ctx);
+ cli_credentials_set_anonymous(anon_creds);
+
+ setup.in.credentials = anon_creds;
+
+ status = smb_composite_sesssetup(session3, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ talloc_free(session4);
+ }
+
+ torture_comment(tctx, "use the same tree as the existing connection\n");
+ tree = smbcli_tree_init(session, tctx, false);
+ tree->tid = cli->tree->tid;
+
+ torture_comment(tctx, "create a file using the new vuid\n");
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using the old vuid\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "write with the new vuid\n");
+ status = smb_raw_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "logoff the new vuid\n");
+ status = smb_raw_ulogoff(session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the new vuid should not now be accessible\n");
+ status = smb_raw_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "second logoff for the new vuid should fail\n");
+ status = smb_raw_ulogoff(session);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRbaduid));
+ talloc_free(tree);
+ talloc_free(session);
+
+ torture_comment(tctx, "the fnum should have been auto-closed\n");
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "create %d secondary security contexts on the same transport\n",
+ (int)ARRAY_SIZE(sessions));
+ for (i=0; i <ARRAY_SIZE(sessions); i++) {
+ setups[i].in.sesskey = cli->transport->negotiate.sesskey;
+ setups[i].in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
+ setups[i].in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+
+ setups[i].in.credentials = samba_cmdline_get_creds();
+ setups[i].in.gensec_settings = gensec_settings;
+
+ sessions[i] = smbcli_session_init(cli->transport, tctx, false, options);
+ composite_contexts[i] = smb_composite_sesssetup_send(sessions[i], &setups[i]);
+
+ }
+
+
+ torture_comment(tctx, "finishing %d secondary security contexts on the same transport\n",
+ (int)ARRAY_SIZE(sessions));
+ for (i=0; i< ARRAY_SIZE(sessions); i++) {
+ status = smb_composite_sesssetup_recv(composite_contexts[i]);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sessions[i]->vuid = setups[i].out.vuid;
+ torture_comment(tctx, "VUID: %d\n", sessions[i]->vuid);
+ status = smb_raw_ulogoff(sessions[i]);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+done:
+ return ret;
+}
+
+
+/*
+ test tree ops
+*/
+static bool test_tree(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ const char *share, *host;
+ struct smbcli_tree *tree;
+ union smb_tcon tcon;
+ union smb_open io;
+ union smb_write wr;
+ union smb_close cl;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ uint8_t c = 1;
+
+ torture_comment(tctx, "TESTING TREE HANDLING\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ share = torture_setting_string(tctx, "share", NULL);
+ host = torture_setting_string(tctx, "host", NULL);
+
+ torture_comment(tctx, "create a second tree context on the same session\n");
+ tree = smbcli_tree_init(cli->session, tctx, false);
+
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ tcon.tconx.in.device = "A:";
+ status = smb_raw_tcon(tree, tctx, &tcon);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ tree->tid = tcon.tconx.out.tid;
+ torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
+
+ torture_comment(tctx, "try a tconx with a bad device type\n");
+ tcon.tconx.in.device = "FOO";
+ status = smb_raw_tcon(tree, tctx, &tcon);
+ CHECK_STATUS(status, NT_STATUS_BAD_DEVICE_TYPE);
+
+
+ torture_comment(tctx, "create a file using the new tid\n");
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using the old tid\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "write with the new tid\n");
+ status = smb_raw_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "disconnect the new tid\n");
+ status = smb_tree_disconnect(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the new tid should not now be accessible\n");
+ status = smb_raw_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "the fnum should have been auto-closed\n");
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ /* close down the new tree */
+ talloc_free(tree);
+
+done:
+ return ret;
+}
+
+/*
+ test tree with ulogoff
+ this demonstrates that a tcon isn't autoclosed by a ulogoff
+ the tcon can be reused using any other valid session later
+*/
+static bool test_tree_ulogoff(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ const char *share, *host;
+ struct smbcli_session *session1;
+ struct smbcli_session *session2;
+ struct smb_composite_sesssetup setup;
+ struct smbcli_tree *tree;
+ union smb_tcon tcon;
+ union smb_open io;
+ union smb_write wr;
+ int fnum1, fnum2;
+ const char *fname1 = BASEDIR "\\test1.txt";
+ const char *fname2 = BASEDIR "\\test2.txt";
+ uint8_t c = 1;
+ struct smbcli_session_options options;
+
+ torture_comment(tctx, "TESTING TREE with ulogoff\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ share = torture_setting_string(tctx, "share", NULL);
+ host = torture_setting_string(tctx, "host", NULL);
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+
+ torture_comment(tctx, "create the first new sessions\n");
+ session1 = smbcli_session_init(cli->transport, tctx, false, options);
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities;
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ setup.in.credentials = samba_cmdline_get_creds();
+ setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+ status = smb_composite_sesssetup(session1, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ session1->vuid = setup.out.vuid;
+ torture_comment(tctx, "vuid1=%d\n", session1->vuid);
+
+ torture_comment(tctx, "create a tree context on the with vuid1\n");
+ tree = smbcli_tree_init(session1, tctx, false);
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ tcon.tconx.in.device = "A:";
+ status = smb_raw_tcon(tree, tctx, &tcon);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ tree->tid = tcon.tconx.out.tid;
+ torture_comment(tctx, "tid=%d\n", tree->tid);
+
+ torture_comment(tctx, "create a file using vuid1\n");
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+ status = smb_raw_open(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using vuid1\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum1;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+ status = smb_raw_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "ulogoff the vuid1\n");
+ status = smb_raw_ulogoff(session1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "create the second new sessions\n");
+ session2 = smbcli_session_init(cli->transport, tctx, false, options);
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities;
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ setup.in.credentials = samba_cmdline_get_creds();
+ setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+ status = smb_composite_sesssetup(session2, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ session2->vuid = setup.out.vuid;
+ torture_comment(tctx, "vuid2=%d\n", session2->vuid);
+
+ torture_comment(tctx, "use the existing tree with vuid2\n");
+ tree->session = session2;
+
+ torture_comment(tctx, "create a file using vuid2\n");
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname2;
+ status = smb_raw_open(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using vuid2\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum2;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+ status = smb_raw_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "ulogoff the vuid2\n");
+ status = smb_raw_ulogoff(session2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* this also demonstrates that SMBtdis doesn't need a valid vuid */
+ torture_comment(tctx, "disconnect the existing tree connection\n");
+ status = smb_tree_disconnect(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "disconnect the existing tree connection\n");
+ status = smb_tree_disconnect(tree);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid));
+
+ /* close down the new tree */
+ talloc_free(tree);
+
+done:
+ return ret;
+}
+
+/*
+ test pid ops
+ this test demonstrates that exit() only sees the PID
+ used for the open() calls
+*/
+static bool test_pid_exit_only_sees_open(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = tctx;
+ bool ret = true;
+ union smb_open io;
+ union smb_write wr;
+ union smb_close cl;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ uint8_t c = 1;
+ uint16_t pid1, pid2;
+
+ torture_comment(tctx, "TESTING PID HANDLING exit() only cares about open() PID\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ pid1 = cli->session->pid;
+ pid2 = pid1 + 1;
+
+ torture_comment(tctx, "pid1=%d pid2=%d\n", pid1, pid2);
+
+ torture_comment(tctx, "create a file using pid1\n");
+ cli->session->pid = pid1;
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using pid2\n");
+ cli->session->pid = pid2;
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "exit pid2\n");
+ cli->session->pid = pid2;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the fnum should still be accessible via pid2\n");
+ cli->session->pid = pid2;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "exit pid2\n");
+ cli->session->pid = pid2;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the fnum should still be accessible via pid1 and pid2\n");
+ cli->session->pid = pid1;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+ cli->session->pid = pid2;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "exit pid1\n");
+ cli->session->pid = pid1;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the fnum should not now be accessible via pid1 or pid2\n");
+ cli->session->pid = pid1;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ cli->session->pid = pid2;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "the fnum should have been auto-closed\n");
+ cli->session->pid = pid1;
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+done:
+ return ret;
+}
+
+/*
+ test pid ops with 2 sessions
+*/
+static bool test_pid_2sess(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smbcli_session *session;
+ struct smb_composite_sesssetup setup;
+ union smb_open io;
+ union smb_write wr;
+ union smb_close cl;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ uint8_t c = 1;
+ uint16_t vuid1, vuid2;
+ struct smbcli_session_options options;
+
+ torture_comment(tctx, "TESTING PID HANDLING WITH 2 SESSIONS\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+
+ torture_comment(tctx, "create a second security context on the same transport\n");
+ session = smbcli_session_init(cli->transport, tctx, false, options);
+
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities; /* ignored in secondary session setup, except by our libs, which care about the extended security bit */
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ setup.in.credentials = samba_cmdline_get_creds();
+ setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+
+ status = smb_composite_sesssetup(session, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ session->vuid = setup.out.vuid;
+
+ vuid1 = cli->session->vuid;
+ vuid2 = session->vuid;
+
+ torture_comment(tctx, "vuid1=%d vuid2=%d\n", vuid1, vuid2);
+
+ torture_comment(tctx, "create a file using the vuid1\n");
+ cli->session->vuid = vuid1;
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using the vuid1 (fnum=%d)\n", fnum);
+ cli->session->vuid = vuid1;
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "exit the pid with vuid2\n");
+ cli->session->vuid = vuid2;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the fnum should still be accessible\n");
+ cli->session->vuid = vuid1;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "exit the pid with vuid1\n");
+ cli->session->vuid = vuid1;
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the fnum should not now be accessible\n");
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "the fnum should have been auto-closed\n");
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+done:
+ return ret;
+}
+
+/*
+ test pid ops with 2 tcons
+*/
+static bool test_pid_2tcon(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ const char *share, *host;
+ struct smbcli_tree *tree;
+ union smb_tcon tcon;
+ union smb_open io;
+ union smb_write wr;
+ union smb_close cl;
+ int fnum1, fnum2;
+ const char *fname1 = BASEDIR "\\test1.txt";
+ const char *fname2 = BASEDIR "\\test2.txt";
+ uint8_t c = 1;
+ uint16_t tid1, tid2;
+
+ torture_comment(tctx, "TESTING PID HANDLING WITH 2 TCONS\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ share = torture_setting_string(tctx, "share", NULL);
+ host = torture_setting_string(tctx, "host", NULL);
+
+ torture_comment(tctx, "create a second tree context on the same session\n");
+ tree = smbcli_tree_init(cli->session, tctx, false);
+
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ tcon.tconx.in.device = "A:";
+ status = smb_raw_tcon(tree, tctx, &tcon);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ tree->tid = tcon.tconx.out.tid;
+
+ tid1 = cli->tree->tid;
+ tid2 = tree->tid;
+ torture_comment(tctx, "tid1=%d tid2=%d\n", tid1, tid2);
+
+ torture_comment(tctx, "create a file using the tid1\n");
+ cli->tree->tid = tid1;
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using the tid1\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum1;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "create a file using the tid2\n");
+ cli->tree->tid = tid2;
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "write using the tid2\n");
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum2;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = 1;
+ wr.writex.in.data = &c;
+
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, 1);
+
+ torture_comment(tctx, "exit the pid\n");
+ status = smb_raw_exit(cli->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "the fnum1 on tid1 should not be accessible\n");
+ cli->tree->tid = tid1;
+ wr.writex.in.file.fnum = fnum1;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "the fnum1 on tid1 should have been auto-closed\n");
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum1;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "the fnum2 on tid2 should not be accessible\n");
+ cli->tree->tid = tid2;
+ wr.writex.in.file.fnum = fnum2;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "the fnum2 on tid2 should have been auto-closed\n");
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum2;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+done:
+ return ret;
+}
+
+struct torture_suite *torture_raw_context(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "context");
+
+ torture_suite_add_1smb_test(suite, "session1", test_session);
+ /*
+ * TODO: add test_session with 'use spnego = false'
+ * torture_suite_add_1smb_test(suite, "session1", test_session);
+ */
+ torture_suite_add_1smb_test(suite, "tree", test_tree);
+ torture_suite_add_1smb_test(suite, "tree_ulogoff", test_tree_ulogoff);
+ torture_suite_add_1smb_test(suite, "pid_only_sess", test_pid_exit_only_sees_open);
+ torture_suite_add_1smb_test(suite, "pid_2sess", test_pid_2sess);
+ torture_suite_add_1smb_test(suite, "pid_2tcon", test_pid_2tcon);
+
+ return suite;
+}
diff --git a/source4/torture/raw/eas.c b/source4/torture/raw/eas.c
new file mode 100644
index 0000000..59baae5
--- /dev/null
+++ b/source4/torture/raw/eas.c
@@ -0,0 +1,594 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test DOS extended attributes
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Guenter Kukkukk 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\testeas"
+
+#define CHECK_STATUS(status, correct) do { \
+ torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, done, "Incorrect status"); \
+ } while (0)
+
+static bool maxeadebug; /* need that here, to allow no file delete in debug case */
+
+static bool check_ea(struct smbcli_state *cli,
+ const char *fname, const char *eaname, const char *value)
+{
+ NTSTATUS status = torture_check_ea(cli, fname, eaname, value);
+ return NT_STATUS_IS_OK(status);
+}
+
+static char bad_ea_chars[] = "\"*+,/:;<=>?[\\]|";
+
+static bool test_eas(struct smbcli_state *cli, struct torture_context *tctx)
+{
+ NTSTATUS status;
+ union smb_setfileinfo setfile;
+ union smb_open io;
+ const char *fname = BASEDIR "\\ea.txt";
+ bool ret = true;
+ char bad_ea_name[7];
+ int i;
+ int fnum = -1;
+
+ torture_comment(tctx, "TESTING SETFILEINFO EA_SET\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ret &= check_ea(cli, fname, "EAONE", NULL);
+
+ torture_comment(tctx, "Adding first two EAs\n");
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.fnum = fnum;
+ setfile.ea_set.in.num_eas = 2;
+ setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "EAONE";
+ setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
+ setfile.ea_set.in.eas[1].flags = 0;
+ setfile.ea_set.in.eas[1].name.s = "SECONDEA";
+ setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
+
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_ea(cli, fname, "EAONE", "VALUE1");
+ ret &= check_ea(cli, fname, "SECONDEA", "ValueTwo");
+
+ torture_comment(tctx, "Modifying 2nd EA\n");
+ setfile.ea_set.in.num_eas = 1;
+ setfile.ea_set.in.eas[0].name.s = "SECONDEA";
+ setfile.ea_set.in.eas[0].value = data_blob_string_const(" Changed Value");
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_ea(cli, fname, "EAONE", "VALUE1");
+ ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
+
+ torture_comment(tctx, "Setting a NULL EA\n");
+ setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
+ setfile.ea_set.in.eas[0].name.s = "NULLEA";
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_ea(cli, fname, "EAONE", "VALUE1");
+ ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
+ ret &= check_ea(cli, fname, "NULLEA", NULL);
+
+ torture_comment(tctx, "Deleting first EA\n");
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "EAONE";
+ setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_ea(cli, fname, "EAONE", NULL);
+ ret &= check_ea(cli, fname, "SECONDEA", " Changed Value");
+
+ torture_comment(tctx, "Deleting second EA\n");
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "SECONDEA";
+ setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_ea(cli, fname, "EAONE", NULL);
+ ret &= check_ea(cli, fname, "SECONDEA", NULL);
+
+ /* Check EA name containing colon. All EA's set
+ must be ignored, not just the one with the bad
+ name. */
+
+ torture_comment(tctx, "Adding bad EA name\n");
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.fnum = fnum;
+ setfile.ea_set.in.num_eas = 3;
+ setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 3);
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "EAONE";
+ setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
+ setfile.ea_set.in.eas[1].flags = 0;
+ setfile.ea_set.in.eas[1].name.s = "SECOND:EA";
+ setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
+ setfile.ea_set.in.eas[2].flags = 0;
+ setfile.ea_set.in.eas[2].name.s = "THIRDEA";
+ setfile.ea_set.in.eas[2].value = data_blob_string_const("ValueThree");
+
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, STATUS_INVALID_EA_NAME);
+
+ ret &= check_ea(cli, fname, "EAONE", NULL);
+ ret &= check_ea(cli, fname, "THIRDEA", NULL);
+
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.fnum = fnum;
+ setfile.ea_set.in.num_eas = 1;
+ setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1);
+ setfile.ea_set.in.eas[0].flags = 0;
+ strlcpy(bad_ea_name, "TEST_X", sizeof(bad_ea_name));
+ setfile.ea_set.in.eas[0].name.s = bad_ea_name;
+
+ torture_comment(tctx, "Testing bad EA name range.\n");
+
+ for (i = 1; i < 256; i++) {
+ setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
+ bad_ea_name[5] = (char)i;
+ torture_comment(tctx, "Testing bad EA name %d.\n", i);
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ if (i < 32 || strchr(bad_ea_chars, i)) {
+ CHECK_STATUS(status, STATUS_INVALID_EA_NAME);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Now delete the EA we just set to make
+ sure we don't run out of room. */
+ setfile.ea_set.in.eas[0].value = data_blob(NULL, 0);
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
+
+
+/*
+ * Helper function to retrieve the max. ea size for one ea name
+ */
+static int test_one_eamax(struct torture_context *tctx,
+ struct smbcli_state *cli, const int fnum,
+ const char *eaname, DATA_BLOB eablob,
+ const int eastart, const int eadebug)
+{
+ NTSTATUS status;
+ struct ea_struct eastruct;
+ union smb_setfileinfo setfile;
+ int i, high, low, maxeasize;
+
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.fnum = fnum;
+ setfile.ea_set.in.num_eas = 1;
+ setfile.ea_set.in.eas = &eastruct;
+ setfile.ea_set.in.eas->flags = 0;
+ setfile.ea_set.in.eas->name.s = eaname;
+ setfile.ea_set.in.eas->value = eablob;
+
+ maxeasize = eablob.length;
+ i = eastart;
+ low = 0;
+ high = maxeasize;
+
+ do {
+ if (eadebug) {
+ torture_comment(tctx, "Testing EA size: %d\n", i);
+ }
+ setfile.ea_set.in.eas->value.length = i;
+
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ if (eadebug) {
+ torture_comment(tctx, "[%s] EA size %d succeeded! "
+ "(high=%d low=%d)\n",
+ eaname, i, high, low);
+ }
+ low = i;
+ if (low == maxeasize) {
+ torture_comment(tctx, "Max. EA size for \"%s\"=%d "
+ "[but could be possibly larger]\n",
+ eaname, low);
+ break;
+ }
+ if (high - low == 1 && high != maxeasize) {
+ torture_comment(tctx, "Max. EA size for \"%s\"=%d\n",
+ eaname, low);
+ break;
+ }
+ i += (high - low + 1) / 2;
+ } else {
+ if (eadebug) {
+ torture_comment(tctx, "[%s] EA size %d failed! "
+ "(high=%d low=%d) [%s]\n",
+ eaname, i, high, low,
+ nt_errstr(status));
+ }
+ high = i;
+ if (high - low <= 1) {
+ torture_comment(tctx, "Max. EA size for \"%s\"=%d\n",
+ eaname, low);
+ break;
+ }
+ i -= (high - low + 1) / 2;
+ }
+ } while (true);
+
+ return low;
+}
+
+/*
+ * Test for maximum ea size - more than one ea name is checked.
+ *
+ * Additional parameters can be passed, to allow further testing:
+ *
+ * default
+ * maxeasize 65536 limit the max. size for a single EA name
+ * maxeanames 101 limit of the number of tested names
+ * maxeastart 1 this EA size is used to test for the 1st EA (atm)
+ * maxeadebug 0 if set true, further debug output is done - in addition
+ * the testfile is not deleted for further inspection!
+ *
+ * Set some/all of these options on the cmdline with:
+ * --option torture:maxeasize=1024 --option torture:maxeadebug=1 ...
+ *
+ */
+static bool test_max_eas(struct smbcli_state *cli, struct torture_context *tctx)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\ea_max.txt";
+ int fnum = -1;
+ bool ret = true;
+ bool err = false;
+
+ int i, j, k, last;
+ size_t total;
+ DATA_BLOB eablob;
+ char *eaname = NULL;
+ int maxeasize;
+ int maxeanames;
+ int maxeastart;
+
+ torture_comment(tctx, "TESTING SETFILEINFO MAX. EA_SET\n");
+
+ maxeasize = torture_setting_int(tctx, "maxeasize", 65536);
+ maxeanames = torture_setting_int(tctx, "maxeanames", 101);
+ maxeastart = torture_setting_int(tctx, "maxeastart", 1);
+ maxeadebug = torture_setting_bool(tctx, "maxeadebug", false);
+
+ /* Do some sanity check on possibly passed parms */
+ if (maxeasize <= 0) {
+ torture_comment(tctx, "Invalid parameter 'maxeasize=%d'",maxeasize);
+ err = true;
+ }
+ if (maxeanames <= 0) {
+ torture_comment(tctx, "Invalid parameter 'maxeanames=%d'",maxeanames);
+ err = true;
+ }
+ if (maxeastart <= 0) {
+ torture_comment(tctx, "Invalid parameter 'maxeastart=%d'",maxeastart);
+ err = true;
+ }
+ if (err) {
+ torture_comment(tctx, "\n\n");
+ goto done;
+ }
+ if (maxeastart > maxeasize) {
+ maxeastart = maxeasize;
+ torture_comment(tctx, "'maxeastart' outside range - corrected to %d\n",
+ maxeastart);
+ }
+ torture_comment(tctx, "MAXEA parms: maxeasize=%d maxeanames=%d maxeastart=%d"
+ " maxeadebug=%d\n", maxeasize, maxeanames, maxeastart,
+ maxeadebug);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ eablob = data_blob_talloc(tctx, NULL, maxeasize);
+ if (eablob.data == NULL) {
+ goto done;
+ }
+ /*
+ * Fill in some EA data - the offset could be easily checked
+ * during a hexdump.
+ */
+ for (i = 0, k = 0; i < eablob.length / 4; i++, k+=4) {
+ eablob.data[k] = k & 0xff;
+ eablob.data[k+1] = (k >> 8) & 0xff;
+ eablob.data[k+2] = (k >> 16) & 0xff;
+ eablob.data[k+3] = (k >> 24) & 0xff;
+ }
+
+ i = eablob.length % 4;
+ if (i-- > 0) {
+ eablob.data[k] = k & 0xff;
+ if (i-- > 0) {
+ eablob.data[k+1] = (k >> 8) & 0xff;
+ if (i-- > 0) {
+ eablob.data[k+2] = (k >> 16) & 0xff;
+ }
+ }
+ }
+ /*
+ * Filesystems might allow max. EAs data for different EA names.
+ * So more than one EA name should be checked.
+ */
+ total = 0;
+ last = maxeastart;
+
+ for (i = 0; i < maxeanames; i++) {
+ if (eaname != NULL) {
+ talloc_free(eaname);
+ }
+ eaname = talloc_asprintf(tctx, "MAX%d", i);
+ if(eaname == NULL) {
+ goto done;
+ }
+ j = test_one_eamax(tctx, cli, fnum, eaname, eablob, last, maxeadebug);
+ if (j <= 0) {
+ break;
+ }
+ total += j;
+ last = j;
+ }
+
+ torture_comment(tctx, "Total EA size:%zu\n", total);
+ if (i == maxeanames) {
+ torture_comment(tctx, "NOTE: More EAs could be available!\n");
+ }
+ if (total == 0) {
+ ret = false;
+ }
+done:
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
+
+/*
+ test using NTTRANS CREATE to create a file with an initial EA set
+*/
+static bool test_nttrans_create(struct smbcli_state *cli, struct torture_context *tctx)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\ea2.txt";
+ const char *fname_bad = BASEDIR "\\ea2_bad.txt";
+ bool ret = true;
+ int fnum = -1;
+ struct ea_struct eas[3];
+ struct smb_ea_list ea_list;
+
+ torture_comment(tctx, "TESTING NTTRANS CREATE WITH EAS\n");
+
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ ea_list.num_eas = 3;
+ ea_list.eas = eas;
+
+ eas[0].flags = 0;
+ eas[0].name.s = "1st EA";
+ eas[0].value = data_blob_string_const("Value One");
+
+ eas[1].flags = 0;
+ eas[1].name.s = "2nd EA";
+ eas[1].value = data_blob_string_const("Second Value");
+
+ eas[2].flags = 0;
+ eas[2].name.s = "and 3rd";
+ eas[2].value = data_blob_string_const("final value");
+
+ io.ntcreatex.in.ea_list = &ea_list;
+ io.ntcreatex.in.sec_desc = NULL;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ret &= check_ea(cli, fname, "EAONE", NULL);
+ ret &= check_ea(cli, fname, "1st EA", "Value One");
+ ret &= check_ea(cli, fname, "2nd EA", "Second Value");
+ ret &= check_ea(cli, fname, "and 3rd", "final value");
+
+ smbcli_close(cli->tree, fnum);
+
+ torture_comment(tctx, "Trying to add EAs on non-create\n");
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.fname = fname;
+
+ ea_list.num_eas = 1;
+ eas[0].flags = 0;
+ eas[0].name.s = "Fourth EA";
+ eas[0].value = data_blob_string_const("Value Four");
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ret &= check_ea(cli, fname, "1st EA", "Value One");
+ ret &= check_ea(cli, fname, "2nd EA", "Second Value");
+ ret &= check_ea(cli, fname, "and 3rd", "final value");
+ ret &= check_ea(cli, fname, "Fourth EA", NULL);
+
+ torture_comment(tctx, "TESTING NTTRANS CREATE WITH BAD EA NAMES\n");
+
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname_bad;
+
+ ea_list.num_eas = 3;
+ ea_list.eas = eas;
+
+ eas[0].flags = 0;
+ eas[0].name.s = "1st EA";
+ eas[0].value = data_blob_string_const("Value One");
+
+ eas[1].flags = 0;
+ eas[1].name.s = "2nd:BAD:EA";
+ eas[1].value = data_blob_string_const("Second Value");
+
+ eas[2].flags = 0;
+ eas[2].name.s = "and 3rd";
+ eas[2].value = data_blob_string_const("final value");
+
+ io.ntcreatex.in.ea_list = &ea_list;
+ io.ntcreatex.in.sec_desc = NULL;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, STATUS_INVALID_EA_NAME);
+
+ /* File must not exist. */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname_bad;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
+
+/*
+ basic testing of EA calls
+*/
+bool torture_raw_eas(struct torture_context *torture, struct smbcli_state *cli)
+{
+ bool ret = true;
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ ret &= test_eas(cli, torture);
+ ret &= test_nttrans_create(cli, torture);
+
+ smb_raw_exit(cli->session);
+
+ return ret;
+}
+
+/*
+ test max EA size
+*/
+bool torture_max_eas(struct torture_context *torture)
+{
+ struct smbcli_state *cli;
+ bool ret = true;
+
+ if (!torture_open_connection(&cli, torture, 0)) {
+ return false;
+ }
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ ret &= test_max_eas(cli, torture);
+
+ smb_raw_exit(cli->session);
+ if (!maxeadebug) {
+ /* in no ea debug case, all files are gone now */
+ smbcli_deltree(cli->tree, BASEDIR);
+ }
+
+ torture_close_connection(cli);
+ return ret;
+}
diff --git a/source4/torture/raw/ioctl.c b/source4/torture/raw/ioctl.c
new file mode 100644
index 0000000..0dc0ac9
--- /dev/null
+++ b/source4/torture/raw/ioctl.c
@@ -0,0 +1,191 @@
+/*
+ Unix SMB/CIFS implementation.
+ ioctl individual test suite
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) James J Myers 2003 <myersjj@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../libcli/smb/smb_constants.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\rawioctl"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%d) Incorrect status %s - should be %s\n", \
+ __LINE__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+
+/* test some ioctls */
+static bool test_ioctl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_ioctl ctl;
+ int fnum;
+ NTSTATUS status;
+ bool ret = true;
+ const char *fname = BASEDIR "\\test.dat";
+
+ printf("TESTING IOCTL FUNCTIONS\n");
+
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ printf("Failed to create test.dat - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Trying 0xFFFF\n");
+ ctl.ioctl.level = RAW_IOCTL_IOCTL;
+ ctl.ioctl.in.file.fnum = fnum;
+ ctl.ioctl.in.request = 0xFFFF;
+
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
+
+ printf("Trying QUERY_JOB_INFO\n");
+ ctl.ioctl.level = RAW_IOCTL_IOCTL;
+ ctl.ioctl.in.file.fnum = fnum;
+ ctl.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
+
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
+
+ printf("Trying bad handle\n");
+ ctl.ioctl.in.file.fnum = fnum+1;
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &ctl);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV, ERRerror));
+
+done:
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
+
+/* test some filesystem control functions */
+static bool test_fsctl(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ int fnum;
+ NTSTATUS status;
+ bool ret = true;
+ const char *fname = BASEDIR "\\test.dat";
+ union smb_ioctl nt;
+
+ printf("\nTESTING FSCTL FUNCTIONS\n");
+
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ if (fnum == -1) {
+ printf("Failed to create test.dat - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Trying FSCTL_FIND_FILES_BY_SID\n");
+ nt.ioctl.level = RAW_IOCTL_NTIOCTL;
+ nt.ntioctl.in.function = FSCTL_FIND_FILES_BY_SID;
+ nt.ntioctl.in.file.fnum = fnum;
+ nt.ntioctl.in.fsctl = true;
+ nt.ntioctl.in.filter = 0;
+ nt.ntioctl.in.max_data = 0;
+ nt.ntioctl.in.blob = data_blob(NULL, 1024);
+ /* definitely not a sid... */
+ generate_random_buffer(nt.ntioctl.in.blob.data,
+ nt.ntioctl.in.blob.length);
+ nt.ntioctl.in.blob.data[1] = 15+1;
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ printf("Got unexpected error code: %s\n",
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ printf("trying sparse file\n");
+ nt.ioctl.level = RAW_IOCTL_NTIOCTL;
+ nt.ntioctl.in.function = FSCTL_SET_SPARSE;
+ nt.ntioctl.in.file.fnum = fnum;
+ nt.ntioctl.in.fsctl = true;
+ nt.ntioctl.in.filter = 0;
+ nt.ntioctl.in.max_data = 0;
+ nt.ntioctl.in.blob = data_blob(NULL, 0);
+
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("trying batch oplock\n");
+ nt.ioctl.level = RAW_IOCTL_NTIOCTL;
+ nt.ntioctl.in.function = FSCTL_REQUEST_BATCH_OPLOCK;
+ nt.ntioctl.in.file.fnum = fnum;
+ nt.ntioctl.in.fsctl = true;
+ nt.ntioctl.in.filter = 0;
+ nt.ntioctl.in.max_data = 0;
+ nt.ntioctl.in.blob = data_blob(NULL, 0);
+
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
+ if (NT_STATUS_IS_OK(status)) {
+ printf("Server supports batch oplock upgrades on open files\n");
+ } else {
+ printf("Server does not support batch oplock upgrades on open files\n");
+ }
+
+ printf("Trying bad handle\n");
+ nt.ntioctl.in.file.fnum = fnum+1;
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+#if 0
+ nt.ntioctl.in.file.fnum = fnum;
+ for (i=0;i<100;i++) {
+ nt.ntioctl.in.function = FSCTL_FILESYSTEM + (i<<2);
+ status = smb_raw_ioctl(cli->tree, mem_ctx, &nt);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ printf("filesystem fsctl 0x%x - %s\n",
+ i, nt_errstr(status));
+ }
+ }
+#endif
+
+done:
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
+
+/*
+ basic testing of some ioctl calls
+*/
+bool torture_raw_ioctl(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ ret &= test_ioctl(cli, torture);
+ ret &= test_fsctl(cli, torture);
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c
new file mode 100644
index 0000000..6dbc9e9
--- /dev/null
+++ b/source4/torture/raw/lock.c
@@ -0,0 +1,3586 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various lock operations
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+#include "torture/raw/proto.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_STATUS_CONT(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STATUS_OR(status, correct1, correct2) do { \
+ if ((!NT_STATUS_EQUAL(status, correct1)) && \
+ (!NT_STATUS_EQUAL(status, correct2))) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s or %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct1), \
+ nt_errstr(correct2)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_STATUS_OR_CONT(status, correct1, correct2) do { \
+ if ((!NT_STATUS_EQUAL(status, correct1)) && \
+ (!NT_STATUS_EQUAL(status, correct2))) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s or %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct1), \
+ nt_errstr(correct2)); \
+ ret = false; \
+ }} while (0)
+#define BASEDIR "\\testlock"
+
+#define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
+#define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
+#define TARGET_IS_WINDOWS(_tctx) \
+ ((torture_setting_bool(_tctx, "w2k3", false)) || \
+ (torture_setting_bool(_tctx, "w2k8", false)) || \
+ (torture_setting_bool(_tctx, "win7", false)))
+#define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
+#define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
+
+#define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
+ (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
+#define TARGET_SUPPORTS_SMBEXIT(_tctx) \
+ (torture_setting_bool(_tctx, "smbexit_pdu_support", true))
+#define TARGET_SUPPORTS_SMBLOCK(_tctx) \
+ (torture_setting_bool(_tctx, "smblock_pdu_support", true))
+#define TARGET_SUPPORTS_OPENX_DENY_DOS(_tctx) \
+ (torture_setting_bool(_tctx, "openx_deny_dos_support", true))
+#define TARGET_RETURNS_RANGE_NOT_LOCKED(_tctx) \
+ (torture_setting_bool(_tctx, "range_not_locked_on_file_close", true))
+/*
+ test SMBlock and SMBunlock ops
+*/
+static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+
+ if (!TARGET_SUPPORTS_SMBLOCK(tctx))
+ torture_skip(tctx, "Target does not support the SMBlock PDU");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing RAW_LOCK_LOCK\n");
+ io.generic.level = RAW_LOCK_LOCK;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ torture_comment(tctx, "Trying 0/0 lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.file.fnum = fnum;
+ io.lock.in.count = 0;
+ io.lock.in.offset = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Trying 0/1 lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.file.fnum = fnum;
+ io.lock.in.count = 1;
+ io.lock.in.offset = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.file.fnum = fnum;
+ io.lock.in.count = 4000;
+ io.lock.in.offset = 0xEEFFFFFF;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.file.fnum = fnum;
+ io.lock.in.count = 4000;
+ io.lock.in.offset = 0xEEFFFFFF;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying max lock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.file.fnum = fnum;
+ io.lock.in.count = 4000;
+ io.lock.in.offset = 0xEF000000;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ cli->session->pid--;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying wrong pid unlock\n");
+ io.lock.level = RAW_LOCK_LOCK;
+ io.lock.in.file.fnum = fnum;
+ io.lock.in.count = 4002;
+ io.lock.in.offset = 10001;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ cli->session->pid++;
+ io.lock.level = RAW_LOCK_UNLOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ cli->session->pid--;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test locking&X ops
+*/
+static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing RAW_LOCK_LOCKX\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 10;
+ lock[0].count = 1;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(tctx, "Trying 0xEEFFFFFF lock\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 4000;
+ lock[0].offset = 0xEEFFFFFF;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying 0xEF000000 lock\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 4000;
+ lock[0].offset = 0xEF000000;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying zero lock\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 0;
+ lock[0].offset = ~0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying max lock\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 0;
+ lock[0].offset = ~0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying 2^63\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 1;
+ lock[0].offset = 1;
+ lock[0].offset <<= 63;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying 2^63 - 1\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 1;
+ lock[0].offset = 1;
+ lock[0].offset <<= 63;
+ lock[0].offset--;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(tctx, "Trying max lock 2\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].count = 1;
+ lock[0].offset = ~0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid++;
+ lock[0].count = 2;
+ status = smb_raw_lock(cli->tree, &io);
+ if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(tctx))
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
+ else
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lock[0].pid--;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ lock[0].count = 1;
+ status = smb_raw_lock(cli->tree, &io);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test high pid
+*/
+static bool test_pidhigh(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ uint8_t c = 1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing high pid\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ cli->session->pid = 1;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to write 1 byte - %s\n",
+ smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 0;
+ lock[0].count = 0xFFFFFFFF;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to read 1 byte - %s\n",
+ smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ cli->session->pid = 2;
+
+ if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "pid is incorrect handled for read with lock!\n");
+ ret = false;
+ goto done;
+ }
+
+ cli->session->pid = 0x10001;
+
+ if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "High pid is used on this server!\n");
+ ret = false;
+ } else {
+ torture_warning(tctx, "High pid is not used on this server (correct)\n");
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test locking&X async operation
+*/
+static bool test_async(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ struct smbcli_session *session;
+ struct smb_composite_sesssetup setup;
+ struct smbcli_tree *tree;
+ union smb_tcon tcon;
+ const char *host, *share;
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\test.txt";
+ time_t t;
+ struct smbcli_request *req, *req2;
+ struct smbcli_session_options options;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX_CANCEL_LOCK\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 110;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ t = time_mono(NULL);
+
+ torture_comment(tctx, "Testing cancel by CANCEL_LOCK\n");
+
+ /* setup a timed lock */
+ io.lockx.in.timeout = 10000;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ /* cancel the wrong range */
+ lock[0].offset = 0;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
+
+ /* cancel with the wrong bits set */
+ lock[0].offset = 100;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
+
+ /* cancel the right range */
+ lock[0].offset = 100;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* receive the failed lock request */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "lock cancel was not immediate (%s)\n", __location__));
+
+ /* MS-CIFS (2.2.4.32.1) states that a cancel is honored if and only
+ * if the lock vector contains one entry. When given multiple cancel
+ * requests in a single PDU we expect the server to return an
+ * error. Samba4 handles this correctly. Windows servers seem to
+ * accept the request but only cancel the first lock. Samba3
+ * now does what Windows does (JRA).
+ */
+ torture_comment(tctx, "Testing multiple cancel\n");
+
+ /* acquire second lock */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[1];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* setup 2 timed locks */
+ t = time_mono(NULL);
+ io.lockx.in.timeout = 10000;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock[0];
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+ io.lockx.in.locks = &lock[1];
+ req2 = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ /* try to cancel both locks in the same packet */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = lock;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_warning(tctx, "Target server accepted a lock cancel "
+ "request with multiple locks. This violates "
+ "MS-CIFS 2.2.4.32.1.\n");
+
+ /* receive the failed lock requests */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "first lock was not cancelled immediately (%s)\n",
+ __location__));
+
+ /* send cancel to second lock */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK |
+ LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[1];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smbcli_request_simple_recv(req2);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "second lock was not cancelled immediately (%s)\n",
+ __location__));
+
+ /* cleanup the second lock */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[1];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* If a lock request contained multiple ranges and we are cancelling
+ * one while it's still pending, what happens? */
+ torture_comment(tctx, "Testing cancel 1/2 lock request\n");
+
+ /* Send request with two ranges */
+ io.lockx.in.timeout = -1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = lock;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup pending lock (%s)\n", __location__));
+
+ /* Try to cancel the first lock range */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Locking request should've failed and second range should be
+ * unlocked */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[1];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Cleanup both locks */
+ io.lockx.in.ulock_cnt = 2;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = lock;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing cancel 2/2 lock request\n");
+
+ /* Lock second range so it contends */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[1];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Send request with two ranges */
+ io.lockx.in.timeout = -1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = lock;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup pending lock (%s)\n", __location__));
+
+ /* Try to cancel the second lock range */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[1];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Locking request should've failed and first range should be
+ * unlocked */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Cleanup both locks */
+ io.lockx.in.ulock_cnt = 2;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.locks = lock;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing cancel by unlock\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.timeout = 5000;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ t = time_mono(NULL);
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "lock cancel by unlock was not immediate (%s) - took %d secs\n",
+ __location__, (int)(time_mono(NULL)-t)));
+
+ torture_comment(tctx, "Testing cancel by close\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ {
+ /*
+ * Make the test block on the second lock
+ * request. This is to regression-test 64c0367.
+ */
+ uint64_t tmp = lock[1].offset;
+ lock[1].offset = lock[0].offset;
+ lock[0].offset = tmp;
+ }
+
+ t = time_mono(NULL);
+ io.lockx.in.timeout = 10000;
+ io.lockx.in.lock_cnt = 2;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smbcli_request_simple_recv(req);
+ if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ else
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "lock cancel by close was not immediate (%s)\n", __location__));
+
+ {
+ /*
+ * Undo the change for 64c0367
+ */
+ uint64_t tmp = lock[1].offset;
+ lock[1].offset = lock[0].offset;
+ lock[0].offset = tmp;
+ }
+
+ torture_comment(tctx, "create a new sessions\n");
+ session = smbcli_session_init(cli->transport, tctx, false, options);
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities;
+ setup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ setup.in.credentials = samba_cmdline_get_creds();
+ setup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+ status = smb_composite_sesssetup(session, &setup);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ session->vuid = setup.out.vuid;
+
+ torture_comment(tctx, "create new tree context\n");
+ share = torture_setting_string(tctx, "share", NULL);
+ host = torture_setting_string(tctx, "host", NULL);
+ tree = smbcli_tree_init(session, tctx, false);
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ tcon.tconx.in.device = "A:";
+ status = smb_raw_tcon(tree, tctx, &tcon);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ tree->tid = tcon.tconx.out.tid;
+
+ torture_comment(tctx, "Testing cancel by exit\n");
+ if (TARGET_SUPPORTS_SMBEXIT(tctx)) {
+ fname = BASEDIR "\\test_exit.txt";
+ fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to reopen %s - %s\n",
+ fname, smbcli_errstr(tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ status = smb_raw_lock(tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ io.lockx.in.timeout = 10000;
+ t = time_mono(NULL);
+ req = smb_raw_lock_send(tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n",
+ __location__));
+
+ status = smb_raw_exit(session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smbcli_request_simple_recv(req);
+ if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ else
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "lock cancel by exit was not immediate (%s)\n",
+ __location__));
+ }
+ else {
+ torture_comment(tctx,
+ " skipping test, SMBExit not supported\n");
+ }
+
+ torture_comment(tctx, "Testing cancel by ulogoff\n");
+ fname = BASEDIR "\\test_ulogoff.txt";
+ fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to reopen %s - %s\n",
+ fname, smbcli_errstr(tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ status = smb_raw_lock(tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ io.lockx.in.timeout = 10000;
+ t = time_mono(NULL);
+ req = smb_raw_lock_send(tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ status = smb_raw_ulogoff(session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smbcli_request_simple_recv(req);
+ if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx)) {
+ if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "lock not canceled by ulogoff - %s "
+ "(ignored because of vfs_vifs fails it)\n",
+ nt_errstr(status));
+ smb_tree_disconnect(tree);
+ smb_raw_exit(session);
+ goto done;
+ }
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ }
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "lock cancel by ulogoff was not immediate (%s)\n", __location__));
+
+ torture_comment(tctx, "Testing cancel by tdis\n");
+ tree->session = cli->session;
+
+ fname = BASEDIR "\\test_tdis.txt";
+ fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to reopen %s - %s\n",
+ fname, smbcli_errstr(tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_lock(tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ io.lockx.in.timeout = 10000;
+ t = time_mono(NULL);
+ req = smb_raw_lock_send(tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ status = smb_tree_disconnect(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smbcli_request_simple_recv(req);
+ if (TARGET_RETURNS_RANGE_NOT_LOCKED(tctx))
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ else
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "lock cancel by tdis was not immediate (%s)\n", __location__));
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
+*/
+static bool test_errorcode(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ union smb_open op;
+ struct smb_lock_entry lock[2];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum, fnum2;
+ const char *fname;
+ struct smbcli_request *req;
+ time_t start;
+ int t;
+ int delay;
+ uint16_t deny_mode = 0;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
+
+ torture_comment(tctx, "Testing with timeout = 0\n");
+ fname = BASEDIR "\\test0.txt";
+ t = 0;
+
+ /*
+ * the first run is with t = 0,
+ * the second with t > 0 (=1)
+ */
+next_run:
+ /*
+ * use the DENY_DOS mode, that creates two fnum's of one low-level
+ * file handle, this demonstrates that the cache is per fnum, not
+ * per file handle
+ */
+ if (TARGET_SUPPORTS_OPENX_DENY_DOS(tctx))
+ deny_mode = OPENX_MODE_DENY_DOS;
+ else
+ deny_mode = OPENX_MODE_DENY_NONE;
+
+ op.openx.level = RAW_OPEN_OPENX;
+ op.openx.in.fname = fname;
+ op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | deny_mode;
+ op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ op.openx.in.search_attrs = 0;
+ op.openx.in.file_attrs = 0;
+ op.openx.in.write_time = 0;
+ op.openx.in.size = 0;
+ op.openx.in.timeout = 0;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.openx.out.file.fnum;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = op.openx.out.file.fnum;
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = t;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
+ * this also demonstrates that the error code cache is per file handle
+ * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
+ */
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+
+ /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* demonstrate that the smbpid doesn't matter */
+ lock[0].pid++;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ lock[0].pid--;
+
+ /*
+ * demonstrate that a successful lock with count = 0 and the same offset,
+ * doesn't reset the error cache
+ */
+ lock[0].offset = 100;
+ lock[0].count = 0;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /*
+ * demonstrate that a successful lock with count = 0 and outside the locked range,
+ * doesn't reset the error cache
+ */
+ lock[0].offset = 110;
+ lock[0].count = 0;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ lock[0].offset = 99;
+ lock[0].count = 0;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* demonstrate that a changing count doesn't reset the error cache */
+ lock[0].offset = 100;
+ lock[0].count = 5;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ lock[0].offset = 100;
+ lock[0].count = 15;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /*
+ * demonstrate that a lock with count = 0 and inside the locked range,
+ * fails and resets the error cache
+ */
+ lock[0].offset = 101;
+ lock[0].count = 0;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* demonstrate that a changing offset resets the error cache */
+ lock[0].offset = 105;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ lock[0].offset = 95;
+ lock[0].count = 9;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /*
+ * demonstrate that a successful lock in a different range
+ * doesn't reset the cache, the failing lock on the 2nd handle
+ * resets the cache
+ */
+ lock[0].offset = 120;
+ lock[0].count = 15;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.file.fnum = fnum;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* end of the loop */
+ if (t == 0) {
+ smb_raw_exit(cli->session);
+ t = 1;
+ torture_comment(tctx, "Testing with timeout > 0 (=%d)\n",
+ t);
+ fname = BASEDIR "\\test1.txt";
+ goto next_run;
+ }
+
+ t = 4000;
+ torture_comment(tctx, "Testing special cases with timeout > 0 (=%d)\n",
+ t);
+
+ /*
+ * the following 3 test sections demonstrate that
+ * the cache is only set when the error is reported
+ * to the client (after the timeout went by)
+ */
+ smb_raw_exit(cli->session);
+ torture_comment(tctx, "Testing a conflict while a lock is pending\n");
+ fname = BASEDIR "\\test2.txt";
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to reopen %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ start = time_mono(NULL);
+ io.lockx.in.timeout = t;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ io.lockx.in.timeout = 0;
+ lock[0].offset = 105;
+ lock[0].count = 10;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ delay = t / 1000;
+ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
+ delay /= 2;
+ }
+
+ torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
+ "lock comes back to early timeout[%d] delay[%d]"
+ "(%s)\n", t, delay, __location__));
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ smbcli_close(cli->tree, fnum);
+ fname = BASEDIR "\\test3.txt";
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to reopen %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ start = time_mono(NULL);
+ io.lockx.in.timeout = t;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ io.lockx.in.timeout = 0;
+ lock[0].offset = 105;
+ lock[0].count = 10;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ delay = t / 1000;
+ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
+ delay /= 2;
+ }
+
+ torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
+ "lock comes back to early timeout[%d] delay[%d]"
+ "(%s)\n", t, delay, __location__));
+
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ smbcli_close(cli->tree, fnum);
+ fname = BASEDIR "\\test4.txt";
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to reopen %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ start = time_mono(NULL);
+ io.lockx.in.timeout = t;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed lock (%s)\n", __location__));
+
+ io.lockx.in.timeout = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ delay = t / 1000;
+ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
+ delay /= 2;
+ }
+
+ torture_assert(tctx,!(time_mono(NULL) < start+delay), talloc_asprintf(tctx,
+ "lock comes back to early timeout[%d] delay[%d]"
+ "(%s)\n", t, delay, __location__));
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test LOCKING_ANDX_CHANGE_LOCKTYPE
+*/
+static bool test_changetype(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t c = 0;
+ const char *fname = BASEDIR "\\test.txt";
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "allowed write on read locked region (%s)\n", __location__);
+ ret = false;
+ goto done;
+ }
+
+ /* windows server don't seem to support this */
+ io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
+
+ if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "allowed write after lock change (%s)\n", __location__);
+ ret = false;
+ goto done;
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+struct double_lock_test {
+ struct smb_lock_entry lock1;
+ struct smb_lock_entry lock2;
+ NTSTATUS exp_status;
+};
+
+/**
+ * Tests zero byte locks.
+ */
+static struct double_lock_test zero_byte_tests[] = {
+ /* {pid, offset, count}, {pid, offset, count}, status */
+
+ /** First, takes a zero byte lock at offset 10. Then:
+ * - Taking 0 byte lock at 10 should succeed.
+ * - Taking 1 byte locks at 9,10,11 should succeed.
+ * - Taking 2 byte lock at 9 should fail.
+ * - Taking 2 byte lock at 10 should succeed.
+ * - Taking 3 byte lock at 9 should fail.
+ */
+ {{1000, 10, 0}, {1001, 10, 0}, NT_STATUS_OK},
+ {{1000, 10, 0}, {1001, 9, 1}, NT_STATUS_OK},
+ {{1000, 10, 0}, {1001, 10, 1}, NT_STATUS_OK},
+ {{1000, 10, 0}, {1001, 11, 1}, NT_STATUS_OK},
+ {{1000, 10, 0}, {1001, 9, 2}, NT_STATUS_LOCK_NOT_GRANTED},
+ {{1000, 10, 0}, {1001, 10, 2}, NT_STATUS_OK},
+ {{1000, 10, 0}, {1001, 9, 3}, NT_STATUS_LOCK_NOT_GRANTED},
+
+ /** Same, but opposite order. */
+ {{1001, 10, 0}, {1000, 10, 0}, NT_STATUS_OK},
+ {{1001, 9, 1}, {1000, 10, 0}, NT_STATUS_OK},
+ {{1001, 10, 1}, {1000, 10, 0}, NT_STATUS_OK},
+ {{1001, 11, 1}, {1000, 10, 0}, NT_STATUS_OK},
+ {{1001, 9, 2}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
+ {{1001, 10, 2}, {1000, 10, 0}, NT_STATUS_OK},
+ {{1001, 9, 3}, {1000, 10, 0}, NT_STATUS_LOCK_NOT_GRANTED},
+
+ /** Zero zero case. */
+ {{1000, 0, 0}, {1001, 0, 0}, NT_STATUS_OK},
+};
+
+static bool test_zerobytelocks(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum, i;
+ const char *fname = BASEDIR "\\zero.txt";
+
+ torture_comment(tctx, "Testing zero length byte range locks:\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /* Setup initial parameters */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; /* Exclusive */
+ io.lockx.in.timeout = 0;
+
+ /* Try every combination of locks in zero_byte_tests. The first lock is
+ * assumed to succeed. The second lock may contend, depending on the
+ * expected status. */
+ for (i = 0;
+ i < ARRAY_SIZE(zero_byte_tests);
+ i++) {
+ torture_comment(tctx, " ... {%d, %llu, %llu} + {%d, %llu, %llu} = %s\n",
+ zero_byte_tests[i].lock1.pid,
+ (unsigned long long) zero_byte_tests[i].lock1.offset,
+ (unsigned long long) zero_byte_tests[i].lock1.count,
+ zero_byte_tests[i].lock2.pid,
+ (unsigned long long) zero_byte_tests[i].lock2.offset,
+ (unsigned long long) zero_byte_tests[i].lock2.count,
+ nt_errstr(zero_byte_tests[i].exp_status));
+
+ /* Lock both locks. */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+
+ io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
+ &zero_byte_tests[i].lock1);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
+ &zero_byte_tests[i].lock2);
+ status = smb_raw_lock(cli->tree, &io);
+
+ if (NT_STATUS_EQUAL(zero_byte_tests[i].exp_status,
+ NT_STATUS_LOCK_NOT_GRANTED)) {
+ /* Allow either of the failure messages and keep going
+ * if we see the wrong status. */
+ CHECK_STATUS_OR_CONT(status,
+ NT_STATUS_LOCK_NOT_GRANTED,
+ NT_STATUS_FILE_LOCK_CONFLICT);
+
+ } else {
+ CHECK_STATUS_CONT(status,
+ zero_byte_tests[i].exp_status);
+ }
+
+ /* Unlock both locks. */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ io.lockx.in.locks = discard_const_p(struct smb_lock_entry,
+ &zero_byte_tests[i].lock1);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_unlock(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum1, fnum2;
+ const char *fname = BASEDIR "\\unlock.txt";
+ struct smb_lock_entry lock1;
+ struct smb_lock_entry lock2;
+
+ torture_comment(tctx, "Testing LOCKX unlock:\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /* Setup initial parameters */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.timeout = 0;
+
+ lock1.pid = cli->session->pid;
+ lock1.offset = 0;
+ lock1.count = 10;
+ lock2.pid = cli->session->pid - 1;
+ lock2.offset = 0;
+ lock2.count = 10;
+
+ /**
+ * Take exclusive lock, then unlock it with a shared-unlock call.
+ */
+ torture_comment(tctx, " taking exclusive lock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = 0;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, " unlock the exclusive with a shared unlock call.\n");
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, " try shared lock on pid2/fnum2, testing the unlock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ io.lockx.in.file.fnum = fnum2;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /**
+ * Unlock a shared lock with an exclusive-unlock call.
+ */
+ torture_comment(tctx, " unlock new shared lock with exclusive unlock call.\n");
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = 0;
+ io.lockx.in.file.fnum = fnum2;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, " try exclusive lock on pid1, testing the unlock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = 0;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /**
+ * Test unlocking of 0-byte locks.
+ */
+
+ torture_comment(tctx, " lock shared and exclusive 0-byte locks, testing that Windows "
+ "always unlocks the exclusive first.\n");
+ lock1.pid = cli->session->pid;
+ lock1.offset = 10;
+ lock1.count = 0;
+ lock2.pid = cli->session->pid;
+ lock2.offset = 5;
+ lock2.count = 10;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+
+ /* lock 0-byte shared
+ * Note: Order of the shared/exclusive locks doesn't matter. */
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* lock 0-byte exclusive */
+ io.lockx.in.mode = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* test contention */
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ io.lockx.in.locks = &lock2;
+ io.lockx.in.file.fnum = fnum2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
+ NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* unlock */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* test - can we take a shared lock? */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ io.lockx.in.file.fnum = fnum2;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+
+ /* XXX Samba 3 will fail this test. This is temporary(because this isn't
+ * new to Win7, it succeeds in WinXP too), until I can come to a
+ * resolution as to whether Samba should support this or not. There is
+ * code to preference unlocking exclusive locks before shared locks,
+ * but its wrapped with "#ifdef ZERO_ZERO". -zkirsch */
+ if (TARGET_IS_SAMBA3(tctx)) {
+ CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
+ NT_STATUS_FILE_LOCK_CONFLICT);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+
+ /* XXX Same as above. */
+ if (TARGET_IS_SAMBA3(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum1);
+ smbcli_close(cli->tree, fnum2);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_multiple_unlock(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum1;
+ const char *fname = BASEDIR "\\unlock_multiple.txt";
+ struct smb_lock_entry lock1;
+ struct smb_lock_entry lock2;
+ struct smb_lock_entry locks[2];
+
+ torture_comment(tctx, "Testing LOCKX multiple unlock:\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /* Setup initial parameters */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.timeout = 0;
+
+ lock1.pid = cli->session->pid;
+ lock1.offset = 0;
+ lock1.count = 10;
+ lock2.pid = cli->session->pid;
+ lock2.offset = 10;
+ lock2.count = 10;
+
+ locks[0] = lock1;
+ locks[1] = lock2;
+
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.mode = 0; /* exclusive */
+
+ /** Test1: Take second lock, but not first. */
+ torture_comment(tctx, " unlock 2 locks, first one not locked. Expect no locks "
+ "unlocked. \n");
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to unlock both locks. */
+ io.lockx.in.ulock_cnt = 2;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = locks;
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* Second lock should not be unlocked. */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /** Test2: Take first lock, but not second. */
+ torture_comment(tctx, " unlock 2 locks, second one not locked. Expect first lock "
+ "unlocked.\n");
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to unlock both locks. */
+ io.lockx.in.ulock_cnt = 2;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = locks;
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* First lock should be unlocked. */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test3: Request 2 locks, second will contend. What happens to the
+ * first? */
+ torture_comment(tctx, " request 2 locks, second one will contend. "
+ "Expect both to fail.\n");
+
+ /* Lock the second range */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock2;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Request both locks */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.locks = locks;
+
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* First lock should be unlocked. */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 2;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = locks;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test4: Request unlock and lock. The lock contends, is the unlock
+ * then re-locked? */
+ torture_comment(tctx, " request unlock and lock, second one will "
+ "contend. Expect the unlock to succeed.\n");
+
+ /* Lock both ranges */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.locks = locks;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Attempt to unlock the first range and lock the second */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = locks;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* The first lock should've been unlocked */
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 2;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = locks;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum1);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * torture_locktest5 covers stacking pretty well, but its missing two tests:
+ * - stacking an exclusive on top of shared fails
+ * - stacking two exclusives fail
+ */
+static bool test_stacking(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum1;
+ const char *fname = BASEDIR "\\stacking.txt";
+ struct smb_lock_entry lock1;
+
+ torture_comment(tctx, "Testing stacking:\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /* Setup initial parameters */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.timeout = 0;
+
+ lock1.pid = cli->session->pid;
+ lock1.offset = 0;
+ lock1.count = 10;
+
+ /**
+ * Try to take a shared lock, then stack an exclusive.
+ */
+ torture_comment(tctx, " stacking an exclusive on top of a shared lock fails.\n");
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
+ NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /**
+ * Prove that two exclusive locks do not stack.
+ */
+ torture_comment(tctx, " two exclusive locks do not stack.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS_OR(status, NT_STATUS_LOCK_NOT_GRANTED,
+ NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /* cleanup */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum1);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test how 0-byte read requests contend with byte range locks
+ */
+static bool test_zerobyteread(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ union smb_read rd;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum1, fnum2;
+ const char *fname = BASEDIR "\\zerobyteread.txt";
+ struct smb_lock_entry lock1;
+ uint8_t c = 1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /* Setup initial parameters */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.timeout = 0;
+
+ lock1.pid = cli->session->pid;
+ lock1.offset = 0;
+ lock1.count = 10;
+
+ ZERO_STRUCT(rd);
+ rd.readx.level = RAW_READ_READX;
+
+ torture_comment(tctx, "Testing zero byte read on lock range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(tctx, " taking exclusive lock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read */
+ torture_comment(tctx, " reading 0 bytes.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 5;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing zero byte read on zero byte lock "
+ "range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(tctx, " taking exclusive 0-byte lock.\n");
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ lock1.offset = 5;
+ lock1.count = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read before the lock */
+ torture_comment(tctx, " reading 0 bytes before the lock.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 4;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read on the lock */
+ torture_comment(tctx, " reading 0 bytes on the lock.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 5;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read after the lock */
+ torture_comment(tctx, " reading 0 bytes after the lock.\n");
+ rd.readx.in.file.fnum = fnum2;
+ rd.readx.in.offset = 6;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = &c;
+ status = smb_raw_read(cli->tree, &rd);
+ torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.file.fnum = fnum1;
+ io.lockx.in.locks = &lock1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum1);
+ smbcli_close(cli->tree, fnum2);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+/*
+ test multi Locking&X operation
+*/
+static bool test_multilock(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\multilock_test.txt";
+ time_t t;
+ struct smbcli_request *req;
+ struct smbcli_session_options options;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX multi-lock\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ /* Create the test file. */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /*
+ * Lock regions 100->109, 120->129 as
+ * two separate write locks in one request.
+ */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 120;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Now request the same locks on a different
+ * context as blocking locks with infinite timeout.
+ */
+
+ io.lockx.in.timeout = 20000;
+ lock[0].pid = cli->session->pid+1;
+ lock[1].pid = cli->session->pid+1;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /* Unlock lock[0] */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[0];
+ lock[0].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Start the clock. */
+ t = time_mono(NULL);
+
+ /* Unlock lock[1] */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[1];
+ lock[1].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* receive the successful blocked lock requests */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Fail if this took more than 2 seconds. */
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "Blocking locks were not granted immediately (%s)\n",
+ __location__));
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test multi2 Locking&X operation
+ This test is designed to show that
+ lock precedence on the server is based
+ on the order received, not on the ability
+ to grant. For example:
+
+ A blocked lock request containing 2 locks
+ will be satisfied before a subsequent blocked
+ lock request over one of the same regions,
+ even if that region is then unlocked. E.g.
+
+ (a) lock 100->109, 120->129 (granted)
+ (b) lock 100->109, 120-129 (blocks)
+ (c) lock 100->109 (blocks)
+ (d) unlock 100->109
+
+ lock (c) will not be granted as lock (b)
+ will take precedence.
+*/
+static bool test_multilock2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\multilock2_test.txt";
+ time_t t;
+ struct smbcli_request *req;
+ struct smbcli_request *req2;
+ struct smbcli_session_options options;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &options);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 2\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ /* Create the test file. */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /*
+ * Lock regions 100->109, 120->129 as
+ * two separate write locks in one request.
+ */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 120;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Now request the same locks on a different
+ * context as blocking locks.
+ */
+
+ io.lockx.in.timeout = 20000;
+ lock[0].pid = cli->session->pid+1;
+ lock[1].pid = cli->session->pid+1;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * Request the first lock again on a separate context.
+ * Wait 2 seconds. This should time out (the previous
+ * multi-lock request should take precedence).
+ */
+
+ io.lockx.in.timeout = 2000;
+ lock[0].pid = cli->session->pid+2;
+ io.lockx.in.lock_cnt = 1;
+ req2 = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /* Unlock lock[0] */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[0];
+ lock[0].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Did the second lock complete (should time out) ? */
+ status = smbcli_request_simple_recv(req2);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+
+ /* Start the clock. */
+ t = time_mono(NULL);
+
+ /* Unlock lock[1] */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[1];
+ lock[1].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* receive the successful blocked lock requests */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Fail if this took more than 2 seconds. */
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "Blocking locks were not granted immediately (%s)\n",
+ __location__));
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test multi3 Locking&X operation
+ This test is designed to show that
+ lock precedence on the server is based
+ on the order received, not on the ability
+ to grant.
+
+ Compared to test_multilock2() (above)
+ this test demonstrates that completely
+ unrelated ranges work independently.
+
+ For example:
+
+ A blocked lock request containing 2 locks
+ will be satisfied before a subsequent blocked
+ lock request over one of the same regions,
+ even if that region is then unlocked. But
+ a lock of a different region goes through. E.g.
+
+ All locks are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
+
+ (a) lock 100->109, 120->129 (granted)
+ (b) lock 100->109, 120->129 (blocks, timeout=20s)
+ (c) lock 100->109 (blocks, timeout=2s)
+ (d) lock 110->119 (granted)
+ (e) lock 110->119 (blocks, timeout=20s)
+ (f) unlock 100->109 (a)
+ (g) lock 100->109 (not granted, blocked by (b))
+ (h) lock 100->109 (not granted, blocked by itself (b))
+ (i) lock (c) will not be granted(conflict, times out)
+ as lock (b) will take precedence.
+ (j) unlock 110-119 (d)
+ (k) lock (e) completes and is not blocked by (a) nor (b)
+ (l) lock 100->109 (not granted(conflict), blocked by (b))
+ (m) lock 100->109 (not granted(conflict), blocked by itself (b))
+ (n) unlock 120-129 (a)
+ (o) lock (b) completes
+*/
+static bool test_multilock3(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ union smb_lock io3;
+ struct smb_lock_entry lock3[1];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\multilock3_test.txt";
+ time_t t;
+ struct smbcli_request *req = NULL;
+ struct smbcli_request *req2 = NULL;
+ struct smbcli_request *req4 = NULL;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 3\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ /* Create the test file. */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /*
+ * a)
+ * Lock regions 100->109, 120->129 as
+ * two separate write locks in one request.
+ */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 120;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * b)
+ * Now request the same locks on a different
+ * context as blocking locks.
+ */
+ io.lockx.in.timeout = 20000;
+ lock[0].pid = cli->session->pid+1;
+ lock[1].pid = cli->session->pid+1;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * c)
+ * Request the first lock again on a separate context.
+ * Wait 2 seconds. This should time out (the previous
+ * multi-lock request should take precedence).
+ */
+ io.lockx.in.timeout = 2000;
+ lock[0].pid = cli->session->pid+2;
+ io.lockx.in.lock_cnt = 1;
+ req2 = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * d)
+ * Lock regions 110->119
+ */
+ io3.lockx.level = RAW_LOCK_LOCKX;
+ io3.lockx.in.file.fnum = fnum;
+ io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 0;
+ io3.lockx.in.lock_cnt = 1;
+ io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock3[0].pid = cli->session->pid+3;
+ lock3[0].offset = 110;
+ lock3[0].count = 10;
+ io3.lockx.in.locks = &lock3[0];
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * e)
+ * try 110-119 again
+ */
+ io3.lockx.in.timeout = 20000;
+ lock3[0].pid = cli->session->pid+4;
+ req4 = smb_raw_lock_send(cli->tree, &io3);
+ torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * f)
+ * Unlock (a) lock[0] 100-109
+ */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[0];
+ lock[0].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * g)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+5;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /*
+ * h)
+ * try to lock lock[0] 100-109 again with
+ * the pid that's still waiting
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
+ "req2 should still wait");
+
+ /*
+ * i)
+ * Did the second lock complete (should time out) ?
+ */
+ status = smbcli_request_simple_recv(req2);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+ torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
+ "req4 should still wait");
+
+ /*
+ * j)
+ * Unlock (d) lock[0] 110-119
+ */
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 1;
+ io3.lockx.in.lock_cnt = 0;
+ lock3[0].pid = cli->session->pid+3;
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * k)
+ * receive the successful blocked lock request (e)
+ * on 110-119 while the 100-109/120-129 is still waiting.
+ */
+ status = smbcli_request_simple_recv(req4);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * l)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+6;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+
+ /*
+ * m)
+ * try to lock lock[0] 100-109 again with
+ * the pid that's still waiting
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+
+ /* Start the clock. */
+ t = time_mono(NULL);
+
+ /*
+ * n)
+ * Unlock lock[1] 120-129 */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[1];
+ lock[1].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * o)
+ * receive the successful blocked lock request (b)
+ */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Fail if this took more than 2 seconds. */
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "Blocking locks were not granted immediately (%s)\n",
+ __location__));
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test multi4 Locking&X operation
+ This test is designed to show that
+ lock precedence on the server is based
+ on the order received, not on the ability
+ to grant.
+
+ Compared to test_multilock3() (above)
+ this test demonstrates that pending read-only/shared
+ locks doesn't block shared locks others.
+
+ The outstanding requests build an implicit
+ database that's checked before checking
+ the already granted locks in the real database.
+
+ For example:
+
+ A blocked read-lock request containing 2 locks
+ will be still be blocked, while one region
+ is still write-locked. While it doesn't block
+ other read-lock requests for the other region. E.g.
+
+ (a) lock(rw) 100->109, 120->129 (granted)
+ (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s)
+ (c) lock(ro) 100->109 (blocks, timeout=MAX)
+ (d) lock(rw) 110->119 (granted)
+ (e) lock(rw) 110->119 (blocks, timeout=20s)
+ (f) unlock 100->109 (a)
+ (g) lock(ro) (c) completes and is not blocked by (a) nor (b)
+ (h) lock(rw) 100->109 (not granted, blocked by (c))
+ (i) lock(rw) 100->109 (pid (b)) (not granted(conflict), blocked by (c))
+ (j) unlock 110-119
+ (k) lock (e) completes and is not blocked by (a) nor (b)
+ (l) lock 100->109 (not granted(conflict), blocked by (b))
+ (m) lock 100->109 (pid (b)) (not granted(conflict), blocked by itself (b))
+ (n) unlock 120-129 (a)
+ (o) lock (b) completes
+*/
+static bool test_multilock4(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ union smb_lock io3;
+ struct smb_lock_entry lock3[1];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\multilock4_test.txt";
+ time_t t;
+ struct smbcli_request *req = NULL;
+ struct smbcli_request *req2 = NULL;
+ struct smbcli_request *req4 = NULL;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 4\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ /* Create the test file. */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /*
+ * a)
+ * Lock regions 100->109, 120->129 as
+ * two separate write locks in one request.
+ */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 120;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * b)
+ * Now request the same locks on a different
+ * context as blocking locks. But readonly.
+ */
+ io.lockx.in.timeout = 20000;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ lock[0].pid = cli->session->pid+1;
+ lock[1].pid = cli->session->pid+1;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * c)
+ * Request the first lock again on a separate context.
+ * Wait forever. The previous multi-lock request (b)
+ * should take precedence. Also readonly.
+ */
+ io.lockx.in.timeout = UINT32_MAX;
+ lock[0].pid = cli->session->pid+2;
+ io.lockx.in.lock_cnt = 1;
+ req2 = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * d)
+ * Lock regions 110->119
+ */
+ io3.lockx.level = RAW_LOCK_LOCKX;
+ io3.lockx.in.file.fnum = fnum;
+ io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 0;
+ io3.lockx.in.lock_cnt = 1;
+ io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock3[0].pid = cli->session->pid+3;
+ lock3[0].offset = 110;
+ lock3[0].count = 10;
+ io3.lockx.in.locks = &lock3[0];
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * e)
+ * try 110-119 again
+ */
+ io3.lockx.in.timeout = 20000;
+ lock3[0].pid = cli->session->pid+4;
+ req4 = smb_raw_lock_send(cli->tree, &io3);
+ torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * f)
+ * Unlock (a) lock[0] 100-109
+ */
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[0];
+ lock[0].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * g)
+ * receive the successful blocked lock request (c)
+ * on 110-119 while (b) 100-109/120-129 is still waiting.
+ */
+ status = smbcli_request_simple_recv(req2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * h)
+ * try to lock lock[0] 100-109 again
+ * (read/write)
+ */
+ lock[0].pid = cli->session->pid+5;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /*
+ * i)
+ * try to lock lock[0] 100-109 again with the pid (b)
+ * that's still waiting.
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+ torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
+ "req4 should still wait");
+
+ /*
+ * j)
+ * Unlock (d) lock[0] 110-119
+ */
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 1;
+ io3.lockx.in.lock_cnt = 0;
+ lock3[0].pid = cli->session->pid+3;
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * k)
+ * receive the successful blocked
+ * lock request (e) on 110-119.
+ */
+ status = smbcli_request_simple_recv(req4);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * l)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+6;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /*
+ * m)
+ * try to lock lock[0] 100-109 again with the pid (b)
+ * that's still waiting
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+
+ /* Start the clock. */
+ t = time_mono(NULL);
+
+ /*
+ * n)
+ * Unlock (a) lock[1] 120-129
+ */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[1];
+ lock[1].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * o)
+ * receive the successful blocked lock request (b)
+ */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Fail if this took more than 2 seconds. */
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "Blocking locks were not granted immediately (%s)\n",
+ __location__));
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test multi5 Locking&X operation
+ This test is designed to show that
+ lock precedence on the server is based
+ on the order received, not on the ability
+ to grant.
+
+ Compared to test_multilock3() (above)
+ this test demonstrates that the initial
+ lock request that block the following
+ exclusive locks can be a shared lock.
+
+ For example:
+
+ All locks except (a) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
+
+ (a) lock(ro) 100->109, 120->129 (granted)
+ (b) lock 100->109, 120->129 (blocks, timeout=20s)
+ (c) lock 100->109 (blocks, timeout=2s)
+ (d) lock 110->119 (granted)
+ (e) lock 110->119 (blocks, timeout=20s)
+ (f) unlock 100->109 (a)
+ (g) lock 100->109 (not granted, blocked by (b))
+ (h) lock 100->109 (not granted, blocked by itself (b))
+ (i) lock (c) will not be granted(conflict, times out)
+ as lock (b) will take precedence.
+ (j) unlock 110-119 (d)
+ (k) lock (e) completes and is not blocked by (a) nor (b)
+ (l) lock 100->109 (not granted(conflict), blocked by (b))
+ (m) lock 100->109 (not granted(conflict), blocked by itself (b))
+ (n) unlock 120-129 (a)
+ (o) lock (b) completes
+*/
+static bool test_multilock5(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ union smb_lock io3;
+ struct smb_lock_entry lock3[1];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\multilock5_test.txt";
+ time_t t;
+ struct smbcli_request *req = NULL;
+ struct smbcli_request *req2 = NULL;
+ struct smbcli_request *req4 = NULL;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 5\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ /* Create the test file. */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /*
+ * a)
+ * Lock regions 100->109, 120->129 as
+ * two separate write locks in one request.
+ * (read only)
+ */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 120;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * b)
+ * Now request the same locks on a different
+ * context as blocking locks.
+ * (read write)
+ */
+ io.lockx.in.timeout = 20000;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid+1;
+ lock[1].pid = cli->session->pid+1;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * c)
+ * Request the first lock again on a separate context.
+ * Wait 2 seconds. This should time out (the previous
+ * multi-lock request should take precedence).
+ * (read write)
+ */
+ io.lockx.in.timeout = 2000;
+ lock[0].pid = cli->session->pid+2;
+ io.lockx.in.lock_cnt = 1;
+ req2 = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * d)
+ * Lock regions 110->119
+ */
+ io3.lockx.level = RAW_LOCK_LOCKX;
+ io3.lockx.in.file.fnum = fnum;
+ io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 0;
+ io3.lockx.in.lock_cnt = 1;
+ io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock3[0].pid = cli->session->pid+3;
+ lock3[0].offset = 110;
+ lock3[0].count = 10;
+ io3.lockx.in.locks = &lock3[0];
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * e)
+ * try 110-119 again
+ */
+ io3.lockx.in.timeout = 20000;
+ lock3[0].pid = cli->session->pid+4;
+ req4 = smb_raw_lock_send(cli->tree, &io3);
+ torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * f)
+ * Unlock (a) lock[0] 100-109
+ *
+ * Note we send LOCKING_ANDX_EXCLUSIVE_LOCK
+ * while the lock used LOCKING_ANDX_SHARED_LOCK
+ * to check if that also works.
+ */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[0];
+ lock[0].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * g)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+5;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /*
+ * h)
+ * try to lock lock[0] 100-109 again with the pid (b)
+ * that's still waiting.
+ * (read write)
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
+ "req2 should still wait");
+
+ /*
+ * i)
+ * Did the second lock complete (should time out) ?
+ */
+ status = smbcli_request_simple_recv(req2);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+ torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
+ "req4 should still wait");
+
+ /*
+ * j)
+ * Unlock (d) lock[0] 110-119
+ */
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 1;
+ io3.lockx.in.lock_cnt = 0;
+ lock3[0].pid = cli->session->pid+3;
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * k)
+ * receive the successful blocked lock requests
+ * on 110-119 while the 100-109/120-129 is still waiting.
+ */
+ status = smbcli_request_simple_recv(req4);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * l)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+6;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /*
+ * m)
+ * try to lock lock[0] 100-109 again with the pid (b)
+ * that's still waiting
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+
+ /* Start the clock. */
+ t = time_mono(NULL);
+
+ /*
+ * n)
+ * Unlock (a) lock[1] 120-129
+ */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[1];
+ lock[1].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * o)
+ * receive the successful blocked lock request (b)
+ */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Fail if this took more than 2 seconds. */
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "Blocking locks were not granted immediately (%s)\n",
+ __location__));
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test multi6 Locking&X operation
+ This test is designed to show that
+ lock precedence on the server is based
+ on the order received, not on the ability
+ to grant.
+
+ Compared to test_multilock4() (above)
+ this test demonstrates the behavior if
+ only just the first blocking lock
+ being a shared lock.
+
+ For example:
+
+ All locks except (b) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw).
+
+ (a) lock 100->109, 120->129 (granted)
+ (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s)
+ (c) lock 100->109 (blocks, timeout=2s)
+ (d) lock 110->119 (granted)
+ (e) lock 110->119 (blocks, timeout=20s)
+ (f) unlock 100->109 (a)
+ (g) lock 100->109 (not granted, blocked by (b))
+ (h) lock 100->109 (not granted, blocked by itself (b))
+ (i) lock (c) will not be granted(conflict, times out)
+ as lock (b) will take precedence.
+ (j) unlock 110-119 (d)
+ (k) lock (e) completes and is not blocked by (a) nor (b)
+ (l) lock 100->109 (not granted(conflict), blocked by (b))
+ (m) lock 100->109 (not granted(conflict), blocked by itself (b))
+ (n) unlock 120-129 (a)
+ (o) lock (b) completes
+*/
+static bool test_multilock6(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock[2];
+ union smb_lock io3;
+ struct smb_lock_entry lock3[1];
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ const char *fname = BASEDIR "\\multilock6_test.txt";
+ time_t t;
+ struct smbcli_request *req = NULL;
+ struct smbcli_request *req2 = NULL;
+ struct smbcli_request *req4 = NULL;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 6\n");
+ io.generic.level = RAW_LOCK_LOCKX;
+
+ /* Create the test file. */
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree)));
+
+ /*
+ * a)
+ * Lock regions 100->109, 120->129 as
+ * two separate write locks in one request.
+ */
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 2;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 100;
+ lock[0].count = 10;
+ lock[1].pid = cli->session->pid;
+ lock[1].offset = 120;
+ lock[1].count = 10;
+ io.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * b)
+ * Now request the same locks on a different
+ * context as blocking locks.
+ * (read only)
+ */
+ io.lockx.in.timeout = 20000;
+ io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
+ lock[0].pid = cli->session->pid+1;
+ lock[1].pid = cli->session->pid+1;
+ req = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * c)
+ * Request the first lock again on a separate context.
+ * Wait 2 seconds. This should time out (the previous
+ * multi-lock request should take precedence).
+ */
+ io.lockx.in.timeout = 2000;
+ io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock[0].pid = cli->session->pid+2;
+ io.lockx.in.lock_cnt = 1;
+ req2 = smb_raw_lock_send(cli->tree, &io);
+ torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * d)
+ * Lock regions 110->119
+ */
+ io3.lockx.level = RAW_LOCK_LOCKX;
+ io3.lockx.in.file.fnum = fnum;
+ io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 0;
+ io3.lockx.in.lock_cnt = 1;
+ io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK;
+ lock3[0].pid = cli->session->pid+3;
+ lock3[0].offset = 110;
+ lock3[0].count = 10;
+ io3.lockx.in.locks = &lock3[0];
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * e)
+ * try 110-119 again
+ */
+ io3.lockx.in.timeout = 20000;
+ lock3[0].pid = cli->session->pid+4;
+ req4 = smb_raw_lock_send(cli->tree, &io3);
+ torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx,
+ "Failed to setup timed locks (%s)\n", __location__));
+
+ /*
+ * f)
+ * Unlock (a) lock[0] 100-109
+ */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[0];
+ lock[0].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * g)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+5;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /*
+ * h)
+ * try to lock lock[0] 100-109 again with the pid (b)
+ * that's still waiting
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV,
+ "req2 should still wait");
+
+ /*
+ * i)
+ * Did the second lock (c) complete (should time out) ?
+ */
+ status = smbcli_request_simple_recv(req2);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+ torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV,
+ "req4 should still wait");
+
+ /*
+ * j)
+ * Unlock (d) lock[0] 110-119
+ */
+ io3.lockx.in.timeout = 0;
+ io3.lockx.in.ulock_cnt = 1;
+ io3.lockx.in.lock_cnt = 0;
+ lock3[0].pid = cli->session->pid+3;
+ status = smb_raw_lock(cli->tree, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * k)
+ * receive the successful blocked lock request (e)
+ * on 110-119 while (b) 100-109/120-129 is still waiting.
+ */
+ status = smbcli_request_simple_recv(req4);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * l)
+ * try to lock lock[0] 100-109 again
+ */
+ lock[0].pid = cli->session->pid+6;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ /*
+ * m)
+ * try to lock lock[0] 100-109 again with the pid (b)
+ * that's still waiting
+ */
+ lock[0].pid = cli->session->pid+1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV,
+ "req should still wait");
+
+ /* Start the clock. */
+ t = time_mono(NULL);
+
+ /*
+ * n)
+ * Unlock (a) lock[1] 120-129
+ */
+ io.lockx.in.timeout = 0;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.locks = &lock[1];
+ lock[1].pid = cli->session->pid;
+ status = smb_raw_lock(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * o)
+ * receive the successful blocked lock request (b)
+ */
+ status = smbcli_request_simple_recv(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Fail if this took more than 2 seconds. */
+ torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx,
+ "Blocking locks were not granted immediately (%s)\n",
+ __location__));
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of lock calls
+*/
+struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "lock");
+
+ torture_suite_add_1smb_test(suite, "lockx", test_lockx);
+ torture_suite_add_1smb_test(suite, "lock", test_lock);
+ torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
+ torture_suite_add_1smb_test(suite, "async", test_async);
+ torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
+ torture_suite_add_1smb_test(suite, "changetype", test_changetype);
+
+ torture_suite_add_1smb_test(suite, "stacking", test_stacking);
+ torture_suite_add_1smb_test(suite, "unlock", test_unlock);
+ torture_suite_add_1smb_test(suite, "multiple_unlock",
+ test_multiple_unlock);
+ torture_suite_add_1smb_test(suite, "zerobytelocks", test_zerobytelocks);
+ torture_suite_add_1smb_test(suite, "zerobyteread", test_zerobyteread);
+ torture_suite_add_1smb_test(suite, "multilock", test_multilock);
+ torture_suite_add_1smb_test(suite, "multilock2", test_multilock2);
+ torture_suite_add_1smb_test(suite, "multilock3", test_multilock3);
+ torture_suite_add_1smb_test(suite, "multilock4", test_multilock4);
+ torture_suite_add_1smb_test(suite, "multilock5", test_multilock5);
+ torture_suite_add_1smb_test(suite, "multilock6", test_multilock6);
+
+ return suite;
+}
diff --git a/source4/torture/raw/lockbench.c b/source4/torture/raw/lockbench.c
new file mode 100644
index 0000000..f122976
--- /dev/null
+++ b/source4/torture/raw/lockbench.c
@@ -0,0 +1,447 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ locking benchmark
+
+ Copyright (C) Andrew Tridgell 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/events/events.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "torture/raw/proto.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "../lib/util/util_net.h"
+
+#define BASEDIR "\\benchlock"
+#define FNAME BASEDIR "\\lock.dat"
+
+static int nprocs;
+static int lock_failed;
+static int num_connected;
+
+enum lock_stage {LOCK_INITIAL, LOCK_LOCK, LOCK_UNLOCK};
+
+struct benchlock_state {
+ struct torture_context *tctx;
+ struct tevent_context *ev;
+ struct smbcli_tree *tree;
+ TALLOC_CTX *mem_ctx;
+ int client_num;
+ int fnum;
+ enum lock_stage stage;
+ int lock_offset;
+ int unlock_offset;
+ int count;
+ int lastcount;
+ struct smbcli_request *req;
+ struct smb_composite_connect reconnect;
+ struct tevent_timer *te;
+
+ /* these are used for reconnections */
+ const char **dest_ports;
+ const char *dest_host;
+ const char *called_name;
+ const char *service_type;
+};
+
+static void lock_completion(struct smbcli_request *);
+
+/*
+ send the next lock request
+*/
+static void lock_send(struct benchlock_state *state)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock;
+
+ switch (state->stage) {
+ case LOCK_INITIAL:
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ state->lock_offset = 0;
+ state->unlock_offset = 0;
+ lock.offset = state->lock_offset;
+ break;
+ case LOCK_LOCK:
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ state->lock_offset = (state->lock_offset+1)%(nprocs+1);
+ lock.offset = state->lock_offset;
+ break;
+ case LOCK_UNLOCK:
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ lock.offset = state->unlock_offset;
+ state->unlock_offset = (state->unlock_offset+1)%(nprocs+1);
+ break;
+ }
+
+ lock.count = 1;
+ lock.pid = state->tree->session->pid;
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 100000;
+ io.lockx.in.locks = &lock;
+ io.lockx.in.file.fnum = state->fnum;
+
+ state->req = smb_raw_lock_send(state->tree, &io);
+ if (state->req == NULL) {
+ DEBUG(0,("Failed to setup lock\n"));
+ lock_failed++;
+ }
+ state->req->async.private_data = state;
+ state->req->async.fn = lock_completion;
+}
+
+static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data);
+
+
+static void reopen_file(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct benchlock_state *state = (struct benchlock_state *)private_data;
+
+ /* reestablish our open file */
+ state->fnum = smbcli_open(state->tree, FNAME, O_RDWR|O_CREAT, DENY_NONE);
+ if (state->fnum == -1) {
+ printf("Failed to open %s on connection %d\n", FNAME, state->client_num);
+ exit(1);
+ }
+
+ num_connected++;
+
+ DEBUG(0,("reconnect to %s finished (%u connected)\n", state->dest_host,
+ num_connected));
+
+ state->stage = LOCK_INITIAL;
+ lock_send(state);
+}
+
+/*
+ complete an async reconnect
+ */
+static void reopen_connection_complete(struct composite_context *ctx)
+{
+ struct benchlock_state *state = (struct benchlock_state *)ctx->async.private_data;
+ NTSTATUS status;
+ struct smb_composite_connect *io = &state->reconnect;
+
+ status = smb_composite_connect_recv(ctx, state->mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ return;
+ }
+
+ talloc_free(state->tree);
+ state->tree = io->out.tree;
+
+ /* do the reopen as a separate event */
+ tevent_add_timer(state->ev, state->mem_ctx, timeval_zero(), reopen_file, state);
+}
+
+
+
+/*
+ reopen a connection
+ */
+static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct benchlock_state *state = (struct benchlock_state *)private_data;
+ struct composite_context *ctx;
+ struct smb_composite_connect *io = &state->reconnect;
+ char *host, *share;
+
+ state->te = NULL;
+
+ if (!torture_get_conn_index(state->client_num, state->mem_ctx, state->tctx, &host, &share)) {
+ DEBUG(0,("Can't find host/share for reconnect?!\n"));
+ exit(1);
+ }
+
+ io->in.dest_host = state->dest_host;
+ io->in.dest_ports = state->dest_ports;
+ io->in.gensec_settings = lpcfg_gensec_settings(state->mem_ctx, state->tctx->lp_ctx);
+ io->in.socket_options = lpcfg_socket_options(state->tctx->lp_ctx);
+ io->in.called_name = state->called_name;
+ io->in.service = share;
+ io->in.service_type = state->service_type;
+ io->in.credentials = samba_cmdline_get_creds();
+ io->in.fallback_to_anonymous = false;
+ io->in.workgroup = lpcfg_workgroup(state->tctx->lp_ctx);
+ lpcfg_smbcli_options(state->tctx->lp_ctx, &io->in.options);
+ lpcfg_smbcli_session_options(state->tctx->lp_ctx, &io->in.session_options);
+
+ /* kill off the remnants of the old connection */
+ talloc_free(state->tree);
+ state->tree = NULL;
+
+ ctx = smb_composite_connect_send(io, state->mem_ctx,
+ lpcfg_resolve_context(state->tctx->lp_ctx),
+ state->ev);
+ if (ctx == NULL) {
+ DEBUG(0,("Failed to setup async reconnect\n"));
+ exit(1);
+ }
+
+ ctx->async.fn = reopen_connection_complete;
+ ctx->async.private_data = state;
+}
+
+
+/*
+ called when a lock completes
+*/
+static void lock_completion(struct smbcli_request *req)
+{
+ struct benchlock_state *state = (struct benchlock_state *)req->async.private_data;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+ state->req = NULL;
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("reopening connection to %s\n", state->dest_host));
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ } else {
+ DEBUG(0,("Lock failed - %s\n", nt_errstr(status)));
+ lock_failed++;
+ }
+ return;
+ }
+
+ switch (state->stage) {
+ case LOCK_INITIAL:
+ state->stage = LOCK_LOCK;
+ break;
+ case LOCK_LOCK:
+ state->stage = LOCK_UNLOCK;
+ break;
+ case LOCK_UNLOCK:
+ state->stage = LOCK_LOCK;
+ break;
+ }
+
+ state->count++;
+ lock_send(state);
+}
+
+
+static void echo_completion(struct smbcli_request *req)
+{
+ struct benchlock_state *state = (struct benchlock_state *)req->async.private_data;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("reopening connection to %s\n", state->dest_host));
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ }
+}
+
+static void report_rate(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct benchlock_state *state = talloc_get_type(private_data,
+ struct benchlock_state);
+ int i;
+ for (i=0;i<nprocs;i++) {
+ printf("%5u ", (unsigned)(state[i].count - state[i].lastcount));
+ state[i].lastcount = state[i].count;
+ }
+ printf("\r");
+ fflush(stdout);
+ tevent_add_timer(ev, state, timeval_current_ofs(1, 0), report_rate, state);
+
+ /* send an echo on each interface to ensure it stays alive - this helps
+ with IP takeover */
+ for (i=0;i<nprocs;i++) {
+ struct smb_echo p;
+ struct smbcli_request *req;
+
+ if (!state[i].tree) {
+ continue;
+ }
+
+ p.in.repeat_count = 1;
+ p.in.size = 0;
+ p.in.data = NULL;
+ req = smb_raw_echo_send(state[i].tree->session->transport, &p);
+ req->async.private_data = &state[i];
+ req->async.fn = echo_completion;
+ }
+}
+
+/*
+ benchmark locking calls
+*/
+bool torture_bench_lock(struct torture_context *torture)
+{
+ bool ret = true;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ int i, j;
+ int timelimit = torture_setting_int(torture, "timelimit", 10);
+ struct timeval tv;
+ struct benchlock_state *state;
+ int total = 0, minops=0;
+ struct smbcli_state *cli;
+ bool progress;
+ off_t offset;
+ int initial_locks = torture_setting_int(torture, "initial_locks", 0);
+
+ progress = torture_setting_bool(torture, "progress", true);
+
+ nprocs = torture_setting_int(torture, "nprocs", 4);
+
+ state = talloc_zero_array(mem_ctx, struct benchlock_state, nprocs);
+
+ printf("Opening %d connections\n", nprocs);
+ for (i=0;i<nprocs;i++) {
+ const struct sockaddr_storage *dest_ss;
+ char addrstr[INET6_ADDRSTRLEN];
+ const char *dest_str;
+ uint16_t dest_port;
+
+ state[i].tctx = torture;
+ state[i].mem_ctx = talloc_new(state);
+ state[i].client_num = i;
+ state[i].ev = torture->ev;
+ if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) {
+ return false;
+ }
+ talloc_steal(state[i].mem_ctx, cli);
+ state[i].tree = cli->tree;
+
+ dest_ss = smbXcli_conn_remote_sockaddr(
+ state[i].tree->session->transport->conn);
+ dest_str = print_sockaddr(addrstr, sizeof(addrstr), dest_ss);
+ dest_port = get_sockaddr_port(dest_ss);
+
+ state[i].dest_host = talloc_strdup(state[i].mem_ctx, dest_str);
+ state[i].dest_ports = talloc_array(state[i].mem_ctx,
+ const char *, 2);
+ state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports,
+ "%u", dest_port);
+ state[i].dest_ports[1] = NULL;
+ state[i].called_name = talloc_strdup(state[i].mem_ctx,
+ smbXcli_conn_remote_name(cli->tree->session->transport->conn));
+ state[i].service_type = talloc_strdup(state[i].mem_ctx, "?????");
+ }
+
+ num_connected = i;
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ goto failed;
+ }
+
+ for (i=0;i<nprocs;i++) {
+ state[i].fnum = smbcli_open(state[i].tree,
+ FNAME,
+ O_RDWR|O_CREAT, DENY_NONE);
+ if (state[i].fnum == -1) {
+ printf("Failed to open %s on connection %d\n", FNAME, i);
+ goto failed;
+ }
+
+ /* Optionally, lock initial_locks for each proc beforehand. */
+ if (i == 0 && initial_locks > 0) {
+ printf("Initializing %d locks on each proc.\n",
+ initial_locks);
+ }
+
+ for (j = 0; j < initial_locks; j++) {
+ offset = (0xFFFFFED8LLU * (i+2)) + j;
+ if (!NT_STATUS_IS_OK(smbcli_lock64(state[i].tree,
+ state[i].fnum, offset, 1, 0, WRITE_LOCK))) {
+ printf("Failed initializing, lock=%d\n", j);
+ goto failed;
+ }
+ }
+
+ state[i].stage = LOCK_INITIAL;
+ lock_send(&state[i]);
+ }
+
+ tv = timeval_current();
+
+ if (progress) {
+ tevent_add_timer(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state);
+ }
+
+ printf("Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ tevent_loop_once(torture->ev);
+
+ if (lock_failed) {
+ DEBUG(0,("locking failed\n"));
+ goto failed;
+ }
+ }
+
+ printf("%.2f ops/second\n", total/timeval_elapsed(&tv));
+ minops = state[0].count;
+ for (i=0;i<nprocs;i++) {
+ printf("[%d] %u ops\n", i, state[i].count);
+ if (state[i].count < minops) minops = state[i].count;
+ }
+ if (minops < 0.5*total/nprocs) {
+ printf("Failed: unbalanced locking\n");
+ goto failed;
+ }
+
+ for (i=0;i<nprocs;i++) {
+ talloc_free(state[i].req);
+ smb_raw_exit(state[i].tree->session);
+ }
+
+ smbcli_deltree(state[0].tree, BASEDIR);
+ talloc_free(mem_ctx);
+ printf("\n");
+ return ret;
+
+failed:
+ smbcli_deltree(state[0].tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return false;
+}
diff --git a/source4/torture/raw/lookuprate.c b/source4/torture/raw/lookuprate.c
new file mode 100644
index 0000000..4243e35
--- /dev/null
+++ b/source4/torture/raw/lookuprate.c
@@ -0,0 +1,318 @@
+/*
+ File lookup rate test.
+
+ Copyright (C) James Peach 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "torture/smbtorture.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\lookuprate"
+#define MISSINGNAME BASEDIR "\\foo"
+
+#define FUZZ_PERCENT 10
+
+#define usec_to_sec(s) ((s) / 1000000)
+#define sec_to_usec(s) ((s) * 1000000)
+
+struct rate_record
+{
+ unsigned dirent_count;
+ unsigned querypath_persec;
+ unsigned findfirst_persec;
+};
+
+static struct rate_record records[] =
+{
+ { 0, 0, 0 }, /* Base (optimal) lookup rate. */
+ { 100, 0, 0},
+ { 1000, 0, 0},
+ { 10000, 0, 0},
+ { 100000, 0, 0}
+};
+
+typedef NTSTATUS lookup_function(struct smbcli_tree *tree, const char * path);
+
+/* Test whether rhs is within fuzz% of lhs. */
+static bool fuzzily_equal(unsigned lhs, unsigned rhs, int percent)
+{
+ double fuzz = (double)lhs * (double)percent/100.0;
+
+ if (((double)rhs >= ((double)lhs - fuzz)) &&
+ ((double)rhs <= ((double)lhs + fuzz))) {
+ return true;
+ }
+
+ return false;
+
+}
+
+static NTSTATUS fill_directory(struct smbcli_tree *tree,
+ const char * path, unsigned count)
+{
+ NTSTATUS status;
+ char *fname = NULL;
+ unsigned i;
+ unsigned current;
+
+ struct timeval start;
+ struct timeval now;
+
+ status = smbcli_mkdir(tree, path);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ printf("filling directory %s with %u files... ", path, count);
+ fflush(stdout);
+
+ current = random();
+ start = timeval_current();
+
+ for (i = 0; i < count; ++i) {
+ int fnum;
+
+ ++current;
+ fname = talloc_asprintf(NULL, "%s\\fill%u",
+ path, current);
+
+ fnum = smbcli_open(tree, fname, O_RDONLY|O_CREAT,
+ DENY_NONE);
+ if (fnum < 0) {
+ talloc_free(fname);
+ return smbcli_nt_error(tree);
+ }
+
+ smbcli_close(tree, fnum);
+ talloc_free(fname);
+ }
+
+ if (count) {
+ double rate;
+ now = timeval_current();
+ rate = (double)count / usec_to_sec((double)usec_time_diff(&now, &start));
+ printf("%u/sec\n", (unsigned)rate);
+ } else {
+ printf("done\n");
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS squash_lookup_error(NTSTATUS status)
+{
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ /* We don't care if the file isn't there. */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+ return NT_STATUS_OK;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ return NT_STATUS_OK;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) {
+ return NT_STATUS_OK;
+ }
+
+ return status;
+}
+
+/* Look up a pathname using TRANS2_QUERY_PATH_INFORMATION. */
+static NTSTATUS querypath_lookup(struct smbcli_tree *tree, const char * path)
+{
+ NTSTATUS status;
+ time_t ftimes[3];
+ size_t fsize;
+ uint16_t fmode;
+
+ status = smbcli_qpathinfo(tree, path, &ftimes[0], &ftimes[1], &ftimes[2],
+ &fsize, &fmode);
+
+ return squash_lookup_error(status);
+}
+
+/* Look up a pathname using TRANS2_FIND_FIRST2. */
+static NTSTATUS findfirst_lookup(struct smbcli_tree *tree, const char * path)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (smbcli_list(tree, path, 0, NULL, NULL) < 0) {
+ status = smbcli_nt_error(tree);
+ }
+
+ return squash_lookup_error(status);
+}
+
+static NTSTATUS lookup_rate_convert(struct smbcli_tree *tree,
+ lookup_function lookup, const char * path, unsigned * rate)
+{
+ NTSTATUS status;
+
+ struct timeval start;
+ struct timeval now;
+ unsigned count = 0;
+ int64_t elapsed = 0;
+
+#define LOOKUP_PERIOD_SEC (2)
+
+ start = timeval_current();
+ while (elapsed < sec_to_usec(LOOKUP_PERIOD_SEC)) {
+
+ status = lookup(tree, path);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ++count;
+ now = timeval_current();
+ elapsed = usec_time_diff(&now, &start);
+ }
+
+#undef LOOKUP_PERIOD_SEC
+
+ *rate = (unsigned)((double)count / (double)usec_to_sec(elapsed));
+ return NT_STATUS_OK;
+}
+
+static bool remove_working_directory(struct smbcli_tree *tree,
+ const char * path)
+{
+ int tries;
+
+ /* Using smbcli_deltree to delete a very large number of files
+ * doesn't work against all servers. Work around this by
+ * retrying.
+ */
+ for (tries = 0; tries < 5; ) {
+ int ret;
+
+ ret = smbcli_deltree(tree, BASEDIR);
+ if (ret == -1) {
+ tries++;
+ printf("(%s) failed to deltree %s: %s\n",
+ __location__, BASEDIR,
+ smbcli_errstr(tree));
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+
+}
+
+/* Verify that looking up a file name takes constant time.
+ *
+ * This test samples the lookup rate for a non-existent filename in a
+ * directory, while varying the number of files in the directory. The
+ * lookup rate should continue to approximate the lookup rate for the
+ * empty directory case.
+ */
+bool torture_bench_lookup(struct torture_context *torture)
+{
+ NTSTATUS status;
+ bool result = false;
+
+ int i;
+ struct smbcli_state *cli = NULL;
+
+ if (!torture_open_connection(&cli, torture, 0)) {
+ goto done;
+ }
+
+ remove_working_directory(cli->tree, BASEDIR);
+
+ for (i = 0; i < ARRAY_SIZE(records); ++i) {
+ printf("Testing lookup rate with %u directory entries\n",
+ records[i].dirent_count);
+
+ status = fill_directory(cli->tree, BASEDIR,
+ records[i].dirent_count);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("failed to fill directory: %s\n", nt_errstr(status));
+ goto done;
+ }
+
+ status = lookup_rate_convert(cli->tree, querypath_lookup,
+ MISSINGNAME, &records[i].querypath_persec);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("querypathinfo of %s failed: %s\n",
+ MISSINGNAME, nt_errstr(status));
+ goto done;
+ }
+
+ status = lookup_rate_convert(cli->tree, findfirst_lookup,
+ MISSINGNAME, &records[i].findfirst_persec);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("findfirst of %s failed: %s\n",
+ MISSINGNAME, nt_errstr(status));
+ goto done;
+ }
+
+ printf("entries = %u, querypath = %u/sec, findfirst = %u/sec\n",
+ records[i].dirent_count,
+ records[i].querypath_persec,
+ records[i].findfirst_persec);
+
+ if (!remove_working_directory(cli->tree, BASEDIR)) {
+ goto done;
+ }
+ }
+
+ /* Ok. We have run all our tests. Walk through the records we
+ * accumulated and figure out whether the lookups took constant
+ * time or not.
+ */
+ result = true;
+ for (i = 0; i < ARRAY_SIZE(records); ++i) {
+ if (!fuzzily_equal(records[0].querypath_persec,
+ records[i].querypath_persec,
+ FUZZ_PERCENT)) {
+ printf("querypath rate for %d entries differed by "
+ "more than %d%% from base rate\n",
+ records[i].dirent_count, FUZZ_PERCENT);
+ result = false;
+ }
+
+ if (!fuzzily_equal(records[0].findfirst_persec,
+ records[i].findfirst_persec,
+ FUZZ_PERCENT)) {
+ printf("findfirst rate for %d entries differed by "
+ "more than %d%% from base rate\n",
+ records[i].dirent_count, FUZZ_PERCENT);
+ result = false;
+ }
+ }
+
+done:
+ if (cli) {
+ remove_working_directory(cli->tree, BASEDIR);
+ talloc_free(cli);
+ }
+
+ return result;
+}
+
+/* vim: set sts=8 sw=8 : */
diff --git a/source4/torture/raw/missing.txt b/source4/torture/raw/missing.txt
new file mode 100644
index 0000000..0f4104b
--- /dev/null
+++ b/source4/torture/raw/missing.txt
@@ -0,0 +1,160 @@
+- RAW-CONTEXT passes on nt4 but TCON doesn't !!??
+
+- all messaging commands
+
+- writebraw
+
+- writebmpx
+
+- acl ops
+
+- readbmpx
+
+- rap commands
+
+- rpc commands
+
+- SMBcopy
+
+- SMBtcon
+
+- SMBecho
+
+- SMBfunique
+
+- SMBsearch vs SMBffirst?
+
+- SMBfclose
+
+- SMBkeepalive
+
+- secondary trans2 and nttrans
+
+- trans2 ioctl
+
+- trans2 session setup
+
+- trans2 DFS ops
+
+- unix ops
+
+--------------
+done:
+
+mkdir
+rmdir
+open
+create
+close
+flush
+unlink
+mv
+getatr
+setatr
+read
+write
+lock
+unlock
+ctemp
+mknew
+chkpath
+exit
+lseek
+tconX
+tdis
+negprot
+dskattr
+search
+lockread
+writeunlock
+readbraw
+setattrE
+getattrE
+lockingX
+ioctl
+openX
+readX
+writeX
+sesssetupX
+trans2
+findclose
+ulogoffX
+nttrans
+ntcreateX
+ntcancel
+trans2_open
+trans2_findfirst
+trans2_findnext?
+trans2_qfsinfo
+trans2_setfsinfo
+trans2_qpathinfo
+trans2_setpathinfo
+trans2_qfileinfo
+trans2_setfileinfo
+trans2_fsctl
+trans2_mkdir
+trans2_findnext
+NTrename
+SMB_QFS_ALLOCATION
+SMB_QFS_VOLUME
+SMB_QFS_VOLUME_INFO
+SMB_QFS_SIZE_INFO
+SMB_QFS_DEVICE_INFO
+SMB_QFS_ATTRIBUTE_INFO
+SMB_QFS_VOLUME_INFORMATION
+SMB_QFS_SIZE_INFORMATION
+SMB_QFS_DEVICE_INFORMATION
+SMB_QFS_ATTRIBUTE_INFORMATION
+SMB_QFS_QUOTA_INFORMATION
+SMB_QFS_FULL_SIZE_INFORMATION
+SMB_QFS_OBJECTID_INFORMATION
+SMB_QFILEINFO_STANDARD
+SMB_QFILEINFO_EA_SIZE
+SMB_QFILEINFO_ALL_EAS
+SMB_QFILEINFO_IS_NAME_VALID
+SMB_QFILEINFO_BASIC_INFO
+SMB_QFILEINFO_STANDARD_INFO
+SMB_QFILEINFO_EA_INFO
+SMB_QFILEINFO_NAME_INFO
+SMB_QFILEINFO_ALL_INFO
+SMB_QFILEINFO_ALT_NAME_INFO
+SMB_QFILEINFO_STREAM_INFO
+SMB_QFILEINFO_COMPRESSION_INFO
+SMB_QFILEINFO_BASIC_INFORMATION
+SMB_QFILEINFO_STANDARD_INFORMATION
+SMB_QFILEINFO_INTERNAL_INFORMATION
+SMB_QFILEINFO_EA_INFORMATION
+SMB_QFILEINFO_ACCESS_INFORMATION
+SMB_QFILEINFO_NAME_INFORMATION
+SMB_QFILEINFO_POSITION_INFORMATION
+SMB_QFILEINFO_MODE_INFORMATION
+SMB_QFILEINFO_ALIGNMENT_INFORMATION
+SMB_QFILEINFO_ALL_INFORMATION
+SMB_QFILEINFO_ALT_NAME_INFORMATION
+SMB_QFILEINFO_STREAM_INFORMATION
+SMB_QFILEINFO_COMPRESSION_INFORMATION
+SMB_QFILEINFO_NETWORK_OPEN_INFORMATION
+SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION
+SMB_SFILEINFO_STANDARD
+SMB_SFILEINFO_EA_SET
+SMB_SFILEINFO_BASIC_INFO
+SMB_SFILEINFO_DISPOSITION_INFO
+SMB_SFILEINFO_ALLOCATION_INFO
+SMB_SFILEINFO_END_OF_FILE_INFO
+SMB_SFILEINFO_UNIX_BASIC
+SMB_SFILEINFO_UNIX_LINK
+SMB_SFILEINFO_BASIC_INFORMATION
+SMB_SFILEINFO_RENAME_INFORMATION
+SMB_SFILEINFO_DISPOSITION_INFORMATION
+SMB_SFILEINFO_POSITION_INFORMATION
+SMB_SFILEINFO_MODE_INFORMATION
+SMB_SFILEINFO_ALLOCATION_INFORMATION
+SMB_SFILEINFO_END_OF_FILE_INFORMATION
+SMB_FIND_STANDARD
+SMB_FIND_EA_SIZE
+SMB_FIND_DIRECTORY_INFO
+SMB_FIND_FULL_DIRECTORY_INFO
+SMB_FIND_NAME_INFO
+SMB_FIND_BOTH_DIRECTORY_INFO
+SMB_FIND_261
+SMB_FIND_262
diff --git a/source4/torture/raw/mkdir.c b/source4/torture/raw/mkdir.c
new file mode 100644
index 0000000..4775016
--- /dev/null
+++ b/source4/torture/raw/mkdir.c
@@ -0,0 +1,171 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_MKDIR_* and RAW_RMDIR_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\mkdirtest"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+/*
+ test mkdir ops
+*/
+static bool test_mkdir(struct smbcli_state *cli, struct torture_context *tctx)
+{
+ union smb_mkdir md;
+ struct smb_rmdir rd;
+ const char *path = BASEDIR "\\mkdir.dir";
+ NTSTATUS status;
+ bool ret = true;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /*
+ basic mkdir
+ */
+ md.mkdir.level = RAW_MKDIR_MKDIR;
+ md.mkdir.in.path = path;
+
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Testing mkdir collision\n");
+
+ /* 2nd create */
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ /* basic rmdir */
+ rd.in.path = path;
+ status = smb_raw_rmdir(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_rmdir(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ printf("Testing mkdir collision with file\n");
+
+ /* name collision with a file */
+ smbcli_close(cli->tree, create_complex_file(cli, tctx, path));
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ printf("Testing rmdir with file\n");
+
+ /* delete a file with rmdir */
+ status = smb_raw_rmdir(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
+
+ smbcli_unlink(cli->tree, path);
+
+ printf("Testing invalid dir\n");
+
+ /* create an invalid dir */
+ md.mkdir.in.path = "..\\..\\..";
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ printf("Testing t2mkdir\n");
+
+ /* try a t2mkdir - need to work out why this fails! */
+ md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
+ md.t2mkdir.in.path = path;
+ md.t2mkdir.in.num_eas = 0;
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_rmdir(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Testing t2mkdir bad path\n");
+ md.t2mkdir.in.path = talloc_asprintf(tctx, "%s\\bad_path\\bad_path",
+ BASEDIR);
+ status = smb_raw_mkdir(cli->tree, &md);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND);
+
+ printf("Testing t2mkdir with EAs\n");
+
+ /* with EAs */
+ md.t2mkdir.level = RAW_MKDIR_T2MKDIR;
+ md.t2mkdir.in.path = path;
+ md.t2mkdir.in.num_eas = 3;
+ md.t2mkdir.in.eas = talloc_array(tctx, struct ea_struct, md.t2mkdir.in.num_eas);
+ md.t2mkdir.in.eas[0].flags = 0;
+ md.t2mkdir.in.eas[0].name.s = "EAONE";
+ md.t2mkdir.in.eas[0].value = data_blob_talloc(tctx, "blah", 4);
+ md.t2mkdir.in.eas[1].flags = 0;
+ md.t2mkdir.in.eas[1].name.s = "EA TWO";
+ md.t2mkdir.in.eas[1].value = data_blob_talloc(tctx, "foo bar", 7);
+ md.t2mkdir.in.eas[2].flags = 0;
+ md.t2mkdir.in.eas[2].name.s = "EATHREE";
+ md.t2mkdir.in.eas[2].value = data_blob_talloc(tctx, "xx1", 3);
+ status = smb_raw_mkdir(cli->tree, &md);
+
+ if (torture_setting_bool(tctx, "samba3", false)
+ && NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)) {
+ d_printf("EAS not supported -- not treating as fatal\n");
+ }
+ else {
+ /*
+ * In Samba3, don't see this error as fatal
+ */
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_check_ea(cli, path, "EAONE", "blah");
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_check_ea(cli, path, "EA TWO", "foo bar");
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_check_ea(cli, path, "EATHREE", "xx1");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_rmdir(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of all RAW_MKDIR_* calls
+*/
+bool torture_raw_mkdir(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+
+ if (!test_mkdir(cli, torture)) {
+ ret = false;
+ }
+
+ return ret;
+}
diff --git a/source4/torture/raw/mux.c b/source4/torture/raw/mux.c
new file mode 100644
index 0000000..4fd5a9e
--- /dev/null
+++ b/source4/torture/raw/mux.c
@@ -0,0 +1,342 @@
+/*
+ Unix SMB/CIFS implementation.
+ basic raw test suite for multiplexing
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\test_mux"
+
+/*
+ test the delayed reply to a open that leads to a sharing violation
+*/
+static bool test_mux_open(struct torture_context *tctx, struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_open io;
+ NTSTATUS status;
+ int fnum1, fnum2;
+ bool ret = true;
+ struct smbcli_request *req1, *req2;
+ struct timeval tv;
+ double d;
+
+ torture_comment(tctx, "Testing multiplexed open/open/close\n");
+
+ torture_comment(tctx, "send first open\n");
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR "\\open.dat";
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "send first open");
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "send 2nd open, non-conflicting\n");
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "send 2nd open, non-conflicting");
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ tv = timeval_current();
+
+ torture_comment(tctx, "send 3rd open, conflicting\n");
+ io.ntcreatex.in.share_access = 0;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION, "send 3rd open, conflicting");
+
+ d = timeval_elapsed(&tv);
+ if (d < 0.5 || d > 1.5) {
+ torture_comment(tctx, "bad timeout for conflict - %.2f should be 1.0\n", d);
+ } else {
+ torture_comment(tctx, "open delay %.2f\n", d);
+ }
+
+ torture_comment(tctx, "send async open, conflicting\n");
+ tv = timeval_current();
+ req1 = smb_raw_open_send(cli->tree, &io);
+
+ torture_comment(tctx, "send 2nd async open, conflicting\n");
+ tv = timeval_current();
+ req2 = smb_raw_open_send(cli->tree, &io);
+
+ torture_comment(tctx, "close first sync open\n");
+ smbcli_close(cli->tree, fnum1);
+
+ torture_comment(tctx, "cancel 2nd async open (should be ignored)\n");
+ smb_raw_ntcancel(req2);
+
+ d = timeval_elapsed(&tv);
+ if (d > 0.25) {
+ torture_comment(tctx, "bad timeout after cancel - %.2f should be <0.25\n", d);
+ torture_assert(tctx, d <= 0.25, "bad timeout after cancel");
+ }
+
+ torture_comment(tctx, "close the 2nd sync open\n");
+ smbcli_close(cli->tree, fnum2);
+
+ torture_comment(tctx, "see if the 1st async open now succeeded\n");
+ status = smb_raw_open_recv(req1, mem_ctx, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "see if the 1st async open now succeeded");
+
+ d = timeval_elapsed(&tv);
+ if (d > 0.25) {
+ torture_comment(tctx, "bad timeout for async conflict - %.2f should be <0.25\n", d);
+ torture_assert(tctx, d <= 0.25, "bad timeout for async conflict");
+ } else {
+ torture_comment(tctx, "async open delay %.2f\n", d);
+ }
+
+ torture_comment(tctx, "2nd async open should have timed out\n");
+ status = smb_raw_open_recv(req2, mem_ctx, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION, "2nd async open should have timed out");
+ d = timeval_elapsed(&tv);
+ if (d < 0.8) {
+ torture_comment(tctx, "bad timeout for async conflict - %.2f should be 1.0\n", d);
+ }
+
+ torture_comment(tctx, "close the 1st async open\n");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ return ret;
+}
+
+
+/*
+ test a write that hits a byte range lock and send the close after the write
+*/
+static bool test_mux_write(struct torture_context *tctx, struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_write io;
+ NTSTATUS status;
+ int fnum;
+ bool ret = true;
+ struct smbcli_request *req;
+
+ torture_comment(tctx, "Testing multiplexed lock/write/close\n");
+
+ fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_comment(tctx, "open failed in mux_write - %s\n", smbcli_errstr(cli->tree));
+ torture_assert(tctx, fnum != -1, "open failed in mux_write");
+ }
+
+ cli->session->pid = 1;
+
+ status = smbcli_lock(cli->tree, fnum, 0, 4, 0, WRITE_LOCK);
+
+ /* lock a range */
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_assert_ntstatus_ok(tctx, status, "lock failed in mux_write");
+ }
+
+ cli->session->pid = 2;
+
+ /* send an async write */
+ io.generic.level = RAW_WRITE_WRITEX;
+ io.writex.in.file.fnum = fnum;
+ io.writex.in.offset = 0;
+ io.writex.in.wmode = 0;
+ io.writex.in.remaining = 0;
+ io.writex.in.count = 4;
+ io.writex.in.data = (const uint8_t *)&fnum;
+ req = smb_raw_write_send(cli->tree, &io);
+
+ /* unlock the range */
+ cli->session->pid = 1;
+ smbcli_unlock(cli->tree, fnum, 0, 4);
+
+ /* and recv the async write reply */
+ status = smb_raw_write_recv(req, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT, "recv the async write reply");
+
+ smbcli_close(cli->tree, fnum);
+
+ return ret;
+}
+
+
+/*
+ test a lock that conflicts with an existing lock
+*/
+static bool test_mux_lock(struct torture_context *tctx, struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_lock io;
+ NTSTATUS status;
+ int fnum;
+ bool ret = true;
+ struct smbcli_request *req;
+ struct smb_lock_entry lock[1];
+ struct timeval t;
+
+ torture_comment(tctx, "TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n");
+
+ fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_comment(tctx, "open failed in mux_lock - %s\n", smbcli_errstr(cli->tree));
+ torture_assert(tctx, fnum != -1, "open failed in mux_lock");
+ }
+
+ torture_comment(tctx, "establishing a lock\n");
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = 0;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.ulock_cnt = 0;
+ lock[0].pid = 1;
+ lock[0].offset = 0;
+ lock[0].count = 4;
+ io.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "establishing a lock");
+
+ torture_comment(tctx, "the second lock will conflict with the first\n");
+ lock[0].pid = 2;
+ io.lockx.in.timeout = 1000;
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT, "the second lock will conflict with the first");
+
+ torture_comment(tctx, "this will too, but we'll unlock while waiting\n");
+ t = timeval_current();
+ req = smb_raw_lock_send(cli->tree, &io);
+
+ torture_comment(tctx, "unlock the first range\n");
+ lock[0].pid = 1;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.timeout = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "unlock the first range");
+
+ torture_comment(tctx, "recv the async reply\n");
+ status = smbcli_request_simple_recv(req);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "recv the async reply");
+
+ torture_comment(tctx, "async lock took %.2f msec\n", timeval_elapsed(&t) * 1000);
+ torture_assert(tctx, timeval_elapsed(&t) <= 0.1, "failed to trigger early lock retry\n");
+
+ torture_comment(tctx, "reopening with an exit\n");
+ smb_raw_exit(cli->session);
+ fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE);
+
+ torture_comment(tctx, "Now trying with a cancel\n");
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.file.fnum = fnum;
+ io.lockx.in.mode = 0;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.ulock_cnt = 0;
+ lock[0].pid = 1;
+ lock[0].offset = 0;
+ lock[0].count = 4;
+ io.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "Now trying with a cancel");
+
+ lock[0].pid = 2;
+ io.lockx.in.timeout = 1000;
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT, "Now trying with a cancel pid 2");
+
+ req = smb_raw_lock_send(cli->tree, &io);
+
+ /* cancel the blocking lock */
+ smb_raw_ntcancel(req);
+
+ torture_comment(tctx, "sending 2nd cancel\n");
+ /* the 2nd cancel is totally harmless, but tests the server trying to
+ cancel an already cancelled request */
+ smb_raw_ntcancel(req);
+
+ torture_comment(tctx, "sent 2nd cancel\n");
+
+ lock[0].pid = 1;
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ io.lockx.in.timeout = 0;
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "clear lock");
+
+ status = smbcli_request_simple_recv(req);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT, "recv 2nd cancel");
+
+ torture_comment(tctx, "cancel a lock using exit to close file\n");
+ lock[0].pid = 1;
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ io.lockx.in.timeout = 1000;
+
+ status = smb_raw_lock(cli->tree, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, "cancel a lock using exit to close file");
+
+ t = timeval_current();
+ lock[0].pid = 2;
+ req = smb_raw_lock_send(cli->tree, &io);
+
+ smb_raw_exit(cli->session);
+ smb_raw_exit(cli->session);
+ smb_raw_exit(cli->session);
+ smb_raw_exit(cli->session);
+
+ torture_comment(tctx, "recv the async reply\n");
+ status = smbcli_request_simple_recv(req);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RANGE_NOT_LOCKED, "recv the async reply");
+ torture_comment(tctx, "async lock exit took %.2f msec\n", timeval_elapsed(&t) * 1000);
+ torture_assert(tctx, timeval_elapsed(&t) <= 0.1, "failed to trigger early lock failure\n");
+
+ return ret;
+}
+
+
+
+/*
+ basic testing of multiplexing notify
+*/
+bool torture_raw_mux(struct torture_context *torture, struct smbcli_state *cli)
+{
+ bool ret = true;
+ TALLOC_CTX *frame;
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+ frame = talloc_stackframe();
+
+ ret &= test_mux_open(torture, cli, frame);
+ ret &= test_mux_write(torture, cli, frame);
+ ret &= test_mux_lock(torture, cli, frame);
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ TALLOC_FREE(frame);
+ return ret;
+}
diff --git a/source4/torture/raw/notify.c b/source4/torture/raw/notify.c
new file mode 100644
index 0000000..f3c3806
--- /dev/null
+++ b/source4/torture/raw/notify.c
@@ -0,0 +1,2297 @@
+/*
+ Unix SMB/CIFS implementation.
+ basic raw test suite for change notify
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "system/filesys.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+#include "lib/events/events.h"
+
+#define BASEDIR "\\test_notify"
+
+#define CHECK_WSTR(tctx, field, value, flags) \
+do { \
+ torture_assert_str_equal(tctx, field.s, value, "values don't match"); \
+ torture_assert(tctx, \
+ !wire_bad_flags(&field, STR_UNICODE, cli->transport), \
+ "wire_bad_flags"); \
+} while (0)
+
+#define BASEDIR_CN1_DIR BASEDIR "_CN1_DIR"
+
+/*
+ basic testing of change notify on directories
+*/
+static bool test_notify_dir(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ union smb_close cl;
+ int i, count, fnum, fnum2;
+ struct smbcli_request *req, *req2;
+ extern int torture_numops;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DIR),
+ "Failed to setup up test directory: " BASEDIR_CN1_DIR);
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_DIR;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ torture_comment(tctx, "Testing notify cancel\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smb_raw_ntcancel(req);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_comment(tctx, "Testing notify mkdir\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "more than one change");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "Testing notify rmdir\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "more than one change");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "Testing notify mkdir - rmdir - mkdir - rmdir\n");
+
+ smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
+ smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
+ smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
+ smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
+ smb_msleep(200);
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 4, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[1].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
+ STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[2].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subdir-name",
+ STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[3].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name, "subdir-name",
+ STR_UNICODE);
+
+ count = torture_numops;
+ torture_comment(tctx, "Testing buffered notify on create of %d files\n", count);
+ for (i=0;i<count;i++) {
+ char *fname = talloc_asprintf(cli,
+ BASEDIR_CN1_DIR "\\test%d.txt",
+ i);
+ int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert_int_not_equal_goto(tctx, fnum3, -1, ret, done,
+ talloc_asprintf(tctx, "Failed to create %s - %s",
+ fname, smbcli_errstr(cli->tree)));
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum3);
+ }
+
+ /* (1st notify) setup a new notify on a different directory handle.
+ This new notify won't see the events above. */
+ notify.nttrans.in.file.fnum = fnum2;
+ req2 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ /* (2nd notify) whereas this notify will see the above buffered events,
+ and it directly returns the buffered events */
+ notify.nttrans.in.file.fnum = fnum;
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smbcli_unlink");
+
+ /* (1st unlink) as the 2nd notify directly returns,
+ this unlink is only seen by the 1st notify and
+ the 3rd notify (later) */
+ torture_comment(tctx, "Testing notify on unlink for the first file\n");
+ status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test0.txt");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smbcli_unlink");
+
+ /* receive the reply from the 2nd notify */
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ count, ret, done,
+ "wrong number of changes");
+ for (i=1;i<count;i++) {
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[i].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ }
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
+ STR_UNICODE);
+
+ torture_comment(tctx, "and now from the 1st notify\n");
+ status = smb_raw_changenotify_recv(req2, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
+ STR_UNICODE);
+
+ torture_comment(tctx, "(3rd notify) this notify will only see the 1st unlink\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smbcli_unlink");
+
+ torture_comment(tctx, "Testing notify on wildcard unlink for %d files\n", count-1);
+ /* (2nd unlink) do a wildcard unlink */
+ status = smbcli_unlink_wcard(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ /* receive the 3rd notify */
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
+ STR_UNICODE);
+
+ /* and we now see the rest of the unlink calls on both directory handles */
+ notify.nttrans.in.file.fnum = fnum;
+ sleep(3);
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ count - 1, ret, done,
+ "wrong number of changes");
+ for (i=0;i<notify.nttrans.out.num_changes;i++) {
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[i].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ }
+ notify.nttrans.in.file.fnum = fnum2;
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ count - 1, ret, done,
+ "wrong number of changes");
+ for (i=0;i<notify.nttrans.out.num_changes;i++) {
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[i].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ }
+
+ torture_comment(tctx, "Testing if a close() on the dir handle triggers the notify reply\n");
+
+ notify.nttrans.in.file.fnum = fnum;
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_close");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 0, ret, done, "no changes expected");
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_DIR);
+ return ret;
+}
+
+/*
+ * Check notify reply for a rename action. Not sure if this is a valid thing
+ * to do, but depending on timing between inotify and messaging we get the
+ * add/remove/modify in any order. This routines tries to find the action/name
+ * pair in any of the three following notify_changes.
+ */
+
+static bool check_rename_reply(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ int line,
+ struct notify_changes *actions,
+ uint32_t action, const char *name)
+{
+ int i;
+
+ for (i=0; i<3; i++) {
+ if (actions[i].action == action) {
+ CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
+ return true;
+ }
+ }
+
+ torture_result(tctx, TORTURE_FAIL,
+ __location__": (%d) expected action %d, not found\n",
+ line, action);
+ return false;
+}
+
+/*
+ testing of recursive change notify
+*/
+
+#define BASEDIR_CN1_RECUR BASEDIR "_CN1_RECUR"
+
+static bool test_notify_recursive(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req1, *req2;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY WITH RECURSION\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_RECUR),
+ "Failed to setup up test directory: " BASEDIR_CN1_RECUR);
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_RECUR;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify, on file or directory name
+ changes. Setup both with and without recursion */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
+ notify.nttrans.in.file.fnum = fnum;
+
+ notify.nttrans.in.recursive = true;
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ notify.nttrans.in.recursive = false;
+ req2 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ /* cancel initial requests so the buffer is setup */
+ smb_raw_ntcancel(req1);
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ smb_raw_ntcancel(req2);
+ status = smb_raw_changenotify_recv(req2, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ /*
+ * Make notifies a bit more interesting in a cluster by doing
+ * the changes against different nodes with --unclist
+ */
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name");
+ smbcli_mkdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1");
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,
+ BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
+ O_CREAT, 0));
+ smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1",
+ BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
+ smbcli_rename(cli->tree,
+ BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
+ BASEDIR_CN1_RECUR "\\subname2-r");
+ smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subname2-r",
+ BASEDIR_CN1_RECUR "\\subname3-r");
+
+ notify.nttrans.in.completion_filter = 0;
+ notify.nttrans.in.recursive = true;
+ smb_msleep(200);
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
+ smbcli_rmdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name");
+ smbcli_unlink(cli->tree, BASEDIR_CN1_RECUR "\\subname3-r");
+
+ smb_msleep(200);
+ notify.nttrans.in.recursive = false;
+ req2 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 11, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[1].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
+ "subdir-name\\subname1", STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[2].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
+ "subdir-name\\subname2", STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[3].action,
+ NOTIFY_ACTION_OLD_NAME, ret, done,
+ "wrong action (exp: OLD_NAME)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
+ "subdir-name\\subname1", STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[4].action,
+ NOTIFY_ACTION_NEW_NAME, ret, done,
+ "wrong action (exp: NEW_NAME)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
+ "subdir-name\\subname1-r", STR_UNICODE);
+
+ ret &= check_rename_reply(tctx,
+ cli, __LINE__, &notify.nttrans.out.changes[5],
+ NOTIFY_ACTION_ADDED, "subname2-r");
+ ret &= check_rename_reply(tctx,
+ cli, __LINE__, &notify.nttrans.out.changes[5],
+ NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
+ ret &= check_rename_reply(tctx,
+ cli, __LINE__, &notify.nttrans.out.changes[5],
+ NOTIFY_ACTION_MODIFIED, "subname2-r");
+
+ ret &= check_rename_reply(tctx,
+ cli, __LINE__, &notify.nttrans.out.changes[8],
+ NOTIFY_ACTION_OLD_NAME, "subname2-r");
+ ret &= check_rename_reply(tctx,
+ cli, __LINE__, &notify.nttrans.out.changes[8],
+ NOTIFY_ACTION_NEW_NAME, "subname3-r");
+ ret &= check_rename_reply(tctx,
+ cli, __LINE__, &notify.nttrans.out.changes[8],
+ NOTIFY_ACTION_MODIFIED, "subname3-r");
+
+ if (!ret) {
+ goto done;
+ }
+
+ status = smb_raw_changenotify_recv(req2, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 3, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
+ "subdir-name\\subname1-r", STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[1].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
+ STR_UNICODE);
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[2].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
+ STR_UNICODE);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_RECUR);
+ return ret;
+}
+
+/*
+ testing of change notify mask change
+*/
+
+#define BASEDIR_CN1_CNMC BASEDIR "_CN1_CNMC"
+
+static bool test_notify_mask_change(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req1, *req2;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_CNMC),
+ "Failed to setup up test directory: " BASEDIR_CN1_CNMC);
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_CNMC;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify, on file or directory name
+ changes. Setup both with and without recursion */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ notify.nttrans.in.file.fnum = fnum;
+
+ notify.nttrans.in.recursive = true;
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ notify.nttrans.in.recursive = false;
+ req2 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ /* cancel initial requests so the buffer is setup */
+ smb_raw_ntcancel(req1);
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ smb_raw_ntcancel(req2);
+ status = smb_raw_changenotify_recv(req2, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ notify.nttrans.in.recursive = true;
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ /* Set to hidden then back again. */
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,BASEDIR_CN1_CNMC "\\tname1", O_CREAT, 0));
+ smbcli_setatr(cli->tree, BASEDIR_CN1_CNMC "\\tname1",
+ FILE_ATTRIBUTE_HIDDEN, 0);
+ smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\tname1");
+
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_MODIFIED, ret, done,
+ "wrong action (exp: MODIFIED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
+ STR_UNICODE);
+
+ /* Now try and change the mask to include other events.
+ * This should not work - once the mask is set on a directory
+ * fnum it seems to be fixed until the fnum is closed. */
+
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
+ notify.nttrans.in.recursive = true;
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ notify.nttrans.in.recursive = false;
+ req2 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1");
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,
+ BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
+ O_CREAT, 0));
+ smbcli_rename(cli->tree,
+ BASEDIR_CN1_CNMC "\\subdir-name\\subname1",
+ BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
+ smbcli_rename(cli->tree,
+ BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
+ BASEDIR_CN1_CNMC "\\subname2-r");
+ smbcli_rename(cli->tree,
+ BASEDIR_CN1_CNMC "\\subname2-r",
+ BASEDIR_CN1_CNMC "\\subname3-r");
+
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
+ smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\subname3-r");
+
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_MODIFIED, ret, done,
+ "wrong action (exp: MODIFIED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
+ STR_UNICODE);
+
+ status = smb_raw_changenotify_recv(req2, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_MODIFIED, ret, done,
+ "wrong action (exp: MODIFIED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
+ STR_UNICODE);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_CNMC);
+ return ret;
+}
+
+
+/*
+ testing of mask bits for change notify
+*/
+
+#define BASEDIR_CN1_NOTM BASEDIR "_CN1_NOTM"
+
+static bool test_notify_mask(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ union smb_chkpath chkpath;
+ int fnum, fnum2;
+ uint32_t mask;
+ int i;
+ char c = 1;
+ struct timeval tv;
+ NTTIME t;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NOTM),
+ "Failed to setup up test directory: " BASEDIR_CN1_NOTM);
+
+ tv = timeval_current_ofs(1000, 0);
+ t = timeval_to_nttime(&tv);
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_NOTM;
+
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.recursive = true;
+
+ chkpath.chkpath.in.path = "\\";
+
+#define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
+ do { \
+ smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
+ for (mask=i=0;i<32;i++) { \
+ struct smbcli_request *req; \
+ status = smb_raw_open(cli->tree, tctx, &io); \
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
+ "smb_raw_open"); \
+ fnum = io.ntcreatex.out.file.fnum; \
+ setup \
+ notify.nttrans.in.file.fnum = fnum; \
+ notify.nttrans.in.completion_filter = ((uint32_t)1<<i); \
+ req = smb_raw_changenotify_send(cli->tree, &notify); \
+ smb_raw_chkpath(cli->tree, &chkpath); \
+ op \
+ smb_msleep(200); smb_raw_ntcancel(req); \
+ status = smb_raw_changenotify_recv(req, tctx, &notify); \
+ cleanup \
+ smbcli_close(cli->tree, fnum); \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
+ "smbcli_close"); \
+ /* special case to cope with file rename behaviour */ \
+ if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
+ notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
+ ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
+ Action == NOTIFY_ACTION_OLD_NAME) { \
+ torture_comment(tctx, "(rename file special handling OK)\n"); \
+ } else { \
+ torture_assert_int_equal_goto(tctx, \
+ notify.nttrans.out.num_changes,\
+ nchanges, ret, done, \
+ talloc_asprintf(tctx, \
+ "nchanges=%d expected=%d action=%d " \
+ "filter=0x%08x\n", \
+ notify.nttrans.out.num_changes, \
+ nchanges, \
+ notify.nttrans.out.changes[0].action, \
+ notify.nttrans.in.completion_filter)); \
+ torture_assert_int_equal_goto(tctx, \
+ notify.nttrans.out.changes[0].action, \
+ Action, ret, done, \
+ talloc_asprintf(tctx, \
+ "nchanges=%d action=%d " \
+ "expectedAction=%d filter=0x%08x\n", \
+ notify.nttrans.out.num_changes, \
+ notify.nttrans.out.changes[0].action, \
+ Action, \
+ notify.nttrans.in.completion_filter)); \
+ torture_assert_str_equal_goto(tctx, \
+ notify.nttrans.out.changes[0].name.s, \
+ "tname1", ret, done, \
+ talloc_asprintf(tctx, \
+ "nchanges=%d action=%d filter=0x%08x " \
+ "name=%s expected_name=tname1\n", \
+ notify.nttrans.out.num_changes, \
+ notify.nttrans.out.changes[0].action, \
+ notify.nttrans.in.completion_filter, \
+ notify.nttrans.out.changes[0].name.s));\
+ } \
+ mask |= ((uint32_t)1<<i); \
+ } \
+ if ((expected) != mask) { \
+ torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
+ 0, ret, done, "Too few bits"); \
+ torture_comment(tctx, "WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
+ mask, expected); \
+ } \
+ } while (0);
+
+ torture_comment(tctx, "Testing mkdir\n");
+ NOTIFY_MASK_TEST("Testing mkdir",;,
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ NOTIFY_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_DIR_NAME, 1);
+
+ torture_comment(tctx, "Testing create file\n");
+ NOTIFY_MASK_TEST("Testing create file",;,
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,
+ BASEDIR_CN1_NOTM "\\tname1",
+ O_CREAT, 0));,
+ smbcli_unlink(cli2->tree,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ NOTIFY_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME, 1);
+
+ torture_comment(tctx, "Testing unlink\n");
+ NOTIFY_MASK_TEST("Testing unlink",
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,
+ BASEDIR_CN1_NOTM "\\tname1",
+ O_CREAT, 0));,
+ smbcli_unlink(cli2->tree,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ ;,
+ NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_FILE_NAME, 1);
+
+ torture_comment(tctx, "Testing rmdir\n");
+ NOTIFY_MASK_TEST("Testing rmdir",
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ ;,
+ NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_DIR_NAME, 1);
+
+ torture_comment(tctx, "Testing rename file\n");
+ NOTIFY_MASK_TEST("Testing rename file",
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,
+ BASEDIR_CN1_NOTM "\\tname1",
+ O_CREAT, 0));,
+ smbcli_rename(cli2->tree,
+ BASEDIR_CN1_NOTM "\\tname1",
+ BASEDIR_CN1_NOTM "\\tname2");,
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
+ NOTIFY_ACTION_OLD_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
+
+ torture_comment(tctx, "Testing rename dir\n");
+ NOTIFY_MASK_TEST("Testing rename dir",
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_rename(cli2->tree,
+ BASEDIR_CN1_NOTM "\\tname1",
+ BASEDIR_CN1_NOTM "\\tname2");,
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
+ NOTIFY_ACTION_OLD_NAME,
+ FILE_NOTIFY_CHANGE_DIR_NAME, 2);
+
+ torture_comment(tctx, "Testing set path attribute\n");
+ NOTIFY_MASK_TEST("Testing set path attribute",
+ smbcli_close(cli->tree,
+ smbcli_open(cli->tree,
+ BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
+ smbcli_setatr(cli2->tree,
+ BASEDIR_CN1_NOTM "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
+
+ torture_comment(tctx, "Testing set path write time\n");
+ NOTIFY_MASK_TEST("Testing set path write time",
+ smbcli_close(cli->tree, smbcli_open(cli->tree,
+ BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
+ smbcli_setatr(cli2->tree,
+ BASEDIR_CN1_NOTM "\\tname1",
+ FILE_ATTRIBUTE_NORMAL, 1000);,
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
+
+ torture_comment(tctx, "Testing set file attribute\n");
+ NOTIFY_MASK_TEST("Testing set file attribute",
+ fnum2 = create_complex_file(cli2, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
+ (smbcli_close(cli2->tree, fnum2),
+ smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_comment(tctx, "Samba3 does not yet support create times "
+ "everywhere\n");
+ }
+ else {
+ torture_comment(tctx, "Testing set file create time\n");
+ NOTIFY_MASK_TEST("Testing set file create time",
+ fnum2 = create_complex_file(cli, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
+ (smbcli_close(cli->tree, fnum2),
+ smbcli_unlink(cli->tree,
+ BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_CREATION, 1);
+ }
+
+ torture_comment(tctx, "Testing set file access time\n");
+ NOTIFY_MASK_TEST("Testing set file access time",
+ fnum2 = create_complex_file(cli, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
+ (smbcli_close(cli->tree, fnum2),
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
+
+ torture_comment(tctx, "Testing set file write time\n");
+ NOTIFY_MASK_TEST("Testing set file write time",
+ fnum2 = create_complex_file(cli, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
+ (smbcli_close(cli->tree, fnum2),
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
+
+ torture_comment(tctx, "Testing set file change time\n");
+ NOTIFY_MASK_TEST("Testing set file change time",
+ fnum2 = create_complex_file(cli, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
+ (smbcli_close(cli->tree, fnum2),
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ 0, 1);
+
+
+ torture_comment(tctx, "Testing write\n");
+ NOTIFY_MASK_TEST("Testing write",
+ fnum2 = create_complex_file(cli2, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
+ (smbcli_close(cli2->tree, fnum2),
+ smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ 0, 1);
+
+ torture_comment(tctx, "Testing truncate\n");
+ NOTIFY_MASK_TEST("Testing truncate",
+ fnum2 = create_complex_file(cli2, tctx,
+ BASEDIR_CN1_NOTM "\\tname1");,
+ smbcli_ftruncate(cli2->tree, fnum2, 10000);,
+ (smbcli_close(cli2->tree, fnum2),
+ smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_NOTM);
+ return ret;
+}
+
+/*
+ basic testing of change notify on files
+*/
+
+#define BASEDIR_CN1_FILE BASEDIR "_CN1_FILE"
+
+static bool test_notify_file(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_close cl;
+ union smb_notify notify;
+ struct smbcli_request *req;
+ int fnum;
+ const char *fname = BASEDIR_CN1_FILE "\\file.txt";
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY ON FILES\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_FILE),
+ "Failed to setup up test directory: " BASEDIR_CN1_FILE);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
+ notify.nttrans.in.recursive = false;
+
+ torture_comment(tctx, "Testing if notifies on file handles are invalid (should be)\n");
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_INVALID_PARAMETER,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ cl.close.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ cl.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_close");
+
+ status = smbcli_unlink(cli->tree, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smbcli_unlink");
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_FILE);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by a tdis
+*/
+#define BASEDIR_CN1_TDIS BASEDIR "_CN1_TDIS"
+
+static bool test_notify_tdis(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req;
+ struct smbcli_state *cli = NULL;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TDIS),
+ "Failed to setup up test directory: " BASEDIR_CN1_TDIS);
+
+ torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
+ "Failed to open connection.");
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_TDIS;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ status = smbcli_tdis(cli);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smbcli_tdis");
+ cli->tree = NULL;
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 0, ret, done, "no changes expected");
+
+done:
+ torture_close_connection(cli);
+ smbcli_deltree(cli1->tree, BASEDIR_CN1_TDIS);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by a exit
+*/
+
+#define BASEDIR_CN1_EX BASEDIR "_CN1_EX"
+
+static bool test_notify_exit(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req;
+ struct smbcli_state *cli = NULL;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_EX),
+ "Failed to setup up test directory: " BASEDIR_CN1_EX);
+
+ torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
+ "Failed to open connection.");
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_EX;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ status = smb_raw_exit(cli->session);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_exit");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 0, ret, done, "no changes expected");
+
+done:
+ torture_close_connection(cli);
+ smbcli_deltree(cli1->tree, BASEDIR_CN1_EX);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by a ulogoff
+*/
+
+#define BASEDIR_CN1_UL BASEDIR "_CN1_UL"
+
+static bool test_notify_ulogoff(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req;
+ struct smbcli_state *cli = NULL;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_UL),
+ "Failed to setup up test directory: " BASEDIR_CN1_UL);
+
+ torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
+ "Failed to open connection.");
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_UL;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ status = smb_raw_ulogoff(cli->session);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_ulogoff");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 0, ret, done, "no changes expected");
+
+done:
+ torture_close_connection(cli);
+ smbcli_deltree(cli1->tree, BASEDIR_CN1_UL);
+ return ret;
+}
+
+static void tcp_dis_handler(struct smbcli_transport *t, void *p)
+{
+ struct smbcli_state *cli = (struct smbcli_state *)p;
+ smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
+ cli->transport = NULL;
+ cli->tree = NULL;
+}
+/*
+ basic testing of change notifies followed by tcp disconnect
+*/
+
+#define BASEDIR_CN1_TCPDIS BASEDIR "_CN1_TCPDIS"
+
+static bool test_notify_tcp_dis(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req;
+ struct smbcli_state *cli = NULL;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
+
+ torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TCPDIS),
+ "Failed to setup up test directory: "
+ BASEDIR_CN1_TCPDIS);
+
+ torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
+ "Failed to open connection.");
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_TCPDIS;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250000, cli);
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_LOCAL_DISCONNECT,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+done:
+ torture_close_connection(cli);
+ smbcli_deltree(cli1->tree, BASEDIR_CN1_TCPDIS);
+ return ret;
+}
+
+/*
+ test setting up two change notify requests on one handle
+*/
+
+#define BASEDIR_CN1_DBL BASEDIR "_CN1_DBL"
+
+static bool test_notify_double(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req1, *req2;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DBL),
+ "Failed to setup up test directory: " BASEDIR_CN1_DBL);
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_DBL;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+ req2 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name2");
+
+ status = smb_raw_changenotify_recv(req2, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
+ STR_UNICODE);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_DBL);
+ return ret;
+}
+
+
+/*
+ test multiple change notifies at different depths and with/without recursion
+*/
+
+#define BASEDIR_CN1_TNT BASEDIR "_CN1_TNT"
+
+static bool test_notify_tree(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ bool ret = true;
+ union smb_notify notify;
+ union smb_open io;
+ struct smbcli_request *req;
+ struct timeval tv;
+ struct {
+ const char *path;
+ bool recursive;
+ uint32_t filter;
+ int expected;
+ int fnum;
+ int counted;
+ } dirs[] = {
+ {
+ .path = BASEDIR_CN1_TNT "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 30,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\zqy",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 8,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\atsy",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 4,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\foo",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\blah",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 13,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\blah",
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 7,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\blah\\a",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\blah\\b",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\blah\\c",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc\\fooblah",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\zqy\\xx",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\zqy\\yyy",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\zqy\\..",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 40,
+ },
+ {
+ .path = BASEDIR_CN1_TNT,
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 40,
+ },
+ {
+ .path = BASEDIR_CN1_TNT,
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 6,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\atsy",
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 4,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 24,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc",
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
+ .expected = 0,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
+ .expected = 0,
+ },
+ {
+ .path = BASEDIR_CN1_TNT "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 24,
+ },
+ };
+ int i;
+ NTSTATUS status;
+ bool all_done = false;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_TNT),
+ "Failed to setup up test directory: " BASEDIR_CN1_TNT);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 20000;
+
+ /*
+ setup the directory tree, and the notify buffer on each directory
+ */
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ io.ntcreatex.in.fname = dirs[i].path;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ dirs[i].fnum = io.ntcreatex.out.file.fnum;
+
+ notify.nttrans.in.completion_filter = dirs[i].filter;
+ notify.nttrans.in.file.fnum = dirs[i].fnum;
+ notify.nttrans.in.recursive = dirs[i].recursive;
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smb_raw_ntcancel(req);
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+ }
+
+ /* trigger 2 events in each dir */
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ char *path = talloc_asprintf(tctx, "%s\\test.dir", dirs[i].path);
+ /*
+ * Make notifies a bit more interesting in a cluster
+ * by doing the changes against different nodes with
+ * --unclist
+ */
+ smbcli_mkdir(cli->tree, path);
+ smbcli_rmdir(cli2->tree, path);
+ talloc_free(path);
+ }
+
+ /* give a bit of time for the events to propagate */
+ tv = timeval_current();
+
+ do {
+ /* count events that have happened in each dir */
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ notify.nttrans.in.file.fnum = dirs[i].fnum;
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smb_raw_ntcancel(req);
+ notify.nttrans.out.num_changes = 0;
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ dirs[i].counted += notify.nttrans.out.num_changes;
+ }
+
+ all_done = true;
+
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ if (dirs[i].counted != dirs[i].expected) {
+ all_done = false;
+ }
+ }
+ } while (!all_done && timeval_elapsed(&tv) < 20);
+
+ torture_comment(tctx, "took %.4f seconds to propagate all events\n", timeval_elapsed(&tv));
+
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ torture_assert_int_equal_goto(tctx,
+ dirs[i].counted, dirs[i].expected, ret, done,
+ talloc_asprintf(tctx,
+ "unexpected number of events for '%s'",
+ dirs[i].path));
+ }
+
+ /*
+ run from the back, closing and deleting
+ */
+ for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
+ smbcli_close(cli->tree, dirs[i].fnum);
+ smbcli_rmdir(cli->tree, dirs[i].path);
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_TNT);
+ return ret;
+}
+
+/*
+ Test response when cached server events exceed single NT NOTFIY response
+ packet size.
+*/
+
+#define BASEDIR_CN1_NO BASEDIR "_CN1_NO"
+
+static bool test_notify_overflow(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ int count = 100;
+ struct smbcli_request *req1;
+ int i;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NO),
+ "Failed to setup up test directory: " BASEDIR_CN1_NO);
+
+ /* get a handle on the directory */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_NO;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify, on name changes. */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+
+ notify.nttrans.in.recursive = true;
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ /* cancel initial requests so the buffer is setup */
+ smb_raw_ntcancel(req1);
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done,
+ "smb_raw_changenotify_recv");
+
+ /* open a lot of files, filling up the server side notify buffer */
+ torture_comment(tctx, "Testing overflowed buffer notify on create of %d files\n",
+ count);
+ for (i=0;i<count;i++) {
+ char *fname = talloc_asprintf(cli,
+ BASEDIR_CN1_NO "\\test%d.txt", i);
+ int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
+ DENY_NONE);
+ torture_assert_int_not_equal_goto(tctx, fnum2, -1, ret, done,
+ talloc_asprintf(tctx, "Failed to create %s - %s",
+ fname, smbcli_errstr(cli->tree)));
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum2);
+ }
+
+ /* expect that 0 events will be returned with NT_STATUS_OK */
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 0, ret, done, "no changes expected");
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_NO);
+ return ret;
+}
+
+/*
+ Test if notifications are returned for changes to the base directory.
+ They shouldn't be.
+*/
+
+#define BASEDIR_CN1_NBASE BASEDIR "_CN1_NBASE"
+
+static bool test_notify_basedir(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req1;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NBASE),
+ "Failed to setup up test directory: " BASEDIR_CN1_NBASE);
+
+ /* get a handle on the directory */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_NBASE;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* create a test file that will also be modified */
+ smbcli_close(cli->tree, smbcli_open(cli->tree,
+ BASEDIR_CN1_NBASE "\\tname1",
+ O_CREAT, 0));
+
+ /* ask for a change notify, on attribute changes. */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ req1 = smb_raw_changenotify_send(cli->tree, &notify);
+
+ /* set attribute on the base dir */
+ smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE, FILE_ATTRIBUTE_HIDDEN, 0);
+
+ /* set attribute on a file to assure we receive a notification */
+ smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE "\\tname1",
+ FILE_ATTRIBUTE_HIDDEN, 0);
+ smb_msleep(200);
+
+ /* check how many responses were given, expect only 1 for the file */
+ status = smb_raw_changenotify_recv(req1, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_MODIFIED, ret, done,
+ "wrong action (exp: MODIFIED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
+ STR_UNICODE);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_NBASE);
+ return ret;
+}
+
+
+/*
+ create a secondary tree connect - used to test for a bug in Samba3 messaging
+ with change notify
+*/
+
+static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
+ struct torture_context *tctx)
+{
+ NTSTATUS status;
+ const char *share, *host;
+ struct smbcli_tree *tree;
+ union smb_tcon tcon;
+
+ share = torture_setting_string(tctx, "share", NULL);
+ host = torture_setting_string(tctx, "host", NULL);
+
+ torture_comment(tctx, "create a second tree context on the same session\n");
+ tree = smbcli_tree_init(cli->session, tctx, false);
+
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ tcon.tconx.in.device = "A:";
+ status = smb_raw_tcon(tree, tctx, &tcon);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tree);
+ torture_comment(tctx, "Failed to create secondary tree\n");
+ return NULL;
+ }
+
+ tree->tid = tcon.tconx.out.tid;
+ torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
+
+ return tree;
+}
+
+
+/*
+ very simple change notify test
+*/
+
+#define BASEDIR_CN1_NTCON BASEDIR "_CN1_NTCON"
+
+static bool test_notify_tcon(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum;
+ struct smbcli_request *req;
+ extern int torture_numops;
+ struct smbcli_tree *tree = NULL;
+
+ torture_comment(tctx, "TESTING SIMPLE CHANGE NOTIFY\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NTCON),
+ "Failed to setup up test directory: " BASEDIR_CN1_NTCON);
+
+ /*
+ get a handle on the directory
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_NTCON;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_open");
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = true;
+
+ torture_comment(tctx, "Testing notify mkdir\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "Testing notify rmdir\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "SIMPLE CHANGE NOTIFY OK\n");
+
+ torture_comment(tctx, "TESTING WITH SECONDARY TCON\n");
+ tree = secondary_tcon(cli, tctx);
+ torture_assert_not_null_goto(tctx, tree, ret, done,
+ "failed to create secondary tcon");
+
+ torture_comment(tctx, "Testing notify mkdir\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "Testing notify rmdir\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "CHANGE NOTIFY WITH TCON OK\n");
+
+ torture_comment(tctx, "Disconnecting secondary tree\n");
+ status = smb_tree_disconnect(tree);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_tree_disconnect");
+ talloc_free(tree);
+
+ torture_comment(tctx, "Testing notify mkdir\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_ADDED, ret, done,
+ "wrong action (exp: ADDED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "Testing notify rmdir\n");
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb_raw_changenotify_recv");
+ torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
+ 1, ret, done, "wrong number of changes");
+ torture_assert_int_equal_goto(tctx,
+ notify.nttrans.out.changes[0].action,
+ NOTIFY_ACTION_REMOVED, ret, done,
+ "wrong action (exp: REMOVED)");
+ CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
+ STR_UNICODE);
+
+ torture_comment(tctx, "CHANGE NOTIFY WITH TDIS OK\n");
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_NTCON);
+ return ret;
+}
+
+struct cb_data {
+ struct smbcli_request *req;
+ bool timed_out;
+};
+
+static void timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct cb_data *cbp = (struct cb_data *)private_data;
+ cbp->req->state = SMBCLI_REQUEST_ERROR;
+ cbp->timed_out = true;
+}
+
+/*
+ testing alignment of multiple change notify infos
+*/
+
+#define BASEDIR_CN1_NALIGN BASEDIR "_CN1_NALIGN"
+
+static bool test_notify_alignment(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ int fnum, fnum2;
+ struct smbcli_request *req;
+ const char *fname = BASEDIR_CN1_NALIGN "\\starter";
+ const char *fnames[] = { "a",
+ "ab",
+ "abc",
+ "abcd" };
+ bool fnames_received[] = {false,
+ false,
+ false,
+ false};
+ size_t total_names_received = 0;
+ size_t num_names = ARRAY_SIZE(fnames);
+ size_t i;
+ char *fpath = NULL;
+
+ torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NALIGN),
+ "Failed to setup up test directory: " BASEDIR_CN1_NALIGN);
+
+ /* get a handle on the directory */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR_CN1_NALIGN;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* ask for a change notify, on file creation */
+ notify.nttrans.level = RAW_NOTIFY_NTTRANS;
+ notify.nttrans.in.buffer_size = 1000;
+ notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ notify.nttrans.in.file.fnum = fnum;
+ notify.nttrans.in.recursive = false;
+
+ /* start change tracking */
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+
+ fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
+ smbcli_close(cli->tree, fnum2);
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
+
+ /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
+ * to be returned in the same packet with all possible 4-byte padding
+ * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
+ * 4-byte aligned. */
+
+ for (i = 0; i < num_names; i++) {
+ fpath = talloc_asprintf(tctx, "%s\\%s",
+ BASEDIR_CN1_NALIGN, fnames[i]);
+ fnum2 = smbcli_open(cli->tree, fpath,
+ O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
+ smbcli_close(cli->tree, fnum2);
+ talloc_free(fpath);
+ }
+
+ /*
+ * Slow cloud filesystems mean we might
+ * not get everything in one go. Keep going
+ * until we get them all.
+ */
+ while (total_names_received < num_names) {
+ struct tevent_timer *te = NULL;
+ struct cb_data to_data = {0};
+
+ /*
+ * We send a notify packet, and let
+ * smb_raw_changenotify_recv() do
+ * the alignment checking for us.
+ */
+ req = smb_raw_changenotify_send(cli->tree, &notify);
+ torture_assert(tctx,
+ req != NULL,
+ "smb_raw_changenotify_send failed\n");
+
+ /* Ensure we don't wait more than 30 seconds. */
+ to_data.req = req;
+ to_data.timed_out = false;
+
+ te = tevent_add_timer(tctx->ev,
+ req,
+ tevent_timeval_current_ofs(30, 0),
+ timeout_cb,
+ &to_data);
+ if (te == NULL) {
+ torture_fail(tctx, "tevent_add_timer fail\n");
+ }
+
+ status = smb_raw_changenotify_recv(req, tctx, &notify);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (to_data.timed_out == true) {
+ torture_fail(tctx, "smb_raw_changenotify_recv "
+ "timed out\n");
+ }
+ }
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb_raw_changenotify_recv");
+
+ for (i = 0; i < notify.nttrans.out.num_changes; i++) {
+ size_t j;
+
+ /* Ensure it was an 'add'. */
+ torture_assert(tctx,
+ notify.nttrans.out.changes[i].action ==
+ NOTIFY_ACTION_ADDED,
+ "");
+
+ for (j = 0; j < num_names; j++) {
+ if (strcmp(notify.nttrans.out.changes[i].name.s,
+ fnames[j]) == 0) {
+ if (fnames_received[j] == true) {
+ const char *err =
+ talloc_asprintf(tctx,
+ "Duplicate "
+ "name %s\n",
+ fnames[j]);
+ if (err == NULL) {
+ torture_fail(tctx,
+ "talloc "
+ "fail\n");
+ }
+ /* already got this. */
+ torture_fail(tctx, err);
+ }
+ fnames_received[j] = true;
+ break;
+ }
+ }
+ if (j == num_names) {
+ /* No name match. */
+ const char *err = talloc_asprintf(tctx,
+ "Unexpected name %s\n",
+ notify.nttrans.out.changes[i].name.s);
+ if (err == NULL) {
+ torture_fail(tctx, "talloc fail\n");
+ }
+ torture_fail(tctx, err);
+ }
+ total_names_received++;
+ }
+ }
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR_CN1_NALIGN);
+ return true;
+}
+
+struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
+
+ torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
+ torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
+ torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
+ torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
+ torture_suite_add_1smb_test(suite, "mask_change",
+ test_notify_mask_change);
+ torture_suite_add_1smb_test(suite, "file", test_notify_file);
+ torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
+ torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
+ torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
+ torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
+ torture_suite_add_1smb_test(suite, "double", test_notify_double);
+ torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
+ torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
+ torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
+ torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);
+
+ return suite;
+}
diff --git a/source4/torture/raw/offline.c b/source4/torture/raw/offline.c
new file mode 100644
index 0000000..262003f
--- /dev/null
+++ b/source4/torture/raw/offline.c
@@ -0,0 +1,514 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ test offline files
+ */
+
+#include "includes.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/events/events.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\testoffline"
+
+static int nconnections;
+static int numstates;
+static int num_connected;
+static int test_failed;
+extern int torture_numops;
+extern int torture_entries;
+static bool test_finished;
+
+enum offline_op {OP_LOADFILE, OP_SAVEFILE, OP_SETOFFLINE, OP_GETOFFLINE, OP_ENDOFLIST};
+
+static double latencies[OP_ENDOFLIST];
+static double worst_latencies[OP_ENDOFLIST];
+
+#define FILE_SIZE 8192
+
+
+struct offline_state {
+ struct torture_context *tctx;
+ struct tevent_context *ev;
+ struct smbcli_tree *tree;
+ TALLOC_CTX *mem_ctx;
+ int client;
+ int fnum;
+ uint32_t count;
+ uint32_t lastcount;
+ uint32_t fnumber;
+ uint32_t offline_count;
+ uint32_t online_count;
+ char *fname;
+ struct smb_composite_loadfile *loadfile;
+ struct smb_composite_savefile *savefile;
+ struct smbcli_request *req;
+ enum offline_op op;
+ struct timeval tv_start;
+};
+
+static void test_offline(struct offline_state *state);
+
+
+static char *filename(TALLOC_CTX *ctx, int i)
+{
+ char *s = talloc_asprintf(ctx, BASEDIR "\\file%u.dat", i);
+ return s;
+}
+
+
+/*
+ called when a loadfile completes
+ */
+static void loadfile_callback(struct composite_context *ctx)
+{
+ struct offline_state *state = ctx->async.private_data;
+ NTSTATUS status;
+ int i;
+
+ status = smb_composite_loadfile_recv(ctx, state->mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to read file '%s' - %s\n",
+ state->loadfile->in.fname, nt_errstr(status));
+ test_failed++;
+ return;
+ }
+
+ /* check the data is correct */
+ if (state->loadfile->out.size != FILE_SIZE) {
+ printf("Wrong file size %u - expected %u\n",
+ state->loadfile->out.size, FILE_SIZE);
+ test_failed++;
+ return;
+ }
+
+ for (i=0;i<FILE_SIZE;i++) {
+ if (state->loadfile->out.data[i] != 1+(state->fnumber % 255)) {
+ printf("Bad data in file %u (got %u expected %u)\n",
+ state->fnumber,
+ state->loadfile->out.data[i],
+ 1+(state->fnumber % 255));
+ test_failed++;
+ return;
+ }
+ }
+
+ talloc_steal(state->loadfile, state->loadfile->out.data);
+
+ state->count++;
+ talloc_free(state->loadfile);
+ state->loadfile = NULL;
+
+ if (!test_finished) {
+ test_offline(state);
+ }
+}
+
+
+/*
+ called when a savefile completes
+ */
+static void savefile_callback(struct composite_context *ctx)
+{
+ struct offline_state *state = ctx->async.private_data;
+ NTSTATUS status;
+
+ status = smb_composite_savefile_recv(ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to save file '%s' - %s\n",
+ state->savefile->in.fname, nt_errstr(status));
+ test_failed++;
+ }
+
+ state->count++;
+ talloc_free(state->savefile);
+ state->savefile = NULL;
+
+ if (!test_finished) {
+ test_offline(state);
+ }
+}
+
+
+/*
+ called when a setoffline completes
+ */
+static void setoffline_callback(struct smbcli_request *req)
+{
+ struct offline_state *state = req->async.private_data;
+ NTSTATUS status;
+
+ status = smbcli_request_simple_recv(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to set offline file '%s' - %s\n",
+ state->fname, nt_errstr(status));
+ test_failed++;
+ }
+
+ state->req = NULL;
+ state->count++;
+
+ if (!test_finished) {
+ test_offline(state);
+ }
+}
+
+
+/*
+ called when a getoffline completes
+ */
+static void getoffline_callback(struct smbcli_request *req)
+{
+ struct offline_state *state = req->async.private_data;
+ NTSTATUS status;
+ union smb_fileinfo io;
+
+ ZERO_STRUCT(io);
+
+ io.getattr.level = RAW_FILEINFO_GETATTR;
+
+ status = smb_raw_pathinfo_recv(req, state->mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to get offline file '%s' - %s\n",
+ state->fname, nt_errstr(status));
+ test_failed++;
+ }
+
+ if (io.getattr.out.attrib & FILE_ATTRIBUTE_OFFLINE) {
+ state->offline_count++;
+ } else {
+ state->online_count++;
+ }
+
+ state->req = NULL;
+ state->count++;
+
+ if (!test_finished) {
+ test_offline(state);
+ }
+}
+
+
+/*
+ send the next offline file fetch request
+*/
+static void test_offline(struct offline_state *state)
+{
+ struct composite_context *ctx;
+ double lat;
+
+ lat = timeval_elapsed(&state->tv_start);
+ if (latencies[state->op] < lat) {
+ latencies[state->op] = lat;
+ }
+
+ state->op = (enum offline_op) (random() % OP_ENDOFLIST);
+
+ state->fnumber = random() % torture_numops;
+ talloc_free(state->fname);
+ state->fname = filename(state->mem_ctx, state->fnumber);
+
+ state->tv_start = timeval_current();
+
+ switch (state->op) {
+ case OP_LOADFILE:
+ state->loadfile = talloc_zero(state->mem_ctx, struct smb_composite_loadfile);
+ state->loadfile->in.fname = state->fname;
+
+ ctx = smb_composite_loadfile_send(state->tree, state->loadfile);
+ if (ctx == NULL) {
+ printf("Failed to setup loadfile for %s\n", state->fname);
+ test_failed = true;
+ }
+
+ talloc_steal(state->loadfile, ctx);
+
+ ctx->async.fn = loadfile_callback;
+ ctx->async.private_data = state;
+ break;
+
+ case OP_SAVEFILE:
+ state->savefile = talloc_zero(state->mem_ctx, struct smb_composite_savefile);
+
+ state->savefile->in.fname = state->fname;
+ state->savefile->in.data = talloc_size(state->savefile, FILE_SIZE);
+ state->savefile->in.size = FILE_SIZE;
+ memset(state->savefile->in.data, 1+(state->fnumber%255), FILE_SIZE);
+
+ ctx = smb_composite_savefile_send(state->tree, state->savefile);
+ if (ctx == NULL) {
+ printf("Failed to setup savefile for %s\n", state->fname);
+ test_failed = true;
+ }
+
+ talloc_steal(state->savefile, ctx);
+
+ ctx->async.fn = savefile_callback;
+ ctx->async.private_data = state;
+ break;
+
+ case OP_SETOFFLINE: {
+ union smb_setfileinfo io;
+ ZERO_STRUCT(io);
+ io.setattr.level = RAW_SFILEINFO_SETATTR;
+ io.setattr.in.attrib = FILE_ATTRIBUTE_OFFLINE;
+ io.setattr.in.file.path = state->fname;
+ /* make the file 1 hour old, to get past minimum age restrictions
+ for HSM systems */
+ io.setattr.in.write_time = time(NULL) - 60*60;
+
+ state->req = smb_raw_setpathinfo_send(state->tree, &io);
+ if (state->req == NULL) {
+ printf("Failed to setup setoffline for %s\n", state->fname);
+ test_failed = true;
+ }
+
+ state->req->async.fn = setoffline_callback;
+ state->req->async.private_data = state;
+ break;
+ }
+
+ case OP_GETOFFLINE: {
+ union smb_fileinfo io;
+ ZERO_STRUCT(io);
+ io.getattr.level = RAW_FILEINFO_GETATTR;
+ io.getattr.in.file.path = state->fname;
+
+ state->req = smb_raw_pathinfo_send(state->tree, &io);
+ if (state->req == NULL) {
+ printf("Failed to setup getoffline for %s\n", state->fname);
+ test_failed = true;
+ }
+
+ state->req->async.fn = getoffline_callback;
+ state->req->async.private_data = state;
+ break;
+ }
+
+ default:
+ printf("bad operation??\n");
+ break;
+ }
+}
+
+
+
+
+static void echo_completion(struct smbcli_request *req)
+{
+ struct offline_state *state = (struct offline_state *)req->async.private_data;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("lost connection\n"));
+ test_failed++;
+ }
+}
+
+static void report_rate(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct offline_state *state = talloc_get_type(private_data,
+ struct offline_state);
+ int i;
+ uint32_t total=0, total_offline=0, total_online=0;
+ for (i=0;i<numstates;i++) {
+ total += state[i].count - state[i].lastcount;
+ if (timeval_elapsed(&state[i].tv_start) > latencies[state[i].op]) {
+ latencies[state[i].op] = timeval_elapsed(&state[i].tv_start);
+ }
+ state[i].lastcount = state[i].count;
+ total_online += state[i].online_count;
+ total_offline += state[i].offline_count;
+ }
+ printf("ops/s=%4u offline=%5u online=%4u set_lat=%.1f/%.1f get_lat=%.1f/%.1f save_lat=%.1f/%.1f load_lat=%.1f/%.1f\n",
+ total, total_offline, total_online,
+ latencies[OP_SETOFFLINE],
+ worst_latencies[OP_SETOFFLINE],
+ latencies[OP_GETOFFLINE],
+ worst_latencies[OP_GETOFFLINE],
+ latencies[OP_SAVEFILE],
+ worst_latencies[OP_SAVEFILE],
+ latencies[OP_LOADFILE],
+ worst_latencies[OP_LOADFILE]);
+ fflush(stdout);
+ tevent_add_timer(ev, state, timeval_current_ofs(1, 0), report_rate, state);
+
+ for (i=0;i<OP_ENDOFLIST;i++) {
+ if (latencies[i] > worst_latencies[i]) {
+ worst_latencies[i] = latencies[i];
+ }
+ latencies[i] = 0;
+ }
+
+ /* send an echo on each interface to ensure it stays alive - this helps
+ with IP takeover */
+ for (i=0;i<numstates;i++) {
+ struct smb_echo p;
+ struct smbcli_request *req;
+
+ if (!state[i].tree) {
+ continue;
+ }
+
+ p.in.repeat_count = 1;
+ p.in.size = 0;
+ p.in.data = NULL;
+ req = smb_raw_echo_send(state[i].tree->session->transport, &p);
+ req->async.private_data = &state[i];
+ req->async.fn = echo_completion;
+ }
+}
+
+/*
+ test offline file handling
+*/
+bool torture_test_offline(struct torture_context *torture)
+{
+ bool ret = true;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ int i;
+ int timelimit = torture_setting_int(torture, "timelimit", 10);
+ struct timeval tv;
+ struct offline_state *state;
+ struct smbcli_state *cli;
+ bool progress;
+ progress = torture_setting_bool(torture, "progress", true);
+
+ nconnections = torture_setting_int(torture, "nprocs", 4);
+ numstates = nconnections * torture_entries;
+
+ state = talloc_zero_array(mem_ctx, struct offline_state, numstates);
+
+ printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections, numstates, torture_numops);
+ for (i=0;i<nconnections;i++) {
+ state[i].tctx = torture;
+ state[i].mem_ctx = talloc_new(state);
+ state[i].ev = torture->ev;
+ if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) {
+ return false;
+ }
+ state[i].tree = cli->tree;
+ state[i].client = i;
+ /* allow more time for offline files */
+ state[i].tree->session->transport->options.request_timeout = 200;
+ }
+
+ /* the others are repeats on the earlier connections */
+ for (i=nconnections;i<numstates;i++) {
+ state[i].tctx = torture;
+ state[i].mem_ctx = talloc_new(state);
+ state[i].ev = torture->ev;
+ state[i].tree = state[i % nconnections].tree;
+ state[i].client = i;
+ }
+
+ num_connected = i;
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ goto failed;
+ }
+
+ /* pre-create files */
+ printf("Pre-creating %u files ....\n", torture_numops);
+ for (i=0;i<torture_numops;i++) {
+ int fnum;
+ char *fname = filename(mem_ctx, i);
+ char buf[FILE_SIZE];
+ NTSTATUS status;
+
+ memset(buf, 1+(i % 255), sizeof(buf));
+
+ fnum = smbcli_open(state[0].tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to open %s on connection %d\n", fname, i);
+ goto failed;
+ }
+
+ if (smbcli_write(state[0].tree, fnum, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
+ printf("Failed to write file of size %u\n", FILE_SIZE);
+ goto failed;
+ }
+
+ status = smbcli_close(state[0].tree, fnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+
+ talloc_free(fname);
+ }
+
+ /* start the async ops */
+ for (i=0;i<numstates;i++) {
+ state[i].tv_start = timeval_current();
+ test_offline(&state[i]);
+ }
+
+ tv = timeval_current();
+
+ if (progress) {
+ tevent_add_timer(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state);
+ }
+
+ printf("Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ tevent_loop_once(torture->ev);
+
+ if (test_failed) {
+ DEBUG(0,("test failed\n"));
+ goto failed;
+ }
+ }
+
+ printf("\nWaiting for completion\n");
+ test_finished = true;
+ for (i=0;i<numstates;i++) {
+ while (state[i].loadfile ||
+ state[i].savefile ||
+ state[i].req) {
+ tevent_loop_once(torture->ev);
+ }
+ }
+
+ printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
+ worst_latencies[OP_SETOFFLINE],
+ worst_latencies[OP_GETOFFLINE],
+ worst_latencies[OP_SAVEFILE],
+ worst_latencies[OP_LOADFILE]);
+
+ smbcli_deltree(state[0].tree, BASEDIR);
+ talloc_free(mem_ctx);
+ printf("\n");
+ return ret;
+
+failed:
+ talloc_free(mem_ctx);
+ return false;
+}
diff --git a/source4/torture/raw/open.c b/source4/torture/raw/open.c
new file mode 100644
index 0000000..697079c
--- /dev/null
+++ b/source4/torture/raw/open.c
@@ -0,0 +1,2253 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_OPEN_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "lib/events/events.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+/* enum for whether reads/writes are possible on a file */
+enum rdwr_mode {RDWR_NONE, RDWR_RDONLY, RDWR_WRONLY, RDWR_RDWR};
+
+#define BASEDIR "\\rawopen"
+
+/*
+ check if a open file can be read/written
+*/
+static enum rdwr_mode check_rdwr(struct smbcli_tree *tree, int fnum)
+{
+ uint8_t c = 1;
+ bool can_read = (smbcli_read(tree, fnum, &c, 0, 1) == 1);
+ bool can_write = (smbcli_write(tree, fnum, 0, &c, 0, 1) == 1);
+ if ( can_read && can_write) return RDWR_RDWR;
+ if ( can_read && !can_write) return RDWR_RDONLY;
+ if (!can_read && can_write) return RDWR_WRONLY;
+ return RDWR_NONE;
+}
+
+/*
+ describe a RDWR mode as a string
+*/
+static const char *rdwr_string(enum rdwr_mode m)
+{
+ switch (m) {
+ case RDWR_NONE: return "NONE";
+ case RDWR_RDONLY: return "RDONLY";
+ case RDWR_WRONLY: return "WRONLY";
+ case RDWR_RDWR: return "RDWR";
+ }
+ return "-";
+}
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CREATE_FILE do { \
+ fnum = create_complex_file(cli, tctx, fname); \
+ if (fnum == -1) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Failed to create %s - %s\n", \
+ __location__, fname, smbcli_errstr(cli->tree)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_RDWR(fnum, correct) do { \
+ enum rdwr_mode m = check_rdwr(cli->tree, fnum); \
+ if (m != correct) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect readwrite mode %s - expected %s\n", \
+ __location__, rdwr_string(m), rdwr_string(correct)); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_TIME(t, field) do { \
+ time_t t1, t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.file.path = fname; \
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t1 = t & ~1; \
+ t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
+ if (labs(t1-t2) > 2) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong time for field %s %s - %s\n", \
+ __location__, #field, \
+ timestring(tctx, t1), \
+ timestring(tctx, t2)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_NTTIME(t, field) do { \
+ NTTIME t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.file.path = fname; \
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t2 = finfo.all_info.out.field; \
+ if (llabs((int64_t)(t-t2)) > 20000) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong time for field %s %s - %s\n", \
+ __location__, #field, \
+ nt_time_string(tctx, t), \
+ nt_time_string(tctx, t2)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_ALL_INFO(v, field) do { \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.file.path = fname; \
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if ((v) != (finfo.all_info.out.field)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for field %s 0x%x - 0x%x\n", \
+ __location__, #field, (unsigned int)(v), (unsigned int)(finfo.all_info.out.field)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
+ __location__, #v, (unsigned int)(v), (unsigned int)(correct)); \
+ ret = false; \
+ }} while (0)
+
+#define SET_ATTRIB(sattrib) do { \
+ union smb_setfileinfo sfinfo; \
+ ZERO_STRUCT(sfinfo.basic_info.in); \
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
+ sfinfo.basic_info.in.file.path = fname; \
+ sfinfo.basic_info.in.attrib = sattrib; \
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_warning(tctx, "(%s) Failed to set attrib 0x%x on %s\n", \
+ __location__, (unsigned int)(sattrib), fname); \
+ }} while (0)
+
+/*
+ test RAW_OPEN_OPEN
+*/
+static bool test_open(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_open.txt";
+ NTSTATUS status;
+ int fnum = -1, fnum2;
+ bool ret = true;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.openold.level = RAW_OPEN_OPEN;
+ io.openold.in.fname = fname;
+ io.openold.in.open_mode = OPEN_FLAGS_FCB;
+ io.openold.in.search_attrs = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ fnum = io.openold.out.file.fnum;
+
+ smbcli_unlink(cli->tree, fname);
+ CREATE_FILE;
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum, RDWR_RDWR);
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum2, RDWR_RDWR);
+ smbcli_close(cli->tree, fnum2);
+ smbcli_close(cli->tree, fnum);
+
+ /* check the read/write modes */
+ io.openold.level = RAW_OPEN_OPEN;
+ io.openold.in.fname = fname;
+ io.openold.in.search_attrs = 0;
+
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum, RDWR_RDONLY);
+ smbcli_close(cli->tree, fnum);
+
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum, RDWR_WRONLY);
+ smbcli_close(cli->tree, fnum);
+
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum, RDWR_RDWR);
+ smbcli_close(cli->tree, fnum);
+
+ /* check the share modes roughly - not a complete matrix */
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum, RDWR_RDWR);
+
+ if (io.openold.in.open_mode != io.openold.out.rmode) {
+ torture_warning(tctx, "(%s) rmode should equal open_mode - 0x%x 0x%x\n",
+ __location__, io.openold.out.rmode, io.openold.in.open_mode);
+ }
+
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_NONE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ | OPEN_FLAGS_DENY_NONE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.openold.out.file.fnum;
+ CHECK_RDWR(fnum2, RDWR_RDONLY);
+ smbcli_close(cli->tree, fnum);
+ smbcli_close(cli->tree, fnum2);
+
+
+ /* check the returned write time */
+ io.openold.level = RAW_OPEN_OPEN;
+ io.openold.in.fname = fname;
+ io.openold.in.search_attrs = 0;
+ io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openold.out.file.fnum;
+
+ /* check other reply fields */
+ CHECK_TIME(io.openold.out.write_time, write_time);
+ CHECK_ALL_INFO(io.openold.out.size, size);
+ CHECK_ALL_INFO(io.openold.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_OPENX
+*/
+static bool test_openx(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_openx.txt";
+ const char *fname_exe = BASEDIR "\\torture_openx.exe";
+ NTSTATUS status;
+ int fnum = -1, fnum2;
+ bool ret = true;
+ int i;
+ struct timeval tv;
+ struct {
+ uint16_t open_func;
+ bool with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { OPENX_OPEN_FUNC_OPEN, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, false, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_FAIL, true, NT_STATUS_DOS(ERRDOS, ERRbadaccess) },
+ { OPENX_OPEN_FUNC_FAIL, false, NT_STATUS_DOS(ERRDOS, ERRbadaccess) },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, false, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, false, NT_STATUS_OK },
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.fname = fname;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 1024*1024;
+ io.openx.in.timeout = 0;
+
+ /* check all combinations of open_func */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ fnum = create_complex_file(cli, tctx, fname);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to create file %s - %s\n",
+ fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+ }
+ io.openx.in.open_func = open_funcs[i].open_func;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) incorrect status %s should be %s "
+ "(i=%d with_file=%d open_func=0x%x)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file,
+ open_funcs[i].open_func);
+ ret = false;
+ }
+ if (NT_STATUS_IS_OK(status)) {
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+ }
+ if (open_funcs[i].with_file) {
+ smbcli_unlink(cli->tree, fname);
+ }
+ }
+
+ smbcli_unlink(cli->tree, fname);
+
+ /* check the basic return fields */
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.file.fnum;
+
+ CHECK_ALL_INFO(io.openx.out.size, size);
+ CHECK_TIME(io.openx.out.write_time, write_time);
+ CHECK_ALL_INFO(io.openx.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
+ CHECK_VAL(io.openx.out.access, OPENX_MODE_ACCESS_RDWR);
+ CHECK_VAL(io.openx.out.ftype, 0);
+ CHECK_VAL(io.openx.out.devstate, 0);
+ CHECK_VAL(io.openx.out.action, OPENX_ACTION_CREATED);
+ CHECK_VAL(io.openx.out.size, 1024*1024);
+ CHECK_ALL_INFO(io.openx.in.size, size);
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* check the fields when the file already existed */
+ fnum2 = create_complex_file(cli, tctx, fname);
+ if (fnum2 == -1) {
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum2);
+
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.file.fnum;
+
+ CHECK_ALL_INFO(io.openx.out.size, size);
+ CHECK_TIME(io.openx.out.write_time, write_time);
+ CHECK_VAL(io.openx.out.action, OPENX_ACTION_EXISTED);
+ CHECK_VAL(io.openx.out.unknown, 0);
+ CHECK_ALL_INFO(io.openx.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
+ smbcli_close(cli->tree, fnum);
+
+ /* now check the search attrib for hidden files - win2003 ignores this? */
+ SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN, attrib);
+
+ io.openx.in.search_attrs = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+
+ io.openx.in.search_attrs = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+
+ SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
+ smbcli_unlink(cli->tree, fname);
+
+ /* and check attrib on create */
+ io.openx.in.open_func = OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE,
+ attrib & ~(FILE_ATTRIBUTE_NONINDEXED|
+ FILE_ATTRIBUTE_SPARSE));
+ }
+ else {
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE,
+ attrib & ~(FILE_ATTRIBUTE_NONINDEXED));
+ }
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* check timeout on create - win2003 ignores the timeout! */
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.file.fnum;
+
+ io.openx.in.timeout = 20000;
+ tv = timeval_current();
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_NONE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+ if (timeval_elapsed(&tv) > 3.0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Incorrect timing in openx with timeout "
+ "- waited %.2f seconds\n",
+ __location__, timeval_elapsed(&tv));
+ ret = false;
+ }
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* now this is a really weird one - open for execute implies create?! */
+ io.openx.in.fname = fname;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_EXEC | OPENX_MODE_DENY_NONE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_FAIL;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 0;
+ io.openx.in.timeout = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+
+ /* check the extended return flag */
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO | OPENX_FLAGS_EXTENDED_RETURN;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.openx.out.access_mask, SEC_STD_ALL);
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+
+ io.openx.in.fname = "\\A.+,;=[].B";
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* Check the mapping for open exec. */
+
+ /* First create an .exe file. */
+ smbcli_unlink(cli->tree, fname_exe);
+ fnum = create_complex_file(cli, tctx, fname_exe);
+ smbcli_close(cli->tree, fnum);
+
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.fname = fname_exe;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_EXEC | OPENX_MODE_DENY_NONE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 0;
+ io.openx.in.timeout = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Can we read and write ? */
+ CHECK_RDWR(io.openx.out.file.fnum, RDWR_RDONLY);
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+ smbcli_unlink(cli->tree, fname);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_T2OPEN
+
+ many thanks to kukks for a sniff showing how this works with os2->w2k
+*/
+static bool test_t2open(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname1 = BASEDIR "\\torture_t2open_yes.txt";
+ const char *fname2 = BASEDIR "\\torture_t2open_no.txt";
+ const char *fname = BASEDIR "\\torture_t2open_3.txt";
+ NTSTATUS status;
+ int fnum;
+ bool ret = true;
+ int i;
+ struct {
+ uint16_t open_func;
+ bool with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { OPENX_OPEN_FUNC_OPEN, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE, false, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_FAIL, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL, false, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE, false, NT_STATUS_OBJECT_NAME_COLLISION },
+ { OPENX_OPEN_FUNC_TRUNC, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC, false, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, true, NT_STATUS_OK },
+ { OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE, false, NT_STATUS_OK },
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum = create_complex_file(cli, tctx, fname1);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): Failed to create file %s - %s\n",
+ __location__, fname1, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ io.t2open.level = RAW_OPEN_T2OPEN;
+ io.t2open.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.t2open.in.open_mode = OPENX_MODE_DENY_NONE | OPENX_MODE_ACCESS_RDWR;
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.search_attrs = 0;
+ io.t2open.in.file_attrs = 0;
+ io.t2open.in.write_time = 0;
+ io.t2open.in.size = 0;
+ io.t2open.in.timeout = 0;
+
+ io.t2open.in.num_eas = 3;
+ io.t2open.in.eas = talloc_array(tctx, struct ea_struct, io.t2open.in.num_eas);
+ io.t2open.in.eas[0].flags = 0;
+ io.t2open.in.eas[0].name.s = ".CLASSINFO";
+ io.t2open.in.eas[0].value = data_blob_talloc(tctx, "first value", 11);
+ io.t2open.in.eas[1].flags = 0;
+ io.t2open.in.eas[1].name.s = "EA TWO";
+ io.t2open.in.eas[1].value = data_blob_talloc(tctx, "foo", 3);
+ io.t2open.in.eas[2].flags = 0;
+ io.t2open.in.eas[2].name.s = "X THIRD";
+ io.t2open.in.eas[2].value = data_blob_talloc(tctx, "xy", 2);
+
+ /* check all combinations of open_func */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ again:
+ if (open_funcs[i].with_file) {
+ io.t2open.in.fname = fname1;
+ } else {
+ io.t2open.in.fname = fname2;
+ }
+ io.t2open.in.open_func = open_funcs[i].open_func;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if ((io.t2open.in.num_eas != 0)
+ && NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)
+ && torture_setting_bool(tctx, "samba3", false)) {
+ torture_warning(tctx, "(%s) EAs not supported, not "
+ "treating as fatal in Samba3 test\n",
+ __location__);
+ io.t2open.in.num_eas = 0;
+ goto again;
+ }
+
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) incorrect status %s should be %s "
+ "(i=%d with_file=%d open_func=0x%x)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file,
+ open_funcs[i].open_func);
+ ret = false;
+ }
+ if (NT_STATUS_IS_OK(status)) {
+ smbcli_close(cli->tree, io.t2open.out.file.fnum);
+ }
+ }
+
+ smbcli_unlink(cli->tree, fname1);
+ smbcli_unlink(cli->tree, fname2);
+
+ /* check the basic return fields */
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.write_time = 0;
+ io.t2open.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.t2open.out.file.fnum;
+
+ CHECK_ALL_INFO(io.t2open.out.size, size);
+#if 0
+ /* windows appears to leak uninitialised memory here */
+ CHECK_VAL(io.t2open.out.write_time, 0);
+#endif
+ CHECK_ALL_INFO(io.t2open.out.attrib, attrib & ~FILE_ATTRIBUTE_NONINDEXED);
+ CHECK_VAL(io.t2open.out.access, OPENX_MODE_DENY_NONE | OPENX_MODE_ACCESS_RDWR);
+ CHECK_VAL(io.t2open.out.ftype, 0);
+ CHECK_VAL(io.t2open.out.devstate, 0);
+ CHECK_VAL(io.t2open.out.action, OPENX_ACTION_CREATED);
+ smbcli_close(cli->tree, fnum);
+
+ status = torture_check_ea(cli, fname, ".CLASSINFO", "first value");
+ CHECK_STATUS(status, io.t2open.in.num_eas
+ ? NT_STATUS_OK : NT_STATUS_EAS_NOT_SUPPORTED);
+ status = torture_check_ea(cli, fname, "EA TWO", "foo");
+ CHECK_STATUS(status, io.t2open.in.num_eas
+ ? NT_STATUS_OK : NT_STATUS_EAS_NOT_SUPPORTED);
+ status = torture_check_ea(cli, fname, "X THIRD", "xy");
+ CHECK_STATUS(status, io.t2open.in.num_eas
+ ? NT_STATUS_OK : NT_STATUS_EAS_NOT_SUPPORTED);
+
+ /* now check the search attrib for hidden files - win2003 ignores this? */
+ SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN, attrib);
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.t2open.out.file.fnum);
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.t2open.out.file.fnum);
+
+ SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
+ smbcli_unlink(cli->tree, fname);
+
+ /* and check attrib on create */
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* check timeout on create - win2003 ignores the timeout! */
+ io.t2open.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+ io.t2open.in.file_attrs = 0;
+ io.t2open.in.timeout = 20000;
+ io.t2open.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_NTCREATEX
+*/
+static bool test_ntcreatex(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_ntcreatex.txt";
+ const char *dname = BASEDIR "\\torture_ntcreatex.dir";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ int i;
+ struct {
+ uint32_t open_disp;
+ bool with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { NTCREATEX_DISP_SUPERSEDE, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_SUPERSEDE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { NTCREATEX_DISP_CREATE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_OVERWRITE_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE_IF, false, NT_STATUS_OK },
+ { 6, true, NT_STATUS_INVALID_PARAMETER },
+ { 6, false, NT_STATUS_INVALID_PARAMETER },
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* reasonable default parameters */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 1024*1024;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* test the open disposition */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to create file %s - %s\n",
+ fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+ }
+ io.ntcreatex.in.open_disposition = open_funcs[i].open_disp;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) incorrect status %s should be %s "
+ "(i=%d with_file=%d open_disp=%d)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file,
+ (int)open_funcs[i].open_disp);
+ ret = false;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ smbcli_unlink(cli->tree, fname);
+ }
+ }
+
+ /* basic field testing */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+
+ /* check fields when the file already existed */
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ fnum = create_complex_file(cli, tctx, fname);
+ if (fnum == -1) {
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+
+ /* create a directory */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.fname = dname;
+ fname = dname;
+
+ smbcli_rmdir(cli->tree, fname);
+ smbcli_unlink(cli->tree, fname);
+
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_VAL(io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.is_directory, 1);
+ CHECK_VAL(io.ntcreatex.out.size, 0);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ smbcli_unlink(cli->tree, fname);
+
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_NTTRANS_CREATE
+*/
+static bool test_nttrans_create(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_ntcreatex.txt";
+ const char *dname = BASEDIR "\\torture_ntcreatex.dir";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ int i;
+ uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
+ uint32_t not_a_directory_mask, unexpected_mask;
+ struct {
+ uint32_t open_disp;
+ bool with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { NTCREATEX_DISP_SUPERSEDE, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_SUPERSEDE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { NTCREATEX_DISP_CREATE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_OVERWRITE_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE_IF, false, NT_STATUS_OK },
+ { 6, true, NT_STATUS_INVALID_PARAMETER },
+ { 6, false, NT_STATUS_INVALID_PARAMETER },
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* reasonable default parameters */
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 1024*1024;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.sec_desc = NULL;
+ io.ntcreatex.in.ea_list = NULL;
+
+ /* test the open disposition */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to create file %s - %s\n",
+ fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+ }
+ io.ntcreatex.in.open_disposition = open_funcs[i].open_disp;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) incorrect status %s should be %s "
+ "(i=%d with_file=%d open_disp=%d)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file,
+ (int)open_funcs[i].open_disp);
+ ret = false;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ smbcli_unlink(cli->tree, fname);
+ }
+ }
+
+ /* basic field testing */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+
+ /* check fields when the file already existed */
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ fnum = create_complex_file(cli, tctx, fname);
+ if (fnum == -1) {
+ ret = false;
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ smbcli_close(cli->tree, fnum);
+
+ /* check no-recall - don't pull a file from tape on a HSM */
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NO_RECALL;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ smbcli_close(cli->tree, fnum);
+
+ /* Check some create options (these all should be ignored) */
+ for (i=0; i < 32; i++) {
+ uint32_t create_option =
+ ((uint32_t)1 << i) & NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
+ if (create_option == 0) {
+ continue;
+ }
+ io.ntcreatex.in.create_options = create_option;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "ntcreatex create option 0x%08x "
+ "gave %s - should give NT_STATUS_OK\n",
+ create_option, nt_errstr(status));
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ smbcli_close(cli->tree, fnum);
+ }
+
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ /* Check for options that should return NOT_SUPPORTED, OK or INVALID_PARAMETER */
+ ok_mask = 0;
+ not_supported_mask = 0;
+ invalid_parameter_mask = 0;
+ not_a_directory_mask = 0;
+ unexpected_mask = 0;
+ for (i=0; i < 32; i++) {
+ uint32_t create_option = (uint32_t)1<<i;
+ if (create_option & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
+ continue;
+ }
+ io.ntcreatex.in.create_options = create_option;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ not_supported_mask |= create_option;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ ok_mask |= create_option;
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ invalid_parameter_mask |= create_option;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
+ not_a_directory_mask |= 1<<i;
+ } else {
+ unexpected_mask |= 1<<i;
+ torture_comment(tctx, "create option 0x%08x returned %s\n",
+ create_option, nt_errstr(status));
+ }
+ }
+
+ CHECK_VAL(ok_mask, 0x00efcfce);
+ CHECK_VAL(not_a_directory_mask, 0x00000001);
+ CHECK_VAL(not_supported_mask, 0x00002000);
+ CHECK_VAL(invalid_parameter_mask, 0xff100030);
+ CHECK_VAL(unexpected_mask, 0x00000000);
+
+ smbcli_unlink(cli->tree, fname);
+
+
+ /* create a directory */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.fname = dname;
+ fname = dname;
+
+ smbcli_rmdir(cli->tree, fname);
+ smbcli_unlink(cli->tree, fname);
+
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_VAL(io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.is_directory, 1);
+ CHECK_VAL(io.ntcreatex.out.size, 0);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+ smbcli_unlink(cli->tree, fname);
+
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ test RAW_OPEN_NTCREATEX with an already opened and byte range locked file
+
+ I've got an application that does a similar sequence of ntcreate&x,
+ locking&x and another ntcreate&x with
+ open_disposition==NTCREATEX_DISP_OVERWRITE_IF. Windows 2003 allows the
+ second open.
+*/
+static bool test_ntcreatex_brlocked(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io, io1;
+ union smb_lock io2;
+ struct smb_lock_entry lock[1];
+ const char *fname = BASEDIR "\\torture_ntcreatex.txt";
+ NTSTATUS status;
+ bool ret = true;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing ntcreatex with a byte range locked file\n");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = 0x2019f;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.ntcreatex.in.security_flags = NTCREATEX_SECURITY_DYNAMIC |
+ NTCREATEX_SECURITY_ALL;
+ io.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io2.lockx.level = RAW_LOCK_LOCKX;
+ io2.lockx.in.file.fnum = io.ntcreatex.out.file.fnum;
+ io2.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io2.lockx.in.timeout = 0;
+ io2.lockx.in.ulock_cnt = 0;
+ io2.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = 0;
+ lock[0].count = 0x1;
+ io2.lockx.in.locks = &lock[0];
+ status = smb_raw_lock(cli->tree, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io1.generic.level = RAW_OPEN_NTCREATEX;
+ io1.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io1.ntcreatex.in.root_fid.fnum = 0;
+ io1.ntcreatex.in.access_mask = 0x20196;
+ io1.ntcreatex.in.alloc_size = 0;
+ io1.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io1.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io1.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io1.ntcreatex.in.create_options = 0;
+ io1.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io1.ntcreatex.in.security_flags = NTCREATEX_SECURITY_DYNAMIC |
+ NTCREATEX_SECURITY_ALL;
+ io1.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, tctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ smbcli_close(cli->tree, io1.ntcreatex.out.file.fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test RAW_OPEN_MKNEW
+*/
+static bool test_mknew(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_mknew.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ time_t basetime = (time(NULL) + 3600*24*3) & ~1;
+ union smb_fileinfo finfo;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.mknew.level = RAW_OPEN_MKNEW;
+ io.mknew.in.attrib = 0;
+ io.mknew.in.write_time = 0;
+ io.mknew.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.mknew.out.file.fnum;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* make sure write_time works */
+ io.mknew.in.write_time = basetime;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.mknew.out.file.fnum;
+ CHECK_TIME(basetime, write_time);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* make sure file_attrs works */
+ io.mknew.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.mknew.out.file.fnum;
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE,
+ attrib & ~FILE_ATTRIBUTE_NONINDEXED);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_CREATE
+*/
+static bool test_create(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_create.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ time_t basetime = (time(NULL) + 3600*24*3) & ~1;
+ union smb_fileinfo finfo;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.create.level = RAW_OPEN_CREATE;
+ io.create.in.attrib = 0;
+ io.create.in.write_time = 0;
+ io.create.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.create.out.file.fnum;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, io.create.out.file.fnum);
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* make sure write_time works */
+ io.create.in.write_time = basetime;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.create.out.file.fnum;
+ CHECK_TIME(basetime, write_time);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ /* make sure file_attrs works */
+ io.create.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.create.out.file.fnum;
+ CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE,
+ attrib & ~FILE_ATTRIBUTE_NONINDEXED);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test RAW_OPEN_CTEMP
+*/
+static bool test_ctemp(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ time_t basetime = (time(NULL) + 3600*24*3) & ~1;
+ union smb_fileinfo finfo;
+ const char *name, *fname = NULL;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ io.ctemp.level = RAW_OPEN_CTEMP;
+ io.ctemp.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ io.ctemp.in.write_time = basetime;
+ io.ctemp.in.directory = BASEDIR;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ctemp.out.file.fnum;
+
+ name = io.ctemp.out.name;
+
+ finfo.generic.level = RAW_FILEINFO_NAME_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fname = finfo.name_info.out.fname.s;
+ torture_comment(tctx, "ctemp name=%s real name=%s\n", name, fname);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ test chained RAW_OPEN_OPENX_READX
+*/
+static bool test_chained(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_chained.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ const char buf[] = "test";
+ char buf2[4];
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fnum = create_complex_file(cli, tctx, fname);
+
+ smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+
+ smbcli_close(cli->tree, fnum);
+
+ io.openxreadx.level = RAW_OPEN_OPENX_READX;
+ io.openxreadx.in.fname = fname;
+ io.openxreadx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openxreadx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ io.openxreadx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ io.openxreadx.in.search_attrs = 0;
+ io.openxreadx.in.file_attrs = 0;
+ io.openxreadx.in.write_time = 0;
+ io.openxreadx.in.size = 1024*1024;
+ io.openxreadx.in.timeout = 0;
+
+ io.openxreadx.in.offset = 0;
+ io.openxreadx.in.mincnt = sizeof(buf2);
+ io.openxreadx.in.maxcnt = sizeof(buf2);
+ io.openxreadx.in.remaining = 0;
+ io.openxreadx.out.data = (uint8_t *)buf2;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openxreadx.out.file.fnum;
+
+ if (memcmp(buf, buf2, MIN(sizeof(buf), sizeof(buf2))) != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "wrong data in reply buffer\n");
+ ret = false;
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ test RAW_OPEN_OPENX without a leading slash on the path.
+ NetApp filers are known to fail on this.
+
+*/
+static bool test_no_leading_slash(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_no_leading_slash.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ const char buf[] = "test";
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ smbcli_unlink(cli->tree, fname);
+
+ /* Create the file */
+ fnum = create_complex_file(cli, tctx, fname);
+ smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+ smbcli_close(cli->tree, fnum);
+
+ /* Prepare to open the file using path without leading slash */
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.fname = fname + 1;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 1024*1024;
+ io.openx.in.timeout = 0;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.openx.out.file.fnum;
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ test RAW_OPEN_OPENX against an existing directory to
+ ensure it returns NT_STATUS_FILE_IS_A_DIRECTORY.
+ Samba 3.2.0 - 3.2.6 are known to fail this.
+
+*/
+static bool test_openx_over_dir(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\openx_over_dir";
+ NTSTATUS status;
+ int d_fnum = -1;
+ int fnum = -1;
+ bool ret = true;
+
+ ZERO_STRUCT(io);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* Create the Directory */
+ status = create_directory_handle(cli->tree, fname, &d_fnum);
+ smbcli_close(cli->tree, d_fnum);
+
+ /* Prepare to open the file over the directory. */
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.fname = fname;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 1024*1024;
+ io.openx.in.timeout = 0;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+ fnum = io.openx.out.file.fnum;
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
+
+static bool test_raw_open_multi(struct torture_context *tctx, struct smbcli_state *cli_ignored)
+{
+ struct smbcli_state *cli;
+ TALLOC_CTX *mem_ctx = talloc_init("torture_test_oplock_multi");
+ const char *fname = "\\test_oplock.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smbcli_state **clients;
+ struct smbcli_request **requests;
+ union smb_open *ios;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ int i, num_files = 3;
+ int num_ok = 0;
+ int num_collision = 0;
+
+ clients = talloc_array(mem_ctx, struct smbcli_state *, num_files);
+ requests = talloc_array(mem_ctx, struct smbcli_request *, num_files);
+ ios = talloc_array(mem_ctx, union smb_open, num_files);
+ if ((tctx->ev == NULL) || (clients == NULL) || (requests == NULL) ||
+ (ios == NULL)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s): talloc failed\n",
+ __location__);
+ return false;
+ }
+
+ if (!torture_open_connection_share(mem_ctx, &cli, tctx, host, share, tctx->ev)) {
+ return false;
+ }
+
+ cli->tree->session->transport->options.request_timeout = 60;
+
+ for (i=0; i<num_files; i++) {
+ if (!torture_open_connection_share(mem_ctx, &(clients[i]),
+ tctx, host, share, tctx->ev)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): Could not open %d'th connection\n",
+ __location__, i);
+ return false;
+ }
+ clients[i]->tree->session->transport->options.request_timeout = 60;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli->tree, fname);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+
+ for (i=0; i<num_files; i++) {
+ ios[i] = io;
+ requests[i] = smb_raw_open_send(clients[i]->tree, &ios[i]);
+ if (requests[i] == NULL) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): could not send %d'th request\n",
+ __location__, i);
+ return false;
+ }
+ }
+
+ torture_comment(tctx, "waiting for replies\n");
+ while (1) {
+ bool unreplied = false;
+ for (i=0; i<num_files; i++) {
+ if (requests[i] == NULL) {
+ continue;
+ }
+ if (requests[i]->state < SMBCLI_REQUEST_DONE) {
+ unreplied = true;
+ break;
+ }
+ status = smb_raw_open_recv(requests[i], mem_ctx,
+ &ios[i]);
+
+ torture_comment(tctx, "File %d returned status %s\n", i,
+ nt_errstr(status));
+
+ if (NT_STATUS_IS_OK(status)) {
+ num_ok += 1;
+ }
+
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_COLLISION)) {
+ num_collision += 1;
+ }
+
+ requests[i] = NULL;
+ }
+ if (!unreplied) {
+ break;
+ }
+
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): tevent_loop_once failed\n", __location__);
+ return false;
+ }
+ }
+
+ if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
+ ret = false;
+ }
+
+ for (i=0; i<num_files; i++) {
+ torture_close_connection(clients[i]);
+ }
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ test opening for delete on a read-only attribute file.
+*/
+static bool test_open_for_delete(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_open_for_delete.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* reasonable default parameters */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_READONLY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* Create the readonly file. */
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ io.ntcreatex.in.create_options = 0;
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ smbcli_close(cli->tree, fnum);
+
+ /* Now try and open for delete only - should succeed. */
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_unlink(cli->tree, fname);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ test chained RAW_OPEN_NTCREATEX_READX
+ Send chained NTCREATEX_READX on a file that doesn't exist, then create
+ the file and try again.
+*/
+static bool test_chained_ntcreatex_readx(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_chained.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+ const char buf[] = "test";
+ char buf2[4];
+
+ ZERO_STRUCT(io);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Checking RAW_NTCREATEX_READX chained on "
+ "non-existent file \n");
+
+ /* ntcreatex parameters */
+ io.generic.level = RAW_OPEN_NTCREATEX_READX;
+ io.ntcreatexreadx.in.flags = 0;
+ io.ntcreatexreadx.in.root_fid.fnum = 0;
+ io.ntcreatexreadx.in.access_mask = SEC_FILE_READ_DATA;
+ io.ntcreatexreadx.in.alloc_size = 0;
+ io.ntcreatexreadx.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatexreadx.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatexreadx.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatexreadx.in.create_options = 0;
+ io.ntcreatexreadx.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.ntcreatexreadx.in.security_flags = 0;
+ io.ntcreatexreadx.in.fname = fname;
+
+ /* readx parameters */
+ io.ntcreatexreadx.in.offset = 0;
+ io.ntcreatexreadx.in.mincnt = sizeof(buf2);
+ io.ntcreatexreadx.in.maxcnt = sizeof(buf2);
+ io.ntcreatexreadx.in.remaining = 0;
+ io.ntcreatexreadx.out.data = (uint8_t *)buf2;
+
+ /* try to open the non-existent file */
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ fnum = io.ntcreatexreadx.out.file.fnum;
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ torture_comment(tctx, "Checking RAW_NTCREATEX_READX chained on "
+ "existing file \n");
+
+ fnum = create_complex_file(cli, mem_ctx, fname);
+ smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatexreadx.out.file.fnum;
+
+ if (memcmp(buf, buf2, MIN(sizeof(buf), sizeof(buf2))) != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): wrong data in reply buffer\n", __location__);
+ ret = false;
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_ntcreatex_opendisp_dir(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *dname = BASEDIR "\\torture_ntcreatex_opendisp_dir";
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+ struct {
+ uint32_t open_disp;
+ bool dir_exists;
+ NTSTATUS correct_status;
+ } open_funcs_dir[] = {
+ { NTCREATEX_DISP_SUPERSEDE, true, NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_SUPERSEDE, false, NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_OPEN, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { NTCREATEX_DISP_CREATE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, true, NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_OVERWRITE, false, NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_OVERWRITE_IF, true, NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_OVERWRITE_IF, false, NT_STATUS_INVALID_PARAMETER },
+ { 6, true, NT_STATUS_INVALID_PARAMETER },
+ { 6, false, NT_STATUS_INVALID_PARAMETER },
+ };
+ union smb_open io;
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.fname = dname;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ smbcli_rmdir(cli->tree, dname);
+ smbcli_unlink(cli->tree, dname);
+
+ /* test the open disposition for directories */
+ torture_comment(tctx, "Testing open dispositions for directories...\n");
+
+ for (i=0; i<ARRAY_SIZE(open_funcs_dir); i++) {
+ if (open_funcs_dir[i].dir_exists) {
+ status = smbcli_mkdir(cli->tree, dname);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): Failed to make directory "
+ "%s - %s\n", __location__, dname,
+ smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ }
+
+ io.ntcreatex.in.open_disposition = open_funcs_dir[i].open_disp;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs_dir[i].correct_status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) incorrect status %s should be %s "
+ "(i=%d dir_exists=%d open_disp=%d)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs_dir[i].correct_status),
+ i, (int)open_funcs_dir[i].dir_exists,
+ (int)open_funcs_dir[i].open_disp);
+ ret = false;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs_dir[i].dir_exists) {
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ smbcli_rmdir(cli->tree, dname);
+ }
+ }
+
+done:
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/**
+ * Test what happens when trying to open a file with directory parameters and
+ * vice-versa. Also test that NTCREATEX_OPTIONS_DIRECTORY is treated as
+ * mandatory and FILE_ATTRIBUTE_DIRECTORY is advisory for directory
+ * creation/opening.
+ */
+static bool test_ntcreatexdir(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = BASEDIR "\\torture_ntcreatex.txt";
+ const char *dname = BASEDIR "\\torture_ntcreatex_dir";
+ NTSTATUS status;
+ int i;
+
+ struct {
+ uint32_t open_disp;
+ uint32_t file_attr;
+ uint32_t create_options;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { NTCREATEX_DISP_SUPERSEDE, 0, NTCREATEX_OPTIONS_DIRECTORY,
+ NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_OPEN, 0, NTCREATEX_OPTIONS_DIRECTORY,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, 0, NTCREATEX_OPTIONS_DIRECTORY,
+ NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, 0, NTCREATEX_OPTIONS_DIRECTORY,
+ NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, 0, NTCREATEX_OPTIONS_DIRECTORY,
+ NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_OVERWRITE_IF, 0, NTCREATEX_OPTIONS_DIRECTORY,
+ NT_STATUS_INVALID_PARAMETER },
+ { NTCREATEX_DISP_SUPERSEDE, FILE_ATTRIBUTE_DIRECTORY, 0,
+ NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, FILE_ATTRIBUTE_DIRECTORY, 0,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, FILE_ATTRIBUTE_DIRECTORY, 0,
+ NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, FILE_ATTRIBUTE_DIRECTORY, 0,
+ NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, FILE_ATTRIBUTE_DIRECTORY, 0,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_OVERWRITE_IF, FILE_ATTRIBUTE_DIRECTORY, 0,
+ NT_STATUS_OK },
+
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* setup some base params. */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ * Test the validity checking for create dispositions, which is done
+ * against the requested parameters rather than what's actually on
+ * disk.
+ */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ io.ntcreatex.in.open_disposition = open_funcs[i].open_disp;
+ io.ntcreatex.in.file_attr = open_funcs[i].file_attr;
+ io.ntcreatex.in.create_options = open_funcs[i].create_options;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) incorrect status %s should be %s "
+ "(i=%d open_disp=%d)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].open_disp);
+ return false;
+ }
+ /* Close and delete the file. */
+ if (NT_STATUS_IS_OK(status)) {
+ if (open_funcs[i].create_options != 0) {
+ /* out attrib should be a directory. */
+ torture_assert_int_equal(tctx,
+ io.ntcreatex.out.attrib,
+ FILE_ATTRIBUTE_DIRECTORY, "should have "
+ "created a directory");
+
+ smbcli_close(cli->tree,
+ io.ntcreatex.out.file.fnum);
+
+ /* Make sure unlink fails. */
+ status = smbcli_unlink(cli->tree, fname);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_FILE_IS_A_DIRECTORY,
+ "unlink should fail for a directory");
+
+ status = smbcli_rmdir(cli->tree, fname);
+ torture_assert_ntstatus_ok(tctx, status,
+ "rmdir failed");
+ } else {
+ torture_assert_int_equal(tctx,
+ io.ntcreatex.out.attrib,
+ FILE_ATTRIBUTE_ARCHIVE, "should not have "
+ "created a directory");
+
+ smbcli_close(cli->tree,
+ io.ntcreatex.out.file.fnum);
+
+ /* Make sure rmdir fails. */
+ status = smbcli_rmdir(cli->tree, fname);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_NOT_A_DIRECTORY,
+ "rmdir should fail for a file");
+
+ status = smbcli_unlink(cli->tree, fname);
+ torture_assert_ntstatus_ok(tctx, status,
+ "unlink failed");
+ }
+ }
+ }
+
+ /* Create a file. */
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create file.");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Try and open the file with file_attr_dir and check the error. */
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "FILE_ATTRIBUTE_DIRECTORY "
+ "doesn't produce a hard failure.");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Try and open file with createx_option_dir and check the error. */
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_A_DIRECTORY,
+ "NTCREATEX_OPTIONS_DIRECTORY will a file from being opened.");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Delete the file and move onto directory testing. */
+ smbcli_unlink(cli->tree, fname);
+
+ /* Now try some tests on a directory. */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create dir.");
+
+ /* out attrib should be a directory. */
+ torture_assert_int_equal(tctx, io.ntcreatex.out.attrib,
+ FILE_ATTRIBUTE_DIRECTORY, "should have created a directory");
+
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Try and open it with normal attr and check the error. */
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "FILE_ATTRIBUTE_NORMAL "
+ "doesn't produce a hard failure.");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Try and open it with file create_options and check the error. */
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_FILE_IS_A_DIRECTORY,
+ "NTCREATEX_OPTIONS_NON_DIRECTORY_FILE should be returned ");
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return true;
+}
+
+/*
+ test opening with truncate on an already open file
+ returns share violation and doesn't truncate the file.
+ Regression test for bug #10671.
+*/
+static bool test_open_for_truncate(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_open_for_truncate.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ ssize_t val = 0;
+ char c = '\0';
+ bool ret = true;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing open truncate disposition.\n");
+
+ /* reasonable default parameters */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Write a byte at offset 1k-1. */
+ val =smbcli_write(cli->tree, fnum, 0, &c, 1023, 1);
+ torture_assert_int_equal(tctx, val, 1, "write failed\n");
+
+ /* Now try and open for read/write with truncate - should fail. */
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_WRITE|SEC_RIGHTS_FILE_READ;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ /* Ensure file size is still 1k */
+ finfo.generic.level = RAW_FILEINFO_GETATTRE;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(finfo.getattre.out.size, 1024);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Ensure truncate actually works */
+ finfo.generic.level = RAW_FILEINFO_GETATTRE;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(finfo.getattre.out.size, 0);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/**
+ * Test for file size to be 0 after create with FILE_SUPERSEDE
+ */
+static bool test_ntcreatex_supersede(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ union smb_fileinfo finfo;
+ const char *fname = BASEDIR "\\torture_ntcreatex_supersede.txt";
+ NTSTATUS status;
+ int fnum = -1;
+ bool ret = true;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* reasonable default parameters */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.size, size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+
+ /* extend the file size */
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.end_of_file_info.in.size = 512;
+ status = smb_raw_setfileinfo(cli->tree, &sfi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* close the file and re-open with to verify new size */
+ smbcli_close(cli->tree, fnum);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_NTTIME(io.ntcreatex.out.write_time, write_time);
+ CHECK_NTTIME(io.ntcreatex.out.change_time, change_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_VAL(io.ntcreatex.out.size, 512);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+
+ /* close and re-open the file with SUPERSEDE flag */
+ smbcli_close(cli->tree, fnum);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.create_options = 0;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* The file size in the superseded create response should be 0 */
+ CHECK_VAL(io.ntcreatex.out.size, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, FILE_WAS_SUPERSEDED);
+ CHECK_NTTIME(io.ntcreatex.out.create_time, create_time);
+ CHECK_NTTIME(io.ntcreatex.out.access_time, access_time);
+ CHECK_ALL_INFO(io.ntcreatex.out.attrib, attrib);
+ CHECK_ALL_INFO(io.ntcreatex.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.ntcreatex.out.is_directory, directory);
+ CHECK_VAL(io.ntcreatex.out.file_type, FILE_TYPE_DISK);
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/* basic testing of all RAW_OPEN_* calls
+*/
+struct torture_suite *torture_raw_open(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "open");
+
+ torture_suite_add_1smb_test(suite, "brlocked", test_ntcreatex_brlocked);
+ torture_suite_add_1smb_test(suite, "open", test_open);
+ torture_suite_add_1smb_test(suite, "open-multi", test_raw_open_multi);
+ torture_suite_add_1smb_test(suite, "openx", test_openx);
+ torture_suite_add_1smb_test(suite, "ntcreatex", test_ntcreatex);
+ torture_suite_add_1smb_test(suite, "nttrans-create", test_nttrans_create);
+ torture_suite_add_1smb_test(suite, "t2open", test_t2open);
+ torture_suite_add_1smb_test(suite, "mknew", test_mknew);
+ torture_suite_add_1smb_test(suite, "create", test_create);
+ torture_suite_add_1smb_test(suite, "ctemp", test_ctemp);
+ torture_suite_add_1smb_test(suite, "chained-openx", test_chained);
+ torture_suite_add_1smb_test(suite, "chained-ntcreatex", test_chained_ntcreatex_readx);
+ torture_suite_add_1smb_test(suite, "no-leading-slash", test_no_leading_slash);
+ torture_suite_add_1smb_test(suite, "openx-over-dir", test_openx_over_dir);
+ torture_suite_add_1smb_test(suite, "open-for-delete", test_open_for_delete);
+ torture_suite_add_1smb_test(suite, "opendisp-dir", test_ntcreatex_opendisp_dir);
+ torture_suite_add_1smb_test(suite, "ntcreatedir", test_ntcreatexdir);
+ torture_suite_add_1smb_test(suite, "open-for-truncate", test_open_for_truncate);
+ torture_suite_add_1smb_test(suite, "ntcreatex_supersede", test_ntcreatex_supersede);
+
+ return suite;
+}
diff --git a/source4/torture/raw/openbench.c b/source4/torture/raw/openbench.c
new file mode 100644
index 0000000..8349f6e
--- /dev/null
+++ b/source4/torture/raw/openbench.c
@@ -0,0 +1,502 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ open benchmark
+
+ Copyright (C) Andrew Tridgell 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/events/events.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "torture/raw/proto.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "../lib/util/util_net.h"
+
+#define BASEDIR "\\benchopen"
+
+static int nprocs;
+static int open_failed;
+static int close_failed;
+static char **fnames;
+static int num_connected;
+static struct tevent_timer *report_te;
+
+struct benchopen_state {
+ struct torture_context *tctx;
+ TALLOC_CTX *mem_ctx;
+ struct tevent_context *ev;
+ struct smbcli_state *cli;
+ struct smbcli_tree *tree;
+ int client_num;
+ int close_fnum;
+ int open_fnum;
+ int close_file_num;
+ int open_file_num;
+ int pending_file_num;
+ int next_file_num;
+ int count;
+ int lastcount;
+ union smb_open open_parms;
+ int open_retries;
+ union smb_close close_parms;
+ struct smbcli_request *req_open;
+ struct smbcli_request *req_close;
+ struct smb_composite_connect reconnect;
+ struct tevent_timer *te;
+
+ /* these are used for reconnections */
+ const char **dest_ports;
+ const char *dest_host;
+ const char *called_name;
+ const char *service_type;
+};
+
+static void next_open(struct benchopen_state *state);
+static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data);
+
+
+/*
+ complete an async reconnect
+ */
+static void reopen_connection_complete(struct composite_context *ctx)
+{
+ struct benchopen_state *state = (struct benchopen_state *)ctx->async.private_data;
+ NTSTATUS status;
+ struct smb_composite_connect *io = &state->reconnect;
+
+ status = smb_composite_connect_recv(ctx, state->mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ return;
+ }
+
+ state->tree = io->out.tree;
+
+ num_connected++;
+
+ DEBUG(0,("[%u] reconnect to %s finished (%u connected)\n",
+ state->client_num, state->dest_host, num_connected));
+
+ state->open_fnum = -1;
+ state->close_fnum = -1;
+ next_open(state);
+}
+
+
+
+/*
+ reopen a connection
+ */
+static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct benchopen_state *state = (struct benchopen_state *)private_data;
+ struct composite_context *ctx;
+ struct smb_composite_connect *io = &state->reconnect;
+ char *host, *share;
+
+ state->te = NULL;
+
+ if (!torture_get_conn_index(state->client_num, state->mem_ctx, state->tctx, &host, &share)) {
+ DEBUG(0,("Can't find host/share for reconnect?!\n"));
+ exit(1);
+ }
+
+ io->in.dest_host = state->dest_host;
+ io->in.dest_ports = state->dest_ports;
+ io->in.socket_options = lpcfg_socket_options(state->tctx->lp_ctx);
+ io->in.called_name = state->called_name;
+ io->in.service = share;
+ io->in.service_type = state->service_type;
+ io->in.credentials = samba_cmdline_get_creds();
+ io->in.fallback_to_anonymous = false;
+ io->in.workgroup = lpcfg_workgroup(state->tctx->lp_ctx);
+ io->in.gensec_settings = lpcfg_gensec_settings(state->mem_ctx, state->tctx->lp_ctx);
+ lpcfg_smbcli_options(state->tctx->lp_ctx, &io->in.options);
+ lpcfg_smbcli_session_options(state->tctx->lp_ctx, &io->in.session_options);
+
+ /* kill off the remnants of the old connection */
+ talloc_free(state->tree);
+ state->tree = NULL;
+ state->open_fnum = -1;
+ state->close_fnum = -1;
+
+ ctx = smb_composite_connect_send(io, state->mem_ctx,
+ lpcfg_resolve_context(state->tctx->lp_ctx),
+ state->ev);
+ if (ctx == NULL) {
+ DEBUG(0,("Failed to setup async reconnect\n"));
+ exit(1);
+ }
+
+ ctx->async.fn = reopen_connection_complete;
+ ctx->async.private_data = state;
+}
+
+static void open_completed(struct smbcli_request *req);
+static void close_completed(struct smbcli_request *req);
+
+
+static void next_open(struct benchopen_state *state)
+{
+ state->count++;
+
+ state->pending_file_num = state->next_file_num;
+ state->next_file_num = (state->next_file_num+1) % (3*nprocs);
+
+ DEBUG(2,("[%d] opening %u\n", state->client_num, state->pending_file_num));
+ state->open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ state->open_parms.ntcreatex.in.flags = 0;
+ state->open_parms.ntcreatex.in.root_fid.fnum = 0;
+ state->open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ state->open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ state->open_parms.ntcreatex.in.alloc_size = 0;
+ state->open_parms.ntcreatex.in.share_access = 0;
+ state->open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ state->open_parms.ntcreatex.in.create_options = 0;
+ state->open_parms.ntcreatex.in.impersonation = 0;
+ state->open_parms.ntcreatex.in.security_flags = 0;
+ state->open_parms.ntcreatex.in.fname = fnames[state->pending_file_num];
+
+ state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
+ state->req_open->async.fn = open_completed;
+ state->req_open->async.private_data = state;
+}
+
+
+static void next_close(struct benchopen_state *state)
+{
+ if (state->close_fnum == -1) {
+ return;
+ }
+ DEBUG(2,("[%d] closing %d (fnum[%d])\n",
+ state->client_num, state->close_file_num, state->close_fnum));
+ state->close_parms.close.level = RAW_CLOSE_CLOSE;
+ state->close_parms.close.in.file.fnum = state->close_fnum;
+ state->close_parms.close.in.write_time = 0;
+
+ state->req_close = smb_raw_close_send(state->tree, &state->close_parms);
+ state->req_close->async.fn = close_completed;
+ state->req_close->async.private_data = state;
+}
+
+/*
+ called when a open completes
+*/
+static void open_completed(struct smbcli_request *req)
+{
+ struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
+ TALLOC_CTX *tmp_ctx = talloc_new(state->mem_ctx);
+ NTSTATUS status;
+
+ status = smb_raw_open_recv(req, tmp_ctx, &state->open_parms);
+
+ talloc_free(tmp_ctx);
+
+ state->req_open = NULL;
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+ talloc_free(state->tree);
+ talloc_free(state->cli);
+ state->tree = NULL;
+ state->cli = NULL;
+ num_connected--;
+ DEBUG(0,("[%u] reopening connection to %s\n",
+ state->client_num, state->dest_host));
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ DEBUG(2,("[%d] retrying open %d\n",
+ state->client_num, state->pending_file_num));
+ state->open_retries++;
+ state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
+ state->req_open->async.fn = open_completed;
+ state->req_open->async.private_data = state;
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ open_failed++;
+ DEBUG(0,("[%u] open failed %d - %s\n",
+ state->client_num, state->pending_file_num,
+ nt_errstr(status)));
+ return;
+ }
+
+ state->close_file_num = state->open_file_num;
+ state->close_fnum = state->open_fnum;
+ state->open_file_num = state->pending_file_num;
+ state->open_fnum = state->open_parms.ntcreatex.out.file.fnum;
+
+ DEBUG(2,("[%d] open completed %d (fnum[%d])\n",
+ state->client_num, state->open_file_num, state->open_fnum));
+
+ if (state->close_fnum != -1) {
+ next_close(state);
+ }
+
+ next_open(state);
+}
+
+/*
+ called when a close completes
+*/
+static void close_completed(struct smbcli_request *req)
+{
+ struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+
+ state->req_close = NULL;
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+ talloc_free(state->tree);
+ talloc_free(state->cli);
+ state->tree = NULL;
+ state->cli = NULL;
+ num_connected--;
+ DEBUG(0,("[%u] reopening connection to %s\n",
+ state->client_num, state->dest_host));
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ close_failed++;
+ DEBUG(0,("[%u] close failed %d (fnum[%d]) - %s\n",
+ state->client_num, state->close_file_num,
+ state->close_fnum,
+ nt_errstr(status)));
+ return;
+ }
+
+ DEBUG(2,("[%d] close completed %d (fnum[%d])\n",
+ state->client_num, state->close_file_num,
+ state->close_fnum));
+}
+
+static void echo_completion(struct smbcli_request *req)
+{
+ struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("[%u] reopening connection to %s\n",
+ state->client_num, state->dest_host));
+ talloc_free(state->te);
+ state->te = tevent_add_timer(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ }
+}
+
+static void report_rate(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct benchopen_state *state = talloc_get_type(private_data,
+ struct benchopen_state);
+ int i;
+ for (i=0;i<nprocs;i++) {
+ printf("%5u ", (unsigned)(state[i].count - state[i].lastcount));
+ state[i].lastcount = state[i].count;
+ }
+ printf("\r");
+ fflush(stdout);
+ report_te = tevent_add_timer(ev, state, timeval_current_ofs(1, 0),
+ report_rate, state);
+
+ /* send an echo on each interface to ensure it stays alive - this helps
+ with IP takeover */
+ for (i=0;i<nprocs;i++) {
+ struct smb_echo p;
+ struct smbcli_request *req;
+
+ if (!state[i].tree) {
+ continue;
+ }
+
+ p.in.repeat_count = 1;
+ p.in.size = 0;
+ p.in.data = NULL;
+ req = smb_raw_echo_send(state[i].tree->session->transport, &p);
+ req->async.private_data = &state[i];
+ req->async.fn = echo_completion;
+ }
+}
+
+/*
+ benchmark open calls
+*/
+bool torture_bench_open(struct torture_context *torture)
+{
+ bool ret = true;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ int i;
+ int timelimit = torture_setting_int(torture, "timelimit", 10);
+ struct timeval tv;
+ struct benchopen_state *state;
+ int total = 0;
+ int total_retries = 0;
+ int minops = 0;
+ bool progress=false;
+
+ progress = torture_setting_bool(torture, "progress", true);
+
+ nprocs = torture_setting_int(torture, "nprocs", 4);
+
+ state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs);
+
+ printf("Opening %d connections\n", nprocs);
+ for (i=0;i<nprocs;i++) {
+ const struct sockaddr_storage *dest_ss;
+ char addrstr[INET6_ADDRSTRLEN];
+ const char *dest_str;
+ uint16_t dest_port;
+
+ state[i].tctx = torture;
+ state[i].mem_ctx = talloc_new(state);
+ state[i].client_num = i;
+ state[i].ev = torture->ev;
+ if (!torture_open_connection_ev(&state[i].cli, i, torture, torture->ev)) {
+ return false;
+ }
+ talloc_steal(state[i].mem_ctx, state[i].cli);
+ state[i].tree = state[i].cli->tree;
+
+ dest_ss = smbXcli_conn_remote_sockaddr(
+ state[i].tree->session->transport->conn);
+ dest_str = print_sockaddr(addrstr, sizeof(addrstr), dest_ss);
+ dest_port = get_sockaddr_port(dest_ss);
+
+ state[i].dest_host = talloc_strdup(state[i].mem_ctx, dest_str);
+ state[i].dest_ports = talloc_array(state[i].mem_ctx,
+ const char *, 2);
+ state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports,
+ "%u", dest_port);
+ state[i].dest_ports[1] = NULL;
+ state[i].called_name = talloc_strdup(state[i].mem_ctx,
+ smbXcli_conn_remote_name(state[i].tree->session->transport->conn));
+ state[i].service_type = talloc_strdup(state[i].mem_ctx, "?????");
+ }
+
+ num_connected = i;
+
+ if (!torture_setup_dir(state[0].cli, BASEDIR)) {
+ goto failed;
+ }
+
+ fnames = talloc_array(mem_ctx, char *, 3*nprocs);
+ for (i=0;i<3*nprocs;i++) {
+ fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i);
+ }
+
+ for (i=0;i<nprocs;i++) {
+ /* all connections start with the same file */
+ state[i].next_file_num = 0;
+ state[i].open_fnum = -1;
+ state[i].close_fnum = -1;
+ next_open(&state[i]);
+ }
+
+ tv = timeval_current();
+
+ if (progress) {
+ report_te = tevent_add_timer(torture->ev, state, timeval_current_ofs(1, 0),
+ report_rate, state);
+ }
+
+ printf("Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ tevent_loop_once(torture->ev);
+
+ if (open_failed) {
+ DEBUG(0,("open failed\n"));
+ goto failed;
+ }
+ if (close_failed) {
+ DEBUG(0,("open failed\n"));
+ goto failed;
+ }
+ }
+
+ talloc_free(report_te);
+ if (progress) {
+ for (i=0;i<nprocs;i++) {
+ printf(" ");
+ }
+ printf("\r");
+ }
+
+ minops = state[0].count;
+ for (i=0;i<nprocs;i++) {
+ total += state[i].count;
+ total_retries += state[i].open_retries;
+ printf("[%d] %u ops (%u retries)\n",
+ i, state[i].count, state[i].open_retries);
+ if (state[i].count < minops) minops = state[i].count;
+ }
+ printf("%.2f ops/second (%d retries)\n",
+ total/timeval_elapsed(&tv), total_retries);
+ if (minops < 0.5*total/nprocs) {
+ printf("Failed: unbalanced open\n");
+ goto failed;
+ }
+
+ for (i=0;i<nprocs;i++) {
+ talloc_free(state[i].req_open);
+ talloc_free(state[i].req_close);
+ smb_raw_exit(state[i].tree->session);
+ }
+
+ smbcli_deltree(state[0].tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+
+failed:
+ talloc_free(mem_ctx);
+ return false;
+}
diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
new file mode 100644
index 0000000..173d5ca
--- /dev/null
+++ b/source4/torture/raw/oplock.c
@@ -0,0 +1,4672 @@
+/*
+ Unix SMB/CIFS implementation.
+ basic raw test suite for oplocks
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/events/events.h"
+#include "param/param.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/raw/proto.h"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_RANGE(v, min, max) do { \
+ if ((v) < (min) || (v) > (max)) { \
+ torture_warning(tctx, "(%s): wrong value for %s got " \
+ "%d - should be between %d and %d\n", \
+ __location__, #v, (int)v, (int)min, (int)max); \
+ }} while (0)
+
+#define CHECK_STRMATCH(v, correct) do { \
+ if (!v || strstr((v),(correct)) == NULL) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got '%s' - should be '%s'\n", \
+ __location__, #v, v?v:"NULL", correct); \
+ ret = false; \
+ } \
+} while (0)
+
+#define CHECK_STATUS(tctx, status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+
+static struct {
+ int fnum;
+ uint8_t level;
+ int count;
+ int failures;
+} break_info;
+
+#define BASEDIR "\\test_oplock"
+
+/*
+ a handler function for oplock break requests. Ack it as a break to level II if possible
+*/
+static bool oplock_handler_ack_to_given(struct smbcli_transport *transport,
+ uint16_t tid, uint16_t fnum,
+ uint8_t level, void *private_data)
+{
+ struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
+ const char *name;
+
+ break_info.fnum = fnum;
+ break_info.level = level;
+ break_info.count++;
+
+ switch (level) {
+ case OPLOCK_BREAK_TO_LEVEL_II:
+ name = "level II";
+ break;
+ case OPLOCK_BREAK_TO_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break_info.failures++;
+ }
+ printf("Acking to %s [0x%02X] in oplock handler\n",
+ name, level);
+
+ return smbcli_oplock_ack(tree, fnum, level);
+}
+
+/*
+ a handler function for oplock break requests. Ack it as a break to none
+*/
+static bool oplock_handler_ack_to_none(struct smbcli_transport *transport,
+ uint16_t tid, uint16_t fnum,
+ uint8_t level, void *private_data)
+{
+ struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
+ break_info.fnum = fnum;
+ break_info.level = level;
+ break_info.count++;
+
+ printf("Acking to none in oplock handler\n");
+
+ return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
+}
+
+/*
+ a handler function for oplock break requests. Let it timeout
+*/
+static bool oplock_handler_timeout(struct smbcli_transport *transport,
+ uint16_t tid, uint16_t fnum,
+ uint8_t level, void *private_data)
+{
+ break_info.fnum = fnum;
+ break_info.level = level;
+ break_info.count++;
+
+ printf("Let oplock break timeout\n");
+ return true;
+}
+
+static void oplock_handler_close_recv(struct smbcli_request *req)
+{
+ NTSTATUS status;
+ status = smbcli_request_simple_recv(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("close failed in oplock_handler_close\n");
+ break_info.failures++;
+ }
+}
+
+/*
+ a handler function for oplock break requests - close the file
+*/
+static bool oplock_handler_close(struct smbcli_transport *transport, uint16_t tid,
+ uint16_t fnum, uint8_t level, void *private_data)
+{
+ union smb_close io;
+ struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
+ struct smbcli_request *req;
+
+ break_info.fnum = fnum;
+ break_info.level = level;
+ break_info.count++;
+
+ io.close.level = RAW_CLOSE_CLOSE;
+ io.close.in.file.fnum = fnum;
+ io.close.in.write_time = 0;
+ req = smb_raw_close_send(tree, &io);
+ if (req == NULL) {
+ printf("failed to send close in oplock_handler_close\n");
+ return false;
+ }
+
+ req->async.fn = oplock_handler_close_recv;
+ req->async.private_data = NULL;
+
+ return true;
+}
+
+static bool open_connection_no_level2_oplocks(struct torture_context *tctx,
+ struct smbcli_state **c)
+{
+ NTSTATUS status;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ options.use_level2_oplocks = false;
+
+ status = smbcli_full_connection(tctx, c,
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ torture_setting_string(tctx, "share", NULL),
+ NULL, lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to open connection - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Timer handler function notifies the registering function that time is up
+*/
+static void timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ bool *timesup = (bool *)private_data;
+ *timesup = true;
+ return;
+}
+
+/*
+ Wait a short period of time to receive a single oplock break request
+*/
+static void torture_wait_for_oplock_break(struct torture_context *tctx)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct tevent_timer *te = NULL;
+ struct timeval ne;
+ bool timesup = false;
+ int old_count = break_info.count;
+
+ /* Wait .1 seconds for an oplock break */
+ ne = tevent_timeval_current_ofs(0, 100000);
+
+ if ((te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup))
+ == NULL)
+ {
+ torture_comment(tctx, "Failed to wait for an oplock break. "
+ "test results may not be accurate.");
+ goto done;
+ }
+
+ while (!timesup && break_info.count < old_count + 1) {
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_comment(tctx, "Failed to wait for an oplock "
+ "break. test results may not be "
+ "accurate.");
+ goto done;
+ }
+ }
+
+done:
+ /* We don't know if the timed event fired and was freed, we received
+ * our oplock break, or some other event triggered the loop. Thus,
+ * we create a tmp_ctx to be able to safely free/remove the timed
+ * event in all 3 cases. */
+ talloc_free(tmp_ctx);
+
+ return;
+}
+
+static uint8_t get_break_level1_to_none_count(struct torture_context *tctx)
+{
+ return torture_setting_bool(tctx, "2_step_break_to_none", false) ?
+ 2 : 1;
+}
+
+static uint8_t get_setinfo_break_count(struct torture_context *tctx)
+{
+ if (TARGET_IS_W2K12(tctx)) {
+ return 2;
+ }
+ if (TARGET_IS_SAMBA3(tctx)) {
+ return 2;
+ }
+ return 1;
+}
+
+static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive1.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_unlink unl;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "a 2nd open should not cause a break\n");
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "unlink it - should also be no break\n");
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_unlink unl;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive oplock (share mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ ZERO_STRUCT(break_info);
+
+ /* now we have 2 level II oplocks... */
+ torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n");
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "close 1st handle\n");
+ smbcli_close(cli1->tree, fnum);
+
+ torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n");
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "close 2nd handle\n");
+ smbcli_close(cli2->tree, fnum2);
+
+ torture_comment(tctx, "unlink it\n");
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive oplock (share mode: none)\n");
+
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setpathinfo EOF should trigger a break to none\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 100;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, get_setinfo_break_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive4.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ /*
+ * Open another non-stat open. This reproduces bug 10216. Make sure it
+ * won't happen again...
+ */
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive5.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE_IF disposition causes oplock break\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, get_break_level1_to_none_count(tctx));
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
+ const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_rename rn;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
+ "oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "rename should not generate a break but get a "
+ "sharing violation\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_RENAME;
+ rn.rename.in.pattern1 = fname1;
+ rn.rename.in.pattern2 = fname2;
+ rn.rename.in.attrib = 0;
+
+ torture_comment(tctx, "trying rename while first file open\n");
+ status = smb_raw_rename(cli2->tree, &rn);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Exclusive version of batch19
+ */
+static bool test_raw_oplock_exclusive7(struct torture_context *tctx,
+ struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_exclusiv6_1.dat";
+ const char *fname2 = BASEDIR "\\test_exclusiv6_2.dat";
+ const char *fname3 = BASEDIR "\\test_exclusiv6_3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+ uint16_t fnum2 = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+ smbcli_unlink(cli1->tree, fname3);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "open a file with an exclusive oplock (share "
+ "mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setpathinfo rename info should trigger a break "
+ "to none\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.path = fname1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K12(tctx)) {
+ /* XP incorrectly breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ /* Exclusive oplocks should not be broken on rename. */
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+ /* Try breaking to level2 and then see if rename breaks the level2.*/
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.fname = fname2;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP already broke to level2. */
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.count, 0);
+ } else if (TARGET_IS_W2K12(tctx)) {
+ /* no break */
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ } else {
+ /* Break to level 2 expected. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ }
+
+ ZERO_STRUCT(break_info);
+ sfi.generic.in.file.path = fname2;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname1+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ /* Level2 oplocks are not broken on rename. */
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.count, 0);
+
+ /* Close and re-open file with oplock. */
+ smbcli_close(cli1->tree, fnum);
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setfileinfo rename info on a client's own fid "
+ "should not trigger a break nor a violation\n");
+ ZERO_STRUCT(break_info);
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1;
+
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP incorrectly breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+done:
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive8(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive8.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum1 = 0;
+ uint16_t fnum2 = 0;
+ uint16_t fnum3 = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "open a file with an exclusive oplock (share "
+ "mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "second open with delete should trigger a "
+ "break\n");
+
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ io.ntcreatex.in.flags = 0;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(break_info.count, get_break_level1_to_none_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+ /* Trigger a little panic in "old" samba code.. */
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum3 = io.ntcreatex.out.file.fnum;
+
+ smbcli_close(cli2->tree, fnum3);
+ smbcli_close(cli2->tree, fnum2);
+ smbcli_close(cli1->tree, fnum1);
+
+done:
+ smbcli_deltree(cli1->tree, BASEDIR);
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ return ret;
+}
+
+static bool test_raw_oplock_exclusive9(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive9.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+ int i;
+
+ struct {
+ uint32_t create_disposition;
+ uint32_t break_level;
+ } levels[] = {
+ { NTCREATEX_DISP_SUPERSEDE, OPLOCK_BREAK_TO_NONE },
+ { NTCREATEX_DISP_OPEN, OPLOCK_BREAK_TO_LEVEL_II },
+ { NTCREATEX_DISP_OVERWRITE_IF, OPLOCK_BREAK_TO_NONE },
+ { NTCREATEX_DISP_OPEN_IF, OPLOCK_BREAK_TO_LEVEL_II },
+ };
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ EXCLUSIVE_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ io.ntcreatex.in.open_disposition =
+ levels[i].create_disposition;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ LEVEL_II_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, levels[i].break_level);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+ }
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_level_ii_1(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_level_ii_1.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+ char c = 0;
+ ssize_t written;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ status = smbcli_close(cli2->tree, fnum2);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ /*
+ * fnum1 has a level2 oplock now
+ */
+
+ ZERO_STRUCT(break_info);
+
+ /*
+ * Don't answer the break to none that will come in
+ */
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_timeout,
+ cli1->tree);
+
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ CHECK_VAL(break_info.failures, 0);
+
+ /*
+ * Check that a write does not cause another break. This used to be a
+ * bug in smbd.
+ */
+
+ ZERO_STRUCT(break_info);
+ written = smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
+ CHECK_VAL(written, 1);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ status = smbcli_close(cli2->tree, fnum2);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ status = smbcli_close(cli1->tree, fnum);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch1.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_unlink unl;
+ uint16_t fnum=0;
+ char c = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH1: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "unlink should generate a break\n");
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "2nd unlink should not generate a break\n");
+ ZERO_STRUCT(break_info);
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ torture_comment(tctx, "writing should generate a self break to none\n");
+ smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_unlink unl;
+ uint16_t fnum=0;
+ char c = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH2: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "unlink should generate a break, which we ack as break to none\n");
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "2nd unlink should not generate a break\n");
+ ZERO_STRUCT(break_info);
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ torture_comment(tctx, "writing should not generate a break\n");
+ smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_unlink unl;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH3: if we close on break then the unlink can succeed\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ ZERO_STRUCT(break_info);
+ status = smb_raw_unlink(cli2->tree, &unl);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch4.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_read rd;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ rd.readx.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = 1;
+ rd.readx.in.maxcnt = 1;
+ rd.readx.in.offset = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ status = smb_raw_read(cli1->tree, &rd);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch5.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch6.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+ char c = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH6: a 2nd open should give a break to level II if the first open allowed shared read\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ //torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none on both\n");
+ smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch7.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when we close instead of ack\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
+
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum2);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli2->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch8.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH8: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch9.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+ char c = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH9: open with attributes only can create file\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
+
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, fnum2);
+
+ torture_comment(tctx, "third oplocked open should grant level2 without break\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none on both\n");
+ smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch9a(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch9a.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+ char c = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH9: open with attributes only can create file\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.create_action, FILE_WAS_CREATED);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "Subsequent attributes open should not break\n");
+
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(io.ntcreatex.out.create_action, FILE_WAS_OPENED);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, fnum2);
+
+ torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
+
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, fnum2);
+
+ torture_comment(tctx, "third oplocked open should grant level2 without break\n");
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none on both\n");
+ smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch10.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock open should grant level2\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+
+ {
+ union smb_write wr;
+ wr.write.level = RAW_WRITE_WRITE;
+ wr.write.in.file.fnum = fnum;
+ wr.write.in.count = 1;
+ wr.write.in.offset = 0;
+ wr.write.in.remaining = 0;
+ wr.write.in.data = (const uint8_t *)"x";
+ status = smb_raw_write(cli1->tree, &wr);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ }
+
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_comment(tctx, "write should trigger a break to none\n");
+ {
+ union smb_write wr;
+ wr.write.level = RAW_WRITE_WRITE;
+ wr.write.in.file.fnum = fnum;
+ wr.write.in.count = 1;
+ wr.write.in.offset = 0;
+ wr.write.in.remaining = 0;
+ wr.write.in.data = (const uint8_t *)"x";
+ status = smb_raw_write(cli1->tree, &wr);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ }
+
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch11.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* Test if a set-eof on pathname breaks an exclusive oplock. */
+ torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks oplocks.\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 100;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, get_setinfo_break_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch12.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
+ torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size breaks oplocks.\n");
+
+ ZERO_STRUCT(break_info);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.allocation_info.in.alloc_size = 65536 * 8;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, get_setinfo_break_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch13.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH13: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE disposition causes oplock break\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+ CHECK_VAL(break_info.count, get_break_level1_to_none_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch14.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH14: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_SUPERSEDE disposition causes oplock break\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, get_break_level1_to_none_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch15(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch15.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
+ torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks a batch oplock (should not).\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli2->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch16.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH16: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE_IF disposition causes oplock break\n");
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, get_break_level1_to_none_count(tctx));
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_batch17_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch17_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_rename rn;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "BATCH17: open a file with an batch oplock (share mode: none)\n");
+
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "rename should trigger a break\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_RENAME;
+ rn.rename.in.pattern1 = fname1;
+ rn.rename.in.pattern2 = fname2;
+ rn.rename.in.attrib = 0;
+
+ torture_comment(tctx, "trying rename while first file open\n");
+ status = smb_raw_rename(cli2->tree, &rn);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_batch18_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch18_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_rename rn;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "BATCH18: open a file with an batch oplock (share mode: none)\n");
+
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "ntrename should trigger a break\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_NTRENAME;
+ rn.ntrename.in.attrib = 0;
+ rn.ntrename.in.flags = RENAME_FLAG_RENAME;
+ rn.ntrename.in.old_name = fname1;
+ rn.ntrename.in.new_name = fname2;
+ torture_comment(tctx, "trying rename while first file open\n");
+ status = smb_raw_rename(cli2->tree, &rn);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_batch19_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch19_2.dat";
+ const char *fname3 = BASEDIR "\\test_batch19_3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+ smbcli_unlink(cli1->tree, fname3);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "BATCH19: open a file with an batch oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setpathinfo rename info should trigger a break "
+ "to none\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.path = fname1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K12(tctx)) {
+ /* Win XP breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) ||
+ TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) {
+ /* Win2K3/2k8 incorrectly doesn't break at all. */
+ CHECK_VAL(break_info.count, 0);
+ } else {
+ /* win7/2k8r2 break to none. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+ /* Close and re-open file with oplock. */
+ smbcli_close(cli1->tree, fnum);
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setfileinfo rename info on a client's own fid "
+ "should not trigger a break nor a violation\n");
+ ZERO_STRUCT(break_info);
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1;
+
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP incorrectly breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+done:
+ smbcli_close(cli1->tree, fnum);
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/****************************************************
+ Called from raw-rename - we need oplock handling for
+ this test so this is why it's in oplock.c, not rename.c
+****************************************************/
+
+bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_trans2rename_1.dat";
+ const char *fname2 = BASEDIR "\\test_trans2rename_2.dat";
+ const char *fname3 = BASEDIR "\\test_trans2rename_3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+ smbcli_unlink(cli1->tree, fname3);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "open a file with an exclusive oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.path = fname1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+ torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1;
+
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+done:
+ smbcli_close(cli1->tree, fnum);
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/****************************************************
+ Called from raw-rename - we need oplock handling for
+ this test so this is why it's in oplock.c, not rename.c
+****************************************************/
+
+bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1)
+{
+ const char *fname1 = BASEDIR "\\test_nttransrename_1.dat";
+ const char *fname2 = BASEDIR "\\test_nttransrename_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi, qpi;
+ union smb_rename rn;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "nttrans_rename: open a file with an exclusive oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ torture_comment(tctx, "nttrans_rename: should not trigger a break nor a share mode violation\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_NTTRANS;
+ rn.nttrans.in.file.fnum = fnum;
+ rn.nttrans.in.flags = 0;
+ rn.nttrans.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_rename(cli1->tree, &rn);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ /* w2k3 does nothing, it doesn't rename the file */
+ torture_comment(tctx, "nttrans_rename: the server should have done nothing\n");
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname1);
+
+ ZERO_STRUCT(qpi);
+ qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qpi.generic.in.file.path = fname1;
+
+ status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qpi.all_info.out.fname.s, fname1);
+
+ ZERO_STRUCT(qpi);
+ qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qpi.generic.in.file.path = fname2;
+
+ status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ torture_comment(tctx, "nttrans_rename: after closing the file the file is still not renamed\n");
+ status = smbcli_close(cli1->tree, fnum);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ ZERO_STRUCT(qpi);
+ qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qpi.generic.in.file.path = fname1;
+
+ status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qpi.all_info.out.fname.s, fname1);
+
+ ZERO_STRUCT(qpi);
+ qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qpi.generic.in.file.path = fname2;
+
+ status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ torture_comment(tctx, "nttrans_rename: rename with an invalid handle gives NT_STATUS_INVALID_HANDLE\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_NTTRANS;
+ rn.nttrans.in.file.fnum = fnum+1;
+ rn.nttrans.in.flags = 0;
+ rn.nttrans.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_rename(cli1->tree, &rn);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_INVALID_HANDLE);
+
+done:
+ smb_raw_exit(cli1->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+
+static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_batch20_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch20_2.dat";
+ const char *fname3 = BASEDIR "\\test_batch20_3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0,fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+ smbcli_unlink(cli1->tree, fname3);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx, "BATCH20: open a file with an batch oplock (share mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.path = fname1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname2+strlen(BASEDIR)+1;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.failures, 0);
+
+ if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K12(tctx)) {
+ /* Win XP breaks to level2. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) ||
+ TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) {
+ /* Win2K3/2k8 incorrectly doesn't break at all. */
+ CHECK_VAL(break_info.count, 0);
+ } else {
+ /* win7/2k8r2 break to none. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ }
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+ torture_comment(tctx, "open a file with the new name an batch oplock (share mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.fname = fname2;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+
+ if (TARGET_IS_WINXP(tctx)) {
+ /* XP broke to level2, and doesn't break again. */
+ CHECK_VAL(break_info.count, 0);
+ } else if (TARGET_IS_W2K3(tctx) || TARGET_IS_W2K8(tctx) ||
+ TARGET_IS_SAMBA3(tctx) || TARGET_IS_SAMBA4(tctx)) {
+ /* Win2K3 incorrectly didn't break before so break now. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ } else {
+ /* win7/2k8r2 broke to none, and doesn't break again. */
+ CHECK_VAL(break_info.count, 0);
+ }
+
+ ZERO_STRUCT(break_info);
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname3+strlen(BASEDIR)+1;
+
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.fnum = fnum2;
+
+ status = smb_raw_fileinfo(cli2->tree, tctx, &qfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+
+done:
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch21(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch21.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb_echo e;
+ uint16_t fnum=0;
+ char c = 0;
+ ssize_t wr;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH21: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "writing should not generate a break\n");
+ wr = smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+ CHECK_VAL(wr, 1);
+ CHECK_STATUS(tctx, smbcli_nt_error(cli1->tree), NT_STATUS_OK);
+
+ ZERO_STRUCT(e);
+ e.in.repeat_count = 1;
+ status = smb_raw_echo(cli1->transport, &e);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch22(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch22.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum = 0, fnum2 = 0, fnum3 = 0;
+ struct timeval tv;
+ int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
+ int te;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH22: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "a 2nd open should not succeed after the oplock "
+ "break timeout\n");
+ tv = timeval_current();
+ smbcli_oplock_handler(cli1->transport, oplock_handler_timeout, cli1->tree);
+ status = smb_raw_open(cli1->tree, tctx, &io);
+
+ if (TARGET_IS_W2K3(tctx)) {
+ /* 2k3 has an issue here. xp/win7 are ok. */
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+ } else {
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ }
+
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ torture_wait_for_oplock_break(tctx);
+ te = (int)timeval_elapsed(&tv);
+
+ /*
+ * Some servers detect clients that let oplocks timeout, so this check
+ * only shows a warning message instead failing the test to eliminate
+ * failures from repeated runs of the test. This isn't ideal, but
+ * it's better than not running the test at all.
+ */
+ CHECK_RANGE(te, timeout - 1, timeout + 15);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 2nd open should succeed after the oplock "
+ "release without break\n");
+ tv = timeval_current();
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+#if 0
+ /* Samba 3.6.0 and above behave as Windows. */
+ if (TARGET_IS_SAMBA3(tctx)) {
+ /* samba3 doesn't grant additional oplocks to bad clients. */
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+ } else {
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ LEVEL_II_OPLOCK_RETURN);
+ }
+#else
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ LEVEL_II_OPLOCK_RETURN);
+#endif
+ torture_wait_for_oplock_break(tctx);
+ te = (int)timeval_elapsed(&tv);
+ /* it should come in without delay */
+ CHECK_RANGE(te+1, 0, timeout);
+ fnum3 = io.ntcreatex.out.file.fnum;
+
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli1->tree, fnum2);
+ smbcli_close(cli1->tree, fnum3);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch23(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch23.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0, fnum2=0,fnum3=0;
+ struct smbcli_state *cli3 = NULL;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ ret = open_connection_no_level2_oplocks(tctx, &cli3);
+ CHECK_VAL(ret, true);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+ smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_given, cli3->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH23: a open and ask for a batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 2nd open without level2 oplock support should generate a break to level2\n");
+ status = smb_raw_open(cli3->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum3 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 3rd open with level2 oplock support should not generate a break\n");
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+ smbcli_close(cli3->tree, fnum3);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smb_raw_exit(cli3->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch24(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch24.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum2=0,fnum3=0;
+ struct smbcli_state *cli3 = NULL;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ ret = open_connection_no_level2_oplocks(tctx, &cli3);
+ CHECK_VAL(ret, true);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+ smbcli_oplock_handler(cli3->transport, oplock_handler_ack_to_given, cli3->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH24: a open without level support and ask for a batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli3->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum3 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 2nd open with level2 oplock support should generate a break to none\n");
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.fnum, fnum3);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli3->tree, fnum3);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smb_raw_exit(cli3->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_batch25(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch25.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "BATCH25: open a file with an batch oplock "
+ "(share mode: none)\n");
+
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "setpathinfo attribute info should not trigger "
+ "a break nor a violation\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_SETATTR;
+ sfi.generic.in.file.path = fname;
+ sfi.setattr.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ sfi.setattr.in.write_time = 0;
+
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Similar to batch17/18, but test with open share mode rather than
+ * share_none.
+ */
+static bool test_raw_oplock_batch26(struct torture_context *tctx,
+ struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname1 = BASEDIR "\\test_batch26_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch26_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_rename rn;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname1);
+ smbcli_unlink(cli1->tree, fname2);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname1;
+
+ torture_comment(tctx,
+ "BATCH26: open a file with an batch oplock "
+ "(share mode: all)\n");
+
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "rename should trigger a break\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_RENAME;
+ rn.rename.in.pattern1 = fname1;
+ rn.rename.in.pattern2 = fname2;
+ rn.rename.in.attrib = 0;
+
+ torture_comment(tctx, "trying rename while first file open\n");
+ status = smb_raw_rename(cli2->tree, &rn);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+ /* Close and reopen with batch again. */
+ smbcli_close(cli1->tree, fnum);
+ ZERO_STRUCT(break_info);
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ /* Now try ntrename. */
+ torture_comment(tctx, "ntrename should trigger a break\n");
+ ZERO_STRUCT(rn);
+ rn.generic.level = RAW_RENAME_NTRENAME;
+ rn.ntrename.in.attrib = 0;
+ rn.ntrename.in.flags = RENAME_FLAG_RENAME;
+ rn.ntrename.in.old_name = fname1;
+ rn.ntrename.in.new_name = fname2;
+ torture_comment(tctx, "trying rename while first file open\n");
+ status = smb_raw_rename(cli2->tree, &rn);
+ CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/* Test how oplocks work on streams. */
+static bool test_raw_oplock_stream1(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname_base = BASEDIR "\\test_stream1.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream, *fname_default_stream;
+ const char *default_stream = "::$DATA";
+ bool ret = true;
+ int fnum = -1;
+ int i;
+ int stream_fnum = -1;
+ uint32_t batch_req = NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK | NTCREATEX_FLAGS_EXTENDED;
+ uint32_t exclusive_req = NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_EXTENDED;
+
+#define NSTREAM_OPLOCK_RESULTS 8
+ struct {
+ const char **fname;
+ bool open_base_file;
+ uint32_t oplock_req;
+ uint32_t oplock_granted;
+ } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
+ /* Request oplock on stream without the base file open. */
+ {&fname_stream, false, batch_req, NO_OPLOCK_RETURN},
+ {&fname_default_stream, false, batch_req, NO_OPLOCK_RETURN},
+ {&fname_stream, false, exclusive_req, EXCLUSIVE_OPLOCK_RETURN},
+ {&fname_default_stream, false, exclusive_req, EXCLUSIVE_OPLOCK_RETURN},
+
+ /* Request oplock on stream with the base file open. */
+ {&fname_stream, true, batch_req, NO_OPLOCK_RETURN},
+ {&fname_default_stream, true, batch_req, NO_OPLOCK_RETURN},
+ {&fname_stream, true, exclusive_req, EXCLUSIVE_OPLOCK_RETURN},
+ {&fname_default_stream, true, exclusive_req, LEVEL_II_OPLOCK_RETURN},
+
+ };
+
+
+ /* Only passes against windows at the moment. */
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "STREAM1 disabled against samba3+4\n");
+ }
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
+ fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
+ default_stream);
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+ smbcli_unlink(cli1->tree, fname_base);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+
+ /* Setup generic open parameters. */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+
+ /* Create the file with a stream */
+ io.ntcreatex.in.fname = fname_stream;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ smbcli_close(cli1->tree, io.ntcreatex.out.file.fnum);
+
+ /* Change the disposition to open now that the file has been created. */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+
+ /* Try some permutations of taking oplocks on streams. */
+ for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
+ const char *fname = *stream_oplock_results[i].fname;
+ bool open_base_file = stream_oplock_results[i].open_base_file;
+ uint32_t oplock_req = stream_oplock_results[i].oplock_req;
+ uint32_t oplock_granted =
+ stream_oplock_results[i].oplock_granted;
+ int base_fnum = -1;
+
+ if (open_base_file) {
+ torture_comment(tctx, "Opening base file: %s with "
+ "%d\n", fname_base, batch_req);
+ io.ntcreatex.in.fname = fname_base;
+ io.ntcreatex.in.flags = batch_req;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ BATCH_OPLOCK_RETURN);
+ base_fnum = io.ntcreatex.out.file.fnum;
+ }
+
+ torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
+ fname, oplock_req);
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = oplock_req;
+
+ /* Do the open with the desired oplock on the stream. */
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, oplock_granted);
+ smbcli_close(cli1->tree, io.ntcreatex.out.file.fnum);
+
+ /* Cleanup the base file if it was opened. */
+ if (base_fnum != -1) {
+ smbcli_close(cli2->tree, base_fnum);
+ }
+ }
+
+ /* Open the stream with an exclusive oplock. */
+ torture_comment(tctx, "Opening stream: %s with %d\n",
+ fname_stream, exclusive_req);
+ io.ntcreatex.in.fname = fname_stream;
+ io.ntcreatex.in.flags = exclusive_req;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+ stream_fnum = io.ntcreatex.out.file.fnum;
+
+ /* Open the base file and see if it contends. */
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "Opening base file: %s with "
+ "%d\n", fname_base, batch_req);
+ io.ntcreatex.in.fname = fname_base;
+ io.ntcreatex.in.flags = batch_req;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ BATCH_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, io.ntcreatex.out.file.fnum);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Open the stream again to see if it contends. */
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "Opening stream again: %s with "
+ "%d\n", fname_base, batch_req);
+ io.ntcreatex.in.fname = fname_stream;
+ io.ntcreatex.in.flags = exclusive_req;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ LEVEL_II_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, io.ntcreatex.out.file.fnum);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Close the stream. */
+ if (stream_fnum != -1) {
+ smbcli_close(cli1->tree, stream_fnum);
+ }
+
+ done:
+ smbcli_close(cli1->tree, fnum);
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_raw_oplock_doc(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_oplock_doc.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ uint16_t fnum=0;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to set up test directory: " BASEDIR);
+
+ /* cleanup */
+ smbcli_unlink(cli->tree, fname);
+
+ smbcli_oplock_handler(cli->transport, oplock_handler_ack_to_given,
+ cli->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "open a file with a batch oplock\n");
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ torture_comment(tctx, "Set delete-on-close\n");
+ status = smbcli_nt_delete_on_close(cli->tree, fnum, true);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "2nd open should not break and get "
+ "DELETE_PENDING\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_DELETE_PENDING);
+ CHECK_VAL(break_info.count, 0);
+
+ smbcli_close(cli->tree, fnum);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/* Open a file with a batch oplock, then open it again from a second client
+ * requesting no oplock. Having two open file handles should break our own
+ * oplock during BRL acquisition.
+ */
+static bool test_raw_oplock_brl1(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ /*int fname, f;*/
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ uint16_t fnum=0;
+ uint16_t fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "open with batch oplock\n");
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+
+ if (smbcli_write(cli1->tree, fnum, 0, buf, 0, sizeof(buf)) !=
+ sizeof(buf))
+ {
+ torture_comment(tctx, "Failed to create file\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.fnum, fnum);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a self BRL acquisition should break to none\n");
+
+ status = smbcli_lock(cli1->tree, fnum, 0, 4, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* expect no oplock break */
+ ZERO_STRUCT(break_info);
+ status = smbcli_lock(cli1->tree, fnum, 2, 4, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.fnum, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+
+}
+
+/* Open a file with a batch oplock on one client and then acquire a brl.
+ * We should not contend our own oplock.
+ */
+static bool test_raw_oplock_brl2(struct torture_context *tctx, struct smbcli_state *cli1)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ /*int fname, f;*/
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ uint16_t fnum=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+
+ if (smbcli_write(cli1->tree, fnum, 0, buf, 0, sizeof(buf)) !=
+ sizeof(buf))
+ {
+ torture_comment(tctx, "Failed to create file\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "a self BRL acquisition should not break to "
+ "none\n");
+
+ status = smbcli_lock(cli1->tree, fnum, 0, 4, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ status = smbcli_lock(cli1->tree, fnum, 2, 4, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* With one file handle open a BRL should not contend our oplock.
+ * Thus, no oplock break will be received and the entire break_info
+ * struct will be 0 */
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.fnum, 0);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+
+done:
+ smb_raw_exit(cli1->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/* Open a file with a batch oplock twice from one client and then acquire a
+ * brl. BRL acquisition should break our own oplock.
+ */
+static bool test_raw_oplock_brl3(struct torture_context *tctx,
+ struct smbcli_state *cli1)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ uint16_t fnum=0;
+ uint16_t fnum2=0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "open with batch oplock\n");
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+
+ if (smbcli_write(cli1->tree, fnum, 0, buf, 0, sizeof(buf)) !=
+ sizeof(buf))
+ {
+ torture_comment(tctx, "Failed to create file\n");
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(tctx, "a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.fnum, fnum);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a self BRL acquisition should break to none\n");
+
+ status = smbcli_lock(cli1->tree, fnum, 0, 4, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+ CHECK_VAL(break_info.fnum, fnum);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* expect no oplock break */
+ ZERO_STRUCT(break_info);
+ status = smbcli_lock(cli1->tree, fnum, 2, 4, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.fnum, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli1->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * Open a file with an exclusive oplock from the 1st client and acquire a
+ * brl. Then open the same file from the 2nd client that should give oplock
+ * break with level2 to the 1st and return no oplock to the 2nd.
+ */
+static bool test_raw_oplock_brl4(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ uint16_t fnum = 0;
+ uint16_t fnum2 = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+ cli1->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "open with exclusive oplock\n");
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+
+ if (smbcli_write(cli1->tree, fnum, 0, buf, 0, sizeof(buf)) !=
+ sizeof(buf))
+ {
+ torture_comment(tctx, "Failed to create file\n");
+ goto done;
+ }
+
+ status = smbcli_lock(cli1->tree, fnum, 0, 1, 0, WRITE_LOCK);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+ torture_comment(tctx, "a 2nd open should give a break to the 1st\n");
+ ZERO_STRUCT(break_info);
+
+ status = smb_raw_open(cli2->tree, tctx, &io);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.fnum, fnum);
+
+ torture_comment(tctx, "and return no oplock to the 2nd\n");
+ fnum2 = io.ntcreatex.out.file.fnum;
+ CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+
+ smbcli_close(cli1->tree, fnum);
+ smbcli_close(cli2->tree, fnum2);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of oplocks
+*/
+struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "oplock");
+
+ torture_suite_add_2smb_test(suite, "exclusive1", test_raw_oplock_exclusive1);
+ torture_suite_add_2smb_test(suite, "exclusive2", test_raw_oplock_exclusive2);
+ torture_suite_add_2smb_test(suite, "exclusive3", test_raw_oplock_exclusive3);
+ torture_suite_add_2smb_test(suite, "exclusive4", test_raw_oplock_exclusive4);
+ torture_suite_add_2smb_test(suite, "exclusive5", test_raw_oplock_exclusive5);
+ torture_suite_add_2smb_test(suite, "exclusive6", test_raw_oplock_exclusive6);
+ torture_suite_add_2smb_test(suite, "exclusive7", test_raw_oplock_exclusive7);
+ torture_suite_add_2smb_test(suite, "exclusive8",
+ test_raw_oplock_exclusive8);
+ torture_suite_add_2smb_test(suite, "exclusive9",
+ test_raw_oplock_exclusive9);
+ torture_suite_add_2smb_test(suite, "level_ii_1",
+ test_raw_oplock_level_ii_1);
+ torture_suite_add_2smb_test(suite, "batch1", test_raw_oplock_batch1);
+ torture_suite_add_2smb_test(suite, "batch2", test_raw_oplock_batch2);
+ torture_suite_add_2smb_test(suite, "batch3", test_raw_oplock_batch3);
+ torture_suite_add_2smb_test(suite, "batch4", test_raw_oplock_batch4);
+ torture_suite_add_2smb_test(suite, "batch5", test_raw_oplock_batch5);
+ torture_suite_add_2smb_test(suite, "batch6", test_raw_oplock_batch6);
+ torture_suite_add_2smb_test(suite, "batch7", test_raw_oplock_batch7);
+ torture_suite_add_2smb_test(suite, "batch8", test_raw_oplock_batch8);
+ torture_suite_add_2smb_test(suite, "batch9", test_raw_oplock_batch9);
+ torture_suite_add_2smb_test(suite, "batch9a", test_raw_oplock_batch9a);
+ torture_suite_add_2smb_test(suite, "batch10", test_raw_oplock_batch10);
+ torture_suite_add_2smb_test(suite, "batch11", test_raw_oplock_batch11);
+ torture_suite_add_2smb_test(suite, "batch12", test_raw_oplock_batch12);
+ torture_suite_add_2smb_test(suite, "batch13", test_raw_oplock_batch13);
+ torture_suite_add_2smb_test(suite, "batch14", test_raw_oplock_batch14);
+ torture_suite_add_2smb_test(suite, "batch15", test_raw_oplock_batch15);
+ torture_suite_add_2smb_test(suite, "batch16", test_raw_oplock_batch16);
+ torture_suite_add_2smb_test(suite, "batch17", test_raw_oplock_batch17);
+ torture_suite_add_2smb_test(suite, "batch18", test_raw_oplock_batch18);
+ torture_suite_add_2smb_test(suite, "batch19", test_raw_oplock_batch19);
+ torture_suite_add_2smb_test(suite, "batch20", test_raw_oplock_batch20);
+ torture_suite_add_2smb_test(suite, "batch21", test_raw_oplock_batch21);
+ torture_suite_add_2smb_test(suite, "batch22", test_raw_oplock_batch22);
+ torture_suite_add_2smb_test(suite, "batch23", test_raw_oplock_batch23);
+ torture_suite_add_2smb_test(suite, "batch24", test_raw_oplock_batch24);
+ torture_suite_add_2smb_test(suite, "batch25", test_raw_oplock_batch25);
+ torture_suite_add_2smb_test(suite, "batch26", test_raw_oplock_batch26);
+ torture_suite_add_2smb_test(suite, "stream1", test_raw_oplock_stream1);
+ torture_suite_add_2smb_test(suite, "doc1", test_raw_oplock_doc);
+ torture_suite_add_2smb_test(suite, "brl1", test_raw_oplock_brl1);
+ torture_suite_add_1smb_test(suite, "brl2", test_raw_oplock_brl2);
+ torture_suite_add_1smb_test(suite, "brl3", test_raw_oplock_brl3);
+ torture_suite_add_2smb_test(suite, "brl4", test_raw_oplock_brl4);
+
+ return suite;
+}
+
+/*
+ stress testing of oplocks
+*/
+bool torture_bench_oplock(struct torture_context *torture)
+{
+ struct smbcli_state **cli;
+ bool ret = true;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ int torture_nprocs = torture_setting_int(torture, "nprocs", 4);
+ int i, count=0;
+ int timelimit = torture_setting_int(torture, "timelimit", 10);
+ union smb_open io;
+ struct timeval tv;
+
+ cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
+
+ torture_comment(torture, "Opening %d connections\n", torture_nprocs);
+ for (i=0;i<torture_nprocs;i++) {
+ if (!torture_open_connection_ev(&cli[i], i, torture, torture->ev)) {
+ return false;
+ }
+ talloc_steal(mem_ctx, cli[i]);
+ smbcli_oplock_handler(cli[i]->transport, oplock_handler_close,
+ cli[i]->tree);
+ }
+
+ if (!torture_setup_dir(cli[0], BASEDIR)) {
+ ret = false;
+ goto done;
+ }
+
+ io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = BASEDIR "\\test.dat";
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ tv = timeval_current();
+
+ /*
+ we open the same file with SHARE_ACCESS_NONE from all the
+ connections in a round robin fashion. Each open causes an
+ oplock break on the previous connection, which is answered
+ by the oplock_handler_close() to close the file.
+
+ This measures how fast we can pass on oplocks, and stresses
+ the oplock handling code
+ */
+ torture_comment(torture, "Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ for (i=0;i<torture_nprocs;i++) {
+ NTSTATUS status;
+
+ status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
+ CHECK_STATUS(torture, status, NT_STATUS_OK);
+ count++;
+ }
+
+ if (torture_setting_bool(torture, "progress", true)) {
+ torture_comment(torture, "%.2f ops/second\r", count/timeval_elapsed(&tv));
+ }
+ }
+
+ torture_comment(torture, "%.2f ops/second\n", count/timeval_elapsed(&tv));
+
+ smb_raw_exit(cli[torture_nprocs-1]->session);
+
+done:
+ smb_raw_exit(cli[0]->session);
+ smbcli_deltree(cli[0]->tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+static struct hold_oplock_info {
+ const char *fname;
+ bool close_on_break;
+ uint32_t share_access;
+ uint16_t fnum;
+} hold_info[] = {
+ {
+ .fname = BASEDIR "\\notshared_close",
+ .close_on_break = true,
+ .share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ },
+ {
+ .fname = BASEDIR "\\notshared_noclose",
+ .close_on_break = false,
+ .share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ },
+ {
+ .fname = BASEDIR "\\shared_close",
+ .close_on_break = true,
+ .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ },
+ {
+ .fname = BASEDIR "\\shared_noclose",
+ .close_on_break = false,
+ .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ },
+};
+
+static bool oplock_handler_hold(struct smbcli_transport *transport,
+ uint16_t tid, uint16_t fnum, uint8_t level,
+ void *private_data)
+{
+ struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
+ struct hold_oplock_info *info;
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(hold_info);i++) {
+ if (hold_info[i].fnum == fnum) break;
+ }
+
+ if (i == ARRAY_SIZE(hold_info)) {
+ printf("oplock break for unknown fnum %u\n", fnum);
+ return false;
+ }
+
+ info = &hold_info[i];
+
+ if (info->close_on_break) {
+ printf("oplock break on %s - closing\n",
+ info->fname);
+ oplock_handler_close(transport, tid, fnum, level, private_data);
+ return true;
+ }
+
+ printf("oplock break on %s - acking break\n", info->fname);
+
+ return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
+}
+
+
+/*
+ used for manual testing of oplocks - especially interaction with
+ other filesystems (such as NFS and local access)
+*/
+bool torture_hold_oplock(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ struct tevent_context *ev = torture->ev;
+ int i;
+
+ printf("Setting up open files with oplocks in %s\n", BASEDIR);
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to set up test directory: " BASEDIR);
+
+ smbcli_oplock_handler(cli->transport, oplock_handler_hold, cli->tree);
+
+ /* setup the files */
+ for (i=0;i<ARRAY_SIZE(hold_info);i++) {
+ union smb_open io;
+ NTSTATUS status;
+ char c = 1;
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = hold_info[i].share_access;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = hold_info[i].fname;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ printf("opening %s\n", hold_info[i].fname);
+
+ status = smb_raw_open(cli->tree, cli, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to open %s - %s\n",
+ hold_info[i].fname, nt_errstr(status));
+ return false;
+ }
+
+ if (io.ntcreatex.out.oplock_level != BATCH_OPLOCK_RETURN) {
+ printf("Oplock not granted for %s - expected %d but got %d\n",
+ hold_info[i].fname, BATCH_OPLOCK_RETURN,
+ io.ntcreatex.out.oplock_level);
+ return false;
+ }
+ hold_info[i].fnum = io.ntcreatex.out.file.fnum;
+
+ /* make the file non-zero size */
+ if (smbcli_write(cli->tree, hold_info[i].fnum, 0, &c, 0, 1) != 1) {
+ printf("Failed to write to file\n");
+ return false;
+ }
+ }
+
+ printf("Waiting for oplock events\n");
+ tevent_loop_wait(ev);
+
+ return true;
+}
diff --git a/source4/torture/raw/pingpong.c b/source4/torture/raw/pingpong.c
new file mode 100644
index 0000000..61f1d6b
--- /dev/null
+++ b/source4/torture/raw/pingpong.c
@@ -0,0 +1,248 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ ping pong test
+
+ Copyright (C) Ronnie Sahlberg 2007
+
+ Significantly based on and borrowed from lockbench.c by
+ Copyright (C) Andrew Tridgell 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ filename is specified by
+ --option=torture:filename=...
+
+ number of locks is specified by
+ --option=torture:num_locks=...
+
+ locktimeout is specified in ms by
+ --option=torture:locktimeout=...
+
+ default is 100 seconds
+ if set to 0 pingpong will instead loop trying the lock operation
+ over and over until it completes.
+
+ reading from the file can be enabled with
+ --option=torture:read=true
+
+ writing to the file can be enabled with
+ --option=torture:write=true
+
+*/
+#include "includes.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+static void lock_byte(struct smbcli_state *cli, int fd, int offset, int lock_timeout)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock;
+ NTSTATUS status;
+
+try_again:
+ ZERO_STRUCT(lock);
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+
+ lock.count = 1;
+ lock.offset = offset;
+ lock.pid = cli->tree->session->pid;
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = lock_timeout;
+ io.lockx.in.locks = &lock;
+ io.lockx.in.file.fnum = fd;
+
+ status = smb_raw_lock(cli->tree, &io);
+
+ /* If we don't use timeouts and we got file lock conflict
+ just try the lock again.
+ */
+ if (lock_timeout==0) {
+ if ( (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status))
+ ||(NT_STATUS_EQUAL(NT_STATUS_LOCK_NOT_GRANTED, status)) ) {
+ goto try_again;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Lock failed\n"));
+ exit(1);
+ }
+}
+
+static void unlock_byte(struct smbcli_state *cli, int fd, int offset)
+{
+ union smb_lock io;
+ struct smb_lock_entry lock;
+ NTSTATUS status;
+
+ ZERO_STRUCT(lock);
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+
+ lock.count = 1;
+ lock.offset = offset;
+ lock.pid = cli->tree->session->pid;
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 100000;
+ io.lockx.in.locks = &lock;
+ io.lockx.in.file.fnum = fd;
+
+ status = smb_raw_lock(cli->tree, &io);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Unlock failed\n"));
+ exit(1);
+ }
+}
+
+static void write_byte(struct smbcli_state *cli, int fd, uint8_t c, int offset)
+{
+ union smb_write io;
+ NTSTATUS status;
+
+ io.generic.level = RAW_WRITE_WRITEX;
+ io.writex.in.file.fnum = fd;
+ io.writex.in.offset = offset;
+ io.writex.in.wmode = 0;
+ io.writex.in.remaining = 0;
+ io.writex.in.count = 1;
+ io.writex.in.data = &c;
+
+ status = smb_raw_write(cli->tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("write failed\n");
+ exit(1);
+ }
+}
+
+static void read_byte(struct smbcli_state *cli, int fd, uint8_t *c, int offset)
+{
+ union smb_read io;
+ NTSTATUS status;
+
+ io.generic.level = RAW_READ_READX;
+ io.readx.in.file.fnum = fd;
+ io.readx.in.mincnt = 1;
+ io.readx.in.maxcnt = 1;
+ io.readx.in.offset = offset;
+ io.readx.in.remaining = 0;
+ io.readx.in.read_for_execute = false;
+ io.readx.out.data = c;
+
+ status = smb_raw_read(cli->tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("read failed\n");
+ exit(1);
+ }
+}
+
+/*
+ ping pong
+*/
+bool torture_ping_pong(struct torture_context *torture)
+{
+ const char *fn;
+ int num_locks;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ static bool do_reads;
+ static bool do_writes;
+ int lock_timeout;
+ int fd;
+ struct smbcli_state *cli;
+ int i;
+ uint8_t incr=0, last_incr=0;
+ uint8_t *val;
+ int count, loops;
+ struct timeval start;
+
+ fn = torture_setting_string(torture, "filename", NULL);
+ if (fn == NULL) {
+ DEBUG(0,("You must specify the filename using --option=torture:filename=...\n"));
+ return false;
+ }
+
+ num_locks = torture_setting_int(torture, "num_locks", -1);
+ if (num_locks == -1) {
+ DEBUG(0,("You must specify num_locks using --option=torture:num_locks=...\n"));
+ return false;
+ }
+
+ do_reads = torture_setting_bool(torture, "read", false);
+ do_writes = torture_setting_bool(torture, "write", false);
+ lock_timeout = torture_setting_int(torture, "lock_timeout", 100000);
+
+ if (!torture_open_connection(&cli, torture, 0)) {
+ DEBUG(0,("Could not open connection\n"));
+ return false;
+ }
+
+ fd = smbcli_open(cli->tree, fn, O_RDWR|O_CREAT, DENY_NONE);
+ if (fd == -1) {
+ printf("Failed to open %s\n", fn);
+ exit(1);
+ }
+
+ write_byte(cli, fd, 0, num_locks);
+ lock_byte(cli, fd, 0, lock_timeout);
+
+
+ start = timeval_current();
+ val = talloc_zero_array(mem_ctx, uint8_t, num_locks);
+ i = 0;
+ count = 0;
+ loops = 0;
+ while (1) {
+ lock_byte(cli, fd, (i+1)%num_locks, lock_timeout);
+
+ if (do_reads) {
+ uint8_t c;
+ read_byte(cli, fd, &c, i);
+ incr = c-val[i];
+ val[i] = c;
+ }
+
+ if (do_writes) {
+ uint8_t c = val[i] + 1;
+ write_byte(cli, fd, c, i);
+ }
+
+ unlock_byte(cli, fd, i);
+
+ i = (i+1)%num_locks;
+ count++;
+ if (loops>num_locks && incr!=last_incr) {
+ last_incr = incr;
+ printf("data increment = %u\n", incr);
+ fflush(stdout);
+ }
+ if (timeval_elapsed(&start) > 1.0) {
+ printf("%8u locks/sec\r",
+ (unsigned)(2*count/timeval_elapsed(&start)));
+ fflush(stdout);
+ start = timeval_current();
+ count=0;
+ }
+ loops++;
+ }
+}
+
diff --git a/source4/torture/raw/qfileinfo.c b/source4/torture/raw/qfileinfo.c
new file mode 100644
index 0000000..1d29281
--- /dev/null
+++ b/source4/torture/raw/qfileinfo.c
@@ -0,0 +1,1084 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_FILEINFO_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "torture/raw/proto.h"
+
+static struct {
+ const char *name;
+ enum smb_fileinfo_level level;
+ unsigned int only_paths:1;
+ unsigned int only_handles:1;
+ uint32_t capability_mask;
+ unsigned int expected_ipc_access_denied:1;
+ NTSTATUS expected_ipc_fnum_status;
+ NTSTATUS fnum_status, fname_status;
+ union smb_fileinfo fnum_finfo, fname_finfo;
+} levels[] = {
+ {
+ .name = "GETATTR",
+ .level = RAW_FILEINFO_GETATTR,
+ .only_paths = 1,
+ .only_handles = 0,
+ .expected_ipc_access_denied = 1,
+ },
+ {
+ .name ="GETATTRE",
+ .level = RAW_FILEINFO_GETATTRE,
+ .only_paths = 0,
+ .only_handles = 1,
+ },
+ {
+ .name ="STANDARD",
+ .level = RAW_FILEINFO_STANDARD,
+ },
+ {
+ .name ="EA_SIZE",
+ .level = RAW_FILEINFO_EA_SIZE,
+ },
+ {
+ .name ="ALL_EAS",
+ .level = RAW_FILEINFO_ALL_EAS,
+ .expected_ipc_fnum_status = NT_STATUS_ACCESS_DENIED,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name ="IS_NAME_VALID",
+ .level = RAW_FILEINFO_IS_NAME_VALID,
+ .only_paths = 1,
+ .only_handles = 0,
+ },
+ {
+ .name ="BASIC_INFO",
+ .level = RAW_FILEINFO_BASIC_INFO,
+ },
+ {
+ .name ="STANDARD_INFO",
+ .level = RAW_FILEINFO_STANDARD_INFO,
+ },
+ {
+ .name ="EA_INFO",
+ .level = RAW_FILEINFO_EA_INFO,
+ },
+ {
+ .name ="NAME_INFO",
+ .level = RAW_FILEINFO_NAME_INFO,
+ },
+ {
+ .name ="ALL_INFO",
+ .level = RAW_FILEINFO_ALL_INFO,
+ },
+ {
+ .name ="ALT_NAME_INFO",
+ .level = RAW_FILEINFO_ALT_NAME_INFO,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name ="STREAM_INFO",
+ .level = RAW_FILEINFO_STREAM_INFO,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name ="COMPRESSION_INFO",
+ .level = RAW_FILEINFO_COMPRESSION_INFO,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name ="UNIX_BASIC_INFO",
+ .level = RAW_FILEINFO_UNIX_BASIC,
+ .only_paths = 0,
+ .only_handles = 0,
+ .capability_mask = CAP_UNIX,
+ },
+ {
+ .name ="UNIX_LINK_INFO",
+ .level = RAW_FILEINFO_UNIX_LINK,
+ .only_paths = 0,
+ .only_handles = 0,
+ .capability_mask = CAP_UNIX,
+ },
+ {
+ .name ="BASIC_INFORMATION",
+ .level = RAW_FILEINFO_BASIC_INFORMATION,
+ },
+ {
+ .name ="STANDARD_INFORMATION",
+ .level = RAW_FILEINFO_STANDARD_INFORMATION,
+ },
+ {
+ .name ="INTERNAL_INFORMATION",
+ .level = RAW_FILEINFO_INTERNAL_INFORMATION,
+ },
+ {
+ .name ="EA_INFORMATION",
+ .level = RAW_FILEINFO_EA_INFORMATION,
+ },
+ {
+ .name = "ACCESS_INFORMATION",
+ .level = RAW_FILEINFO_ACCESS_INFORMATION,
+ },
+ {
+ .name = "NAME_INFORMATION",
+ .level = RAW_FILEINFO_NAME_INFORMATION,
+ },
+ {
+ .name ="POSITION_INFORMATION",
+ .level = RAW_FILEINFO_POSITION_INFORMATION,
+ },
+ {
+ .name ="MODE_INFORMATION",
+ .level = RAW_FILEINFO_MODE_INFORMATION,
+ },
+ {
+ .name ="ALIGNMENT_INFORMATION",
+ .level = RAW_FILEINFO_ALIGNMENT_INFORMATION,
+ },
+ {
+ .name ="ALL_INFORMATION",
+ .level = RAW_FILEINFO_ALL_INFORMATION,
+ },
+ {
+ .name ="ALT_NAME_INFORMATION",
+ .level = RAW_FILEINFO_ALT_NAME_INFORMATION,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name ="STREAM_INFORMATION",
+ .level = RAW_FILEINFO_STREAM_INFORMATION,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name = "COMPRESSION_INFORMATION",
+ .level = RAW_FILEINFO_COMPRESSION_INFORMATION,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name ="NETWORK_OPEN_INFORMATION",
+ .level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ {
+ .name = "ATTRIBUTE_TAG_INFORMATION",
+ .level = RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION,
+ .expected_ipc_fnum_status = NT_STATUS_INVALID_PARAMETER,
+ .fnum_status = NT_STATUS_SUCCESS,
+ .fname_status = NT_STATUS_SUCCESS,
+ .fnum_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ .fname_finfo = {
+ .generic = {
+ .level = 0,
+ },
+ },
+ },
+ { .name = NULL, },
+};
+
+/*
+ compare a dos time (2 second resolution) to a nt time
+*/
+static int dos_nt_time_cmp(time_t t, NTTIME nt)
+{
+ time_t t2 = nt_time_to_unix(nt);
+ if (labs(t2 - t) <= 2) return 0;
+ return t2 > t ? 1 : -1;
+}
+
+
+/*
+ find a level in the levels[] table
+*/
+static union smb_fileinfo *fnum_find(const char *name)
+{
+ int i;
+ for (i=0; levels[i].name; i++) {
+ if (NT_STATUS_IS_OK(levels[i].fnum_status) &&
+ strcmp(name, levels[i].name) == 0 &&
+ !levels[i].only_paths) {
+ return &levels[i].fnum_finfo;
+ }
+ }
+ return NULL;
+}
+
+/*
+ find a level in the levels[] table
+*/
+static union smb_fileinfo *fname_find(bool is_ipc, const char *name)
+{
+ int i;
+ if (is_ipc) {
+ return NULL;
+ }
+ for (i=0; levels[i].name; i++) {
+ if (NT_STATUS_IS_OK(levels[i].fname_status) &&
+ strcmp(name, levels[i].name) == 0 &&
+ !levels[i].only_handles) {
+ return &levels[i].fname_finfo;
+ }
+ }
+ return NULL;
+}
+
+/* local macros to make the code below more readable */
+#define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
+ printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
+ #n1, #v1, (unsigned int)s1->n1.out.v1, \
+ #n2, #v2, (unsigned int)s2->n2.out.v2, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+#define STR_EQUAL(n1, v1, n2, v2) do {if (strcmp_safe(s1->n1.out.v1.s, s2->n2.out.v2.s) || \
+ s1->n1.out.v1.private_length != s2->n2.out.v2.private_length) { \
+ printf("%s/%s [%s/%d] != %s/%s [%s/%d] at %s(%d)\n", \
+ #n1, #v1, s1->n1.out.v1.s, s1->n1.out.v1.private_length, \
+ #n2, #v2, s2->n2.out.v2.s, s2->n2.out.v2.private_length, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+#define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
+ printf("%s/%s != %s/%s at %s(%d)\n", \
+ #n1, #v1, \
+ #n2, #v2, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+/* used to find hints on unknown values - and to make sure
+ we zero-fill */
+#if 0 /* unused */
+#define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
+ printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
+ #n1, #v1, \
+ (unsigned int)s1->n1.out.v1, \
+ (unsigned int)s1->n1.out.v1, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+#endif
+
+/* basic testing of all RAW_FILEINFO_* calls
+ for each call we test that it succeeds, and where possible test
+ for consistency between the calls.
+*/
+static bool torture_raw_qfileinfo_internals(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_tree *tree,
+ int fnum, const char *fname,
+ bool is_ipc)
+{
+ size_t i;
+ bool ret = true;
+ size_t count;
+ union smb_fileinfo *s1, *s2;
+ NTTIME correct_time;
+ uint64_t correct_size;
+ uint32_t correct_attrib;
+ const char *correct_name;
+ bool skip_streams = false;
+
+ /* scan all the fileinfo and pathinfo levels */
+ for (i=0; levels[i].name; i++) {
+ if (!levels[i].only_paths) {
+ levels[i].fnum_finfo.generic.level = levels[i].level;
+ levels[i].fnum_finfo.generic.in.file.fnum = fnum;
+ levels[i].fnum_status = smb_raw_fileinfo(tree, mem_ctx,
+ &levels[i].fnum_finfo);
+ }
+
+ if (!levels[i].only_handles) {
+ levels[i].fname_finfo.generic.level = levels[i].level;
+ levels[i].fname_finfo.generic.in.file.path = talloc_strdup(mem_ctx, fname);
+ levels[i].fname_status = smb_raw_pathinfo(tree, mem_ctx,
+ &levels[i].fname_finfo);
+ }
+ }
+
+ /* check for completely broken levels */
+ for (count=i=0; levels[i].name; i++) {
+ uint32_t cap = tree->session->transport->negotiate.capabilities;
+ /* see if this server claims to support this level */
+ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
+ continue;
+ }
+
+ if (is_ipc) {
+ if (levels[i].expected_ipc_access_denied && NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, levels[i].fname_status)) {
+ } else if (!levels[i].only_handles &&
+ NT_STATUS_EQUAL(levels[i].fname_status,
+ NT_STATUS_NOT_SUPPORTED)) {
+ torture_warning(torture, "fname level %s %s",
+ levels[i].name,
+ nt_errstr(levels[i].fname_status));
+ continue;
+ } else if (!levels[i].only_handles && !NT_STATUS_EQUAL(NT_STATUS_INVALID_DEVICE_REQUEST, levels[i].fname_status)) {
+ printf("ERROR: fname level %s failed, expected NT_STATUS_INVALID_DEVICE_REQUEST - %s\n",
+ levels[i].name, nt_errstr(levels[i].fname_status));
+ count++;
+ }
+ if (!levels[i].only_paths &&
+ (NT_STATUS_EQUAL(levels[i].fnum_status,
+ NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(levels[i].fnum_status,
+ NT_STATUS_NOT_IMPLEMENTED))) {
+ torture_warning(torture, "fnum level %s %s",
+ levels[i].name,
+ nt_errstr(levels[i].fnum_status));
+ continue;
+ }
+ if (!levels[i].only_paths && !NT_STATUS_EQUAL(levels[i].expected_ipc_fnum_status, levels[i].fnum_status)) {
+ printf("ERROR: fnum level %s failed, expected %s - %s\n",
+ levels[i].name, nt_errstr(levels[i].expected_ipc_fnum_status),
+ nt_errstr(levels[i].fnum_status));
+ count++;
+ }
+ } else {
+ if (!levels[i].only_paths &&
+ (NT_STATUS_EQUAL(levels[i].fnum_status,
+ NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(levels[i].fnum_status,
+ NT_STATUS_NOT_IMPLEMENTED))) {
+ torture_warning(torture, "fnum level %s %s",
+ levels[i].name,
+ nt_errstr(levels[i].fnum_status));
+ continue;
+ }
+
+ if (!levels[i].only_handles &&
+ (NT_STATUS_EQUAL(levels[i].fname_status,
+ NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(levels[i].fname_status,
+ NT_STATUS_NOT_IMPLEMENTED))) {
+ torture_warning(torture, "fname level %s %s",
+ levels[i].name,
+ nt_errstr(levels[i].fname_status));
+ continue;
+ }
+
+ if (!levels[i].only_paths && !NT_STATUS_IS_OK(levels[i].fnum_status)) {
+ printf("ERROR: fnum level %s failed - %s\n",
+ levels[i].name, nt_errstr(levels[i].fnum_status));
+ count++;
+ }
+ if (!levels[i].only_handles && !NT_STATUS_IS_OK(levels[i].fname_status)) {
+ printf("ERROR: fname level %s failed - %s\n",
+ levels[i].name, nt_errstr(levels[i].fname_status));
+ count++;
+ }
+ }
+
+ }
+
+ if (count != 0) {
+ ret = false;
+ printf("%zu levels failed\n", count);
+ if (count > 35) {
+ torture_fail(torture, "too many level failures - giving up");
+ }
+ }
+
+ /* see if we can do streams */
+ s1 = fnum_find("STREAM_INFO");
+ if (!s1 || s1->stream_info.out.num_streams == 0) {
+ if (!is_ipc) {
+ printf("STREAM_INFO broken (%d) - skipping streams checks\n",
+ s1 ? s1->stream_info.out.num_streams : -1);
+ }
+ skip_streams = true;
+ }
+
+
+ /* this code is incredibly repititive but doesn't lend itself to loops, so
+ we use lots of macros to make it less painful */
+
+ /* first off we check the levels that are supposed to be aliases. It will be quite rare for
+ this code to fail, but we need to check it for completeness */
+
+
+
+#define ALIAS_CHECK(sname1, sname2) \
+ do { \
+ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
+ if (s1 && s2) { INFO_CHECK } \
+ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
+ if (s1 && s2) { INFO_CHECK } \
+ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
+ if (s1 && s2) { INFO_CHECK } \
+ } while (0)
+
+#define INFO_CHECK \
+ STRUCT_EQUAL(basic_info, create_time, basic_info, create_time); \
+ STRUCT_EQUAL(basic_info, access_time, basic_info, access_time); \
+ STRUCT_EQUAL(basic_info, write_time, basic_info, write_time); \
+ STRUCT_EQUAL(basic_info, change_time, basic_info, change_time); \
+ VAL_EQUAL (basic_info, attrib, basic_info, attrib);
+
+ ALIAS_CHECK("BASIC_INFO", "BASIC_INFORMATION");
+
+#undef INFO_CHECK
+#define INFO_CHECK \
+ VAL_EQUAL(standard_info, alloc_size, standard_info, alloc_size); \
+ VAL_EQUAL(standard_info, size, standard_info, size); \
+ VAL_EQUAL(standard_info, nlink, standard_info, nlink); \
+ VAL_EQUAL(standard_info, delete_pending, standard_info, delete_pending); \
+ VAL_EQUAL(standard_info, directory, standard_info, directory);
+
+ ALIAS_CHECK("STANDARD_INFO", "STANDARD_INFORMATION");
+
+#undef INFO_CHECK
+#define INFO_CHECK \
+ VAL_EQUAL(ea_info, ea_size, ea_info, ea_size);
+
+ ALIAS_CHECK("EA_INFO", "EA_INFORMATION");
+
+#undef INFO_CHECK
+#define INFO_CHECK \
+ STR_EQUAL(name_info, fname, name_info, fname);
+
+ ALIAS_CHECK("NAME_INFO", "NAME_INFORMATION");
+
+#undef INFO_CHECK
+#define INFO_CHECK \
+ STRUCT_EQUAL(all_info, create_time, all_info, create_time); \
+ STRUCT_EQUAL(all_info, access_time, all_info, access_time); \
+ STRUCT_EQUAL(all_info, write_time, all_info, write_time); \
+ STRUCT_EQUAL(all_info, change_time, all_info, change_time); \
+ VAL_EQUAL(all_info, attrib, all_info, attrib); \
+ VAL_EQUAL(all_info, alloc_size, all_info, alloc_size); \
+ VAL_EQUAL(all_info, size, all_info, size); \
+ VAL_EQUAL(all_info, nlink, all_info, nlink); \
+ VAL_EQUAL(all_info, delete_pending, all_info, delete_pending); \
+ VAL_EQUAL(all_info, directory, all_info, directory); \
+ VAL_EQUAL(all_info, ea_size, all_info, ea_size); \
+ STR_EQUAL(all_info, fname, all_info, fname);
+
+ ALIAS_CHECK("ALL_INFO", "ALL_INFORMATION");
+
+#undef INFO_CHECK
+#define INFO_CHECK \
+ VAL_EQUAL(compression_info, compressed_size,compression_info, compressed_size); \
+ VAL_EQUAL(compression_info, format, compression_info, format); \
+ VAL_EQUAL(compression_info, unit_shift, compression_info, unit_shift); \
+ VAL_EQUAL(compression_info, chunk_shift, compression_info, chunk_shift); \
+ VAL_EQUAL(compression_info, cluster_shift, compression_info, cluster_shift);
+
+ ALIAS_CHECK("COMPRESSION_INFO", "COMPRESSION_INFORMATION");
+
+
+#undef INFO_CHECK
+#define INFO_CHECK \
+ STR_EQUAL(alt_name_info, fname, alt_name_info, fname);
+
+ ALIAS_CHECK("ALT_NAME_INFO", "ALT_NAME_INFORMATION");
+
+
+#define TIME_CHECK_NT(sname, stype, tfield) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
+ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
+ nt_time_string(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, correct_time)); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && memcmp(&s1->stype.out.tfield, &correct_time, sizeof(correct_time)) != 0) { \
+ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
+ nt_time_string(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, correct_time)); \
+ ret = false; \
+ }} while (0)
+
+#define TIME_CHECK_DOS(sname, stype, tfield) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
+ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
+ timestring(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, correct_time)); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && dos_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
+ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
+ timestring(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, correct_time)); \
+ ret = false; \
+ }} while (0)
+
+#if 0 /* unused */
+#define TIME_CHECK_UNX(sname, stype, tfield) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
+ printf("(%d) handle %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
+ timestring(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, correct_time)); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && unx_nt_time_cmp(s1->stype.out.tfield, correct_time) != 0) { \
+ printf("(%d) path %s/%s incorrect - %s should be %s\n", __LINE__, #stype, #tfield, \
+ timestring(mem_ctx, s1->stype.out.tfield), \
+ nt_time_string(mem_ctx, correct_time)); \
+ ret = false; \
+ }} while (0)
+#endif
+
+ /* now check that all the times that are supposed to be equal are correct */
+ s1 = fnum_find("BASIC_INFO");
+ correct_time = s1->basic_info.out.create_time;
+ torture_comment(torture, "create_time: %s\n", nt_time_string(mem_ctx, correct_time));
+
+ TIME_CHECK_NT ("BASIC_INFO", basic_info, create_time);
+ TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, create_time);
+ TIME_CHECK_DOS("GETATTRE", getattre, create_time);
+ TIME_CHECK_DOS("STANDARD", standard, create_time);
+ TIME_CHECK_DOS("EA_SIZE", ea_size, create_time);
+ TIME_CHECK_NT ("ALL_INFO", all_info, create_time);
+ TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, create_time);
+
+ s1 = fnum_find("BASIC_INFO");
+ correct_time = s1->basic_info.out.access_time;
+ torture_comment(torture, "access_time: %s\n", nt_time_string(mem_ctx, correct_time));
+
+ TIME_CHECK_NT ("BASIC_INFO", basic_info, access_time);
+ TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, access_time);
+ TIME_CHECK_DOS("GETATTRE", getattre, access_time);
+ TIME_CHECK_DOS("STANDARD", standard, access_time);
+ TIME_CHECK_DOS("EA_SIZE", ea_size, access_time);
+ TIME_CHECK_NT ("ALL_INFO", all_info, access_time);
+ TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, access_time);
+
+ s1 = fnum_find("BASIC_INFO");
+ correct_time = s1->basic_info.out.write_time;
+ torture_comment(torture, "write_time : %s\n", nt_time_string(mem_ctx, correct_time));
+
+ TIME_CHECK_NT ("BASIC_INFO", basic_info, write_time);
+ TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, write_time);
+ TIME_CHECK_DOS("GETATTR", getattr, write_time);
+ TIME_CHECK_DOS("GETATTRE", getattre, write_time);
+ TIME_CHECK_DOS("STANDARD", standard, write_time);
+ TIME_CHECK_DOS("EA_SIZE", ea_size, write_time);
+ TIME_CHECK_NT ("ALL_INFO", all_info, write_time);
+ TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, write_time);
+
+ s1 = fnum_find("BASIC_INFO");
+ correct_time = s1->basic_info.out.change_time;
+ torture_comment(torture, "change_time: %s\n", nt_time_string(mem_ctx, correct_time));
+
+ TIME_CHECK_NT ("BASIC_INFO", basic_info, change_time);
+ TIME_CHECK_NT ("BASIC_INFORMATION", basic_info, change_time);
+ TIME_CHECK_NT ("ALL_INFO", all_info, change_time);
+ TIME_CHECK_NT ("NETWORK_OPEN_INFORMATION", network_open_information, change_time);
+
+
+#define SIZE_CHECK(sname, stype, tfield) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && s1->stype.out.tfield != correct_size) { \
+ printf("(%d) handle %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
+ (unsigned int)s1->stype.out.tfield, \
+ (unsigned int)correct_size); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && s1->stype.out.tfield != correct_size) { \
+ printf("(%d) path %s/%s incorrect - %u should be %u\n", __LINE__, #stype, #tfield, \
+ (unsigned int)s1->stype.out.tfield, \
+ (unsigned int)correct_size); \
+ ret = false; \
+ }} while (0)
+
+ s1 = fnum_find("STANDARD_INFO");
+ correct_size = s1->standard_info.out.size;
+ torture_comment(torture, "size: %u\n", (unsigned int)correct_size);
+
+ SIZE_CHECK("GETATTR", getattr, size);
+ SIZE_CHECK("GETATTRE", getattre, size);
+ SIZE_CHECK("STANDARD", standard, size);
+ SIZE_CHECK("EA_SIZE", ea_size, size);
+ SIZE_CHECK("STANDARD_INFO", standard_info, size);
+ SIZE_CHECK("STANDARD_INFORMATION", standard_info, size);
+ SIZE_CHECK("ALL_INFO", all_info, size);
+ SIZE_CHECK("ALL_INFORMATION", all_info, size);
+ SIZE_CHECK("COMPRESSION_INFO", compression_info, compressed_size);
+ SIZE_CHECK("COMPRESSION_INFORMATION", compression_info, compressed_size);
+ SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, size);
+ if (!skip_streams) {
+ SIZE_CHECK("STREAM_INFO", stream_info, streams[0].size);
+ SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].size);
+ }
+
+
+ s1 = fnum_find("STANDARD_INFO");
+ correct_size = s1->standard_info.out.alloc_size;
+ torture_comment(torture, "alloc_size: %u\n", (unsigned int)correct_size);
+
+ SIZE_CHECK("GETATTRE", getattre, alloc_size);
+ SIZE_CHECK("STANDARD", standard, alloc_size);
+ SIZE_CHECK("EA_SIZE", ea_size, alloc_size);
+ SIZE_CHECK("STANDARD_INFO", standard_info, alloc_size);
+ SIZE_CHECK("STANDARD_INFORMATION", standard_info, alloc_size);
+ SIZE_CHECK("ALL_INFO", all_info, alloc_size);
+ SIZE_CHECK("ALL_INFORMATION", all_info, alloc_size);
+ SIZE_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, alloc_size);
+ if (!skip_streams) {
+ SIZE_CHECK("STREAM_INFO", stream_info, streams[0].alloc_size);
+ SIZE_CHECK("STREAM_INFORMATION", stream_info, streams[0].alloc_size);
+ }
+
+#define ATTRIB_CHECK(sname, stype, tfield) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && s1->stype.out.tfield != correct_attrib) { \
+ printf("(%d) handle %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
+ (unsigned int)s1->stype.out.tfield, \
+ (unsigned int)correct_attrib); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && s1->stype.out.tfield != correct_attrib) { \
+ printf("(%d) path %s/%s incorrect - 0x%x should be 0x%x\n", __LINE__, #stype, #tfield, \
+ (unsigned int)s1->stype.out.tfield, \
+ (unsigned int)correct_attrib); \
+ ret = false; \
+ }} while (0)
+
+ s1 = fnum_find("BASIC_INFO");
+ correct_attrib = s1->basic_info.out.attrib;
+ torture_comment(torture, "attrib: 0x%x\n", (unsigned int)correct_attrib);
+
+ ATTRIB_CHECK("GETATTR", getattr, attrib);
+ if (!is_ipc) {
+ ATTRIB_CHECK("GETATTRE", getattre, attrib);
+ ATTRIB_CHECK("STANDARD", standard, attrib);
+ ATTRIB_CHECK("EA_SIZE", ea_size, attrib);
+ }
+ ATTRIB_CHECK("BASIC_INFO", basic_info, attrib);
+ ATTRIB_CHECK("BASIC_INFORMATION", basic_info, attrib);
+ ATTRIB_CHECK("ALL_INFO", all_info, attrib);
+ ATTRIB_CHECK("ALL_INFORMATION", all_info, attrib);
+ ATTRIB_CHECK("NETWORK_OPEN_INFORMATION", network_open_information, attrib);
+ ATTRIB_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
+
+ correct_name = fname;
+ torture_comment(torture, "name: %s\n", correct_name);
+
+#define NAME_CHECK(sname, stype, tfield, flags) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
+ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
+ printf("(%d) handle %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
+ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && (strcmp_safe(s1->stype.out.tfield.s, correct_name) != 0 || \
+ wire_bad_flags(&s1->stype.out.tfield, flags, tree->session->transport))) { \
+ printf("(%d) path %s/%s incorrect - '%s/%d'\n", __LINE__, #stype, #tfield, \
+ s1->stype.out.tfield.s, s1->stype.out.tfield.private_length); \
+ ret = false; \
+ }} while (0)
+
+ NAME_CHECK("NAME_INFO", name_info, fname, STR_UNICODE);
+ NAME_CHECK("NAME_INFORMATION", name_info, fname, STR_UNICODE);
+
+ /* the ALL_INFO file name is the full path on the filesystem */
+ s1 = fnum_find("ALL_INFO");
+ if (s1 && !s1->all_info.out.fname.s) {
+ torture_fail(torture, "ALL_INFO didn't give a filename");
+ }
+ if (s1 && s1->all_info.out.fname.s) {
+ char *p = strrchr(s1->all_info.out.fname.s, '\\');
+ if (!p) {
+ printf("Not a full path in all_info/fname? - '%s'\n",
+ s1->all_info.out.fname.s);
+ ret = false;
+ } else {
+ if (strcmp_safe(correct_name, p) != 0) {
+ printf("incorrect basename in all_info/fname - '%s'\n",
+ s1->all_info.out.fname.s);
+ ret = false;
+ }
+ }
+ if (wire_bad_flags(&s1->all_info.out.fname, STR_UNICODE, tree->session->transport)) {
+ printf("Should not null terminate all_info/fname\n");
+ ret = false;
+ }
+ }
+
+ s1 = fnum_find("ALT_NAME_INFO");
+ if (s1) {
+ correct_name = s1->alt_name_info.out.fname.s;
+ }
+
+ if (!correct_name) {
+ torture_comment(torture, "no alternate name information\n");
+ } else {
+ torture_comment(torture, "alt_name: %s\n", correct_name);
+
+ NAME_CHECK("ALT_NAME_INFO", alt_name_info, fname, STR_UNICODE);
+ NAME_CHECK("ALT_NAME_INFORMATION", alt_name_info, fname, STR_UNICODE);
+
+ /* and make sure we can open by alternate name */
+ smbcli_close(tree, fnum);
+ fnum = smbcli_nt_create_full(tree, correct_name, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+ if (fnum == -1) {
+ printf("Unable to open by alt_name - %s\n", smbcli_errstr(tree));
+ ret = false;
+ }
+
+ if (!skip_streams) {
+ correct_name = "::$DATA";
+ torture_comment(torture, "stream_name: %s\n", correct_name);
+
+ NAME_CHECK("STREAM_INFO", stream_info, streams[0].stream_name, STR_UNICODE);
+ NAME_CHECK("STREAM_INFORMATION", stream_info, streams[0].stream_name, STR_UNICODE);
+ }
+ }
+
+ /* make sure the EAs look right */
+ s1 = fnum_find("ALL_EAS");
+ s2 = fnum_find("ALL_INFO");
+ if (s1) {
+ for (i=0;i<s1->all_eas.out.num_eas;i++) {
+ printf(" flags=%d %s=%*.*s\n",
+ s1->all_eas.out.eas[i].flags,
+ s1->all_eas.out.eas[i].name.s,
+ (int)s1->all_eas.out.eas[i].value.length,
+ (int)s1->all_eas.out.eas[i].value.length,
+ s1->all_eas.out.eas[i].value.data);
+ }
+ }
+ if (s1 && s2) {
+ if (s1->all_eas.out.num_eas == 0) {
+ if (s2->all_info.out.ea_size != 0) {
+ printf("ERROR: num_eas==0 but fnum all_info.out.ea_size == %d\n",
+ s2->all_info.out.ea_size);
+ }
+ } else {
+ if (s2->all_info.out.ea_size !=
+ ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas)) {
+ printf("ERROR: ea_list_size=%d != fnum all_info.out.ea_size=%d\n",
+ (int)ea_list_size(s1->all_eas.out.num_eas, s1->all_eas.out.eas),
+ (int)s2->all_info.out.ea_size);
+ }
+ }
+ }
+ s2 = fname_find(is_ipc, "ALL_EAS");
+ if (s2) {
+ VAL_EQUAL(all_eas, num_eas, all_eas, num_eas);
+ for (i=0;i<s1->all_eas.out.num_eas;i++) {
+ VAL_EQUAL(all_eas, eas[i].flags, all_eas, eas[i].flags);
+ STR_EQUAL(all_eas, eas[i].name, all_eas, eas[i].name);
+ VAL_EQUAL(all_eas, eas[i].value.length, all_eas, eas[i].value.length);
+ }
+ }
+
+#define VAL_CHECK(sname1, stype1, tfield1, sname2, stype2, tfield2) do { \
+ s1 = fnum_find(sname1); s2 = fnum_find(sname2); \
+ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
+ printf("(%d) handle %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
+ #stype1, #tfield1, #stype2, #tfield2, \
+ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname1); s2 = fname_find(is_ipc, sname2); \
+ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
+ printf("(%d) path %s/%s != %s/%s - 0x%x vs 0x%x\n", __LINE__, \
+ #stype1, #tfield1, #stype2, #tfield2, \
+ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
+ ret = false; \
+ } \
+ s1 = fnum_find(sname1); s2 = fname_find(is_ipc, sname2); \
+ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
+ printf("(%d) handle %s/%s != path %s/%s - 0x%x vs 0x%x\n", __LINE__, \
+ #stype1, #tfield1, #stype2, #tfield2, \
+ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
+ ret = false; \
+ } \
+ s1 = fname_find(is_ipc, sname1); s2 = fnum_find(sname2); \
+ if (s1 && s2 && s1->stype1.out.tfield1 != s2->stype2.out.tfield2) { \
+ printf("(%d) path %s/%s != handle %s/%s - 0x%x vs 0x%x\n", __LINE__, \
+ #stype1, #tfield1, #stype2, #tfield2, \
+ s1->stype1.out.tfield1, s2->stype2.out.tfield2); \
+ ret = false; \
+ }} while (0)
+
+ VAL_CHECK("STANDARD_INFO", standard_info, delete_pending,
+ "ALL_INFO", all_info, delete_pending);
+ VAL_CHECK("STANDARD_INFO", standard_info, directory,
+ "ALL_INFO", all_info, directory);
+ VAL_CHECK("STANDARD_INFO", standard_info, nlink,
+ "ALL_INFO", all_info, nlink);
+ s1 = fnum_find("BASIC_INFO");
+ if (s1 && is_ipc) {
+ if (s1->basic_info.out.attrib != FILE_ATTRIBUTE_NORMAL) {
+ printf("(%d) attrib basic_info/nlink incorrect - %d should be %d\n", __LINE__, s1->basic_info.out.attrib, (int)FILE_ATTRIBUTE_NORMAL);
+ ret = false;
+ }
+ }
+ s1 = fnum_find("STANDARD_INFO");
+ if (s1 && is_ipc) {
+ if (s1->standard_info.out.nlink != 1) {
+ printf("(%d) nlinks standard_info/nlink incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.nlink);
+ ret = false;
+ }
+ if (s1->standard_info.out.delete_pending != 1) {
+ printf("(%d) nlinks standard_info/delete_pending incorrect - %d should be 1\n", __LINE__, s1->standard_info.out.delete_pending);
+ ret = false;
+ }
+ }
+ VAL_CHECK("EA_INFO", ea_info, ea_size,
+ "ALL_INFO", all_info, ea_size);
+ if (!is_ipc) {
+ VAL_CHECK("EA_SIZE", ea_size, ea_size,
+ "ALL_INFO", all_info, ea_size);
+ }
+
+#define NAME_PATH_CHECK(sname, stype, field) do { \
+ s1 = fname_find(is_ipc, sname); s2 = fnum_find(sname); \
+ if (s1 && s2) { \
+ VAL_EQUAL(stype, field, stype, field); \
+ } \
+} while (0)
+
+
+ s1 = fnum_find("INTERNAL_INFORMATION");
+ if (s1) {
+ torture_comment(torture, "file_id=%.0f\n", (double)s1->internal_information.out.file_id);
+ }
+
+ NAME_PATH_CHECK("INTERNAL_INFORMATION", internal_information, file_id);
+ NAME_PATH_CHECK("POSITION_INFORMATION", position_information, position);
+ if (s1 && s2) {
+ printf("fnum pos = %.0f, fname pos = %.0f\n",
+ (double)s2->position_information.out.position,
+ (double)s1->position_information.out.position );
+ }
+ NAME_PATH_CHECK("MODE_INFORMATION", mode_information, mode);
+ NAME_PATH_CHECK("ALIGNMENT_INFORMATION", alignment_information, alignment_requirement);
+ NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, attrib);
+ NAME_PATH_CHECK("ATTRIBUTE_TAG_INFORMATION", attribute_tag_information, reparse_tag);
+
+#if 0
+ /* these are expected to differ */
+ NAME_PATH_CHECK("ACCESS_INFORMATION", access_information, access_flags);
+#endif
+
+#if 0 /* unused */
+#define UNKNOWN_CHECK(sname, stype, tfield) do { \
+ s1 = fnum_find(sname); \
+ if (s1 && s1->stype.out.tfield != 0) { \
+ printf("(%d) handle %s/%s unknown != 0 (0x%x)\n", __LINE__, \
+ #stype, #tfield, \
+ (unsigned int)s1->stype.out.tfield); \
+ } \
+ s1 = fname_find(is_ipc, sname); \
+ if (s1 && s1->stype.out.tfield != 0) { \
+ printf("(%d) path %s/%s unknown != 0 (0x%x)\n", __LINE__, \
+ #stype, #tfield, \
+ (unsigned int)s1->stype.out.tfield); \
+ }} while (0)
+#endif
+ /* now get a bit fancier .... */
+
+ /* when we set the delete disposition then the link count should drop
+ to 0 and delete_pending should be 1 */
+
+ return ret;
+}
+
+/* basic testing of all RAW_FILEINFO_* calls
+ for each call we test that it succeeds, and where possible test
+ for consistency between the calls.
+*/
+bool torture_raw_qfileinfo(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ int fnum;
+ bool ret;
+ const char *fname = "\\torture_qfileinfo.txt";
+
+ fnum = create_complex_file(cli, torture, fname);
+ if (fnum == -1) {
+ printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree, fnum, fname, false /* is_ipc */);
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+
+ return ret;
+}
+
+bool torture_raw_qfileinfo_pipe(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ int fnum;
+ const char *fname = "\\lsass";
+ union smb_open op;
+ NTSTATUS status;
+
+ op.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.access_mask =
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_WRITE_EA |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ op.ntcreatex.in.file_attr = 0;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.impersonation =
+ NTCREATEX_IMPERSONATION_IMPERSONATION;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, torture, &op);
+ torture_assert_ntstatus_ok(torture, status, "smb_raw_open failed");
+
+ fnum = op.ntcreatex.out.file.fnum;
+
+ ret = torture_raw_qfileinfo_internals(torture, torture, cli->tree,
+ fnum, fname,
+ true /* is_ipc */);
+
+ smbcli_close(cli->tree, fnum);
+ return ret;
+}
diff --git a/source4/torture/raw/qfsinfo.c b/source4/torture/raw/qfsinfo.c
new file mode 100644
index 0000000..6be6c42
--- /dev/null
+++ b/source4/torture/raw/qfsinfo.c
@@ -0,0 +1,340 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_QFS_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <math.h>
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/basic/proto.h"
+#include "torture/raw/proto.h"
+
+
+static struct {
+ const char *name;
+ enum smb_fsinfo_level level;
+ uint32_t capability_mask;
+ NTSTATUS status;
+ union smb_fsinfo fsinfo;
+} levels[] = {
+ {
+ .name = "DSKATTR",
+ .level = RAW_QFS_DSKATTR,
+ },
+ {
+ .name = "ALLOCATION",
+ .level = RAW_QFS_ALLOCATION,
+ },
+ {
+ .name = "VOLUME",
+ .level = RAW_QFS_VOLUME,
+ },
+ {
+ .name = "VOLUME_INFO",
+ .level = RAW_QFS_VOLUME_INFO,
+ },
+ {
+ .name = "SIZE_INFO",
+ .level = RAW_QFS_SIZE_INFO,
+ },
+ {
+ .name = "DEVICE_INFO",
+ .level = RAW_QFS_DEVICE_INFO,
+ },
+ {
+ .name = "ATTRIBUTE_INFO",
+ .level = RAW_QFS_ATTRIBUTE_INFO,
+ },
+ {
+ .name = "UNIX_INFO",
+ .level = RAW_QFS_UNIX_INFO,
+ .capability_mask = CAP_UNIX,
+ },
+ {
+ .name = "VOLUME_INFORMATION",
+ .level = RAW_QFS_VOLUME_INFORMATION,
+ },
+ {
+ .name = "SIZE_INFORMATION",
+ .level = RAW_QFS_SIZE_INFORMATION,
+ },
+ {
+ .name = "DEVICE_INFORMATION",
+ .level = RAW_QFS_DEVICE_INFORMATION,
+ },
+ {
+ .name = "ATTRIBUTE_INFORMATION",
+ .level = RAW_QFS_ATTRIBUTE_INFORMATION,
+ },
+ {
+ .name = "QUOTA_INFORMATION",
+ .level = RAW_QFS_QUOTA_INFORMATION,
+ },
+ {
+ .name = "FULL_SIZE_INFORMATION",
+ .level = RAW_QFS_FULL_SIZE_INFORMATION,
+ },
+#if 0
+ /* w2k3 seems to no longer support this */
+ {"OBJECTID_INFORMATION", RAW_QFS_OBJECTID_INFORMATION, },
+#endif
+ { .name = NULL, },
+};
+
+
+/*
+ find a level in the levels[] table
+*/
+static union smb_fsinfo *find(const char *name)
+{
+ int i;
+ for (i=0; levels[i].name; i++) {
+ if (strcmp(name, levels[i].name) == 0 &&
+ NT_STATUS_IS_OK(levels[i].status)) {
+ return &levels[i].fsinfo;
+ }
+ }
+ return NULL;
+}
+
+/* local macros to make the code below more readable */
+#define VAL_EQUAL(n1, v1, n2, v2) do {if (s1->n1.out.v1 != s2->n2.out.v2) { \
+ printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
+ #n1, #v1, (unsigned int)s1->n1.out.v1, \
+ #n2, #v2, (unsigned int)s2->n2.out.v2, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+#define VAL_APPROX_EQUAL(n1, v1, n2, v2) do {if (abs((int)(s1->n1.out.v1) - (int)(s2->n2.out.v2)) > 0.1*s1->n1.out.v1) { \
+ printf("%s/%s [%u] != %s/%s [%u] at %s(%d)\n", \
+ #n1, #v1, (unsigned int)s1->n1.out.v1, \
+ #n2, #v2, (unsigned int)s2->n2.out.v2, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+#define STR_EQUAL(n1, v1, n2, v2) do { \
+ if (strcmp_safe(s1->n1.out.v1, s2->n2.out.v2)) { \
+ printf("%s/%s [%s] != %s/%s [%s] at %s(%d)\n", \
+ #n1, #v1, s1->n1.out.v1, \
+ #n2, #v2, s2->n2.out.v2, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+#define STRUCT_EQUAL(n1, v1, n2, v2) do {if (memcmp(&s1->n1.out.v1,&s2->n2.out.v2,sizeof(s1->n1.out.v1))) { \
+ printf("%s/%s != %s/%s at %s(%d)\n", \
+ #n1, #v1, \
+ #n2, #v2, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+/* used to find hints on unknown values - and to make sure
+ we zero-fill */
+#define VAL_UNKNOWN(n1, v1) do {if (s1->n1.out.v1 != 0) { \
+ printf("%s/%s non-zero unknown - %u (0x%x) at %s(%d)\n", \
+ #n1, #v1, \
+ (unsigned int)s1->n1.out.v1, \
+ (unsigned int)s1->n1.out.v1, \
+ __FILE__, __LINE__); \
+ ret = false; \
+}} while(0)
+
+/* basic testing of all RAW_QFS_* calls
+ for each call we test that it succeeds, and where possible test
+ for consistency between the calls.
+
+ Some of the consistency tests assume that the target filesystem is
+ quiescent, which is sometimes hard to achieve
+*/
+bool torture_raw_qfsinfo(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ size_t i;
+ bool ret = true;
+ size_t count;
+ union smb_fsinfo *s1, *s2;
+
+ /* scan all the levels, pulling the results */
+ for (i=0; levels[i].name; i++) {
+ torture_comment(torture, "Running level %s\n", levels[i].name);
+ levels[i].fsinfo.generic.level = levels[i].level;
+ levels[i].status = smb_raw_fsinfo(cli->tree, torture, &levels[i].fsinfo);
+ }
+
+ /* check for completely broken levels */
+ for (count=i=0; levels[i].name; i++) {
+ uint32_t cap = cli->transport->negotiate.capabilities;
+ /* see if this server claims to support this level */
+ if ((cap & levels[i].capability_mask) != levels[i].capability_mask) {
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(levels[i].status)) {
+ printf("ERROR: level %s failed - %s\n",
+ levels[i].name, nt_errstr(levels[i].status));
+ count++;
+ }
+ }
+
+ if (count != 0) {
+ torture_comment(torture, "%zu levels failed\n", count);
+ torture_assert(torture, count > 13, "too many level failures - giving up");
+ }
+
+ torture_comment(torture, "check for correct aliases\n");
+ s1 = find("SIZE_INFO");
+ s2 = find("SIZE_INFORMATION");
+ if (s1 && s2) {
+ VAL_EQUAL(size_info, total_alloc_units, size_info, total_alloc_units);
+ VAL_APPROX_EQUAL(size_info, avail_alloc_units, size_info, avail_alloc_units);
+ VAL_EQUAL(size_info, sectors_per_unit, size_info, sectors_per_unit);
+ VAL_EQUAL(size_info, bytes_per_sector, size_info, bytes_per_sector);
+ }
+
+ s1 = find("DEVICE_INFO");
+ s2 = find("DEVICE_INFORMATION");
+ if (s1 && s2) {
+ VAL_EQUAL(device_info, device_type, device_info, device_type);
+ VAL_EQUAL(device_info, characteristics, device_info, characteristics);
+ }
+
+ s1 = find("VOLUME_INFO");
+ s2 = find("VOLUME_INFORMATION");
+ if (s1 && s2) {
+ STRUCT_EQUAL(volume_info, create_time, volume_info, create_time);
+ VAL_EQUAL (volume_info, serial_number, volume_info, serial_number);
+ STR_EQUAL (volume_info, volume_name.s, volume_info, volume_name.s);
+ torture_comment(torture, "volume_info.volume_name = '%s'\n", s1->volume_info.out.volume_name.s);
+ }
+
+ s1 = find("ATTRIBUTE_INFO");
+ s2 = find("ATTRIBUTE_INFORMATION");
+ if (s1 && s2) {
+ VAL_EQUAL(attribute_info, fs_attr,
+ attribute_info, fs_attr);
+ VAL_EQUAL(attribute_info, max_file_component_length,
+ attribute_info, max_file_component_length);
+ STR_EQUAL(attribute_info, fs_type.s, attribute_info, fs_type.s);
+ torture_comment(torture, "attribute_info.fs_type = '%s'\n", s1->attribute_info.out.fs_type.s);
+ }
+
+ torture_comment(torture, "check for consistent disk sizes\n");
+ s1 = find("DSKATTR");
+ s2 = find("ALLOCATION");
+ if (s1 && s2) {
+ double size1, size2;
+ double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
+ size1 = 1.0 *
+ s1->dskattr.out.units_total *
+ s1->dskattr.out.blocks_per_unit *
+ s1->dskattr.out.block_size / scale;
+ size2 = 1.0 *
+ s2->allocation.out.sectors_per_unit *
+ s2->allocation.out.total_alloc_units *
+ s2->allocation.out.bytes_per_sector / scale;
+ if (fabs(size1 - size2) > 1) {
+ printf("Inconsistent total size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
+ size1, size2);
+ ret = false;
+ }
+ torture_comment(torture, "total disk = %.0f MB\n", size1*scale/1.0e6);
+ }
+
+ torture_comment(torture, "check consistent free disk space\n");
+ s1 = find("DSKATTR");
+ s2 = find("ALLOCATION");
+ if (s1 && s2) {
+ double size1, size2;
+ double scale = s1->dskattr.out.blocks_per_unit * s1->dskattr.out.block_size;
+ size1 = 1.0 *
+ s1->dskattr.out.units_free *
+ s1->dskattr.out.blocks_per_unit *
+ s1->dskattr.out.block_size / scale;
+ size2 = 1.0 *
+ s2->allocation.out.sectors_per_unit *
+ s2->allocation.out.avail_alloc_units *
+ s2->allocation.out.bytes_per_sector / scale;
+ if (fabs(size1 - size2) > 1) {
+ printf("Inconsistent avail size in DSKATTR and ALLOCATION - size1=%.0f size2=%.0f\n",
+ size1, size2);
+ ret = false;
+ }
+ torture_comment(torture, "free disk = %.0f MB\n", size1*scale/1.0e6);
+ }
+
+ torture_comment(torture, "volume info consistency\n");
+ s1 = find("VOLUME");
+ s2 = find("VOLUME_INFO");
+ if (s1 && s2) {
+ VAL_EQUAL(volume, serial_number, volume_info, serial_number);
+ STR_EQUAL(volume, volume_name.s, volume_info, volume_name.s);
+ }
+
+ /* disk size consistency - notice that 'avail_alloc_units' maps to the caller
+ available allocation units, not the total */
+ s1 = find("SIZE_INFO");
+ s2 = find("FULL_SIZE_INFORMATION");
+ if (s1 && s2) {
+ VAL_EQUAL(size_info, total_alloc_units, full_size_information, total_alloc_units);
+ VAL_APPROX_EQUAL(size_info, avail_alloc_units, full_size_information, call_avail_alloc_units);
+ VAL_EQUAL(size_info, sectors_per_unit, full_size_information, sectors_per_unit);
+ VAL_EQUAL(size_info, bytes_per_sector, full_size_information, bytes_per_sector);
+ }
+
+ printf("check for non-zero unknown fields\n");
+ s1 = find("QUOTA_INFORMATION");
+ if (s1) {
+ VAL_UNKNOWN(quota_information, unknown[0]);
+ VAL_UNKNOWN(quota_information, unknown[1]);
+ VAL_UNKNOWN(quota_information, unknown[2]);
+ }
+
+ s1 = find("OBJECTID_INFORMATION");
+ if (s1) {
+ VAL_UNKNOWN(objectid_information, unknown[0]);
+ VAL_UNKNOWN(objectid_information, unknown[1]);
+ VAL_UNKNOWN(objectid_information, unknown[2]);
+ VAL_UNKNOWN(objectid_information, unknown[3]);
+ VAL_UNKNOWN(objectid_information, unknown[4]);
+ VAL_UNKNOWN(objectid_information, unknown[5]);
+ }
+
+
+#define STR_CHECK(sname, stype, field, flags) do { \
+ s1 = find(sname); \
+ if (s1) { \
+ if (s1->stype.out.field.s && wire_bad_flags(&s1->stype.out.field, flags, cli->transport)) { \
+ printf("(%d) incorrect string termination in %s/%s\n", \
+ __LINE__, #stype, #field); \
+ ret = false; \
+ } \
+ }} while (0)
+
+ torture_comment(torture, "check for correct termination\n");
+
+ STR_CHECK("VOLUME", volume, volume_name, 0);
+ STR_CHECK("VOLUME_INFO", volume_info, volume_name, STR_UNICODE);
+ STR_CHECK("VOLUME_INFORMATION", volume_info, volume_name, STR_UNICODE);
+ STR_CHECK("ATTRIBUTE_INFO", attribute_info, fs_type, STR_UNICODE);
+ STR_CHECK("ATTRIBUTE_INFORMATION", attribute_info, fs_type, STR_UNICODE);
+
+ return ret;
+}
diff --git a/source4/torture/raw/raw.c b/source4/torture/raw/raw.c
new file mode 100644
index 0000000..b3716b6
--- /dev/null
+++ b/source4/torture/raw/raw.c
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "torture/util.h"
+#include "torture/smbtorture.h"
+#include "torture/raw/proto.h"
+
+NTSTATUS torture_raw_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "raw");
+ /* RAW smb tests */
+ torture_suite_add_simple_test(suite, "bench-oplock", torture_bench_oplock);
+ torture_suite_add_simple_test(suite, "ping-pong", torture_ping_pong);
+ torture_suite_add_simple_test(suite, "bench-lock", torture_bench_lock);
+ torture_suite_add_simple_test(suite, "bench-open", torture_bench_open);
+ torture_suite_add_simple_test(suite, "bench-lookup",
+ torture_bench_lookup);
+ torture_suite_add_simple_test(suite, "bench-tcon",
+ torture_bench_treeconnect);
+ torture_suite_add_simple_test(suite, "offline", torture_test_offline);
+ torture_suite_add_1smb_test(suite, "qfsinfo", torture_raw_qfsinfo);
+ torture_suite_add_1smb_test(suite, "qfileinfo", torture_raw_qfileinfo);
+ torture_suite_add_1smb_test(suite, "qfileinfo.ipc", torture_raw_qfileinfo_pipe);
+ torture_suite_add_suite(suite, torture_raw_sfileinfo(suite));
+ torture_suite_add_suite(suite, torture_raw_search(suite));
+ torture_suite_add_1smb_test(suite, "close", torture_raw_close);
+ torture_suite_add_suite(suite, torture_raw_open(suite));
+ torture_suite_add_1smb_test(suite, "mkdir", torture_raw_mkdir);
+ torture_suite_add_suite(suite, torture_raw_oplock(suite));
+ torture_suite_add_1smb_test(suite, "hold-oplock", torture_hold_oplock);
+ torture_suite_add_suite(suite, torture_raw_notify(suite));
+ torture_suite_add_1smb_test(suite, "mux", torture_raw_mux);
+ torture_suite_add_1smb_test(suite, "ioctl", torture_raw_ioctl);
+ torture_suite_add_1smb_test(suite, "chkpath", torture_raw_chkpath);
+ torture_suite_add_suite(suite, torture_raw_unlink(suite));
+ torture_suite_add_suite(suite, torture_raw_read(suite));
+ torture_suite_add_suite(suite, torture_raw_write(suite));
+ torture_suite_add_suite(suite, torture_raw_lock(suite));
+ torture_suite_add_suite(suite, torture_raw_context(suite));
+ torture_suite_add_suite(suite, torture_raw_session(suite));
+ torture_suite_add_suite(suite, torture_raw_rename(suite));
+ torture_suite_add_1smb_test(suite, "seek", torture_raw_seek);
+ torture_suite_add_1smb_test(suite, "eas", torture_raw_eas);
+ torture_suite_add_suite(suite, torture_raw_streams(suite));
+ torture_suite_add_suite(suite, torture_raw_acls(suite));
+ torture_suite_add_suite(suite, torture_raw_composite(suite));
+ torture_suite_add_1smb_test(suite, "samba3hide", torture_samba3_hide);
+ torture_suite_add_1smb_test(suite, "samba3closeerr", torture_samba3_closeerr);
+ torture_suite_add_1smb_test(suite, "samba3rootdirfid",
+ torture_samba3_rootdirfid);
+ torture_suite_add_1smb_test(suite, "samba3rootdirfid2",
+ torture_samba3_rootdirfid2);
+ torture_suite_add_1smb_test(suite, "samba3checkfsp", torture_samba3_checkfsp);
+ torture_suite_add_1smb_test(suite, "samba3oplocklogoff", torture_samba3_oplock_logoff);
+ torture_suite_add_1smb_test(suite, "samba3badnameblob", torture_samba3_check_openX_badname);
+ torture_suite_add_simple_test(suite, "samba3badpath", torture_samba3_badpath);
+ torture_suite_add_1smb_test(suite, "samba3caseinsensitive",
+ torture_samba3_caseinsensitive);
+ torture_suite_add_1smb_test(suite, "samba3posixtimedlock",
+ torture_samba3_posixtimedlock);
+ torture_suite_add_simple_test(suite, "scan-eamax", torture_max_eas);
+
+ suite->description = talloc_strdup(suite, "Tests for the raw SMB interface");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/raw/read.c b/source4/torture/raw/read.c
new file mode 100644
index 0000000..6160e3e
--- /dev/null
+++ b/source4/torture/raw/read.c
@@ -0,0 +1,1039 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various read operations
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ torture_assert_ntstatus_equal_goto(tctx, status, correct, ret, \
+ done, "incorrect status"); \
+ } while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ torture_assert_int_equal_goto(tctx, (v), (correct), ret, done, \
+ "Incorrect value"); \
+ } while (0)
+
+#define CHECK_BUFFER(buf, seed, len) do { \
+ if (!check_buffer(tctx, buf, seed, len, __LINE__)) { \
+ ret = false; \
+ torture_fail_goto(tctx, done, "buffer check failed\n"); \
+ }} while (0)
+
+#define CHECK_READX_ALIGN(io) do { \
+ if ((io.readx.out.flags2 & FLAGS2_UNICODE_STRINGS) && \
+ (io.readx.out.data_offset % 2 != 0)) { \
+ ret = false; \
+ torture_fail_goto(tctx, done, "data not 16 bit aligned\n"); \
+ }} while (0)
+
+#define BASEDIR "\\testread"
+
+
+/*
+ setup a random buffer based on a seed
+*/
+static void setup_buffer(uint8_t *buf, unsigned int seed, int len)
+{
+ int i;
+ srandom(seed);
+ for (i=0;i<len;i++) buf[i] = random();
+}
+
+/*
+ check a random buffer based on a seed
+*/
+static bool check_buffer(struct torture_context *tctx, uint8_t *buf,
+ unsigned int seed, int len, int line)
+{
+ int i;
+ srandom(seed);
+ for (i=0;i<len;i++) {
+ uint8_t v = random();
+ if (buf[i] != v) {
+ torture_warning(tctx, "Buffer incorrect at line %d! "
+ "ofs=%d v1=0x%x v2=0x%x\n", line, i,
+ buf[i], v);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ test read ops
+*/
+static bool test_read(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_read io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned int seed = time(NULL);
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ if (!torture_setting_bool(tctx, "read_support", true)) {
+ printf("server refuses to support READ\n");
+ return true;
+ }
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing RAW_READ_READ\n");
+ io.generic.level = RAW_READ_READ;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.read.in.file.fnum = fnum;
+ io.read.in.count = 1;
+ io.read.in.offset = 0;
+ io.read.in.remaining = 0;
+ io.read.out.data = buf;
+ status = smb_raw_read(cli->tree, &io);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.read.out.nread, 0);
+
+ printf("Trying zero file read\n");
+ io.read.in.count = 0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.read.out.nread, 0);
+
+ printf("Trying bad fnum\n");
+ io.read.in.file.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ io.read.in.file.fnum = fnum;
+
+ smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.read.in.file.fnum = fnum;
+ io.read.in.offset = 0;
+ io.read.in.remaining = 0;
+ io.read.in.count = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.read.out.nread, strlen(test_data));
+ if (memcmp(buf, test_data, strlen(test_data)) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
+ goto done;
+ }
+
+ printf("Trying short read\n");
+ io.read.in.offset = 1;
+ io.read.in.count = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.read.out.nread, strlen(test_data)-1);
+ if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
+ goto done;
+ }
+
+ if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+ printf("Trying max offset\n");
+ io.read.in.offset = ~0;
+ io.read.in.count = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.read.out.nread, 0);
+ }
+
+ setup_buffer(buf, seed, maxsize);
+ smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+ memset(buf, 0, maxsize);
+
+ printf("Trying large read\n");
+ io.read.in.offset = 0;
+ io.read.in.count = ~0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_BUFFER(buf, seed, io.read.out.nread);
+
+
+ printf("Trying locked region\n");
+ cli->session->pid++;
+ if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+ printf("Failed to lock file at %d\n", __LINE__);
+ ret = false;
+ goto done;
+ }
+ cli->session->pid--;
+ memset(buf, 0, maxsize);
+ io.read.in.offset = 0;
+ io.read.in.count = ~0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test lockread ops
+*/
+static bool test_lockread(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_read io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned int seed = time(NULL);
+
+ if (!cli->transport->negotiate.lockread_supported) {
+ printf("Server does not support lockread - skipping\n");
+ return true;
+ }
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing RAW_READ_LOCKREAD\n");
+ io.generic.level = RAW_READ_LOCKREAD;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.lockread.in.file.fnum = fnum;
+ io.lockread.in.count = 1;
+ io.lockread.in.offset = 1;
+ io.lockread.in.remaining = 0;
+ io.lockread.out.data = buf;
+ status = smb_raw_read(cli->tree, &io);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lockread.out.nread, 0);
+
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ printf("Trying zero file read\n");
+ io.lockread.in.count = 0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_unlock(cli->tree, fnum, 1, 1);
+
+ printf("Trying bad fnum\n");
+ io.lockread.in.file.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ io.lockread.in.file.fnum = fnum;
+
+ smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.lockread.in.file.fnum = fnum;
+ io.lockread.in.offset = 0;
+ io.lockread.in.remaining = 0;
+ io.lockread.in.count = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ smbcli_unlock(cli->tree, fnum, 1, 0);
+
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lockread.out.nread, strlen(test_data));
+ if (memcmp(buf, test_data, strlen(test_data)) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
+ goto done;
+ }
+
+ printf("Trying short read\n");
+ io.lockread.in.offset = 1;
+ io.lockread.in.count = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ smbcli_unlock(cli->tree, fnum, 0, strlen(test_data));
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VALUE(io.lockread.out.nread, strlen(test_data)-1);
+ if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
+ goto done;
+ }
+
+ if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+ printf("Trying max offset\n");
+ io.lockread.in.offset = ~0;
+ io.lockread.in.count = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lockread.out.nread, 0);
+ }
+
+ setup_buffer(buf, seed, maxsize);
+ smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+ memset(buf, 0, maxsize);
+
+ printf("Trying large read\n");
+ io.lockread.in.offset = 0;
+ io.lockread.in.count = ~0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ smbcli_unlock(cli->tree, fnum, 1, strlen(test_data));
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_BUFFER(buf, seed, io.lockread.out.nread);
+ smbcli_unlock(cli->tree, fnum, 0, 0xFFFF);
+
+
+ printf("Trying locked region\n");
+ cli->session->pid++;
+ if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+ printf("Failed to lock file at %d\n", __LINE__);
+ ret = false;
+ goto done;
+ }
+ cli->session->pid--;
+ memset(buf, 0, maxsize);
+ io.lockread.in.offset = 0;
+ io.lockread.in.count = ~0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test readx ops
+*/
+static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_read io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned int seed = time(NULL);
+ struct smbcli_request *smbreq = NULL;
+ unsigned int i;
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing RAW_READ_READX\n");
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.generic.level = RAW_READ_READX;
+ io.readx.in.file.fnum = fnum;
+ io.readx.in.mincnt = 1;
+ io.readx.in.maxcnt = 1;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ io.readx.in.read_for_execute = false;
+ io.readx.out.data = buf;
+ status = smb_raw_read(cli->tree, &io);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying zero file read\n");
+ io.readx.in.mincnt = 0;
+ io.readx.in.maxcnt = 0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying bad fnum\n");
+ io.readx.in.file.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+ io.readx.in.file.fnum = fnum;
+
+ smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Checking reserved fields are [0]\n");
+ io.readx.in.file.fnum = fnum;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ io.readx.in.read_for_execute = false;
+ io.readx.in.mincnt = strlen(test_data);
+ io.readx.in.maxcnt = strlen(test_data);
+ smbreq = smb_raw_read_send(cli->tree, &io);
+ if (smbreq == NULL) {
+ ret = false;
+ torture_fail_goto(tctx, done, "smb_raw_read_send failed\n");
+ }
+ if (!smbcli_request_receive(smbreq) ||
+ smbcli_request_is_error(smbreq)) {
+ status = smbcli_request_destroy(smbreq);
+ torture_fail_goto(tctx, done, "receive failed\n");
+ }
+
+ if (smbreq->in.wct != 12) {
+ ret = false;
+ printf("Incorrect wct %u (should be 12)\n",
+ (unsigned int)smbreq->in.wct);
+ status = smbcli_request_destroy(smbreq);
+ torture_fail_goto(tctx, done, "bad wct\n");
+ }
+
+ /* Ensure VWV8 - WVW11 are zero. */
+ for (i = 8; i < 12; i++) {
+ uint16_t br = SVAL(smbreq->in.vwv, VWV(i));
+ if (br != 0) {
+ status = smbcli_request_destroy(smbreq);
+ ret = false;
+ printf("reserved field %u is %u not zero\n",
+ i,
+ (unsigned int)br);
+ torture_fail_goto(tctx, done, "bad reserved field\n");
+ }
+ }
+
+ smbcli_request_destroy(smbreq);
+
+ printf("Trying small read\n");
+ io.readx.in.file.fnum = fnum;
+ io.readx.in.offset = 0;
+ io.readx.in.remaining = 0;
+ io.readx.in.read_for_execute = false;
+ io.readx.in.mincnt = strlen(test_data);
+ io.readx.in.maxcnt = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, strlen(test_data));
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_READX_ALIGN(io);
+ if (memcmp(buf, test_data, strlen(test_data)) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
+ goto done;
+ }
+
+ printf("Trying short read\n");
+ io.readx.in.offset = 1;
+ io.readx.in.mincnt = strlen(test_data);
+ io.readx.in.maxcnt = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, strlen(test_data)-1);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_READX_ALIGN(io);
+ if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
+ goto done;
+ }
+
+ if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+ printf("Trying max offset\n");
+ io.readx.in.offset = 0xffffffff;
+ io.readx.in.mincnt = strlen(test_data);
+ io.readx.in.maxcnt = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_READX_ALIGN(io);
+ }
+
+ printf("Trying mincnt past EOF\n");
+ memset(buf, 0, maxsize);
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 100;
+ io.readx.in.maxcnt = 110;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_VALUE(io.readx.out.nread, strlen(test_data));
+ CHECK_READX_ALIGN(io);
+ if (memcmp(buf, test_data, strlen(test_data)) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
+ goto done;
+ }
+
+
+ setup_buffer(buf, seed, maxsize);
+ smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+ memset(buf, 0, maxsize);
+
+ printf("Trying page sized read\n");
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 0x1000;
+ io.readx.in.maxcnt = 0x1000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readx.out.nread);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying page + 1 sized read (check alignment)\n");
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 0x1001;
+ io.readx.in.maxcnt = 0x1001;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readx.out.nread);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying large read (UINT16_MAX)\n");
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 0xFFFF;
+ io.readx.in.maxcnt = 0xFFFF;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readx.out.nread);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying extra large read\n");
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 100;
+ io.readx.in.maxcnt = 80000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ if (io.readx.out.nread == io.readx.in.maxcnt) {
+ printf("SAMBA: large read extension\n");
+ CHECK_VALUE(io.readx.out.nread, 80000);
+ } else {
+ CHECK_VALUE(io.readx.out.nread, 0x10000);
+ }
+ CHECK_BUFFER(buf, seed, io.readx.out.nread);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying mincnt > maxcnt\n");
+ memset(buf, 0, maxsize);
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 30000;
+ io.readx.in.maxcnt = 20000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readx.out.nread);
+ CHECK_READX_ALIGN(io);
+
+ printf("Trying mincnt < maxcnt\n");
+ memset(buf, 0, maxsize);
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 20000;
+ io.readx.in.maxcnt = 30000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(io.readx.out.compaction_mode, 0);
+ CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readx.out.nread);
+ CHECK_READX_ALIGN(io);
+
+ if (cli->transport->negotiate.capabilities & CAP_LARGE_READX) {
+ printf("Trying large readx\n");
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 0;
+ io.readx.in.maxcnt = 0x10000 - 1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0xFFFF);
+ CHECK_READX_ALIGN(io);
+
+ io.readx.in.maxcnt = 0x10000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0x10000);
+ CHECK_READX_ALIGN(io);
+
+ io.readx.in.maxcnt = 0x10001;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (io.readx.out.nread == io.readx.in.maxcnt) {
+ printf("SAMBA: large read extension\n");
+ CHECK_VALUE(io.readx.out.nread, 0x10001);
+ } else {
+ CHECK_VALUE(io.readx.out.nread, 0x10000);
+ }
+ } else {
+ printf("Server does not support the CAP_LARGE_READX extension\n");
+ }
+
+ printf("Trying locked region\n");
+ cli->session->pid++;
+ if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+ printf("Failed to lock file at %d\n", __LINE__);
+ ret = false;
+ goto done;
+ }
+ cli->session->pid--;
+ memset(buf, 0, maxsize);
+ io.readx.in.offset = 0;
+ io.readx.in.mincnt = 100;
+ io.readx.in.maxcnt = 200;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ printf("skipping large file tests - CAP_LARGE_FILES not set\n");
+ goto done;
+ }
+
+ printf("Trying large offset read\n");
+ io.readx.in.offset = ((uint64_t)0x2) << 32;
+ io.readx.in.mincnt = 10;
+ io.readx.in.maxcnt = 10;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0);
+ CHECK_READX_ALIGN(io);
+
+ if (NT_STATUS_IS_ERR(smbcli_lock64(cli->tree, fnum, io.readx.in.offset, 1, 0, WRITE_LOCK))) {
+ printf("Failed to lock file at %d\n", __LINE__);
+ ret = false;
+ goto done;
+ }
+
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readx.out.nread, 0);
+ CHECK_READX_ALIGN(io);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test readbraw ops
+*/
+static bool test_readbraw(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_read io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *test_data = "TEST DATA";
+ unsigned int seed = time(NULL);
+
+ if (!cli->transport->negotiate.readbraw_supported) {
+ printf("Server does not support readbraw - skipping\n");
+ return true;
+ }
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing RAW_READ_READBRAW\n");
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Trying empty file read\n");
+ io.generic.level = RAW_READ_READBRAW;
+ io.readbraw.in.file.fnum = fnum;
+ io.readbraw.in.mincnt = 1;
+ io.readbraw.in.maxcnt = 1;
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.timeout = 0;
+ io.readbraw.out.data = buf;
+ status = smb_raw_read(cli->tree, &io);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+
+ printf("Trying zero file read\n");
+ io.readbraw.in.mincnt = 0;
+ io.readbraw.in.maxcnt = 0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+
+ printf("Trying bad fnum\n");
+ io.readbraw.in.file.fnum = fnum+1;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+ io.readbraw.in.file.fnum = fnum;
+
+ smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+
+ printf("Trying small read\n");
+ io.readbraw.in.file.fnum = fnum;
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.mincnt = strlen(test_data);
+ io.readbraw.in.maxcnt = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, strlen(test_data));
+ if (memcmp(buf, test_data, strlen(test_data)) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
+ goto done;
+ }
+
+ printf("Trying short read\n");
+ io.readbraw.in.offset = 1;
+ io.readbraw.in.mincnt = strlen(test_data);
+ io.readbraw.in.maxcnt = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, strlen(test_data)-1);
+ if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
+ ret = false;
+ printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
+ goto done;
+ }
+
+ if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+ printf("Trying max offset\n");
+ io.readbraw.in.offset = ~0;
+ io.readbraw.in.mincnt = strlen(test_data);
+ io.readbraw.in.maxcnt = strlen(test_data);
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+ }
+
+ setup_buffer(buf, seed, maxsize);
+ smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+ memset(buf, 0, maxsize);
+
+ printf("Trying large read\n");
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.mincnt = ~0;
+ io.readbraw.in.maxcnt = ~0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0xFFFF);
+ CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
+
+ printf("Trying mincnt > maxcnt\n");
+ memset(buf, 0, maxsize);
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.mincnt = 30000;
+ io.readbraw.in.maxcnt = 20000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, io.readbraw.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
+
+ printf("Trying mincnt < maxcnt\n");
+ memset(buf, 0, maxsize);
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.mincnt = 20000;
+ io.readbraw.in.maxcnt = 30000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, io.readbraw.in.maxcnt);
+ CHECK_BUFFER(buf, seed, io.readbraw.out.nread);
+
+ printf("Trying locked region\n");
+ cli->session->pid++;
+ if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+ printf("Failed to lock file at %d\n", __LINE__);
+ ret = false;
+ goto done;
+ }
+ cli->session->pid--;
+ memset(buf, 0, maxsize);
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.mincnt = 100;
+ io.readbraw.in.maxcnt = 200;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+
+ printf("Trying locked region with timeout\n");
+ memset(buf, 0, maxsize);
+ io.readbraw.in.offset = 0;
+ io.readbraw.in.mincnt = 100;
+ io.readbraw.in.maxcnt = 200;
+ io.readbraw.in.timeout = 10000;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+
+ if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+ printf("Trying large offset read\n");
+ io.readbraw.in.offset = ((uint64_t)0x2) << 32;
+ io.readbraw.in.mincnt = 10;
+ io.readbraw.in.maxcnt = 10;
+ io.readbraw.in.timeout = 0;
+ status = smb_raw_read(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.readbraw.out.nread, 0);
+ }
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test read for execute
+*/
+static bool test_read_for_execute(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_open op;
+ union smb_write wr;
+ union smb_read rd;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum=0;
+ uint8_t *buf;
+ const int maxsize = 900;
+ const char *fname = BASEDIR "\\test.txt";
+ const uint8_t data[] = "TEST DATA";
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing RAW_READ_READX with read_for_execute\n");
+
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ wr.generic.level = RAW_WRITE_WRITEX;
+ wr.writex.in.file.fnum = fnum;
+ wr.writex.in.offset = 0;
+ wr.writex.in.wmode = 0;
+ wr.writex.in.remaining = 0;
+ wr.writex.in.count = ARRAY_SIZE(data);
+ wr.writex.in.data = data;
+ status = smb_raw_write(cli->tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(wr.writex.out.nwritten, ARRAY_SIZE(data));
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("open file with SEC_FILE_EXECUTE\n");
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_FILE_EXECUTE;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
+ rd.generic.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = maxsize;
+ rd.readx.in.offset = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = true;
+ rd.readx.out.data = buf;
+ status = smb_raw_read(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
+ CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(rd.readx.out.compaction_mode, 0);
+
+ printf("read without FLAGS2_READ_PERMIT_EXECUTE (should fail)\n");
+ rd.generic.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = maxsize;
+ rd.readx.in.offset = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = buf;
+ status = smb_raw_read(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ status = smbcli_close(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("open file with SEC_FILE_READ_DATA\n");
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
+ rd.generic.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = maxsize;
+ rd.readx.in.offset = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = true;
+ rd.readx.out.data = buf;
+ status = smb_raw_read(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
+ CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(rd.readx.out.compaction_mode, 0);
+
+ printf("read without FLAGS2_READ_PERMIT_EXECUTE\n");
+ rd.generic.level = RAW_READ_READX;
+ rd.readx.in.file.fnum = fnum;
+ rd.readx.in.mincnt = 0;
+ rd.readx.in.maxcnt = maxsize;
+ rd.readx.in.offset = 0;
+ rd.readx.in.remaining = 0;
+ rd.readx.in.read_for_execute = false;
+ rd.readx.out.data = buf;
+ status = smb_raw_read(cli->tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
+ CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
+ CHECK_VALUE(rd.readx.out.compaction_mode, 0);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of read calls
+*/
+struct torture_suite *torture_raw_read(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "read");
+
+ torture_suite_add_1smb_test(suite, "read", test_read);
+ torture_suite_add_1smb_test(suite, "readx", test_readx);
+ torture_suite_add_1smb_test(suite, "lockread", test_lockread);
+ torture_suite_add_1smb_test(suite, "readbraw", test_readbraw);
+ torture_suite_add_1smb_test(suite, "read for execute",
+ test_read_for_execute);
+
+ return suite;
+}
diff --git a/source4/torture/raw/rename.c b/source4/torture/raw/rename.c
new file mode 100644
index 0000000..5f48c05
--- /dev/null
+++ b/source4/torture/raw/rename.c
@@ -0,0 +1,692 @@
+/*
+ Unix SMB/CIFS implementation.
+ rename test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect %s %d - should be %d\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define BASEDIR "\\testrename"
+
+/*
+ test SMBmv ops
+*/
+static bool test_mv(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_rename io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum = -1;
+ const char *fname1 = BASEDIR "\\test1.txt";
+ const char *fname2 = BASEDIR "\\test2.txt";
+ const char *Fname1 = BASEDIR "\\Test1.txt";
+ union smb_fileinfo finfo;
+ union smb_open op;
+
+ torture_comment(tctx, "Testing SMBmv\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Trying simple rename\n");
+
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname1;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ io.generic.level = RAW_RENAME_RENAME;
+ io.rename.in.pattern1 = fname1;
+ io.rename.in.pattern2 = fname2;
+ io.rename.in.attrib = 0;
+
+ torture_comment(tctx, "trying rename while first file open\n");
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ smbcli_close(cli->tree, fnum);
+
+ op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+ op.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "trying rename while first file open with SHARE_ACCESS_DELETE\n");
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.rename.in.pattern1 = fname2;
+ io.rename.in.pattern2 = fname1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Trying case-changing rename\n");
+ io.rename.in.pattern1 = fname1;
+ io.rename.in.pattern2 = Fname1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.all_info.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (strcmp(finfo.all_info.out.fname.s, Fname1) != 0) {
+ torture_warning(tctx, "(%s) Incorrect filename [%s] after case-changing "
+ "rename, should be [%s]\n", __location__,
+ finfo.all_info.out.fname.s, Fname1);
+ }
+
+ io.rename.in.pattern1 = fname1;
+ io.rename.in.pattern2 = fname2;
+
+ torture_comment(tctx, "trying rename while not open\n");
+ smb_raw_exit(cli->session);
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Trying self rename\n");
+ io.rename.in.pattern1 = fname2;
+ io.rename.in.pattern2 = fname2;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.rename.in.pattern1 = fname1;
+ io.rename.in.pattern2 = fname1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+static bool test_osxrename(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_rename io;
+ union smb_unlink io_un;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum = -1;
+ const char *fname1 = BASEDIR "\\test1";
+ const char *FNAME1 = BASEDIR "\\TEST1";
+ union smb_fileinfo finfo;
+ union smb_open op;
+
+ torture_comment(tctx, "\nTesting OSX Rename\n");
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ op.ntcreatex.in.create_options = 0;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = fname1;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ io.generic.level = RAW_RENAME_RENAME;
+ io.rename.in.attrib = 0;
+
+ smbcli_close(cli->tree, fnum);
+
+ /* Rename by changing case. First check for the
+ * existence of the file with the "newname".
+ * If we find one and both the output and input are same case,
+ * delete it. */
+
+ torture_comment(tctx, "Checking os X rename (case changing)\n");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.all_info.in.file.path = FNAME1;
+ torture_comment(tctx, "Looking for file %s \n",FNAME1);
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Name of the file found %s \n", finfo.all_info.out.fname.s);
+ if (strcmp(finfo.all_info.out.fname.s, finfo.all_info.in.file.path) == 0) {
+ /* If file is found with the same case delete it */
+ torture_comment(tctx, "Deleting File %s \n", finfo.all_info.out.fname.s);
+ io_un.unlink.in.pattern = finfo.all_info.out.fname.s;
+ io_un.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io_un);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+ }
+
+ io.rename.in.pattern1 = fname1;
+ io.rename.in.pattern2 = FNAME1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.all_info.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_comment(tctx, "File name after rename %s \n",finfo.all_info.out.fname.s);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test SMBntrename ops
+*/
+static bool test_ntrename(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_rename io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum, i;
+ const char *fname1 = BASEDIR "\\test1.txt";
+ const char *fname2 = BASEDIR "\\test2.txt";
+ union smb_fileinfo finfo;
+
+ torture_comment(tctx, "Testing SMBntrename\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Trying simple rename\n");
+
+ fnum = create_complex_file(cli, tctx, fname1);
+
+ io.generic.level = RAW_RENAME_NTRENAME;
+ io.ntrename.in.old_name = fname1;
+ io.ntrename.in.new_name = fname2;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.cluster_size = 0;
+ io.ntrename.in.flags = RENAME_FLAG_RENAME;
+
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ smbcli_close(cli->tree, fnum);
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Trying self rename\n");
+ io.ntrename.in.old_name = fname2;
+ io.ntrename.in.new_name = fname2;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.ntrename.in.old_name = fname1;
+ io.ntrename.in.new_name = fname1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ torture_comment(tctx, "trying wildcard rename\n");
+ io.ntrename.in.old_name = BASEDIR "\\*.txt";
+ io.ntrename.in.new_name = fname1;
+
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ torture_comment(tctx, "Checking attrib handling\n");
+ torture_set_file_attribute(cli->tree, fname2, FILE_ATTRIBUTE_HIDDEN);
+ io.ntrename.in.old_name = fname2;
+ io.ntrename.in.new_name = fname1;
+ io.ntrename.in.attrib = 0;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
+
+ io.ntrename.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
+
+ torture_comment(tctx, "Checking hard link\n");
+ io.ntrename.in.old_name = fname1;
+ io.ntrename.in.new_name = fname2;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.flags = RENAME_FLAG_HARD_LINK;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname2;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 2);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
+
+ finfo.generic.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 2);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
+
+ torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
+
+ smbcli_unlink(cli->tree, fname2);
+
+ finfo.generic.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 1);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
+
+ torture_comment(tctx, "Checking copy\n");
+ io.ntrename.in.old_name = fname1;
+ io.ntrename.in.new_name = fname2;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.flags = RENAME_FLAG_COPY;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 1);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname2;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 1);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
+
+ torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_SYSTEM);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname2;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 1);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_NORMAL);
+
+ finfo.generic.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 1);
+ CHECK_VALUE(finfo.all_info.out.attrib, FILE_ATTRIBUTE_SYSTEM);
+
+ torture_set_file_attribute(cli->tree, fname1, FILE_ATTRIBUTE_NORMAL);
+
+ smbcli_unlink(cli->tree, fname2);
+
+ finfo.generic.in.file.path = fname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.all_info.out.nlink, 1);
+
+ torture_comment(tctx, "Checking invalid flags\n");
+ io.ntrename.in.old_name = fname1;
+ io.ntrename.in.new_name = fname2;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.flags = 0;
+ status = smb_raw_rename(cli->tree, &io);
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ io.ntrename.in.flags = 300;
+ status = smb_raw_rename(cli->tree, &io);
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ io.ntrename.in.flags = 0x106;
+ status = smb_raw_rename(cli->tree, &io);
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "Checking unknown field\n");
+ io.ntrename.in.old_name = fname1;
+ io.ntrename.in.new_name = fname2;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.flags = RENAME_FLAG_RENAME;
+ io.ntrename.in.cluster_size = 0xff;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Trying RENAME_FLAG_MOVE_CLUSTER_INFORMATION\n");
+
+ io.ntrename.in.old_name = fname2;
+ io.ntrename.in.new_name = fname1;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
+ io.ntrename.in.cluster_size = 1;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ io.ntrename.in.flags = RENAME_FLAG_COPY;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+#if 0
+ {
+ char buf[16384];
+ fnum = smbcli_open(cli->tree, fname1, O_RDWR, DENY_NONE);
+ memset(buf, 1, sizeof(buf));
+ smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+ smbcli_close(cli->tree, fnum);
+
+ fnum = smbcli_open(cli->tree, fname2, O_RDWR, DENY_NONE);
+ memset(buf, 1, sizeof(buf));
+ smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf)-1);
+ smbcli_close(cli->tree, fnum);
+
+ torture_all_info(cli->tree, fname1);
+ torture_all_info(cli->tree, fname2);
+ }
+
+
+ io.ntrename.in.flags = RENAME_FLAG_MOVE_CLUSTER_INFORMATION;
+ status = smb_raw_rename(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ for (i=0;i<20000;i++) {
+ io.ntrename.in.cluster_size = i;
+ status = smb_raw_rename(cli->tree, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ torture_warning(tctx, "i=%d status=%s\n", i, nt_errstr(status));
+ }
+ }
+#endif
+
+ torture_comment(tctx, "Checking other flags\n");
+
+ for (i=0;i<0xFFF;i++) {
+ if (i == RENAME_FLAG_RENAME ||
+ i == RENAME_FLAG_HARD_LINK ||
+ i == RENAME_FLAG_COPY) {
+ continue;
+ }
+
+ io.ntrename.in.old_name = fname2;
+ io.ntrename.in.new_name = fname1;
+ io.ntrename.in.flags = i;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.cluster_size = 0;
+ status = smb_raw_rename(cli->tree, &io);
+ if (TARGET_IS_WIN7(tctx)){
+ if (!NT_STATUS_EQUAL(status,
+ NT_STATUS_INVALID_PARAMETER)) {
+ torture_warning(tctx, "flags=0x%x status=%s\n",
+ i, nt_errstr(status));
+ }
+ } else {
+ if (!NT_STATUS_EQUAL(status,
+ NT_STATUS_ACCESS_DENIED)) {
+ torture_warning(tctx, "flags=0x%x status=%s\n",
+ i, nt_errstr(status));
+ }
+ }
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test dir rename.
+*/
+static bool test_dir_rename(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ union smb_rename ren_io;
+ NTSTATUS status;
+ const char *dname1 = BASEDIR "\\dir_for_rename";
+ const char *dname2 = BASEDIR "\\renamed_dir";
+ const char *dname1_long = BASEDIR "\\dir_for_rename_long";
+ const char *fname = BASEDIR "\\dir_for_rename\\file.txt";
+ const char *sname = BASEDIR "\\renamed_dir:a stream:$DATA";
+ bool ret = true;
+ int fnum = -1;
+
+ torture_comment(tctx, "Checking rename on a directory containing an open file.\n");
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* create a directory */
+ smbcli_rmdir(cli->tree, dname1);
+ smbcli_rmdir(cli->tree, dname2);
+ smbcli_rmdir(cli->tree, dname1_long);
+ smbcli_unlink(cli->tree, dname1);
+ smbcli_unlink(cli->tree, dname2);
+ smbcli_unlink(cli->tree, dname1_long);
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.fname = dname1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fnum = io.ntcreatex.out.file.fnum;
+ smbcli_close(cli->tree, fnum);
+
+ /* create the longname directory */
+ io.ntcreatex.in.fname = dname1_long;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fnum = io.ntcreatex.out.file.fnum;
+ smbcli_close(cli->tree, fnum);
+
+ /* Now create and hold open a file. */
+ ZERO_STRUCT(io);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* Create the file. */
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Now try and rename the directory. */
+
+ ZERO_STRUCT(ren_io);
+ ren_io.generic.level = RAW_RENAME_RENAME;
+ ren_io.rename.in.pattern1 = dname1;
+ ren_io.rename.in.pattern2 = dname2;
+ ren_io.rename.in.attrib = 0;
+
+ status = smb_raw_rename(cli->tree, &ren_io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ /* Close the file and try the rename. */
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_rename(cli->tree, &ren_io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Now try just holding a second handle on the directory and holding
+ * it open across a rename. This should be allowed.
+ */
+ io.ntcreatex.in.fname = dname2;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+
+ io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ren_io.generic.level = RAW_RENAME_RENAME;
+ ren_io.rename.in.pattern1 = dname2;
+ ren_io.rename.in.pattern2 = dname1;
+ ren_io.rename.in.attrib = 0;
+
+ status = smb_raw_rename(cli->tree, &ren_io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* close our handle to the directory. */
+ smbcli_close(cli->tree, fnum);
+
+ /* Open a handle on the long name, and then
+ * try a rename. This would catch a regression
+ * in bug #6781.
+ */
+ io.ntcreatex.in.fname = dname1_long;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+
+ io.ntcreatex.in.access_mask = SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_EA | SEC_FILE_READ_DATA;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ren_io.generic.level = RAW_RENAME_RENAME;
+ ren_io.rename.in.pattern1 = dname1;
+ ren_io.rename.in.pattern2 = dname2;
+ ren_io.rename.in.attrib = 0;
+
+ status = smb_raw_rename(cli->tree, &ren_io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* close our handle to the longname directory. */
+ smbcli_close(cli->tree, fnum);
+
+ /*
+ * Now try opening a stream on the directory and holding it open
+ * across a rename. This should be allowed.
+ */
+ io.ntcreatex.in.fname = sname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ren_io.generic.level = RAW_RENAME_RENAME;
+ ren_io.rename.in.pattern1 = dname2;
+ ren_io.rename.in.pattern2 = dname1;
+ ren_io.rename.in.attrib = 0;
+
+ status = smb_raw_rename(cli->tree, &ren_io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+
+ if (fnum != -1) {
+ smbcli_close(cli->tree, fnum);
+ }
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+extern bool test_trans2rename(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2);
+extern bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1);
+
+/*
+ basic testing of rename calls
+*/
+struct torture_suite *torture_raw_rename(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "rename");
+
+ torture_suite_add_1smb_test(suite, "mv", test_mv);
+ /* test_trans2rename and test_nttransrename are actually in torture/raw/oplock.c to
+ use the handlers and macros there. */
+ torture_suite_add_2smb_test(suite, "trans2rename", test_trans2rename);
+ torture_suite_add_1smb_test(suite, "nttransrename", test_nttransrename);
+ torture_suite_add_1smb_test(suite, "ntrename", test_ntrename);
+ torture_suite_add_1smb_test(suite, "osxrename", test_osxrename);
+ torture_suite_add_1smb_test(suite, "directory rename", test_dir_rename);
+
+ return suite;
+}
diff --git a/source4/torture/raw/samba3hide.c b/source4/torture/raw/samba3hide.c
new file mode 100644
index 0000000..d28f91e
--- /dev/null
+++ b/source4/torture/raw/samba3hide.c
@@ -0,0 +1,326 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test samba3 hide unreadable/unwriteable
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+static void init_unixinfo_nochange(union smb_setfileinfo *info)
+{
+ ZERO_STRUCTP(info);
+ info->unix_basic.level = RAW_SFILEINFO_UNIX_BASIC;
+ info->unix_basic.in.mode = SMB_MODE_NO_CHANGE;
+
+ info->unix_basic.in.end_of_file = SMB_SIZE_NO_CHANGE_HI;
+ info->unix_basic.in.end_of_file <<= 32;
+ info->unix_basic.in.end_of_file |= SMB_SIZE_NO_CHANGE_LO;
+
+ info->unix_basic.in.num_bytes = SMB_SIZE_NO_CHANGE_HI;
+ info->unix_basic.in.num_bytes <<= 32;
+ info->unix_basic.in.num_bytes |= SMB_SIZE_NO_CHANGE_LO;
+
+ info->unix_basic.in.status_change_time = SMB_TIME_NO_CHANGE_HI;
+ info->unix_basic.in.status_change_time <<= 32;
+ info->unix_basic.in.status_change_time |= SMB_TIME_NO_CHANGE_LO;
+
+ info->unix_basic.in.access_time = SMB_TIME_NO_CHANGE_HI;
+ info->unix_basic.in.access_time <<= 32;
+ info->unix_basic.in.access_time |= SMB_TIME_NO_CHANGE_LO;
+
+ info->unix_basic.in.change_time = SMB_TIME_NO_CHANGE_HI;
+ info->unix_basic.in.change_time <<= 32;
+ info->unix_basic.in.change_time |= SMB_TIME_NO_CHANGE_LO;
+
+ info->unix_basic.in.uid = SMB_UID_NO_CHANGE;
+ info->unix_basic.in.gid = SMB_GID_NO_CHANGE;
+}
+
+struct list_state {
+ const char *fname;
+ bool visible;
+};
+
+static void set_visible(struct clilist_file_info *i, const char *mask,
+ void *priv)
+{
+ struct list_state *state = (struct list_state *)priv;
+
+ if (strcasecmp_m(state->fname, i->name) == 0)
+ state->visible = true;
+}
+
+static bool is_visible(struct smbcli_tree *tree, const char *fname)
+{
+ struct list_state state;
+
+ state.visible = false;
+ state.fname = fname;
+
+ if (smbcli_list(tree, "*.*", 0, set_visible, &state) < 0) {
+ return false;
+ }
+ return state.visible;
+}
+
+static bool is_readable(struct smbcli_tree *tree, const char *fname)
+{
+ int fnum;
+ fnum = smbcli_open(tree, fname, O_RDONLY, DENY_NONE);
+ if (fnum < 0) {
+ return false;
+ }
+ smbcli_close(tree, fnum);
+ return true;
+}
+
+static bool is_writeable(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
+ const char *fname)
+{
+ int fnum;
+ fnum = smbcli_open(tree, fname, O_WRONLY, DENY_NONE);
+ if (fnum < 0) {
+ return false;
+ }
+ smbcli_close(tree, fnum);
+ return true;
+}
+
+/*
+ * This is not an exact method because there's a ton of reasons why a getatr
+ * might fail. But for our purposes it's sufficient.
+ */
+
+static bool smbcli_file_exists(struct smbcli_tree *tree, const char *fname)
+{
+ return NT_STATUS_IS_OK(smbcli_getatr(tree, fname, NULL, NULL, NULL));
+}
+
+static NTSTATUS smbcli_setup_unix(struct smbcli_tree *tree)
+{
+ union smb_fsinfo fsinfo;
+ union smb_setfsinfo set_fsinfo;
+ NTSTATUS status;
+
+ ZERO_STRUCT(fsinfo);
+ ZERO_STRUCT(set_fsinfo);
+
+ fsinfo.generic.level = RAW_QFS_UNIX_INFO;
+ status = smb_raw_fsinfo(tree, NULL, &fsinfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("smb_raw_fsinfo failed %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ set_fsinfo.generic.level = RAW_SETFS_UNIX_INFO;
+ set_fsinfo.unix_info.in.major_version = fsinfo.unix_info.out.major_version;
+ set_fsinfo.unix_info.in.minor_version = fsinfo.unix_info.out.minor_version;
+ set_fsinfo.unix_info.in.capability = fsinfo.unix_info.out.capability;
+
+ status = smb_raw_setfsinfo(tree, NULL, &set_fsinfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("smb_raw_setfsinfo failed %s\n",
+ nt_errstr(status));
+ }
+ return status;
+}
+
+static NTSTATUS smbcli_chmod(struct smbcli_tree *tree, const char *fname,
+ uint64_t permissions)
+{
+ union smb_setfileinfo sfinfo;
+ init_unixinfo_nochange(&sfinfo);
+ sfinfo.unix_basic.in.file.path = fname;
+ sfinfo.unix_basic.in.permissions = permissions;
+ return smb_raw_setpathinfo(tree, &sfinfo);
+}
+
+bool torture_samba3_hide(struct torture_context *torture, struct smbcli_state *cli)
+{
+ const char *fname = "torture_samba3_hide.txt";
+ int fnum;
+ NTSTATUS status;
+ struct smbcli_tree *hideunread;
+ struct smbcli_tree *hideunwrite;
+
+ status = smbcli_setup_unix(cli->tree);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_fail(torture,
+ talloc_asprintf(torture, "smbcli_setup_unix failed %s\n",
+ nt_errstr(status)));
+ }
+
+ status = torture_second_tcon(torture, cli->session, "hideunread",
+ &hideunread);
+ torture_assert_ntstatus_ok(torture, status, "second_tcon(hideunread) failed\n");
+
+ status = torture_second_tcon(torture, cli->session, "hideunwrite",
+ &hideunwrite);
+ torture_assert_ntstatus_ok(torture, status, "second_tcon(hideunwrite) failed\n");
+
+ status = smbcli_unlink(cli->tree, fname);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
+ smbcli_setatr(cli->tree, fname, 0, -1);
+ smbcli_unlink(cli->tree, fname);
+ }
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_fail(torture,
+ talloc_asprintf(torture, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
+ }
+
+ smbcli_close(cli->tree, fnum);
+
+ if (!smbcli_file_exists(cli->tree, fname)) {
+ torture_fail(torture, talloc_asprintf(torture, "%s does not exist\n", fname));
+ }
+
+ /* R/W file should be visible everywhere */
+
+ status = smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
+ torture_assert_ntstatus_ok(torture, status, "smbcli_chmod failed\n");
+
+ if (!is_writeable(torture, cli->tree, fname)) {
+ torture_fail(torture, "File not writable\n");
+ }
+ if (!is_readable(cli->tree, fname)) {
+ torture_fail(torture, "File not readable\n");
+ }
+ if (!is_visible(cli->tree, fname)) {
+ torture_fail(torture, "r/w file not visible via normal share\n");
+ }
+ if (!is_visible(hideunread, fname)) {
+ torture_fail(torture, "r/w file not visible via hide unreadable\n");
+ }
+ if (!is_visible(hideunwrite, fname)) {
+ torture_fail(torture, "r/w file not visible via hide unwriteable\n");
+ }
+
+ /* R/O file should not be visible via hide unwriteable files */
+
+ status = smbcli_chmod(cli->tree, fname, UNIX_R_USR);
+ torture_assert_ntstatus_ok(torture, status, "smbcli_chmod failed\n");
+
+ if (is_writeable(torture, cli->tree, fname)) {
+ torture_fail(torture, "r/o is writable\n");
+ }
+ if (!is_readable(cli->tree, fname)) {
+ torture_fail(torture, "r/o not readable\n");
+ }
+ if (!is_visible(cli->tree, fname)) {
+ torture_fail(torture, "r/o file not visible via normal share\n");
+ }
+ if (!is_visible(hideunread, fname)) {
+ torture_fail(torture, "r/o file not visible via hide unreadable\n");
+ }
+ if (is_visible(hideunwrite, fname)) {
+ torture_fail(torture, "r/o file visible via hide unwriteable\n");
+ }
+
+ /* inaccessible file should be only visible on normal share */
+
+ status = smbcli_chmod(cli->tree, fname, 0);
+ torture_assert_ntstatus_ok(torture, status, "smbcli_chmod failed\n");
+
+ if (is_writeable(torture, cli->tree, fname)) {
+ torture_fail(torture, "inaccessible file is writable\n");
+ }
+ if (is_readable(cli->tree, fname)) {
+ torture_fail(torture, "inaccessible file is readable\n");
+ }
+ if (!is_visible(cli->tree, fname)) {
+ torture_fail(torture, "inaccessible file not visible via normal share\n");
+ }
+ if (is_visible(hideunread, fname)) {
+ torture_fail(torture, "inaccessible file visible via hide unreadable\n");
+ }
+ if (is_visible(hideunwrite, fname)) {
+ torture_fail(torture, "inaccessible file visible via hide unwriteable\n");
+ }
+
+ smbcli_chmod(cli->tree, fname, UNIX_R_USR|UNIX_W_USR);
+ smbcli_unlink(cli->tree, fname);
+
+ return true;
+}
+
+/*
+ * Try to force smb_close to return an error. The only way I can think of is
+ * to open a file with delete on close, chmod the parent dir to 000 and then
+ * close. smb_close should return NT_STATUS_ACCESS_DENIED.
+ */
+
+bool torture_samba3_closeerr(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ bool result = false;
+ NTSTATUS status;
+ const char *dname = "closeerr.dir";
+ const char *fname = "closeerr.dir\\closerr.txt";
+ int fnum;
+
+ smbcli_deltree(cli->tree, dname);
+
+ torture_assert_ntstatus_ok(
+ tctx, smbcli_mkdir(cli->tree, dname),
+ talloc_asprintf(tctx, "smbcli_mdir failed: (%s)\n",
+ smbcli_errstr(cli->tree)));
+
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
+ DENY_NONE);
+ torture_assert(tctx, fnum != -1,
+ talloc_asprintf(tctx, "smbcli_open failed: %s\n",
+ smbcli_errstr(cli->tree)));
+ smbcli_close(cli->tree, fnum);
+
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ NTCREATEX_DISP_OPEN, 0, 0);
+
+ torture_assert(tctx, fnum != -1,
+ talloc_asprintf(tctx, "smbcli_open failed: %s\n",
+ smbcli_errstr(cli->tree)));
+
+ status = smbcli_nt_delete_on_close(cli->tree, fnum, true);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "setting delete_on_close on file failed !");
+
+ status = smbcli_chmod(cli->tree, dname, 0);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "smbcli_chmod on file failed !");
+
+ status = smbcli_close(cli->tree, fnum);
+
+ smbcli_chmod(cli->tree, dname, UNIX_R_USR|UNIX_W_USR|UNIX_X_USR);
+ smbcli_deltree(cli->tree, dname);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_ACCESS_DENIED,
+ "smbcli_close");
+
+ result = true;
+
+ return result;
+}
diff --git a/source4/torture/raw/samba3misc.c b/source4/torture/raw/samba3misc.c
new file mode 100644
index 0000000..35271aa
--- /dev/null
+++ b/source4/torture/raw/samba3misc.c
@@ -0,0 +1,1137 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test some misc Samba3 code paths
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/events/events.h"
+#include "param/param.h"
+#include "torture/raw/proto.h"
+
+/*
+ The next 2 functions are stolen from source4/libcli/raw/rawfile.c
+ but allow us to send a raw data blob instead of an OpenX name.
+*/
+
+#define SETUP_REQUEST(cmd, wct, buflen) do { \
+ req = smbcli_request_setup(tree, cmd, wct, buflen); \
+ if (!req) return NULL; \
+} while (0)
+
+static struct smbcli_request *smb_raw_openX_name_blob_send(struct smbcli_tree *tree,
+ union smb_open *parms,
+ const DATA_BLOB *pname_blob)
+{
+ struct smbcli_request *req = NULL;
+
+ if (parms->generic.level != RAW_OPEN_OPENX) {
+ return NULL;
+ }
+
+ SETUP_REQUEST(SMBopenX, 15, 0);
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->openx.in.flags);
+ SSVAL(req->out.vwv, VWV(3), parms->openx.in.open_mode);
+ SSVAL(req->out.vwv, VWV(4), parms->openx.in.search_attrs);
+ SSVAL(req->out.vwv, VWV(5), parms->openx.in.file_attrs);
+ raw_push_dos_date3(tree->session->transport,
+ req->out.vwv, VWV(6), parms->openx.in.write_time);
+ SSVAL(req->out.vwv, VWV(8), parms->openx.in.open_func);
+ SIVAL(req->out.vwv, VWV(9), parms->openx.in.size);
+ SIVAL(req->out.vwv, VWV(11),parms->openx.in.timeout);
+ SIVAL(req->out.vwv, VWV(13),0); /* reserved */
+ smbcli_req_append_blob(req, pname_blob);
+
+ if (!smbcli_request_send(req)) {
+ smbcli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+static NTSTATUS smb_raw_openX_name_blob(struct smbcli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_open *parms,
+ const DATA_BLOB *pname_blob)
+{
+ struct smbcli_request *req = smb_raw_openX_name_blob_send(tree, parms, pname_blob);
+ return smb_raw_open_recv(req, mem_ctx, parms);
+}
+
+static NTSTATUS raw_smbcli_openX_name_blob(struct smbcli_tree *tree,
+ const DATA_BLOB *pname_blob,
+ int flags,
+ int share_mode,
+ int *fnum)
+{
+ union smb_open open_parms;
+ unsigned int openfn=0;
+ unsigned int accessmode=0;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_openX_name_blob");
+ if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+ if (flags & O_CREAT) {
+ openfn |= OPENX_OPEN_FUNC_CREATE;
+ }
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC) {
+ openfn |= OPENX_OPEN_FUNC_TRUNC;
+ } else {
+ openfn |= OPENX_OPEN_FUNC_OPEN;
+ }
+ }
+
+ accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= OPENX_MODE_ACCESS_RDWR;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= OPENX_MODE_ACCESS_WRITE;
+ } else if ((flags & O_ACCMODE) == O_RDONLY) {
+ accessmode |= OPENX_MODE_ACCESS_READ;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= OPENX_MODE_WRITE_THRU;
+ }
+#endif
+
+ if (share_mode == DENY_FCB) {
+ accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
+ }
+
+ open_parms.openx.level = RAW_OPEN_OPENX;
+ open_parms.openx.in.flags = 0;
+ open_parms.openx.in.open_mode = accessmode;
+ open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ open_parms.openx.in.file_attrs = 0;
+ open_parms.openx.in.write_time = 0;
+ open_parms.openx.in.open_func = openfn;
+ open_parms.openx.in.size = 0;
+ open_parms.openx.in.timeout = 0;
+ open_parms.openx.in.fname = NULL;
+
+ status = smb_raw_openX_name_blob(tree, mem_ctx, &open_parms, pname_blob);
+ talloc_free(mem_ctx);
+
+ if (fnum && NT_STATUS_IS_OK(status)) {
+ *fnum = open_parms.openx.out.file.fnum;
+ }
+
+ return status;
+}
+
+
+#define CHECK_STATUS(torture, status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(torture, TORTURE_FAIL, "%s: Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ } \
+} while (0)
+
+bool torture_samba3_checkfsp(struct torture_context *torture, struct smbcli_state *cli)
+{
+ const char *fname = "test.txt";
+ const char *dirname = "testdir";
+ int fnum;
+ NTSTATUS status;
+ bool ret = true;
+ TALLOC_CTX *mem_ctx;
+ ssize_t nread;
+ char buf[16];
+ struct smbcli_tree *tree2;
+
+ torture_assert(torture, mem_ctx = talloc_init("torture_samba3_checkfsp"), "talloc_init failed\n");
+
+ torture_assert_ntstatus_equal(torture, torture_second_tcon(torture, cli->session,
+ torture_setting_string(torture, "share", NULL),
+ &tree2),
+ NT_STATUS_OK,
+ "creating second tcon");
+
+ /* Try a read on an invalid FID */
+
+ nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf));
+ CHECK_STATUS(torture, smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE);
+
+ /* Try a read on a directory handle */
+
+ torture_assert(torture, torture_setup_dir(cli, dirname), "creating test directory");
+
+ /* Open the directory */
+ {
+ union smb_open io;
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = dirname;
+ status = smb_raw_open(cli->tree, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(torture, TORTURE_FAIL, "smb_open on the directory failed: %s\n",
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+ fnum = io.ntcreatex.out.file.fnum;
+ }
+
+ /* Try a read on the directory */
+
+ nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf));
+ if (nread >= 0) {
+ torture_result(torture, TORTURE_FAIL, "smbcli_read on a directory succeeded, expected "
+ "failure\n");
+ ret = false;
+ }
+
+ CHECK_STATUS(torture, smbcli_nt_error(cli->tree),
+ NT_STATUS_INVALID_DEVICE_REQUEST);
+
+ /* Same test on the second tcon */
+
+ nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
+ if (nread >= 0) {
+ torture_result(torture, TORTURE_FAIL, "smbcli_read on a directory succeeded, expected "
+ "failure\n");
+ ret = false;
+ }
+
+ CHECK_STATUS(torture, smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
+
+ smbcli_close(cli->tree, fnum);
+
+ /* Try a normal file read on a second tcon */
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(torture, TORTURE_FAIL, "Failed to create %s - %s\n", fname,
+ smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf));
+ CHECK_STATUS(torture, smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE);
+
+ smbcli_close(cli->tree, fnum);
+
+ done:
+ smbcli_deltree(cli->tree, dirname);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
+{
+ union smb_open open_parms;
+ unsigned int openfn=0;
+ unsigned int accessmode=0;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_open");
+ if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+ if (flags & O_CREAT) {
+ openfn |= OPENX_OPEN_FUNC_CREATE;
+ }
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC) {
+ openfn |= OPENX_OPEN_FUNC_TRUNC;
+ } else {
+ openfn |= OPENX_OPEN_FUNC_OPEN;
+ }
+ }
+
+ accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= OPENX_MODE_ACCESS_RDWR;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= OPENX_MODE_ACCESS_WRITE;
+ } else if ((flags & O_ACCMODE) == O_RDONLY) {
+ accessmode |= OPENX_MODE_ACCESS_READ;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= OPENX_MODE_WRITE_THRU;
+ }
+#endif
+
+ if (share_mode == DENY_FCB) {
+ accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
+ }
+
+ open_parms.openx.level = RAW_OPEN_OPENX;
+ open_parms.openx.in.flags = 0;
+ open_parms.openx.in.open_mode = accessmode;
+ open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ open_parms.openx.in.file_attrs = 0;
+ open_parms.openx.in.write_time = 0;
+ open_parms.openx.in.open_func = openfn;
+ open_parms.openx.in.size = 0;
+ open_parms.openx.in.timeout = 0;
+ open_parms.openx.in.fname = fname;
+
+ status = smb_raw_open(tree, mem_ctx, &open_parms);
+ talloc_free(mem_ctx);
+
+ if (fnum && NT_STATUS_IS_OK(status)) {
+ *fnum = open_parms.openx.out.file.fnum;
+ }
+
+ return status;
+}
+
+static NTSTATUS raw_smbcli_t2open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum)
+{
+ union smb_open io;
+ unsigned int openfn=0;
+ unsigned int accessmode=0;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_t2open");
+ if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+ if (flags & O_CREAT) {
+ openfn |= OPENX_OPEN_FUNC_CREATE;
+ }
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC) {
+ openfn |= OPENX_OPEN_FUNC_TRUNC;
+ } else {
+ openfn |= OPENX_OPEN_FUNC_OPEN;
+ }
+ }
+
+ accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= OPENX_MODE_ACCESS_RDWR;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= OPENX_MODE_ACCESS_WRITE;
+ } else if ((flags & O_ACCMODE) == O_RDONLY) {
+ accessmode |= OPENX_MODE_ACCESS_READ;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= OPENX_MODE_WRITE_THRU;
+ }
+#endif
+
+ if (share_mode == DENY_FCB) {
+ accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
+ }
+
+ memset(&io, '\0', sizeof(io));
+ io.t2open.level = RAW_OPEN_T2OPEN;
+ io.t2open.in.flags = 0;
+ io.t2open.in.open_mode = accessmode;
+ io.t2open.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ io.t2open.in.file_attrs = 0;
+ io.t2open.in.write_time = 0;
+ io.t2open.in.open_func = openfn;
+ io.t2open.in.size = 0;
+ io.t2open.in.timeout = 0;
+ io.t2open.in.fname = fname;
+
+ io.t2open.in.num_eas = 1;
+ io.t2open.in.eas = talloc_array(mem_ctx, struct ea_struct, io.t2open.in.num_eas);
+ io.t2open.in.eas[0].flags = 0;
+ io.t2open.in.eas[0].name.s = ".CLASSINFO";
+ io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "first value", 11);
+
+ status = smb_raw_open(tree, mem_ctx, &io);
+ talloc_free(mem_ctx);
+
+ if (fnum && NT_STATUS_IS_OK(status)) {
+ *fnum = io.openx.out.file.fnum;
+ }
+
+ return status;
+}
+
+static NTSTATUS raw_smbcli_ntcreate(struct smbcli_tree *tree, const char *fname, int *fnum)
+{
+ union smb_open io;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_t2open");
+ if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+ memset(&io, '\0', sizeof(io));
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(tree, mem_ctx, &io);
+ talloc_free(mem_ctx);
+
+ if (fnum && NT_STATUS_IS_OK(status)) {
+ *fnum = io.openx.out.file.fnum;
+ }
+
+ return status;
+}
+
+
+bool torture_samba3_badpath(struct torture_context *torture)
+{
+ struct smbcli_state *cli_nt = NULL;
+ struct smbcli_state *cli_dos = NULL;
+ const char *fname = "test.txt";
+ const char *fname1 = "test1.txt";
+ const char *dirname = "testdir";
+ char *fpath;
+ char *fpath1;
+ int fnum;
+ NTSTATUS status;
+ bool ret = true;
+ TALLOC_CTX *mem_ctx;
+ bool nt_status_support;
+ bool client_ntlmv2_auth;
+
+ torture_assert(torture, mem_ctx = talloc_init("torture_samba3_badpath"), "talloc_init failed");
+
+ nt_status_support = lpcfg_nt_status_support(torture->lp_ctx);
+ client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(torture->lp_ctx);
+
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "yes"), ret, fail, "Could not set 'client ntlmv2 auth = yes'\n");
+
+ torture_assert_goto(torture, torture_open_connection(&cli_nt, torture, 0), ret, fail, "Could not open NTSTATUS connection\n");
+
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "no"), ret, fail, "Could not set 'client ntlmv2 auth = no'\n");
+
+ torture_assert_goto(torture, torture_open_connection(&cli_dos, torture, 1), ret, fail, "Could not open DOS connection\n");
+
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support",
+ nt_status_support ? "yes":"no"),
+ ret, fail, "Could not set 'nt status support' back to where it was\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth",
+ client_ntlmv2_auth ? "yes":"no"),
+ ret, fail, "Could not set 'client ntlmv2 auth' back to where it was\n");
+
+ torture_assert(torture, torture_setup_dir(cli_nt, dirname), "creating test directory");
+
+ status = smbcli_chkpath(cli_nt->tree, dirname);
+ CHECK_STATUS(torture, status, NT_STATUS_OK);
+
+ status = smbcli_chkpath(cli_nt->tree,
+ talloc_asprintf(mem_ctx, "%s\\bla", dirname));
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ status = smbcli_chkpath(cli_dos->tree,
+ talloc_asprintf(mem_ctx, "%s\\bla", dirname));
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ status = smbcli_chkpath(cli_nt->tree,
+ talloc_asprintf(mem_ctx, "%s\\bla\\blub",
+ dirname));
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ status = smbcli_chkpath(cli_dos->tree,
+ talloc_asprintf(mem_ctx, "%s\\bla\\blub",
+ dirname));
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ torture_assert_goto(torture, fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname),
+ ret, fail, "Could not allocate fpath\n");
+
+ fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(torture, TORTURE_FAIL, "Could not create file %s: %s\n", fpath,
+ smbcli_errstr(cli_nt->tree));
+ goto fail;
+ }
+ smbcli_close(cli_nt->tree, fnum);
+
+ if (!(fpath1 = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname1))) {
+ goto fail;
+ }
+ fnum = smbcli_open(cli_nt->tree, fpath1, O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(torture, TORTURE_FAIL, "Could not create file %s: %s\n", fpath1,
+ smbcli_errstr(cli_nt->tree));
+ goto fail;
+ }
+ smbcli_close(cli_nt->tree, fnum);
+
+ /*
+ * Do a whole bunch of error code checks on chkpath
+ */
+
+ status = smbcli_chkpath(cli_nt->tree, fpath);
+ CHECK_STATUS(torture, status, NT_STATUS_NOT_A_DIRECTORY);
+ status = smbcli_chkpath(cli_dos->tree, fpath);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ status = smbcli_chkpath(cli_nt->tree, "..");
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+ status = smbcli_chkpath(cli_dos->tree, "..");
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
+
+ status = smbcli_chkpath(cli_nt->tree, ".");
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_chkpath(cli_dos->tree, ".");
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ status = smbcli_chkpath(cli_nt->tree, "\t");
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_chkpath(cli_dos->tree, "\t");
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ status = smbcli_chkpath(cli_nt->tree, "\t\\bla");
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_chkpath(cli_dos->tree, "\t\\bla");
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ status = smbcli_chkpath(cli_nt->tree, "<");
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_chkpath(cli_dos->tree, "<");
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ status = smbcli_chkpath(cli_nt->tree, "<\\bla");
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_chkpath(cli_dos->tree, "<\\bla");
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRbadpath));
+
+ /*
+ * .... And the same gang against getatr. Note that the DOS error codes
+ * differ....
+ */
+
+ status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OK);
+ status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OK);
+
+ status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+ status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
+
+ status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ /* Try the same set with openX. */
+
+ status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+ status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath));
+
+ status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_INVALID);
+ status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS, ERRinvalidname));
+
+ /* Let's test EEXIST error code mapping. */
+ status = raw_smbcli_open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION);
+ status = raw_smbcli_open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
+
+ status = raw_smbcli_t2open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)
+ || !torture_setting_bool(torture, "samba3", false)) {
+ /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION);
+ }
+ status = raw_smbcli_t2open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS,ERReasnotsupported))
+ || !torture_setting_bool(torture, "samba3", false)) {
+ /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
+ }
+
+ status = raw_smbcli_ntcreate(cli_nt->tree, fpath, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION);
+ status = raw_smbcli_ntcreate(cli_dos->tree, fpath, NULL);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRfilexists));
+
+ /* Try the rename test. */
+ {
+ union smb_rename io;
+ memset(&io, '\0', sizeof(io));
+ io.rename.in.pattern1 = fpath1;
+ io.rename.in.pattern2 = fpath;
+
+ /* Try with SMBmv rename. */
+ status = smb_raw_rename(cli_nt->tree, &io);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION);
+ status = smb_raw_rename(cli_dos->tree, &io);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRrename));
+
+ /* Try with NT rename. */
+ io.generic.level = RAW_RENAME_NTRENAME;
+ io.ntrename.in.old_name = fpath1;
+ io.ntrename.in.new_name = fpath;
+ io.ntrename.in.attrib = 0;
+ io.ntrename.in.cluster_size = 0;
+ io.ntrename.in.flags = RENAME_FLAG_RENAME;
+
+ status = smb_raw_rename(cli_nt->tree, &io);
+ CHECK_STATUS(torture, status, NT_STATUS_OBJECT_NAME_COLLISION);
+ status = smb_raw_rename(cli_dos->tree, &io);
+ CHECK_STATUS(torture, status, NT_STATUS_DOS(ERRDOS,ERRrename));
+ }
+
+ goto done;
+
+ fail:
+ ret = false;
+
+ done:
+ if (cli_nt != NULL) {
+ smbcli_deltree(cli_nt->tree, dirname);
+ torture_close_connection(cli_nt);
+ }
+ if (cli_dos != NULL) {
+ torture_close_connection(cli_dos);
+ }
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static void count_fn(struct clilist_file_info *info, const char *name,
+ void *private_data)
+{
+ int *counter = (int *)private_data;
+ *counter += 1;
+}
+
+bool torture_samba3_caseinsensitive(struct torture_context *torture, struct smbcli_state *cli)
+{
+ TALLOC_CTX *mem_ctx;
+ const char *dirname = "insensitive";
+ const char *ucase_dirname = "InSeNsItIvE";
+ const char *fname = "foo";
+ char *fpath;
+ int fnum;
+ int counter = 0;
+ bool ret = false;
+
+ if (!(mem_ctx = talloc_init("torture_samba3_caseinsensitive"))) {
+ torture_result(torture, TORTURE_FAIL, "talloc_init failed\n");
+ return false;
+ }
+
+ torture_assert(torture, torture_setup_dir(cli, dirname), "creating test directory");
+
+ if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) {
+ goto done;
+ }
+ fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(torture, TORTURE_FAIL,
+ "Could not create file %s: %s", fpath,
+ smbcli_errstr(cli->tree));
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ smbcli_list(cli->tree, talloc_asprintf(
+ mem_ctx, "%s\\*", ucase_dirname),
+ FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN
+ |FILE_ATTRIBUTE_SYSTEM,
+ count_fn, (void *)&counter);
+
+ if (counter == 3) {
+ ret = true;
+ }
+ else {
+ torture_result(torture, TORTURE_FAIL,
+ "expected 3 entries, got %d", counter);
+ ret = false;
+ }
+
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static void close_locked_file(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval now,
+ void *private_data)
+{
+ int *pfd = (int *)private_data;
+
+ TALLOC_FREE(te);
+
+ if (*pfd != -1) {
+ close(*pfd);
+ *pfd = -1;
+ }
+}
+
+struct lock_result_state {
+ NTSTATUS status;
+ bool done;
+};
+
+static void receive_lock_result(struct smbcli_request *req)
+{
+ struct lock_result_state *state =
+ (struct lock_result_state *)req->async.private_data;
+
+ state->status = smbcli_request_simple_recv(req);
+ state->done = true;
+}
+
+/*
+ * Check that Samba3 correctly deals with conflicting local posix byte range
+ * locks on an underlying file via "normal" SMB1 (without unix extensions).
+ *
+ * Note: This test depends on "posix locking = yes".
+ * Note: To run this test, use "--option=torture:localdir=<LOCALDIR>"
+ */
+
+bool torture_samba3_posixtimedlock(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ const char *dirname = "posixlock";
+ const char *fname = "locked";
+ const char *fpath;
+ const char *localdir;
+ const char *localname;
+ int fnum = -1;
+
+ int fd = -1;
+ struct flock posix_lock;
+
+ union smb_lock io;
+ struct smb_lock_entry lock_entry;
+ struct smbcli_request *req;
+ struct lock_result_state lock_result;
+
+ struct tevent_timer *te;
+
+ torture_assert(tctx, torture_setup_dir(cli, dirname), "creating test directory");
+
+ if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) {
+ torture_warning(tctx, "talloc failed\n");
+ ret = false;
+ goto done;
+ }
+ fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_warning(tctx, "Could not create file %s: %s\n", fpath,
+ smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) {
+ torture_warning(tctx, "Need 'localdir' setting\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname,
+ fname))) {
+ torture_warning(tctx, "talloc failed\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Lock a byte range from posix
+ */
+
+ fd = open(localname, O_RDWR);
+ if (fd == -1) {
+ torture_warning(tctx, "open(%s) failed: %s\n",
+ localname, strerror(errno));
+ goto done;
+ }
+
+ posix_lock.l_type = F_WRLCK;
+ posix_lock.l_whence = SEEK_SET;
+ posix_lock.l_start = 0;
+ posix_lock.l_len = 1;
+
+ if (fcntl(fd, F_SETLK, &posix_lock) == -1) {
+ torture_warning(tctx, "fcntl failed: %s\n", strerror(errno));
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Try a cifs brlock without timeout to see if posix locking = yes
+ */
+
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+
+ lock_entry.count = 1;
+ lock_entry.offset = 0;
+ lock_entry.pid = cli->tree->session->pid;
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 0;
+ io.lockx.in.locks = &lock_entry;
+ io.lockx.in.file.fnum = fnum;
+
+ status = smb_raw_lock(cli->tree, &io);
+
+ ret = true;
+ CHECK_STATUS(tctx, status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ if (!ret) {
+ goto done;
+ }
+
+ /*
+ * Now fire off a timed brlock, unlock the posix lock and see if the
+ * timed lock gets through.
+ */
+
+ io.lockx.in.timeout = 5000;
+
+ req = smb_raw_lock_send(cli->tree, &io);
+ if (req == NULL) {
+ torture_warning(tctx, "smb_raw_lock_send failed\n");
+ ret = false;
+ goto done;
+ }
+
+ lock_result.done = false;
+ req->async.fn = receive_lock_result;
+ req->async.private_data = &lock_result;
+
+ te = tevent_add_timer(tctx->ev,
+ tctx, timeval_current_ofs(1, 0),
+ close_locked_file, &fd);
+ if (te == NULL) {
+ torture_warning(tctx, "tevent_add_timer failed\n");
+ ret = false;
+ goto done;
+ }
+
+ while ((fd != -1) || (!lock_result.done)) {
+ if (tevent_loop_once(tctx->ev) == -1) {
+ torture_warning(tctx, "tevent_loop_once failed: %s\n",
+ strerror(errno));
+ ret = false;
+ goto done;
+ }
+ }
+
+ CHECK_STATUS(tctx, lock_result.status, NT_STATUS_OK);
+
+ done:
+ if (fnum != -1) {
+ smbcli_close(cli->tree, fnum);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ smbcli_deltree(cli->tree, dirname);
+ return ret;
+}
+
+bool torture_samba3_rootdirfid(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ uint16_t dnum;
+ union smb_open io;
+ const char *fname = "testfile";
+ bool ret = false;
+
+ smbcli_unlink(cli->tree, fname);
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.access_mask =
+ SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ
+ | NTCREATEX_SHARE_ACCESS_READ;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = "\\";
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io),
+ NT_STATUS_OK,
+ ret, done, "smb_open on the directory failed: %s\n");
+
+ dnum = io.ntcreatex.out.file.fnum;
+
+ io.ntcreatex.in.flags =
+ NTCREATEX_FLAGS_REQUEST_OPLOCK
+ | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.root_fid.fnum = dnum;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = fname;
+
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io),
+ NT_STATUS_OK,
+ ret, done, "smb_open on the file failed");
+
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ smbcli_close(cli->tree, dnum);
+ smbcli_unlink(cli->tree, fname);
+
+ ret = true;
+ done:
+ return ret;
+}
+
+bool torture_samba3_rootdirfid2(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ int fnum;
+ uint16_t dnum;
+ union smb_open io;
+ const char *dirname1 = "dir1";
+ const char *dirname2 = "dir1/dir2";
+ const char *path = "dir1/dir2/testfile";
+ const char *relname = "dir2/testfile";
+ bool ret = false;
+
+ smbcli_deltree(cli->tree, dirname1);
+
+ torture_assert(tctx, torture_setup_dir(cli, dirname1), "creating test directory");
+ torture_assert(tctx, torture_setup_dir(cli, dirname2), "creating test directory");
+
+ fnum = smbcli_open(cli->tree, path, O_RDWR | O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Could not create file: %s",
+ smbcli_errstr(cli->tree));
+ goto done;
+ }
+ smbcli_close(cli->tree, fnum);
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.access_mask =
+ SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ
+ | NTCREATEX_SHARE_ACCESS_READ;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = dirname1;
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io),
+ NT_STATUS_OK,
+ ret, done, "smb_open on the directory failed: %s\n");
+
+ dnum = io.ntcreatex.out.file.fnum;
+
+ io.ntcreatex.in.flags =
+ NTCREATEX_FLAGS_REQUEST_OPLOCK
+ | NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ io.ntcreatex.in.root_fid.fnum = dnum;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = relname;
+
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io),
+ NT_STATUS_OK,
+ ret, done, "smb_open on the file failed");
+
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ smbcli_close(cli->tree, dnum);
+
+ ret = true;
+done:
+ smbcli_deltree(cli->tree, dirname1);
+ return ret;
+}
+
+bool torture_samba3_oplock_logoff(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_open io;
+ const char *fname = "testfile";
+ bool ret = false;
+ struct smbcli_request *req;
+ struct smb_echo echo_req;
+
+ smbcli_unlink(cli->tree, fname);
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.access_mask =
+ SEC_STD_SYNCHRONIZE | SEC_FILE_EXECUTE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.fname = "testfile";
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_open(cli->tree, tctx, &io),
+ NT_STATUS_OK,
+ ret, done, "first smb_open on the file failed");
+
+ /*
+ * Create a conflicting open, causing the one-second delay
+ */
+
+ torture_assert_goto(tctx, req = smb_raw_open_send(cli->tree, &io),
+ ret, done, "smb_raw_open_send on the file failed");
+
+ /*
+ * Pull the VUID from under that request. As of Nov 3, 2008 all Samba3
+ * versions (3.0, 3.2 and master) would spin sending ERRinvuid errors
+ * as long as the client is still connected.
+ */
+
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_ulogoff(cli->session),
+ NT_STATUS_OK,
+ ret, done, "ulogoff failed failed");
+
+ echo_req.in.repeat_count = 1;
+ echo_req.in.size = 1;
+ echo_req.in.data = discard_const_p(uint8_t, "");
+
+ torture_assert_ntstatus_equal_goto(tctx, smb_raw_echo(cli->session->transport, &echo_req),
+ NT_STATUS_OK,
+ ret, done, "smb_raw_echo failed");
+
+ ret = true;
+ done:
+ return ret;
+}
+
+bool torture_samba3_check_openX_badname(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = false;
+ int fnum = -1;
+ DATA_BLOB name_blob = data_blob_talloc(cli->tree, NULL, 65535);
+
+ if (name_blob.data == NULL) {
+ return false;
+ }
+ memset(name_blob.data, 0xcc, 65535);
+ status = raw_smbcli_openX_name_blob(cli->tree, &name_blob, O_RDWR, DENY_NONE, &fnum);
+ CHECK_STATUS(tctx, status, NT_STATUS_OBJECT_NAME_INVALID);
+ ret = true;
+
+ return ret;
+}
diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
new file mode 100644
index 0000000..575bbd0
--- /dev/null
+++ b/source4/torture/raw/search.c
@@ -0,0 +1,1653 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_SEARCH_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/util/tsort.h"
+#include "torture/raw/proto.h"
+
+#undef strncasecmp
+
+#define BASEDIR "\\testsearch"
+
+#define CHECK_STATUS_LEVEL(__tctx, __status, __level, __supp) \
+ do { \
+ if (NT_STATUS_EQUAL(__status, \
+ NT_STATUS_NOT_SUPPORTED) || \
+ NT_STATUS_EQUAL(__status, \
+ NT_STATUS_NOT_IMPLEMENTED)) { \
+ __supp = false; \
+ } else { \
+ __supp = true; \
+ } \
+ if (__supp) { \
+ torture_assert_ntstatus_ok_goto(__tctx, \
+ __status, ret, done, #__level" failed"); \
+ } else { \
+ torture_warning(__tctx, "(%s) Info " \
+ "level "#__level" is %s", \
+ __location__, nt_errstr(__status)); \
+ } \
+ } while (0)
+
+/*
+ callback function for single_search
+*/
+static bool single_search_callback(void *private_data, const union smb_search_data *file)
+{
+ union smb_search_data *data = (union smb_search_data *)private_data;
+
+ *data = *file;
+
+ return true;
+}
+
+/*
+ do a single file (non-wildcard) search
+*/
+NTSTATUS torture_single_search(struct smbcli_state *cli,
+ TALLOC_CTX *tctx,
+ const char *pattern,
+ enum smb_search_level level,
+ enum smb_search_data_level data_level,
+ uint16_t attrib,
+ union smb_search_data *data)
+{
+ union smb_search_first io;
+ union smb_search_close c;
+ NTSTATUS status;
+
+ switch (level) {
+ case RAW_SEARCH_SEARCH:
+ case RAW_SEARCH_FFIRST:
+ case RAW_SEARCH_FUNIQUE:
+ io.search_first.level = level;
+ io.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
+ io.search_first.in.max_count = 1;
+ io.search_first.in.search_attrib = attrib;
+ io.search_first.in.pattern = pattern;
+ break;
+
+ case RAW_SEARCH_TRANS2:
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = data_level;
+ io.t2ffirst.in.search_attrib = attrib;
+ io.t2ffirst.in.max_count = 1;
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = pattern;
+ break;
+
+ case RAW_SEARCH_SMB2:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, (void *)data, single_search_callback);
+
+ if (NT_STATUS_IS_OK(status) && level == RAW_SEARCH_FFIRST) {
+ c.fclose.level = RAW_FINDCLOSE_FCLOSE;
+ c.fclose.in.max_count = 1;
+ c.fclose.in.search_attrib = 0;
+ c.fclose.in.id = data->search.id;
+ status = smb_raw_search_close(cli->tree, &c);
+ }
+
+ return status;
+}
+
+
+static struct {
+ const char *name;
+ enum smb_search_level level;
+ enum smb_search_data_level data_level;
+ int name_offset;
+ int resume_key_offset;
+ uint32_t capability_mask;
+ NTSTATUS status;
+ union smb_search_data data;
+} levels[] = {
+ {
+ .name = "FFIRST",
+ .level = RAW_SEARCH_FFIRST,
+ .data_level = RAW_SEARCH_DATA_SEARCH,
+ .name_offset = offsetof(union smb_search_data,
+ search.name),
+ .resume_key_offset = -1,
+ },
+ {
+ .name = "FUNIQUE",
+ .level = RAW_SEARCH_FUNIQUE,
+ .data_level = RAW_SEARCH_DATA_SEARCH,
+ .name_offset = offsetof(union smb_search_data,
+ search.name),
+ .resume_key_offset = -1,
+ },
+ {
+ .name = "SEARCH",
+ .level = RAW_SEARCH_SEARCH,
+ .data_level = RAW_SEARCH_DATA_SEARCH,
+ .name_offset = offsetof(union smb_search_data,
+ search.name),
+ .resume_key_offset = -1,
+ },
+ {
+ .name = "STANDARD",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_STANDARD,
+ .name_offset = offsetof(union smb_search_data,
+ standard.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ standard.resume_key),
+ },
+ {
+ .name = "EA_SIZE",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_EA_SIZE,
+ .name_offset = offsetof(union smb_search_data,
+ ea_size.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ ea_size.resume_key),
+ },
+ {
+ .name = "DIRECTORY_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ directory_info.file_index),
+ },
+ {
+ .name = "FULL_DIRECTORY_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ full_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ full_directory_info.file_index),
+ },
+ {
+ .name = "NAME_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_NAME_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ name_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ name_info.file_index),
+ },
+ {
+ .name = "BOTH_DIRECTORY_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ both_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ both_directory_info.file_index),
+ },
+ {
+ .name = "ID_FULL_DIRECTORY_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ id_full_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ id_full_directory_info.file_index),
+ },
+ {
+ .name = "ID_BOTH_DIRECTORY_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ id_both_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ id_both_directory_info.file_index),
+ },
+ {
+ .name = "UNIX_INFO",
+ .level = RAW_SEARCH_TRANS2,
+ .data_level = RAW_SEARCH_DATA_UNIX_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ unix_info.name),
+ .resume_key_offset = offsetof(union smb_search_data,
+ unix_info.file_index),
+ .capability_mask = CAP_UNIX
+ },
+};
+
+
+/*
+ return level name
+*/
+static const char *level_name(enum smb_search_level level,
+ enum smb_search_data_level data_level)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (level == levels[i].level &&
+ data_level == levels[i].data_level) {
+ return levels[i].name;
+ }
+ }
+ return NULL;
+}
+
+/*
+ extract the name from a smb_data structure and level
+*/
+static const char *extract_name(void *data, enum smb_search_level level,
+ enum smb_search_data_level data_level)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (level == levels[i].level &&
+ data_level == levels[i].data_level) {
+ return *(const char **)(levels[i].name_offset + (char *)data);
+ }
+ }
+ return NULL;
+}
+
+/*
+ extract the name from a smb_data structure and level
+*/
+static uint32_t extract_resume_key(void *data, enum smb_search_level level,
+ enum smb_search_data_level data_level)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (level == levels[i].level &&
+ data_level == levels[i].data_level) {
+ return *(uint32_t *)(levels[i].resume_key_offset + (char *)data);
+ }
+ }
+ return 0;
+}
+
+/* find a level in the table by name */
+static union smb_search_data *find(const char *name)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (NT_STATUS_IS_OK(levels[i].status) &&
+ strcmp(levels[i].name, name) == 0) {
+ return &levels[i].data;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Negotiate SMB1+POSIX.
+ */
+
+static NTSTATUS setup_smb1_posix(struct torture_context *tctx,
+ struct smbcli_state *cli_unix)
+{
+ struct smb_trans2 tp;
+ uint16_t setup;
+ uint8_t data[12];
+ uint8_t params[4];
+ uint32_t cap = cli_unix->transport->negotiate.capabilities;
+
+ if ((cap & CAP_UNIX) == 0) {
+ /*
+ * Server doesn't support SMB1+POSIX.
+ * The caller will skip the UNIX info
+ * level anyway.
+ */
+ torture_comment(tctx,
+ "Server doesn't support SMB1+POSIX\n");
+ return NT_STATUS_OK;
+ }
+
+ /* Setup POSIX on this connection. */
+ SSVAL(data, 0, CIFS_UNIX_MAJOR_VERSION);
+ SSVAL(data, 2, CIFS_UNIX_MINOR_VERSION);
+ SBVAL(data,4,((uint64_t)(
+ CIFS_UNIX_POSIX_ACLS_CAP|
+ CIFS_UNIX_POSIX_PATHNAMES_CAP|
+ CIFS_UNIX_FCNTL_LOCKS_CAP|
+ CIFS_UNIX_EXTATTR_CAP|
+ CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
+ setup = TRANSACT2_SETFSINFO;
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.max_param = 0;
+ tp.in.max_data = 0;
+ tp.in.setup = &setup;
+ tp.in.trans_name = NULL;
+ SSVAL(params, 0, 0);
+ SSVAL(params, 2, SMB_SET_CIFS_UNIX_INFO);
+ tp.in.params = data_blob_talloc(tctx, params, 4);
+ tp.in.data = data_blob_talloc(tctx, data, 12);
+ return smb_raw_trans2(cli_unix->tree, tctx, &tp);
+}
+
+/*
+ basic testing of all RAW_SEARCH_* calls using a single file
+*/
+static bool test_one_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct smbcli_state *cli_unix)
+{
+ bool ret = true;
+ int fnum;
+ const char *fname = "torture_search.txt";
+ const char *fname2 = "torture_search-NOTEXIST.txt";
+ NTSTATUS status;
+ int i;
+ union smb_fileinfo all_info, alt_info, name_info, internal_info;
+ bool all_info_supported, alt_info_supported, name_info_supported,
+ internal_info_supported;
+ union smb_search_data *s;
+
+ status = setup_smb1_posix(tctx, cli_unix);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__"setup_smb1_posix() failed (%s)\n",
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ fnum = create_complex_file(cli, tctx, fname);
+ if (fnum == -1) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__"ERROR: open of %s failed (%s)\n",
+ fname,
+ smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ /* call all the levels */
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ NTSTATUS expected_status;
+ uint32_t cap = cli->transport->negotiate.capabilities;
+ struct smbcli_state *cli_search = cli;
+
+ torture_comment(tctx, "Testing %s\n", levels[i].name);
+
+ if (levels[i].data_level == RAW_SEARCH_DATA_UNIX_INFO) {
+ /*
+ * For an SMB1+POSIX info level, use the cli_unix
+ * connection.
+ */
+ cli_search = cli_unix;
+ }
+
+ levels[i].status = torture_single_search(cli_search, tctx, fname,
+ levels[i].level,
+ levels[i].data_level,
+ 0,
+ &levels[i].data);
+
+ /* see if this server claims to support this level */
+ if (((cap & levels[i].capability_mask) != levels[i].capability_mask)
+ || NT_STATUS_EQUAL(levels[i].status, NT_STATUS_NOT_SUPPORTED)) {
+ printf("search level %s(%d) not supported by server\n",
+ levels[i].name, (int)levels[i].level);
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(levels[i].status)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__"search level %s(%d) failed - %s\n",
+ levels[i].name, (int)levels[i].level,
+ nt_errstr(levels[i].status));
+ ret = false;
+ continue;
+ }
+
+ status = torture_single_search(cli_search, tctx, fname2,
+ levels[i].level,
+ levels[i].data_level,
+ 0,
+ &levels[i].data);
+
+ expected_status = NT_STATUS_NO_SUCH_FILE;
+ if (levels[i].level == RAW_SEARCH_SEARCH ||
+ levels[i].level == RAW_SEARCH_FFIRST ||
+ levels[i].level == RAW_SEARCH_FUNIQUE) {
+ expected_status = STATUS_NO_MORE_FILES;
+ }
+ if (!NT_STATUS_EQUAL(status, expected_status)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ __location__"search level %s(%d) should fail with %s - %s\n",
+ levels[i].name, (int)levels[i].level,
+ nt_errstr(expected_status),
+ nt_errstr(status));
+ ret = false;
+ }
+ }
+
+ /* get the all_info file into to check against */
+ all_info.generic.level = RAW_FILEINFO_ALL_INFO;
+ all_info.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &all_info);
+ CHECK_STATUS_LEVEL(tctx, status, "RAW_FILEINFO_ALL_INFO",
+ all_info_supported);
+
+ alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
+ alt_info.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &alt_info);
+ CHECK_STATUS_LEVEL(tctx, status, "RAW_FILEINFO_ALT_NAME_INFO",
+ alt_info_supported);
+
+ internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
+ internal_info.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &internal_info);
+ CHECK_STATUS_LEVEL(tctx, status, "RAW_FILEINFO_INTERNAL_INFORMATION",
+ internal_info_supported);
+
+ name_info.generic.level = RAW_FILEINFO_NAME_INFO;
+ name_info.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &name_info);
+ CHECK_STATUS_LEVEL(tctx, status, "RAW_FILEINFO_NAME_INFO",
+ name_info_supported);
+
+#define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if ((s->sname1.field1) != (v.sname2.out.field2)) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
+ __location__, \
+ #sname1, #field1, (int)s->sname1.field1, \
+ #sname2, #field2, (int)v.sname2.out.field2); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (s->sname1.field1 != (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, timestring(tctx, s->sname1.field1), \
+ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (s->sname1.field1 != v.sname2.out.field2) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, nt_time_string(tctx, s->sname1.field1), \
+ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1, \
+ #sname2, #field2, v.sname2.out.field2.s); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1.s || \
+ strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \
+ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1.s, \
+ #sname2, #field2, v.sname2.out.field2.s); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_NAME(name, sname1, field1, fname, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1.s || \
+ strcmp(s->sname1.field1.s, fname) || \
+ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [%s] != %s\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1.s, \
+ fname); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1 || \
+ strcmp(s->sname1.field1, fname)) { \
+ torture_result(tctx,\
+ TORTURE_FAIL,\
+ "(%s) %s/%s [%s] != %s\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1, \
+ fname); \
+ ret = false; \
+ } \
+ }} while (0)
+
+ /* check that all the results are as expected */
+ CHECK_VAL("SEARCH", search, attrib, all_info, all_info, attrib&0xFFF);
+ CHECK_VAL("STANDARD", standard, attrib, all_info, all_info, attrib&0xFFF);
+ CHECK_VAL("EA_SIZE", ea_size, attrib, all_info, all_info, attrib&0xFFF);
+ CHECK_VAL("DIRECTORY_INFO", directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, attrib, all_info, all_info, attrib);
+ CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, attrib, all_info, all_info, attrib);
+
+ CHECK_TIME("SEARCH", search, write_time, all_info, all_info, write_time);
+ CHECK_TIME("STANDARD", standard, write_time, all_info, all_info, write_time);
+ CHECK_TIME("EA_SIZE", ea_size, write_time, all_info, all_info, write_time);
+ CHECK_TIME("STANDARD", standard, create_time, all_info, all_info, create_time);
+ CHECK_TIME("EA_SIZE", ea_size, create_time, all_info, all_info, create_time);
+ CHECK_TIME("STANDARD", standard, access_time, all_info, all_info, access_time);
+ CHECK_TIME("EA_SIZE", ea_size, access_time, all_info, all_info, access_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, write_time, all_info, all_info, write_time);
+ CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, write_time, all_info, all_info, write_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, create_time, all_info, all_info, create_time);
+ CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, create_time, all_info, all_info, create_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, access_time, all_info, all_info, access_time);
+ CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, access_time, all_info, all_info, access_time);
+
+ CHECK_NTTIME("DIRECTORY_INFO", directory_info, change_time, all_info, all_info, change_time);
+ CHECK_NTTIME("FULL_DIRECTORY_INFO", full_directory_info, change_time, all_info, all_info, change_time);
+ CHECK_NTTIME("BOTH_DIRECTORY_INFO", both_directory_info, change_time, all_info, all_info, change_time);
+ CHECK_NTTIME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, change_time, all_info, all_info, change_time);
+ CHECK_NTTIME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, change_time, all_info, all_info, change_time);
+
+ CHECK_VAL("SEARCH", search, size, all_info, all_info, size);
+ CHECK_VAL("STANDARD", standard, size, all_info, all_info, size);
+ CHECK_VAL("EA_SIZE", ea_size, size, all_info, all_info, size);
+ CHECK_VAL("DIRECTORY_INFO", directory_info, size, all_info, all_info, size);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, size, all_info, all_info, size);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, size, all_info, all_info, size);
+ CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, size, all_info, all_info, size);
+ CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, size, all_info, all_info, size);
+ CHECK_VAL("UNIX_INFO", unix_info, size, all_info, all_info, size);
+
+ CHECK_VAL("STANDARD", standard, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("EA_SIZE", ea_size, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("DIRECTORY_INFO", directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, alloc_size, all_info, all_info, alloc_size);
+ CHECK_VAL("UNIX_INFO", unix_info, alloc_size, all_info, all_info, alloc_size);
+
+ CHECK_VAL("EA_SIZE", ea_size, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, ea_size, all_info, all_info, ea_size);
+ CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, ea_size, all_info, all_info, ea_size);
+
+ if (alt_info_supported) {
+ CHECK_STR("SEARCH", search, name, alt_info, alt_name_info,
+ fname);
+ CHECK_WSTR("BOTH_DIRECTORY_INFO", both_directory_info,
+ short_name, alt_info, alt_name_info, fname, STR_UNICODE);
+ }
+
+ CHECK_NAME("STANDARD", standard, name, fname, 0);
+ CHECK_NAME("EA_SIZE", ea_size, name, fname, 0);
+ CHECK_NAME("DIRECTORY_INFO", directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname, STR_TERMINATE_ASCII);
+
+ if (name_info_supported) {
+ CHECK_NAME("NAME_INFO", name_info, name, fname,
+ STR_TERMINATE_ASCII);
+ }
+
+ CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_UNIX_NAME("UNIX_INFO", unix_info, name, fname, STR_TERMINATE_ASCII);
+
+ if (internal_info_supported) {
+ CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info,
+ file_id, internal_info, internal_information, file_id);
+ CHECK_VAL("ID_BOTH_DIRECTORY_INFO", id_both_directory_info,
+ file_id, internal_info, internal_information, file_id);
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_unlink(cli->tree, fname);
+
+ return ret;
+}
+
+
+struct multiple_result {
+ TALLOC_CTX *tctx;
+ int count;
+ union smb_search_data *list;
+};
+
+/*
+ callback function for multiple_search
+*/
+static bool multiple_search_callback(void *private_data, const union smb_search_data *file)
+{
+ struct multiple_result *data = (struct multiple_result *)private_data;
+
+
+ data->count++;
+ data->list = talloc_realloc(data->tctx,
+ data->list,
+ union smb_search_data,
+ data->count);
+
+ data->list[data->count-1] = *file;
+
+ return true;
+}
+
+enum continue_type {CONT_FLAGS, CONT_NAME, CONT_RESUME_KEY};
+
+/*
+ do a single file (non-wildcard) search
+*/
+static NTSTATUS multiple_search(struct smbcli_state *cli,
+ TALLOC_CTX *tctx,
+ const char *pattern,
+ enum smb_search_data_level data_level,
+ enum continue_type cont_type,
+ void *data)
+{
+ union smb_search_first io;
+ union smb_search_next io2;
+ NTSTATUS status;
+ const int per_search = 100;
+ struct multiple_result *result = (struct multiple_result *)data;
+
+ if (data_level == RAW_SEARCH_DATA_SEARCH) {
+ io.search_first.level = RAW_SEARCH_SEARCH;
+ io.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
+ io.search_first.in.max_count = per_search;
+ io.search_first.in.search_attrib = 0;
+ io.search_first.in.pattern = pattern;
+ } else {
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = data_level;
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = per_search;
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = pattern;
+ if (cont_type == CONT_RESUME_KEY) {
+ io.t2ffirst.in.flags |= FLAG_TRANS2_FIND_REQUIRE_RESUME |
+ FLAG_TRANS2_FIND_BACKUP_INTENT;
+ }
+ }
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, data, multiple_search_callback);
+
+
+ while (NT_STATUS_IS_OK(status)) {
+ if (data_level == RAW_SEARCH_DATA_SEARCH) {
+ io2.search_next.level = RAW_SEARCH_SEARCH;
+ io2.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
+ io2.search_next.in.max_count = per_search;
+ io2.search_next.in.search_attrib = 0;
+ io2.search_next.in.id = result->list[result->count-1].search.id;
+ } else {
+ io2.t2fnext.level = RAW_SEARCH_TRANS2;
+ io2.t2fnext.data_level = data_level;
+ io2.t2fnext.in.handle = io.t2ffirst.out.handle;
+ io2.t2fnext.in.max_count = per_search;
+ io2.t2fnext.in.resume_key = 0;
+ io2.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
+ io2.t2fnext.in.last_name = "";
+ switch (cont_type) {
+ case CONT_RESUME_KEY:
+ io2.t2fnext.in.resume_key = extract_resume_key(&result->list[result->count-1],
+ io2.t2fnext.level, io2.t2fnext.data_level);
+ if (io2.t2fnext.in.resume_key == 0) {
+ printf("Server does not support resume by key for level %s\n",
+ level_name(io2.t2fnext.level, io2.t2fnext.data_level));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+ io2.t2fnext.in.flags |= FLAG_TRANS2_FIND_REQUIRE_RESUME |
+ FLAG_TRANS2_FIND_BACKUP_INTENT;
+ break;
+ case CONT_NAME:
+ io2.t2fnext.in.last_name = extract_name(&result->list[result->count-1],
+ io2.t2fnext.level, io2.t2fnext.data_level);
+ break;
+ case CONT_FLAGS:
+ io2.t2fnext.in.flags |= FLAG_TRANS2_FIND_CONTINUE;
+ break;
+ }
+ }
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, data, multiple_search_callback);
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ if (data_level == RAW_SEARCH_DATA_SEARCH) {
+ if (io2.search_next.out.count == 0) {
+ break;
+ }
+ } else if (io2.t2fnext.out.count == 0 ||
+ io2.t2fnext.out.end_of_search) {
+ break;
+ }
+ }
+
+ return status;
+}
+
+#define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status")
+
+#define CHECK_VALUE(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value");
+
+#define CHECK_STRING(v, correct) torture_assert_casestr_equal(tctx, v, correct, "incorrect value");
+
+
+static enum smb_search_data_level compare_data_level;
+
+static int search_compare(union smb_search_data *d1, union smb_search_data *d2)
+{
+ const char *s1, *s2;
+ enum smb_search_level level;
+
+ if (compare_data_level == RAW_SEARCH_DATA_SEARCH) {
+ level = RAW_SEARCH_SEARCH;
+ } else {
+ level = RAW_SEARCH_TRANS2;
+ }
+
+ s1 = extract_name(d1, level, compare_data_level);
+ s2 = extract_name(d2, level, compare_data_level);
+ return strcmp_safe(s1, s2);
+}
+
+
+
+/*
+ basic testing of search calls using many files
+*/
+static bool test_many_files(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const int num_files = 700;
+ int i, fnum, t;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ struct {
+ const char *name;
+ const char *cont_name;
+ enum smb_search_data_level data_level;
+ enum continue_type cont_type;
+ } search_types[] = {
+ {"SEARCH", "ID", RAW_SEARCH_DATA_SEARCH, CONT_RESUME_KEY},
+ {"BOTH_DIRECTORY_INFO", "NAME", RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_NAME},
+ {"BOTH_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_FLAGS},
+ {"BOTH_DIRECTORY_INFO", "KEY", RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_RESUME_KEY},
+ {"STANDARD", "FLAGS", RAW_SEARCH_DATA_STANDARD, CONT_FLAGS},
+ {"STANDARD", "KEY", RAW_SEARCH_DATA_STANDARD, CONT_RESUME_KEY},
+ {"STANDARD", "NAME", RAW_SEARCH_DATA_STANDARD, CONT_NAME},
+ {"EA_SIZE", "FLAGS", RAW_SEARCH_DATA_EA_SIZE, CONT_FLAGS},
+ {"EA_SIZE", "KEY", RAW_SEARCH_DATA_EA_SIZE, CONT_RESUME_KEY},
+ {"EA_SIZE", "NAME", RAW_SEARCH_DATA_EA_SIZE, CONT_NAME},
+ {"DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_FLAGS},
+ {"DIRECTORY_INFO", "KEY", RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_RESUME_KEY},
+ {"DIRECTORY_INFO", "NAME", RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_NAME},
+ {"FULL_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_FLAGS},
+ {"FULL_DIRECTORY_INFO", "KEY", RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_RESUME_KEY},
+ {"FULL_DIRECTORY_INFO", "NAME", RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_NAME},
+ {"ID_FULL_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_FLAGS},
+ {"ID_FULL_DIRECTORY_INFO", "KEY", RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESUME_KEY},
+ {"ID_FULL_DIRECTORY_INFO", "NAME", RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_NAME},
+ {"ID_BOTH_DIRECTORY_INFO", "NAME", RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_NAME},
+ {"ID_BOTH_DIRECTORY_INFO", "FLAGS", RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_FLAGS},
+ {"ID_BOTH_DIRECTORY_INFO", "KEY", RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESUME_KEY}
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Testing with %d files\n", num_files);
+
+ for (i=0;i<num_files;i++) {
+ fname = talloc_asprintf(cli, BASEDIR "\\t%03d-%d.txt", i, i);
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ torture_assert(tctx, fnum != -1, "Failed to create");
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+
+
+ for (t=0;t<ARRAY_SIZE(search_types);t++) {
+ ZERO_STRUCT(result);
+
+ if ((search_types[t].cont_type == CONT_RESUME_KEY) &&
+ (search_types[t].data_level != RAW_SEARCH_DATA_SEARCH) &&
+ !torture_setting_bool(tctx, "resume_key_support", true)) {
+ torture_comment(tctx,
+ "SKIP: Continue %s via %s\n",
+ search_types[t].name, search_types[t].cont_name);
+ continue;
+ }
+
+ result.tctx = talloc_new(tctx);
+
+ torture_comment(tctx,
+ "Continue %s via %s\n", search_types[t].name, search_types[t].cont_name);
+
+ status = multiple_search(cli, tctx, BASEDIR "\\*.*",
+ search_types[t].data_level,
+ search_types[t].cont_type,
+ &result);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ torture_warning(tctx, "search level %s not supported "
+ "by server",
+ search_types[t].name);
+ continue;
+ }
+ torture_assert_ntstatus_ok(tctx, status, "search failed");
+ CHECK_VALUE(result.count, num_files);
+
+ compare_data_level = search_types[t].data_level;
+
+ TYPESAFE_QSORT(result.list, result.count, search_compare);
+
+ for (i=0;i<result.count;i++) {
+ const char *s;
+ enum smb_search_level level;
+ if (compare_data_level == RAW_SEARCH_DATA_SEARCH) {
+ level = RAW_SEARCH_SEARCH;
+ } else {
+ level = RAW_SEARCH_TRANS2;
+ }
+ s = extract_name(&result.list[i], level, compare_data_level);
+ fname = talloc_asprintf(cli, "t%03d-%d.txt", i, i);
+ torture_assert_str_equal(tctx, fname, s, "Incorrect name");
+ talloc_free(fname);
+ }
+ talloc_free(result.tctx);
+ }
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ check a individual file result
+*/
+static bool check_result(struct multiple_result *result, const char *name, bool exist, uint32_t attrib)
+{
+ int i;
+ for (i=0;i<result->count;i++) {
+ if (strcmp(name, result->list[i].both_directory_info.name.s) == 0) break;
+ }
+ if (i == result->count) {
+ if (exist) {
+ printf("failed: '%s' should exist with attribute %s\n",
+ name, attrib_string(result->list, attrib));
+ return false;
+ }
+ return true;
+ }
+
+ if (!exist) {
+ printf("failed: '%s' should NOT exist (has attribute %s)\n",
+ name, attrib_string(result->list, result->list[i].both_directory_info.attrib));
+ return false;
+ }
+
+ if ((result->list[i].both_directory_info.attrib&0xFFF) != attrib) {
+ printf("failed: '%s' should have attribute 0x%x (has 0x%x)\n",
+ name,
+ attrib, result->list[i].both_directory_info.attrib);
+ return false;
+ }
+ return true;
+}
+
+/*
+ test what happens when the directory is modified during a search
+*/
+static bool test_modify_search(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const int num_files = 20;
+ int i, fnum;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ union smb_search_first io;
+ union smb_search_next io2;
+ union smb_setfileinfo sfinfo;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Creating %d files\n", num_files);
+
+ for (i=num_files-1;i>=0;i--) {
+ fname = talloc_asprintf(cli, BASEDIR "\\t%03d-%d.txt", i, i);
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+
+ printf("pulling the first file\n");
+ ZERO_STRUCT(result);
+ result.tctx = talloc_new(tctx);
+
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = 0;
+ io.t2ffirst.in.flags = 0;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = BASEDIR "\\*.*";
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, 1);
+
+ printf("pulling the second file\n");
+ io2.t2fnext.level = RAW_SEARCH_TRANS2;
+ io2.t2fnext.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
+ io2.t2fnext.in.handle = io.t2ffirst.out.handle;
+ io2.t2fnext.in.max_count = 1;
+ io2.t2fnext.in.resume_key = 0;
+ io2.t2fnext.in.flags = 0;
+ io2.t2fnext.in.last_name = result.list[result.count-1].both_directory_info.name.s;
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, 2);
+
+ result.count = 0;
+
+ printf("Changing attributes and deleting\n");
+ smbcli_open(cli->tree, BASEDIR "\\T003-03.txt.2", O_CREAT|O_RDWR, DENY_NONE);
+ smbcli_open(cli->tree, BASEDIR "\\T013-13.txt.2", O_CREAT|O_RDWR, DENY_NONE);
+ fnum = create_complex_file(cli, tctx, BASEDIR "\\T013-13.txt.3");
+ smbcli_unlink(cli->tree, BASEDIR "\\T014-14.txt");
+ torture_set_file_attribute(cli->tree, BASEDIR "\\T015-15.txt", FILE_ATTRIBUTE_HIDDEN);
+ torture_set_file_attribute(cli->tree, BASEDIR "\\T016-16.txt", FILE_ATTRIBUTE_NORMAL);
+ torture_set_file_attribute(cli->tree, BASEDIR "\\T017-17.txt", FILE_ATTRIBUTE_SYSTEM);
+ torture_set_file_attribute(cli->tree, BASEDIR "\\T018-18.txt", 0);
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io2.t2fnext.level = RAW_SEARCH_TRANS2;
+ io2.t2fnext.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
+ io2.t2fnext.in.handle = io.t2ffirst.out.handle;
+ io2.t2fnext.in.max_count = num_files + 3;
+ io2.t2fnext.in.resume_key = 0;
+ io2.t2fnext.in.flags = 0;
+ io2.t2fnext.in.last_name = ".";
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, 20);
+
+ ret &= check_result(&result, "t009-9.txt", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(&result, "t014-14.txt", false, 0);
+ ret &= check_result(&result, "t015-15.txt", false, 0);
+ ret &= check_result(&result, "t016-16.txt", true, FILE_ATTRIBUTE_NORMAL);
+ ret &= check_result(&result, "t017-17.txt", false, 0);
+ ret &= check_result(&result, "t018-18.txt", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(&result, "t019-19.txt", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(&result, "T013-13.txt.2", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(&result, "T003-3.txt.2", false, 0);
+ ret &= check_result(&result, "T013-13.txt.3", true, FILE_ATTRIBUTE_ARCHIVE);
+
+ if (!ret) {
+ for (i=0;i<result.count;i++) {
+ printf("%s %s (0x%x)\n",
+ result.list[i].both_directory_info.name.s,
+ attrib_string(tctx, result.list[i].both_directory_info.attrib),
+ result.list[i].both_directory_info.attrib);
+ }
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ testing if directories always come back sorted
+*/
+static bool test_sorted(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ const int num_files = 700;
+ int i, fnum;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Creating %d files\n", num_files);
+
+ for (i=0;i<num_files;i++) {
+ fname = talloc_asprintf(cli, BASEDIR "\\%s.txt", generate_random_str_list(tctx, 10, "abcdefgh"));
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+
+
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+
+ status = multiple_search(cli, tctx, BASEDIR "\\*.*",
+ RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
+ CONT_NAME, &result);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, num_files);
+
+ for (i=0;i<num_files-1;i++) {
+ const char *name1, *name2;
+ name1 = result.list[i].both_directory_info.name.s;
+ name2 = result.list[i+1].both_directory_info.name.s;
+ if (strcasecmp_m(name1, name2) > 0) {
+ printf("non-alphabetical order at entry %d '%s' '%s'\n",
+ i, name1, name2);
+ printf("Server does not produce sorted directory listings (not an error)\n");
+ goto done;
+ }
+ }
+
+ talloc_free(result.list);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+
+/*
+ basic testing of many old style search calls using separate dirs
+*/
+static bool test_many_dirs(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const int num_dirs = 20;
+ int i, fnum, n;
+ char *fname, *dname;
+ bool ret = true;
+ NTSTATUS status;
+ union smb_search_data *file, *file2, *file3;
+
+ if (!torture_setting_bool(tctx, "raw_search_search", true)) {
+ torture_comment(tctx, "Skipping these tests as the server "
+ "doesn't support old style search calls\n");
+ return true;
+ }
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Creating %d dirs\n", num_dirs);
+
+ for (i=0;i<num_dirs;i++) {
+ dname = talloc_asprintf(cli, BASEDIR "\\d%d", i);
+ status = smbcli_mkdir(cli->tree, dname);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("(%s) Failed to create %s - %s\n",
+ __location__, dname, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ for (n=0;n<3;n++) {
+ fname = talloc_asprintf(cli, BASEDIR "\\d%d\\f%d-%d.txt", i, i, n);
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ if (fnum == -1) {
+ printf("(%s) Failed to create %s - %s\n",
+ __location__, fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+
+ talloc_free(dname);
+ }
+
+ file = talloc_zero_array(tctx, union smb_search_data, num_dirs);
+ file2 = talloc_zero_array(tctx, union smb_search_data, num_dirs);
+ file3 = talloc_zero_array(tctx, union smb_search_data, num_dirs);
+
+ printf("Search first on %d dirs\n", num_dirs);
+
+ for (i=0;i<num_dirs;i++) {
+ union smb_search_first io;
+ io.search_first.level = RAW_SEARCH_SEARCH;
+ io.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
+ io.search_first.in.max_count = 1;
+ io.search_first.in.search_attrib = 0;
+ io.search_first.in.pattern = talloc_asprintf(tctx, BASEDIR "\\d%d\\*.txt", i);
+ fname = talloc_asprintf(tctx, "f%d-", i);
+
+ io.search_first.out.count = 0;
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, (void *)&file[i], single_search_callback);
+ if (io.search_first.out.count != 1) {
+ printf("(%s) search first gave %d entries for dir %d - %s\n",
+ __location__, io.search_first.out.count, i, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (strncasecmp(file[i].search.name, fname, strlen(fname)) != 0) {
+ printf("(%s) incorrect name '%s' expected '%s'[12].txt\n",
+ __location__, file[i].search.name, fname);
+ ret = false;
+ goto done;
+ }
+
+ talloc_free(fname);
+ }
+
+ printf("Search next on %d dirs\n", num_dirs);
+
+ for (i=0;i<num_dirs;i++) {
+ union smb_search_next io2;
+
+ io2.search_next.level = RAW_SEARCH_SEARCH;
+ io2.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
+ io2.search_next.in.max_count = 1;
+ io2.search_next.in.search_attrib = 0;
+ io2.search_next.in.id = file[i].search.id;
+ fname = talloc_asprintf(tctx, "f%d-", i);
+
+ io2.search_next.out.count = 0;
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, (void *)&file2[i], single_search_callback);
+ if (io2.search_next.out.count != 1) {
+ printf("(%s) search next gave %d entries for dir %d - %s\n",
+ __location__, io2.search_next.out.count, i, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (strncasecmp(file2[i].search.name, fname, strlen(fname)) != 0) {
+ printf("(%s) incorrect name '%s' expected '%s'[12].txt\n",
+ __location__, file2[i].search.name, fname);
+ ret = false;
+ goto done;
+ }
+
+ talloc_free(fname);
+ }
+
+
+ printf("Search next (rewind) on %d dirs\n", num_dirs);
+
+ for (i=0;i<num_dirs;i++) {
+ union smb_search_next io2;
+
+ io2.search_next.level = RAW_SEARCH_SEARCH;
+ io2.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
+ io2.search_next.in.max_count = 1;
+ io2.search_next.in.search_attrib = 0;
+ io2.search_next.in.id = file[i].search.id;
+ fname = talloc_asprintf(tctx, "f%d-", i);
+ io2.search_next.out.count = 0;
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, (void *)&file3[i], single_search_callback);
+ if (io2.search_next.out.count != 1) {
+ printf("(%s) search next gave %d entries for dir %d - %s\n",
+ __location__, io2.search_next.out.count, i, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (strncasecmp(file3[i].search.name, file2[i].search.name, 3) != 0) {
+ printf("(%s) incorrect name '%s' on rewind at dir %d\n",
+ __location__, file2[i].search.name, i);
+ ret = false;
+ goto done;
+ }
+
+ if (torture_setting_bool(tctx, "rewind_support", true) &&
+ strcmp(file3[i].search.name, file2[i].search.name) != 0) {
+ printf("(%s) server did not rewind - got '%s' expected '%s'\n",
+ __location__, file3[i].search.name, file2[i].search.name);
+ ret = false;
+ goto done;
+ }
+
+ talloc_free(fname);
+ }
+
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+/*
+ testing of OS/2 style delete
+*/
+static bool test_os2_delete(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const int num_files = 700;
+ const int delete_count = 4;
+ int total_deleted = 0;
+ int i, fnum;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ union smb_search_first io;
+ union smb_search_next io2;
+ struct multiple_result result;
+
+ if (!torture_setting_bool(tctx, "search_ea_size", true)){
+ torture_comment(tctx,
+ "Server does not support RAW_SEARCH_EA_SIZE "
+ "level. Skipping this test\n");
+ return true;
+ }
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing OS/2 style delete on %d files\n", num_files);
+
+ for (i=0;i<num_files;i++) {
+ fname = talloc_asprintf(cli, BASEDIR "\\file%u.txt", i);
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+
+
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = RAW_SEARCH_DATA_EA_SIZE;
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = 100;
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = BASEDIR "\\*";
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ for (i=0;i<MIN(result.count, delete_count);i++) {
+ fname = talloc_asprintf(cli, BASEDIR "\\%s", result.list[i].ea_size.name.s);
+ status = smbcli_unlink(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ total_deleted++;
+ talloc_free(fname);
+ }
+
+ io2.t2fnext.level = RAW_SEARCH_TRANS2;
+ io2.t2fnext.data_level = RAW_SEARCH_DATA_EA_SIZE;
+ io2.t2fnext.in.handle = io.t2ffirst.out.handle;
+ io2.t2fnext.in.max_count = 100;
+ io2.t2fnext.in.resume_key = result.list[i-1].ea_size.resume_key;
+ io2.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME;
+ io2.t2fnext.in.last_name = result.list[i-1].ea_size.name.s;
+
+ do {
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, &result, multiple_search_callback);
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ for (i=0;i<MIN(result.count, delete_count);i++) {
+ fname = talloc_asprintf(cli, BASEDIR "\\%s", result.list[i].ea_size.name.s);
+ status = smbcli_unlink(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ total_deleted++;
+ talloc_free(fname);
+ }
+
+ if (i>0) {
+ io2.t2fnext.in.resume_key = result.list[i-1].ea_size.resume_key;
+ io2.t2fnext.in.last_name = result.list[i-1].ea_size.name.s;
+ }
+ } while (NT_STATUS_IS_OK(status) && result.count != 0);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (total_deleted != num_files) {
+ printf("error: deleted %d - expected to delete %d\n",
+ total_deleted, num_files);
+ ret = false;
+ }
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+
+static int ealist_cmp(union smb_search_data *r1, union smb_search_data *r2)
+{
+ return strcmp(r1->ea_list.name.s, r2->ea_list.name.s);
+}
+
+/*
+ testing of the rather strange ea_list level
+*/
+static bool test_ea_list(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ int fnum;
+ bool ret = true;
+ NTSTATUS status;
+ union smb_search_first io;
+ union smb_search_next nxt;
+ struct multiple_result result;
+ union smb_setfileinfo setfile;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Testing RAW_SEARCH_EA_LIST level\n");
+
+ if (!torture_setting_bool(tctx, "search_ea_support", true) ||
+ !torture_setting_bool(tctx, "ea_support", true)) {
+ printf("..skipped per target configuration.\n");
+ return true;
+ }
+
+ fnum = smbcli_open(cli->tree, BASEDIR "\\file1.txt", O_CREAT|O_RDWR, DENY_NONE);
+ smbcli_close(cli->tree, fnum);
+
+ fnum = smbcli_open(cli->tree, BASEDIR "\\file2.txt", O_CREAT|O_RDWR, DENY_NONE);
+ smbcli_close(cli->tree, fnum);
+
+ fnum = smbcli_open(cli->tree, BASEDIR "\\file3.txt", O_CREAT|O_RDWR, DENY_NONE);
+ smbcli_close(cli->tree, fnum);
+
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.path = BASEDIR "\\file2.txt";
+ setfile.ea_set.in.num_eas = 2;
+ setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "EA ONE";
+ setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE 1");
+ setfile.ea_set.in.eas[1].flags = 0;
+ setfile.ea_set.in.eas[1].name.s = "SECOND EA";
+ setfile.ea_set.in.eas[1].value = data_blob_string_const("Value Two");
+
+ status = smb_raw_setpathinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ setfile.generic.in.file.path = BASEDIR "\\file3.txt";
+ status = smb_raw_setpathinfo(cli->tree, &setfile);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = RAW_SEARCH_DATA_EA_LIST;
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = 2;
+ io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = BASEDIR "\\*";
+ io.t2ffirst.in.num_names = 2;
+ io.t2ffirst.in.ea_names = talloc_array(tctx, struct ea_name, 2);
+ io.t2ffirst.in.ea_names[0].name.s = "SECOND EA";
+ io.t2ffirst.in.ea_names[1].name.s = "THIRD EA";
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, 2);
+
+ nxt.t2fnext.level = RAW_SEARCH_TRANS2;
+ nxt.t2fnext.data_level = RAW_SEARCH_DATA_EA_LIST;
+ nxt.t2fnext.in.handle = io.t2ffirst.out.handle;
+ nxt.t2fnext.in.max_count = 2;
+ nxt.t2fnext.in.resume_key = result.list[1].ea_list.resume_key;
+ nxt.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME | FLAG_TRANS2_FIND_CONTINUE;
+ nxt.t2fnext.in.last_name = result.list[1].ea_list.name.s;
+ nxt.t2fnext.in.num_names = 2;
+ nxt.t2fnext.in.ea_names = talloc_array(tctx, struct ea_name, 2);
+ nxt.t2fnext.in.ea_names[0].name.s = "SECOND EA";
+ nxt.t2fnext.in.ea_names[1].name.s = "THIRD EA";
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &nxt, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* we have to sort the result as different servers can return directories
+ in different orders */
+ TYPESAFE_QSORT(result.list, result.count, ealist_cmp);
+
+ CHECK_VALUE(result.count, 3);
+ CHECK_VALUE(result.list[0].ea_list.eas.num_eas, 2);
+ CHECK_STRING(result.list[0].ea_list.name.s, "file1.txt");
+ CHECK_STRING(result.list[0].ea_list.eas.eas[0].name.s, "SECOND EA");
+ CHECK_VALUE(result.list[0].ea_list.eas.eas[0].value.length, 0);
+ CHECK_STRING(result.list[0].ea_list.eas.eas[1].name.s, "THIRD EA");
+ CHECK_VALUE(result.list[0].ea_list.eas.eas[1].value.length, 0);
+
+ CHECK_STRING(result.list[1].ea_list.name.s, "file2.txt");
+ CHECK_STRING(result.list[1].ea_list.eas.eas[0].name.s, "SECOND EA");
+ CHECK_VALUE(result.list[1].ea_list.eas.eas[0].value.length, 9);
+ CHECK_STRING((const char *)result.list[1].ea_list.eas.eas[0].value.data, "Value Two");
+ CHECK_STRING(result.list[1].ea_list.eas.eas[1].name.s, "THIRD EA");
+ CHECK_VALUE(result.list[1].ea_list.eas.eas[1].value.length, 0);
+
+ CHECK_STRING(result.list[2].ea_list.name.s, "file3.txt");
+ CHECK_STRING(result.list[2].ea_list.eas.eas[0].name.s, "SECOND EA");
+ CHECK_VALUE(result.list[2].ea_list.eas.eas[0].value.length, 9);
+ CHECK_STRING((const char *)result.list[2].ea_list.eas.eas[0].value.data, "Value Two");
+ CHECK_STRING(result.list[2].ea_list.eas.eas[1].name.s, "THIRD EA");
+ CHECK_VALUE(result.list[2].ea_list.eas.eas[1].value.length, 0);
+
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ Test the behavior of max count parameter in TRANS2_FIND_FIRST2 and
+ TRANS2_FIND_NEXT2 queries
+*/
+static bool test_max_count(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const int num_files = 2;
+ int i, fnum;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ union smb_search_first io;
+ union smb_search_next io2;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "Creating %d files\n", num_files);
+
+ for (i=num_files-1;i>=0;i--) {
+ fname = talloc_asprintf(cli, BASEDIR "\\t%03d-%d.txt", i, i);
+ fnum = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
+ if (fnum == -1) {
+ torture_comment(tctx,
+ "Failed to create %s - %s\n",
+ fname, smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ talloc_free(fname);
+ smbcli_close(cli->tree, fnum);
+ }
+
+ torture_comment(tctx, "Set max_count parameter to 0. "
+ "This should return 1 entry\n");
+ ZERO_STRUCT(result);
+ result.tctx = talloc_new(tctx);
+
+ io.t2ffirst.level = RAW_SEARCH_TRANS2;
+ io.t2ffirst.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
+ io.t2ffirst.in.search_attrib = 0;
+ io.t2ffirst.in.max_count = 0;
+ io.t2ffirst.in.flags = 0;
+ io.t2ffirst.in.storage_type = 0;
+ io.t2ffirst.in.pattern = BASEDIR "\\*.*";
+
+ status = smb_raw_search_first(cli->tree, tctx,
+ &io, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, 1);
+
+ torture_comment(tctx, "Set max_count to 1. This should also "
+ "return 1 entry\n");
+ io2.t2fnext.level = RAW_SEARCH_TRANS2;
+ io2.t2fnext.data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
+ io2.t2fnext.in.handle = io.t2ffirst.out.handle;
+ io2.t2fnext.in.max_count = 1;
+ io2.t2fnext.in.resume_key = 0;
+ io2.t2fnext.in.flags = 0;
+ io2.t2fnext.in.last_name =
+ result.list[result.count-1].both_directory_info.name.s;
+
+ status = smb_raw_search_next(cli->tree, tctx,
+ &io2, &result, multiple_search_callback);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(result.count, 2);
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+
+ return ret;
+}
+
+/*
+ basic testing of all RAW_SEARCH_* calls using a single file
+*/
+struct torture_suite *torture_raw_search(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "search");
+
+ torture_suite_add_2smb_test(suite, "one file search", test_one_file);
+ torture_suite_add_1smb_test(suite, "many files", test_many_files);
+ torture_suite_add_1smb_test(suite, "sorted", test_sorted);
+ torture_suite_add_1smb_test(suite, "modify search", test_modify_search);
+ torture_suite_add_1smb_test(suite, "many dirs", test_many_dirs);
+ torture_suite_add_1smb_test(suite, "os2 delete", test_os2_delete);
+ torture_suite_add_1smb_test(suite, "ea list", test_ea_list);
+ torture_suite_add_1smb_test(suite, "max count", test_max_count);
+
+ return suite;
+}
diff --git a/source4/torture/raw/seek.c b/source4/torture/raw/seek.c
new file mode 100644
index 0000000..6bac828
--- /dev/null
+++ b/source4/torture/raw/seek.c
@@ -0,0 +1,242 @@
+/*
+ Unix SMB/CIFS implementation.
+ seek test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%d) Incorrect status %s - should be %s\n", \
+ __LINE__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ if ((v) != (correct)) { \
+ printf("(%d) Incorrect value %s=%d - should be %d\n", \
+ __LINE__, #v, (int)v, (int)correct); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define BASEDIR "\\testseek"
+
+/*
+ test seek ops
+*/
+static bool test_seek(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+ union smb_seek io;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum, fnum2;
+ const char *fname = BASEDIR "\\test.txt";
+ uint8_t c[2];
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ return false;
+ }
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ printf("Failed to open test.txt - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum;
+
+ printf("Trying bad handle\n");
+ io.lseek.in.file.fnum = fnum+1;
+ io.lseek.in.mode = SEEK_MODE_START;
+ io.lseek.in.offset = 0;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ printf("Trying simple seek\n");
+ io.lseek.in.file.fnum = fnum;
+ io.lseek.in.mode = SEEK_MODE_START;
+ io.lseek.in.offset = 17;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, 17);
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 0);
+
+ printf("Trying relative seek\n");
+ io.lseek.in.file.fnum = fnum;
+ io.lseek.in.mode = SEEK_MODE_CURRENT;
+ io.lseek.in.offset = -3;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, 14);
+
+ printf("Trying end seek\n");
+ io.lseek.in.file.fnum = fnum;
+ io.lseek.in.mode = SEEK_MODE_END;
+ io.lseek.in.offset = 0;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.all_info.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, finfo.all_info.out.size);
+
+ printf("Trying max seek\n");
+ io.lseek.in.file.fnum = fnum;
+ io.lseek.in.mode = SEEK_MODE_START;
+ io.lseek.in.offset = -1;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, 0xffffffff);
+
+ printf("Testing position information change\n");
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 0);
+
+ printf("Trying max overflow\n");
+ io.lseek.in.file.fnum = fnum;
+ io.lseek.in.mode = SEEK_MODE_CURRENT;
+ io.lseek.in.offset = 1000;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, 999);
+
+ printf("Testing position information change\n");
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 0);
+
+ printf("trying write to update offset\n");
+ ZERO_STRUCT(c);
+ if (smbcli_write(cli->tree, fnum, 0, c, 0, 2) != 2) {
+ printf("Write failed - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Testing position information change\n");
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 0);
+
+ io.lseek.in.file.fnum = fnum;
+ io.lseek.in.mode = SEEK_MODE_CURRENT;
+ io.lseek.in.offset = 0;
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, 2);
+
+ if (smbcli_read(cli->tree, fnum, c, 0, 1) != 1) {
+ printf("Read failed - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+
+ printf("Testing position information change\n");
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 1);
+
+ status = smb_raw_seek(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.lseek.out.offset, 1);
+
+ printf("Testing position information\n");
+ fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ if (fnum2 == -1) {
+ printf("2nd open failed - %s\n", smbcli_errstr(cli->tree));
+ ret = false;
+ goto done;
+ }
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.position_information.in.file.fnum = fnum2;
+ sfinfo.position_information.in.position = 25;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum2;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 25);
+
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 1);
+
+ printf("position_information via paths\n");
+
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.position_information.in.file.path = fname;
+ sfinfo.position_information.in.position = 32;
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.fnum = fnum2;
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 25);
+
+ finfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ finfo.position_information.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(finfo.position_information.out.position, 0);
+
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ basic testing of seek calls
+*/
+bool torture_raw_seek(struct torture_context *torture, struct smbcli_state *cli)
+{
+ bool ret = true;
+
+ ret &= test_seek(cli, torture);
+
+ return ret;
+}
diff --git a/source4/torture/raw/session.c b/source4/torture/raw/session.c
new file mode 100644
index 0000000..76ae808
--- /dev/null
+++ b/source4/torture/raw/session.c
@@ -0,0 +1,446 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for session setup operations
+ Copyright (C) Gregor Beck 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture.h"
+#include "libcli/libcli.h"
+#include "torture/raw/proto.h"
+#include "smb_composite/smb_composite.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+#include "torture/util.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/resolve/resolve.h"
+
+
+static bool test_session_reauth1(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ struct smb_composite_sesssetup io;
+ int fnum, num;
+ const int dlen = 255;
+ char *data;
+ char fname[256];
+ char buf[dlen+1];
+ bool ok = true;
+ uint16_t vuid1 = cli->session->vuid;
+
+ data = generate_random_str(tctx, dlen);
+ torture_assert(tctx, (data != NULL), "memory allocation failed");
+ snprintf(fname, sizeof(fname), "raw_session_reconnect_%.8s.dat", data);
+
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OPEN_IF,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE,
+ 0);
+ torture_assert_ntstatus_ok_goto(tctx, smbcli_nt_error(cli->tree), ok,
+ done, "create file");
+ torture_assert_goto(tctx, fnum > 0, ok, done, "create file");
+
+ num = smbcli_smbwrite(cli->tree, fnum, data, 0, dlen);
+ torture_assert_int_equal_goto(tctx, num, dlen, ok, done, "write file");
+
+ ZERO_STRUCT(io);
+ io.in.sesskey = cli->transport->negotiate.sesskey;
+ io.in.capabilities = cli->transport->negotiate.capabilities;
+ io.in.credentials = samba_cmdline_get_creds();
+ io.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ io.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx);
+ status = smb_composite_sesssetup(cli->session, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "setup2");
+ torture_assert_int_equal_goto(tctx, io.out.vuid, vuid1, ok, done, "setup2");
+
+ buf[dlen] = '\0';
+
+ num = smbcli_read(cli->tree, fnum, &buf, 0, dlen);
+ torture_assert_int_equal_goto(tctx, num, dlen, ok, done, "read file");
+ torture_assert_str_equal_goto(tctx, buf, data, ok, done, "read file");
+
+done:
+ talloc_free(data);
+
+ if (fnum > 0) {
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_ok(tctx, status, "close");
+ }
+ return ok;
+}
+
+static bool test_session_reauth2_oplock_timeout(
+ struct smbcli_transport *transport, uint16_t tid, uint16_t fnum,
+ uint8_t level, void *private_data)
+{
+ return true;
+}
+
+static bool test_session_reauth2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ char *random_string;
+ char *fname;
+ union smb_open io_open;
+ struct smb_composite_sesssetup io_sesssetup;
+ union smb_fileinfo io_qsecdesc;
+ struct smbcli_request *req;
+ struct cli_credentials *anon_creds;
+ NTSTATUS status;
+ uint16_t fnum;
+ ssize_t nwritten;
+ uint16_t vuid1 = cli->session->vuid;
+
+ random_string = generate_random_str(tctx, 8);
+ torture_assert(tctx, (random_string != NULL),
+ "memory allocation failed");
+ fname = talloc_asprintf(tctx, "raw_session_reauth2_%s.dat",
+ random_string);
+ talloc_free(random_string);
+ torture_assert(tctx, (fname != NULL), "memory allocation failed");
+
+ smbcli_unlink(cli->tree, fname);
+ smbcli_oplock_handler(cli->transport,
+ test_session_reauth2_oplock_timeout,
+ cli->tree);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io_open);
+ io_open.generic.level = RAW_OPEN_NTCREATEX;
+ io_open.ntcreatex.in.root_fid.fnum = 0;
+ io_open.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
+ io_open.ntcreatex.in.alloc_size = 0;
+ io_open.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io_open.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io_open.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io_open.ntcreatex.in.create_options = 0;
+ io_open.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io_open.ntcreatex.in.security_flags = 0;
+ io_open.ntcreatex.in.fname = fname;
+
+ torture_comment(tctx, "open with batch oplock\n");
+ io_open.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli->tree, tctx, &io_open);
+ torture_assert_ntstatus_ok(tctx, status, "smb_raw_open failed");
+
+ fnum = io_open.ntcreatex.out.file.fnum;
+ torture_assert(
+ tctx,
+ (io_open.ntcreatex.out.oplock_level == BATCH_OPLOCK_RETURN),
+ "did not get batch oplock");
+
+ io_open.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+ req = smb_raw_open_send(cli->tree, &io_open);
+ torture_assert(tctx, (req != NULL), "memory allocation failed");
+
+ /*
+ * Make sure the open went through
+ */
+ status = smbcli_chkpath(cli->tree, "\\");
+ torture_assert_ntstatus_ok(tctx, status, "smb_chkpath failed");
+
+ status = smbcli_nt_delete_on_close(cli->tree, fnum, true);
+ torture_assert_ntstatus_ok(tctx, status, "could not set delete on "
+ "close");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, (anon_creds != NULL), "memory allocation failed");
+
+ ZERO_STRUCT(io_sesssetup);
+ io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey;
+ io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities;
+ io_sesssetup.in.credentials = anon_creds;
+ io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ io_sesssetup.in.gensec_settings = lpcfg_gensec_settings(
+ tctx, tctx->lp_ctx);
+ status = smb_composite_sesssetup(cli->session, &io_sesssetup);
+ torture_assert_ntstatus_ok(tctx, status, "setup2 failed");
+ torture_assert_int_equal(tctx, io_sesssetup.out.vuid, vuid1, "setup2");
+
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_ok(tctx, status, "close failed");
+
+ status = smb_raw_open_recv(req, tctx, &io_open);
+ torture_assert_ntstatus_ok(tctx, status, "2nd open failed");
+
+ fnum = io_open.ntcreatex.out.file.fnum;
+
+ nwritten = smbcli_write(cli->tree, fnum, 0, fname, 0, strlen(fname));
+ torture_assert(tctx, (nwritten == strlen(fname)),
+ "smbcli_write failed");
+
+ ZERO_STRUCT(io_qsecdesc);
+ io_qsecdesc.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ io_qsecdesc.query_secdesc.in.file.fnum = fnum;
+ io_qsecdesc.query_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ status = smb_raw_fileinfo(cli->tree, tctx, &io_qsecdesc);
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_ACCESS_DENIED,
+ "anon qsecdesc did not return ACCESS_DENIED");
+
+ ZERO_STRUCT(io_sesssetup);
+ io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey;
+ io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities;
+ io_sesssetup.in.credentials = samba_cmdline_get_creds();
+ io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ io_sesssetup.in.gensec_settings = lpcfg_gensec_settings(
+ tctx, tctx->lp_ctx);
+ status = smb_composite_sesssetup(cli->session, &io_sesssetup);
+ torture_assert_ntstatus_ok(tctx, status, "setup3 failed");
+ torture_assert_int_equal(tctx, io_sesssetup.out.vuid, vuid1, "setup2");
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &io_qsecdesc);
+ torture_assert_ntstatus_ok(tctx, status, "2nd qsecdesc failed");
+
+ status = smbcli_nt_delete_on_close(cli->tree, fnum, true);
+ torture_assert_ntstatus_ok(tctx, status, "could not set delete on "
+ "close");
+
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_ok(tctx, status, "close failed");
+
+ return true;
+}
+
+static bool test_session_expire1(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct smbcli_state *cli = NULL;
+ enum credentials_use_kerberos use_kerberos;
+ char fname[256];
+ union smb_fileinfo qfinfo;
+ uint16_t vuid;
+ uint16_t fnum = 0;
+ struct smb_composite_sesssetup io_sesssetup;
+ size_t i;
+
+ use_kerberos = cli_credentials_get_kerberos_state(
+ samba_cmdline_get_creds());
+ if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) {
+ torture_warning(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ torture_skip(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ }
+
+ torture_assert_int_equal(tctx,
+ use_kerberos,
+ CRED_USE_KERBEROS_REQUIRED,
+ "please use --use-kerberos=required");
+
+ lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=4");
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(tctx, &cli,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share, NULL,
+ lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smbcli_full_connection failed");
+
+ vuid = cli->session->vuid;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, 256, "session_expire1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smbcli_unlink(cli->tree, fname);
+
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE,
+ NTCREATEX_DISP_OPEN_IF,
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE,
+ 0);
+ torture_assert_ntstatus_ok_goto(tctx, smbcli_nt_error(cli->tree), ret,
+ done, "create file");
+ torture_assert_goto(tctx, fnum > 0, ret, done, "create file");
+
+ /* get the access information */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ qfinfo.access_information.in.file.fnum = fnum;
+
+ for (i=0; i < 2; i++) {
+ torture_comment(tctx, "query info => OK\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "raw_fileinfo failed");
+
+ torture_comment(tctx, "sleep 10 seconds\n");
+ smb_msleep(10*1000);
+ }
+
+ /*
+ * the krb5 library may not handle expired creds
+ * well, lets start with an empty ccache.
+ */
+ cli_credentials_invalidate_ccache(samba_cmdline_get_creds(),
+ CRED_SPECIFIED);
+
+ /*
+ * now with CAP_DYNAMIC_REAUTH
+ *
+ * This should trigger NT_STATUS_NETWORK_SESSION_EXPIRED
+ */
+ ZERO_STRUCT(io_sesssetup);
+ io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey;
+ io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities;
+ io_sesssetup.in.capabilities |= CAP_DYNAMIC_REAUTH;
+ io_sesssetup.in.credentials = samba_cmdline_get_creds();
+ io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ io_sesssetup.in.gensec_settings = lpcfg_gensec_settings(tctx,
+ tctx->lp_ctx);
+
+ torture_comment(tctx, "reauth with CAP_DYNAMIC_REAUTH => OK\n");
+ ZERO_STRUCT(io_sesssetup.out);
+ status = smb_composite_sesssetup(cli->session, &io_sesssetup);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "reauth failed");
+ torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid,
+ ret, done, "reauth");
+
+ for (i=0; i < 2; i++) {
+ torture_comment(tctx, "query info => OK\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "raw_fileinfo failed");
+
+ torture_comment(tctx, "sleep 10 seconds\n");
+ smb_msleep(10*1000);
+
+ torture_comment(tctx, "query info => EXPIRED\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "raw_fileinfo expired");
+
+ /*
+ * the krb5 library may not handle expired creds
+ * well, lets start with an empty ccache.
+ */
+ cli_credentials_invalidate_ccache(
+ samba_cmdline_get_creds(), CRED_SPECIFIED);
+
+ torture_comment(tctx, "reauth with CAP_DYNAMIC_REAUTH => OK\n");
+ ZERO_STRUCT(io_sesssetup.out);
+ status = smb_composite_sesssetup(cli->session, &io_sesssetup);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "reauth failed");
+ torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid,
+ ret, done, "reauth");
+ }
+
+ torture_comment(tctx, "query info => OK\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "raw_fileinfo failed");
+
+ /*
+ * the krb5 library may not handle expired creds
+ * well, lets start with an empty ccache.
+ */
+ cli_credentials_invalidate_ccache(samba_cmdline_get_creds(),
+ CRED_SPECIFIED);
+
+ /*
+ * now without CAP_DYNAMIC_REAUTH
+ *
+ * This should not trigger NT_STATUS_NETWORK_SESSION_EXPIRED
+ */
+ torture_comment(tctx, "reauth without CAP_DYNAMIC_REAUTH => OK\n");
+ io_sesssetup.in.capabilities &= ~CAP_DYNAMIC_REAUTH;
+
+ ZERO_STRUCT(io_sesssetup.out);
+ status = smb_composite_sesssetup(cli->session, &io_sesssetup);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "reauth failed");
+ torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid,
+ ret, done, "reauth");
+
+ for (i=0; i < 2; i++) {
+ torture_comment(tctx, "query info => OK\n");
+
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "raw_fileinfo failed");
+
+ torture_comment(tctx, "sleep 5 seconds\n");
+ smb_msleep(5*1000);
+ }
+
+ torture_comment(tctx, "query info => OK\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "raw_fileinfo failed");
+
+ ret = true;
+done:
+ if (fnum > 0) {
+ smbcli_close(cli->tree, fnum);
+ }
+
+ talloc_free(cli);
+ lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=0");
+ return ret;
+}
+
+struct torture_suite *torture_raw_session(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "session");
+ suite->description = talloc_strdup(suite, "RAW-SESSION tests");
+
+ torture_suite_add_1smb_test(suite, "reauth1", test_session_reauth1);
+ torture_suite_add_1smb_test(suite, "reauth2", test_session_reauth2);
+ torture_suite_add_simple_test(suite, "expire1", test_session_expire1);
+
+ return suite;
+}
diff --git a/source4/torture/raw/setfileinfo.c b/source4/torture/raw/setfileinfo.c
new file mode 100644
index 0000000..45ff819
--- /dev/null
+++ b/source4/torture/raw/setfileinfo.c
@@ -0,0 +1,1152 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_SFILEINFO_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\testsfileinfo"
+
+/* basic testing of all RAW_SFILEINFO_* calls
+ for each call we test that it succeeds, and where possible test
+ for consistency between the calls.
+*/
+static bool
+torture_raw_sfileinfo_base(struct torture_context *torture, struct smbcli_state *cli)
+{
+ bool ret = true;
+ int fnum = -1;
+ char *fnum_fname;
+ char *path_fname;
+ char *path_fname_new;
+ union smb_fileinfo finfo1, finfo2;
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status, status2;
+ const char *call_name;
+ time_t basetime = (time(NULL) - 86400) & ~1;
+ bool check_fnum;
+ int n = time(NULL) % 100;
+
+ path_fname = talloc_asprintf(torture, BASEDIR "\\fname_test_%d.txt", n);
+ path_fname_new = talloc_asprintf(torture, BASEDIR "\\fname_test_new_%d.txt", n);
+ fnum_fname = talloc_asprintf(torture, BASEDIR "\\fnum_test_%d.txt", n);
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+#define RECREATE_FILE(fname) do { \
+ if (fnum != -1) smbcli_close(cli->tree, fnum); \
+ fnum = create_complex_file(cli, torture, fname); \
+ if (fnum == -1) { \
+ printf("(%s) ERROR: open of %s failed (%s)\n", \
+ __location__, fname, smbcli_errstr(cli->tree)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define RECREATE_BOTH do { \
+ RECREATE_FILE(path_fname); \
+ smbcli_close(cli->tree, fnum); \
+ RECREATE_FILE(fnum_fname); \
+ } while (0)
+
+ RECREATE_BOTH;
+
+#define CHECK_CALL_FNUM(call, rightstatus) do { \
+ check_fnum = true; \
+ call_name = #call; \
+ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
+ sfinfo.generic.in.file.fnum = fnum; \
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \
+ torture_warning(torture, \
+ "(%s) %s - %s", __location__, #call, \
+ nt_errstr(status)); \
+ } else if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = false; \
+ } \
+ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
+ finfo1.generic.in.file.fnum = fnum; \
+ status2 = smb_raw_fileinfo(cli->tree, torture, &finfo1); \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \
+ torture_warning(torture, \
+ "(%s) %s - %s", __location__, #call, \
+ nt_errstr(status)); \
+ } else if (!NT_STATUS_IS_OK(status2)) { \
+ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_CALL_PATH(call, rightstatus) do { \
+ check_fnum = false; \
+ call_name = #call; \
+ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
+ sfinfo.generic.in.file.path = path_fname; \
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
+ sfinfo.generic.in.file.path = path_fname_new; \
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
+ } \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \
+ torture_warning(torture, \
+ "(%s) %s - %s", __location__, #call, \
+ nt_errstr(status)); \
+ } else if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = false; \
+ } \
+ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
+ finfo1.generic.in.file.path = path_fname; \
+ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo1); \
+ if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
+ finfo1.generic.in.file.path = path_fname_new; \
+ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo1); \
+ } \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \
+ torture_warning(torture, \
+ "(%s) %s - %s", __location__, #call, \
+ nt_errstr(status)); \
+ } else if (!NT_STATUS_IS_OK(status2)) { \
+ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status2)); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK1(call) \
+ do { if (NT_STATUS_IS_OK(status)) { \
+ finfo2.generic.level = RAW_FILEINFO_ ## call; \
+ if (check_fnum) { \
+ finfo2.generic.in.file.fnum = fnum; \
+ status2 = smb_raw_fileinfo(cli->tree, torture, &finfo2); \
+ } else { \
+ finfo2.generic.in.file.path = path_fname; \
+ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo2); \
+ if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \
+ finfo2.generic.in.file.path = path_fname_new; \
+ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo2); \
+ } \
+ } \
+ if (!NT_STATUS_IS_OK(status2)) { \
+ printf("%s - %s\n", #call, nt_errstr(status2)); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_VALUE(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \
+ printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
+ call_name, #stype, #field, \
+ (unsigned int)value, (unsigned int)finfo2.stype.out.field); \
+ dump_all_info(torture, &finfo1); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_TIME(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \
+ printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
+ call_name, #stype, #field, \
+ (unsigned int)value, \
+ (unsigned int)nt_time_to_unix(finfo2.stype.out.field)); \
+ printf("\t%s", timestring(torture, value)); \
+ printf("\t%s\n", nt_time_string(torture, finfo2.stype.out.field)); \
+ dump_all_info(torture, &finfo1); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STR(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && strcmp(finfo2.stype.out.field, value) != 0) { \
+ printf("(%s) %s - %s/%s should be '%s' - '%s'\n", __location__, \
+ call_name, #stype, #field, \
+ value, \
+ finfo2.stype.out.field); \
+ dump_all_info(torture, &finfo1); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+
+ printf("Test setattr\n");
+ sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY;
+ sfinfo.setattr.in.write_time = basetime;
+ CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
+ CHECK_VALUE (ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
+ CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
+
+ printf("setting to NORMAL doesn't do anything\n");
+ sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ sfinfo.setattr.in.write_time = 0;
+ CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
+ CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
+
+ printf("a zero write_time means don't change\n");
+ sfinfo.setattr.in.attrib = 0;
+ sfinfo.setattr.in.write_time = 0;
+ CHECK_CALL_PATH(SETATTR, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
+ CHECK_TIME (ALL_INFO, all_info, write_time, basetime);
+
+ printf("Test setattre\n");
+ sfinfo.setattre.in.create_time = basetime + 20;
+ sfinfo.setattre.in.access_time = basetime + 30;
+ sfinfo.setattre.in.write_time = basetime + 40;
+ CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40);
+
+ sfinfo.setattre.in.create_time = 0;
+ sfinfo.setattre.in.access_time = 0;
+ sfinfo.setattre.in.write_time = 0;
+ CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40);
+
+ printf("Test standard level\n");
+ sfinfo.standard.in.create_time = basetime + 100;
+ sfinfo.standard.in.access_time = basetime + 200;
+ sfinfo.standard.in.write_time = basetime + 300;
+ CHECK_CALL_FNUM(STANDARD, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+
+ printf("Test basic_info level\n");
+ basetime += 86400;
+ unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
+ unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
+ unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
+ CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+ CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
+
+ printf("a zero time means don't change\n");
+ unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
+ sfinfo.basic_info.in.attrib = 0;
+ CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+ CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY);
+
+ printf("Test basic_information level\n");
+ basetime += 86400;
+ unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
+ unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
+ unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+ CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
+
+ CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+ CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
+
+ torture_comment(torture, "try to change a file to a directory\n");
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_INVALID_PARAMETER);
+
+ printf("a zero time means don't change\n");
+ unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+ CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
+
+ CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100);
+ CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200);
+ CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300);
+
+ /* interesting - w2k3 leaves change_time as current time for 0 change time
+ in setpathinfo
+ CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400);
+ */
+ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL);
+
+ printf("Test disposition_info level\n");
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
+ CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
+
+ sfinfo.disposition_info.in.delete_on_close = 0;
+ CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
+ CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
+
+ printf("Test disposition_information level\n");
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
+ CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
+
+ /* this would delete the file! */
+ /*
+ CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1);
+ CHECK_VALUE(ALL_INFO, all_info, nlink, 0);
+ */
+
+ sfinfo.disposition_info.in.delete_on_close = 0;
+ CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
+ CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
+
+ CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0);
+ CHECK_VALUE(ALL_INFO, all_info, nlink, 1);
+
+ printf("Test allocation_info level\n");
+ sfinfo.allocation_info.in.alloc_size = 0;
+ CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 0);
+ CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
+
+ sfinfo.allocation_info.in.alloc_size = 4096;
+ CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096);
+ CHECK_VALUE(ALL_INFO, all_info, size, 0);
+
+ RECREATE_BOTH;
+ sfinfo.allocation_info.in.alloc_size = 0;
+ CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 0);
+ CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
+
+ CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 0);
+ CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
+
+ sfinfo.allocation_info.in.alloc_size = 4096;
+ CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096);
+ CHECK_VALUE(ALL_INFO, all_info, size, 0);
+
+ /* setting the allocation size up via setpathinfo seems
+ to be broken in w2k3 */
+ CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0);
+ CHECK_VALUE(ALL_INFO, all_info, size, 0);
+
+ printf("Test end_of_file_info level\n");
+ sfinfo.end_of_file_info.in.size = 37;
+ CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 37);
+
+ sfinfo.end_of_file_info.in.size = 7;
+ CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 7);
+
+ sfinfo.end_of_file_info.in.size = 37;
+ CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 37);
+
+ CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 37);
+
+ sfinfo.end_of_file_info.in.size = 7;
+ CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 7);
+
+ CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(ALL_INFO, all_info, size, 7);
+
+ printf("Test position_information level\n");
+ sfinfo.position_information.in.position = 123456;
+ CHECK_CALL_FNUM(POSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456);
+
+ CHECK_CALL_PATH(POSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(POSITION_INFORMATION, position_information, position, 0);
+
+ printf("Test mode_information level\n");
+ sfinfo.mode_information.in.mode = 2;
+ CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2);
+
+ CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
+
+ sfinfo.mode_information.in.mode = 1;
+ CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
+ CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
+
+ sfinfo.mode_information.in.mode = 0;
+ CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
+
+ CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
+
+#if 0
+ printf("Test unix_basic level\n");
+ CHECK_CALL_FNUM(UNIX_BASIC, NT_STATUS_OK);
+ CHECK_CALL_PATH(UNIX_BASIC, NT_STATUS_OK);
+
+ printf("Test unix_link level\n");
+ CHECK_CALL_FNUM(UNIX_LINK, NT_STATUS_OK);
+ CHECK_CALL_PATH(UNIX_LINK, NT_STATUS_OK);
+#endif
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_close(cli->tree, fnum);
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) {
+ printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree));
+ }
+ if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) {
+ printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree));
+ }
+
+ return ret;
+}
+
+/*
+ * basic testing of all RAW_SFILEINFO_RENAME call
+ */
+static bool
+torture_raw_sfileinfo_rename(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ int fnum_saved, d_fnum, fnum2, fnum = -1;
+ char *fnum_fname;
+ char *fnum_fname_new;
+ char *path_fname;
+ char *path_fname_new;
+ char *path_dname;
+ char *path_dname_new;
+ char *saved_name;
+ char *saved_name_new;
+ union smb_fileinfo finfo1, finfo2;
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status, status2;
+ const char *call_name;
+ bool check_fnum;
+ int n = time(NULL) % 100;
+
+ path_fname = talloc_asprintf(torture, BASEDIR "\\fname_test_%d.txt", n);
+ path_fname_new = talloc_asprintf(torture, BASEDIR "\\fname_test_new_%d.txt", n);
+ fnum_fname = talloc_asprintf(torture, BASEDIR "\\fnum_test_%d.txt", n);
+ fnum_fname_new = talloc_asprintf(torture, BASEDIR "\\fnum_test_new_%d.txt", n);
+ path_dname = talloc_asprintf(torture, BASEDIR "\\dname_test_%d", n);
+ path_dname_new = talloc_asprintf(torture, BASEDIR "\\dname_test_new_%d", n);
+
+ torture_assert(torture, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ RECREATE_BOTH;
+
+ ZERO_STRUCT(sfinfo);
+
+ smbcli_close(cli->tree, create_complex_file(cli, torture, fnum_fname_new));
+ smbcli_close(cli->tree, create_complex_file(cli, torture, path_fname_new));
+
+ sfinfo.rename_information.in.overwrite = 0;
+ sfinfo.rename_information.in.root_fid = 0;
+ sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
+ CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ sfinfo.rename_information.in.new_name = fnum_fname_new;
+ sfinfo.rename_information.in.overwrite = 1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_NOT_SUPPORTED);
+
+ sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
+
+ printf("Trying rename with dest file open\n");
+ fnum2 = create_complex_file(cli, torture, fnum_fname);
+ sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
+
+ fnum_saved = fnum;
+ fnum = fnum2;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK);
+ fnum = fnum_saved;
+
+ printf("Trying rename with dest file open and delete_on_close\n");
+ sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_ACCESS_DENIED);
+
+ smbcli_close(cli->tree, fnum2);
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
+
+ printf("Trying rename with source file open twice\n");
+ sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
+
+ fnum2 = create_complex_file(cli, torture, fnum_fname);
+ sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 0;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname_new);
+ smbcli_close(cli->tree, fnum2);
+
+ sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 0;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
+
+ sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 1;
+ CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new);
+
+ sfinfo.rename_information.in.new_name = fnum_fname+strlen(BASEDIR)+1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
+
+ sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1;
+ CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_fname);
+
+ printf("Trying rename with a root fid\n");
+ status = create_directory_handle(cli->tree, BASEDIR, &d_fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sfinfo.rename_information.in.new_name = fnum_fname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.root_fid = d_fnum;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_INVALID_PARAMETER);
+ CHECK_STR(NAME_INFO, name_info, fname.s, fnum_fname);
+ smbcli_close(cli->tree, d_fnum);
+
+ printf("Trying rename directory\n");
+ if (!torture_setup_dir(cli, path_dname)) {
+ ret = false;
+ goto done;
+ }
+ saved_name = path_fname;
+ saved_name_new = path_fname_new;
+ path_fname = path_dname;
+ path_fname_new = path_dname_new;
+ sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 0;
+ sfinfo.rename_information.in.root_fid = 0;
+ CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new);
+ path_fname = saved_name;
+ path_fname_new = saved_name_new;
+
+ if (torture_setting_bool(torture, "samba3", false)) {
+ printf("SKIP: Trying rename directory with a handle\n");
+ printf("SKIP: Trying rename by path while a handle is open\n");
+ printf("SKIP: Trying rename directory by path while a handle is open\n");
+ goto done;
+ }
+
+ printf("Trying rename directory with a handle\n");
+ status = create_directory_handle(cli->tree, path_dname_new, &d_fnum);
+ fnum_saved = fnum;
+ fnum = d_fnum;
+ saved_name = fnum_fname;
+ saved_name_new = fnum_fname_new;
+ fnum_fname = path_dname;
+ fnum_fname_new = path_dname_new;
+ sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 0;
+ sfinfo.rename_information.in.root_fid = 0;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_dname);
+ smbcli_close(cli->tree, d_fnum);
+ fnum = fnum_saved;
+ fnum_fname = saved_name;
+ fnum_fname_new = saved_name_new;
+
+ printf("Trying rename by path while a handle is open\n");
+ fnum_saved = fnum;
+ fnum = create_complex_file(cli, torture, path_fname);
+ sfinfo.rename_information.in.new_name = path_fname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 0;
+ sfinfo.rename_information.in.root_fid = 0;
+ CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new);
+ /* check that the handle returns the same name */
+ check_fnum = true;
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_fname_new);
+ /* rename it back on the handle */
+ sfinfo.rename_information.in.new_name = path_fname+strlen(BASEDIR)+1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_fname);
+ check_fnum = false;
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_fname);
+ smbcli_close(cli->tree, fnum);
+ fnum = fnum_saved;
+
+ printf("Trying rename directory by path while a handle is open\n");
+ status = create_directory_handle(cli->tree, path_dname, &d_fnum);
+ fnum_saved = fnum;
+ fnum = d_fnum;
+ saved_name = path_fname;
+ saved_name_new = path_fname_new;
+ path_fname = path_dname;
+ path_fname_new = path_dname_new;
+ sfinfo.rename_information.in.new_name = path_dname_new+strlen(BASEDIR)+1;
+ sfinfo.rename_information.in.overwrite = 0;
+ sfinfo.rename_information.in.root_fid = 0;
+ CHECK_CALL_PATH(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new);
+ path_fname = saved_name;
+ path_fname_new = saved_name_new;
+ saved_name = fnum_fname;
+ saved_name_new = fnum_fname_new;
+ fnum_fname = path_dname;
+ fnum_fname_new = path_dname_new;
+ /* check that the handle returns the same name */
+ check_fnum = true;
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_dname_new);
+ /* rename it back on the handle */
+ sfinfo.rename_information.in.new_name = path_dname+strlen(BASEDIR)+1;
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_dname);
+ fnum_fname = saved_name;
+ fnum_fname_new = saved_name_new;
+ saved_name = path_fname;
+ saved_name_new = path_fname_new;
+ path_fname = path_dname;
+ path_fname_new = path_dname_new;
+ check_fnum = false;
+ CHECK_STR(NAME_INFO, name_info, fname.s, path_dname);
+ smbcli_close(cli->tree, d_fnum);
+ fnum = fnum_saved;
+ path_fname = saved_name;
+ path_fname_new = saved_name_new;
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ look for the w2k3 setpathinfo STANDARD bug
+*/
+static bool torture_raw_sfileinfo_bug(struct torture_context *torture,
+ struct smbcli_state *cli)
+{
+ const char *fname = "\\bug3.txt";
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status;
+ int fnum;
+
+ if (!torture_setting_bool(torture, "dangerous", false))
+ torture_skip(torture,
+ "torture_raw_sfileinfo_bug disabled - enable dangerous tests to use\n");
+
+ fnum = create_complex_file(cli, torture, fname);
+ smbcli_close(cli->tree, fnum);
+
+ sfinfo.generic.level = RAW_SFILEINFO_STANDARD;
+ sfinfo.generic.in.file.path = fname;
+
+ sfinfo.standard.in.create_time = 0;
+ sfinfo.standard.in.access_time = 0;
+ sfinfo.standard.in.write_time = 0;
+
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo);
+ printf("%s - %s\n", fname, nt_errstr(status));
+
+ printf("now try and delete %s\n", fname);
+
+ return true;
+}
+
+/**
+ * Test both the snia cifs RAW_SFILEINFO_END_OF_FILE_INFO and the undocumented
+ * pass-through RAW_SFILEINFO_END_OF_FILE_INFORMATION in the context of
+ * trans2setpathinfo.
+ */
+static bool
+torture_raw_sfileinfo_eof(struct torture_context *tctx,
+ struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_sfileinfo_end_of_file.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ union smb_fileinfo qfi;
+ uint16_t fnum = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+
+ /* Open the file sharing none. */
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Try to sfileinfo to extend the file. */
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 100;
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+ /* There should be share mode contention in this case. */
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_SHARING_VIOLATION, ret, done, "Status should be "
+ "SHARING_VIOLATION");
+
+ /* Make sure the size is still 0. */
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_STANDARD_INFO;
+ qfi.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli2->tree, tctx, &qfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+
+ torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 0,
+ "alloc_size should be 0 since the setpathinfo failed.");
+
+ /* Try again with the pass through instead of documented version. */
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 100;
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+ /*
+ * Looks like a windows bug:
+ * http://lists.samba.org/archive/cifs-protocol/2009-November/001130.html
+ */
+ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
+ /* It succeeds! This is just weird! */
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "Status should be OK");
+
+ /* Verify that the file was actually extended to 100. */
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_STANDARD_INFO;
+ qfi.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli2->tree, tctx, &qfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "Status should be OK");
+
+ torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 100,
+ "alloc_size should be 100 since the setpathinfo "
+ "succeeded.");
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_SHARING_VIOLATION, ret, done, "Status should be "
+ "SHARING_VIOLATION");
+ }
+
+ /* close the first file. */
+ smbcli_close(cli1->tree, fnum);
+ fnum = 0;
+
+ /* Try to sfileinfo to extend the file again (non-pass-through). */
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 200;
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+ /* This should cause the client to return invalid level. */
+ if (TARGET_IS_W2K8(tctx) || TARGET_IS_WIN7(tctx)) {
+ /*
+ * Windows sends back an invalid packet that smbclient sees
+ * and returns INTERNAL_ERROR.
+ */
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_INTERNAL_ERROR, ret, done, "Status should be "
+ "INTERNAL_ERROR");
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_INVALID_LEVEL, ret, done, "Status should be "
+ "INVALID_LEVEL");
+ }
+
+ /* Try to extend the file now with the passthrough level. */
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ status = smb_raw_setpathinfo(cli2->tree, &sfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+
+ /* Verify that the file was actually extended to 200. */
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_STANDARD_INFO;
+ qfi.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli2->tree, tctx, &qfi);
+
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+ torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 200,
+ "alloc_size should be 200 since the setpathinfo succeeded.");
+
+ /* Open the file so end of file can be set by handle. */
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_WRITE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Try sfileinfo to extend the file by handle (non-pass-through). */
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.end_of_file_info.in.size = 300;
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+
+ /* Verify that the file was actually extended to 300. */
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_STANDARD_INFO;
+ qfi.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli1->tree, tctx, &qfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+ torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 300,
+ "alloc_size should be 300 since the setpathinfo succeeded.");
+
+ /* Try sfileinfo to extend the file by handle (pass-through). */
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.end_of_file_info.in.size = 400;
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+
+ /* Verify that the file was actually extended to 300. */
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_STANDARD_INFO;
+ qfi.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli1->tree, tctx, &qfi);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done, "Status should be OK");
+ torture_assert_u64_equal(tctx, qfi.standard_info.out.size, 400,
+ "alloc_size should be 400 since the setpathinfo succeeded.");
+ done:
+ if (fnum > 0) {
+ smbcli_close(cli1->tree, fnum);
+ fnum = 0;
+ }
+
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool
+torture_raw_sfileinfo_eof_access(struct torture_context *tctx,
+ struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_exclusive3.dat";
+ NTSTATUS status, expected_status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ uint16_t fnum=0;
+ uint32_t access_mask = 0;
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ /*
+ * base ntcreatex parms
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+
+
+ for (access_mask = 1; access_mask <= 0x00001FF; access_mask++) {
+ io.ntcreatex.in.access_mask = access_mask;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ continue;
+ }
+
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFO;
+ sfi.generic.in.file.fnum = fnum;
+ sfi.end_of_file_info.in.size = 100;
+
+ status = smb_raw_setfileinfo(cli1->tree, &sfi);
+
+ expected_status = (access_mask & SEC_FILE_WRITE_DATA) ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ if (!NT_STATUS_EQUAL(expected_status, status)) {
+ torture_comment(tctx, "0x%x wrong\n", access_mask);
+ }
+
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ expected_status, ret, done, "Status Wrong");
+
+ smbcli_close(cli1->tree, fnum);
+ }
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+static bool
+torture_raw_sfileinfo_archive(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ const char *fname = BASEDIR "\\test_archive.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfinfo;
+ union smb_fileinfo finfo;
+ uint16_t fnum=0;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ /* cleanup */
+ smbcli_unlink(cli->tree, fname);
+
+ /*
+ * create a normal file, verify archive bit
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "open failed");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_assert_int_equal(tctx,
+ io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_ARCHIVE,
+ "archive bit not set");
+
+ /*
+ * try to turn off archive bit
+ */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "setfileinfo failed");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "fileinfo failed");
+
+ torture_assert_int_equal(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_NORMAL,
+ "archive bit set");
+
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "close failed");
+
+ status = smbcli_unlink(cli->tree, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "unlink failed");
+
+ /*
+ * create a directory, verify no archive bit
+ */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_DIR_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "directory open failed");
+ fnum = io.ntcreatex.out.file.fnum;
+
+ torture_assert_int_equal(tctx,
+ io.ntcreatex.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY,
+ "archive bit set");
+
+ /*
+ * verify you can turn on archive bit
+ */
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "setfileinfo failed");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "fileinfo failed");
+
+ torture_assert_int_equal(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE,
+ "archive bit not set");
+
+ /*
+ * and try to turn it back off
+ */
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ sfinfo.generic.in.file.fnum = fnum;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "setfileinfo failed");
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.fnum = fnum;
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "fileinfo failed");
+
+ torture_assert_int_equal(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY,
+ "archive bit set");
+
+ status = smbcli_close(cli->tree, fnum);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK,
+ ret, done, "close failed");
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+struct torture_suite *torture_raw_sfileinfo(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "sfileinfo");
+
+ torture_suite_add_1smb_test(suite, "base", torture_raw_sfileinfo_base);
+ torture_suite_add_1smb_test(suite, "rename", torture_raw_sfileinfo_rename);
+ torture_suite_add_1smb_test(suite, "bug", torture_raw_sfileinfo_bug);
+ torture_suite_add_2smb_test(suite, "end-of-file",
+ torture_raw_sfileinfo_eof);
+ torture_suite_add_2smb_test(suite, "end-of-file-access",
+ torture_raw_sfileinfo_eof_access);
+ torture_suite_add_1smb_test(suite, "archive",
+ torture_raw_sfileinfo_archive);
+
+ return suite;
+}
diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c
new file mode 100644
index 0000000..3b16db3
--- /dev/null
+++ b/source4/torture/raw/streams.c
@@ -0,0 +1,2091 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test alternate data streams
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/locale.h"
+#include "torture/torture.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/security_descriptor.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/util/tsort.h"
+#include "torture/raw/proto.h"
+
+#define BASEDIR "\\teststreams"
+
+#define CHECK_STATUS(status, correct) \
+ torture_assert_ntstatus_equal_goto(tctx,status,correct,ret,done,"CHECK_STATUS")
+
+#define CHECK_VALUE(v, correct) \
+ torture_assert_int_equal(tctx,v,correct,"CHECK_VALUE")
+
+#define CHECK_NTTIME(v, correct) \
+ torture_assert_u64_equal(tctx,v,correct,"CHECK_NTTIME")
+
+#define CHECK_STR(v, correct) do { \
+ bool ok; \
+ if ((v) && !(correct)) { \
+ ok = false; \
+ } else if (!(v) && (correct)) { \
+ ok = false; \
+ } else if (!(v) && !(correct)) { \
+ ok = true; \
+ } else if (strcmp((v), (correct)) == 0) { \
+ ok = true; \
+ } else { \
+ ok = false; \
+ } \
+ torture_assert(tctx,ok,\
+ talloc_asprintf(tctx, "got '%s', expected '%s'",\
+ (v)?(v):"NULL", (correct)?(correct):"NULL")); \
+} while (0)
+
+/*
+ check that a stream has the right contents
+*/
+static bool check_stream(struct smbcli_state *cli, const char *location,
+ TALLOC_CTX *mem_ctx,
+ const char *fname, const char *sname,
+ const char *value)
+{
+ int fnum;
+ const char *full_name;
+ uint8_t *buf;
+ ssize_t ret;
+
+ full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
+
+ fnum = smbcli_open(cli->tree, full_name, O_RDONLY, DENY_NONE);
+
+ if (value == NULL) {
+ if (fnum != -1) {
+ printf("(%s) should have failed stream open of %s\n",
+ location, full_name);
+ return false;
+ }
+ return true;
+ }
+
+ if (fnum == -1) {
+ printf("(%s) Failed to open stream '%s' - %s\n",
+ location, full_name, smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ buf = talloc_array(mem_ctx, uint8_t, strlen(value)+11);
+
+ ret = smbcli_read(cli->tree, fnum, buf, 0, strlen(value)+11);
+ if (ret != strlen(value)) {
+ printf("(%s) Failed to read %lu bytes from stream '%s' - got %d\n",
+ location, (long)strlen(value), full_name, (int)ret);
+ return false;
+ }
+
+ if (memcmp(buf, value, strlen(value)) != 0) {
+ printf("(%s) Bad data in stream\n", location);
+ return false;
+ }
+
+ smbcli_close(cli->tree, fnum);
+ return true;
+}
+
+static int qsort_string(char * const *s1, char * const *s2)
+{
+ return strcmp(*s1, *s2);
+}
+
+static int qsort_stream(const struct stream_struct *s1, const struct stream_struct *s2)
+{
+ return strcmp(s1->stream_name.s, s2->stream_name.s);
+}
+
+static bool check_stream_list(struct torture_context *tctx,
+ struct smbcli_state *cli, const char *fname,
+ int num_exp, const char **exp)
+{
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(cli);
+ char **exp_sort;
+ struct stream_struct *stream_sort;
+ bool ret = false;
+ int fail = -1;
+
+ finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
+ finfo.generic.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli->tree, tmp_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VALUE(finfo.stream_info.out.num_streams, num_exp);
+
+ if (num_exp == 0) {
+ ret = true;
+ goto done;
+ }
+
+ exp_sort = (char **)talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
+
+ if (exp_sort == NULL) {
+ goto done;
+ }
+
+ TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
+
+ stream_sort = (struct stream_struct *)talloc_memdup(tmp_ctx,
+ finfo.stream_info.out.streams,
+ finfo.stream_info.out.num_streams *
+ sizeof(*stream_sort));
+
+ if (stream_sort == NULL) {
+ goto done;
+ }
+
+ TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
+
+ for (i=0; i<num_exp; i++) {
+ if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
+ fail = i;
+ goto show_streams;
+ }
+ }
+
+ ret = true;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+
+show_streams:
+ for (i=0; i<num_exp; i++) {
+ torture_comment(tctx, "stream names '%s' '%s'\n",
+ exp_sort[i], stream_sort[i].stream_name.s);
+ }
+ CHECK_STR(stream_sort[fail].stream_name.s, exp_sort[fail]);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ test behavior of streams on directories
+*/
+static bool test_stream_dir(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream.txt";
+ const char *sname1;
+ bool ret = true;
+ const char *basedir_data;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ basedir_data = talloc_asprintf(tctx, "%s::$DATA", BASEDIR);
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
+
+ printf("(%s) opening non-existent directory stream\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
+
+ printf("(%s) opening basedir stream\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = basedir_data;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
+
+ printf("(%s) opening basedir ::$DATA stream\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0x10;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = basedir_data;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+
+ printf("(%s) list the streams on the basedir\n", __location__);
+ ret &= check_stream_list(tctx, cli, BASEDIR, 0, NULL);
+done:
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test basic behavior of streams on directories
+*/
+static bool test_stream_io(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream.txt";
+ const char *sname1, *sname2;
+ bool ret = true;
+ int fnum = -1;
+ ssize_t retsize;
+
+ const char *one[] = { "::$DATA" };
+ const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
+ const char *three[] = { "::$DATA", ":Stream One:$DATA",
+ ":Second Stream:$DATA" };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
+ sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
+
+ printf("(%s) creating a stream on a non-existent file\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ ret &= check_stream(cli, __location__, tctx, fname, "Stream One", NULL);
+
+ printf("(%s) check that open of base file is allowed\n", __location__);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ printf("(%s) writing to stream\n", __location__);
+ retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
+ CHECK_VALUE(retsize, 9);
+
+ smbcli_close(cli->tree, fnum);
+
+ ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test data");
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.fname = sname1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ printf("(%s) modifying stream\n", __location__);
+ retsize = smbcli_write(cli->tree, fnum, 0, "MORE DATA ", 5, 10);
+ CHECK_VALUE(retsize, 10);
+
+ smbcli_close(cli->tree, fnum);
+
+ ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$FOO", NULL);
+
+ printf("(%s) creating a stream2 on a existing file\n", __location__);
+ io.ntcreatex.in.fname = sname2;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ printf("(%s) modifying stream\n", __location__);
+ retsize = smbcli_write(cli->tree, fnum, 0, "SECOND STREAM", 0, 13);
+ CHECK_VALUE(retsize, 13);
+
+ smbcli_close(cli->tree, fnum);
+
+ ret &= check_stream(cli, __location__, tctx, fname, "Stream One", "test MORE DATA ");
+ ret &= check_stream(cli, __location__, tctx, fname, "Stream One:$DATA", "test MORE DATA ");
+ ret &= check_stream(cli, __location__, tctx, fname, "Stream One:", NULL);
+ ret &= check_stream(cli, __location__, tctx, fname, "Second Stream", "SECOND STREAM");
+ ret &= check_stream(cli, __location__, tctx, fname,
+ "SECOND STREAM:$DATA", "SECOND STREAM");
+ ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$DATA", "SECOND STREAM");
+ ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:", NULL);
+ ret &= check_stream(cli, __location__, tctx, fname, "Second Stream:$FOO", NULL);
+
+ check_stream_list(tctx, cli, fname, 3, three);
+
+ printf("(%s) deleting stream\n", __location__);
+ status = smbcli_unlink(cli->tree, sname1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ check_stream_list(tctx, cli, fname, 2, two);
+
+ printf("(%s) delete a stream via delete-on-close\n", __location__);
+ io.ntcreatex.in.fname = sname2;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ smbcli_close(cli->tree, fnum);
+ status = smbcli_unlink(cli->tree, sname2);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ check_stream_list(tctx, cli, fname, 1, one);
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.fname = sname1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ printf("(%s) deleting file\n", __location__);
+ status = smbcli_unlink(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test stream sharemodes
+*/
+static bool test_stream_sharemodes(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream.txt";
+ const char *sname1, *sname2;
+ bool ret = true;
+ int fnum1 = -1;
+ int fnum2 = -1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
+ sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
+
+ printf("(%s) testing stream share mode conflicts\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ /*
+ * A different stream does not give a sharing violation
+ */
+
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ /*
+ * ... whereas the same stream does with unchanged access/share_access
+ * flags
+ */
+
+ io.ntcreatex.in.fname = sname1;
+ io.ntcreatex.in.open_disposition = 0;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+done:
+ if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
+ if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
+ status = smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * Test FILE_SHARE_DELETE on streams
+ *
+ * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
+ * with SEC_STD_DELETE.
+ *
+ * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
+ * be opened with SEC_STD_DELETE.
+ *
+ * A stream held open with FILE_SHARE_DELETE allows the file to be
+ * deleted. After the main file is deleted, access to the open file descriptor
+ * still works, but all name-based access to both the main file as well as the
+ * stream is denied with DELETE pending.
+ *
+ * This means, an open of the main file with SEC_STD_DELETE should walk all
+ * streams and also open them with SEC_STD_DELETE. If any of these opens gives
+ * SHARING_VIOLATION, the main open fails.
+ *
+ * Closing the main file after delete_on_close has been set does not really
+ * unlink it but leaves the corresponding share mode entry with
+ * delete_on_close being set around until all streams are closed.
+ *
+ * Opening a stream must also look at the main file's share mode entry, look
+ * at the delete_on_close bit and potentially return DELETE_PENDING.
+ */
+
+static bool test_stream_delete(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream.txt";
+ const char *sname1;
+ bool ret = true;
+ int fnum = -1;
+ uint8_t buf[9];
+ ssize_t retsize;
+ union smb_fileinfo finfo;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
+
+ printf("(%s) opening non-existent file stream\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
+ CHECK_VALUE(retsize, 9);
+
+ /*
+ * One stream opened without FILE_SHARE_DELETE prevents the main file
+ * to be deleted or even opened with DELETE access
+ */
+
+ status = smbcli_unlink(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ smbcli_close(cli->tree, fnum);
+
+ /*
+ * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
+ */
+
+ io.ntcreatex.in.fname = sname1;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ status = smbcli_unlink(cli->tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * file access still works on the stream while the main file is closed
+ */
+
+ retsize = smbcli_read(cli->tree, fnum, buf, 0, 9);
+ CHECK_VALUE(retsize, 9);
+
+ finfo.generic.level = RAW_FILEINFO_STANDARD;
+ finfo.generic.in.file.path = fname;
+
+ /*
+ * name-based access to both the main file and the stream does not
+ * work anymore but gives DELETE_PENDING
+ */
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
+
+ /*
+ * older S3 doesn't do this
+ */
+ finfo.generic.in.file.path = sname1;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
+
+ /*
+ * fd-based qfileinfo on the stream still works, the stream does not
+ * have the delete-on-close bit set. This could mean that open on the
+ * stream first opens the main file
+ */
+
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO;
+ finfo.all_info.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* w2k and w2k3 return 0 and w2k8 returns 1 */
+ if (TARGET_IS_WINXP(tctx) || TARGET_IS_W2K3(tctx) ||
+ TARGET_IS_SAMBA3(tctx)) {
+ CHECK_VALUE(finfo.all_info.out.delete_pending, 0);
+ } else {
+ CHECK_VALUE(finfo.all_info.out.delete_pending, 1);
+ }
+
+ smbcli_close(cli->tree, fnum);
+
+ /*
+ * After closing the stream the file is really gone.
+ */
+
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA
+ |SEC_STD_DELETE;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test stream names
+*/
+static bool test_stream_names(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ union smb_fileinfo info;
+ union smb_fileinfo finfo;
+ union smb_fileinfo stinfo;
+ union smb_setfileinfo sinfo;
+ const char *fname = BASEDIR "\\stream_names.txt";
+ const char *sname1, *sname1b, *sname1c, *sname1d;
+ const char *sname2, *snamew, *snamew2;
+ const char *snamer1;
+ bool ret = true;
+ int fnum1 = -1;
+ int fnum2 = -1;
+ int fnum3 = -1;
+ int i;
+ const char *four[4] = {
+ "::$DATA",
+ ":\x05Stream\n One:$DATA",
+ ":MStream Two:$DATA",
+ ":?Stream*:$DATA"
+ };
+ const char *five1[5] = {
+ "::$DATA",
+ ":\x05Stream\n One:$DATA",
+ ":BeforeRename:$DATA",
+ ":MStream Two:$DATA",
+ ":?Stream*:$DATA"
+ };
+ const char *five2[5] = {
+ "::$DATA",
+ ":\x05Stream\n One:$DATA",
+ ":AfterRename:$DATA",
+ ":MStream Two:$DATA",
+ ":?Stream*:$DATA"
+ };
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "\x05Stream\n One");
+ sname1b = talloc_asprintf(tctx, "%s:", sname1);
+ sname1c = talloc_asprintf(tctx, "%s:$FOO", sname1);
+ sname1d = talloc_asprintf(tctx, "%s:?D*a", sname1);
+ sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "MStream Two");
+ snamew = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "?Stream*");
+ snamew2 = talloc_asprintf(tctx, "%s\\stream*:%s:$DATA", BASEDIR, "?Stream*");
+ snamer1 = talloc_asprintf(tctx, "%s:%s:$DATA", fname, "BeforeRename");
+
+ printf("(%s) testing stream names\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "Adding two EAs to base file\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.generic.level = RAW_SFILEINFO_EA_SET;
+ sinfo.generic.in.file.fnum = fnum1;
+ sinfo.ea_set.in.num_eas = 2;
+ sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 2);
+ sinfo.ea_set.in.eas[0].flags = 0;
+ sinfo.ea_set.in.eas[0].name.s = "EAONE";
+ sinfo.ea_set.in.eas[0].value = data_blob_string_const("VALUE1");
+ sinfo.ea_set.in.eas[1].flags = 0;
+ sinfo.ea_set.in.eas[1].name.s = "SECONDEA";
+ sinfo.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo");
+
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Make sure the create time of the streams are different from the
+ * base file.
+ */
+ sleep(2);
+ smbcli_close(cli->tree, fnum1);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ torture_comment(tctx, "Adding one EAs to first stream file\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.generic.level = RAW_SFILEINFO_EA_SET;
+ sinfo.generic.in.file.fnum = fnum1;
+ sinfo.ea_set.in.num_eas = 1;
+ sinfo.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1);
+ sinfo.ea_set.in.eas[0].flags = 0;
+ sinfo.ea_set.in.eas[0].name.s = "STREAMEA";
+ sinfo.ea_set.in.eas[0].value = data_blob_string_const("EA_VALUE1");
+
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ status = torture_check_ea(cli, sname1, "STREAMEA", "EA_VALUE1");
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ ZERO_STRUCT(info);
+ info.generic.level = RAW_FILEINFO_ALL_EAS;
+ info.all_eas.in.file.path = sname1;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &info);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * A different stream does not give a sharing violation
+ */
+
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ /*
+ * ... whereas the same stream does with unchanged access/share_access
+ * flags
+ */
+
+ io.ntcreatex.in.fname = sname1;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.ntcreatex.in.fname = sname1b;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ io.ntcreatex.in.fname = sname1c;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /* w2k returns INVALID_PARAMETER */
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
+ io.ntcreatex.in.fname = sname1d;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /* w2k returns INVALID_PARAMETER */
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.ntcreatex.in.fname = snamew;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum3 = io.ntcreatex.out.file.fnum;
+
+ io.ntcreatex.in.fname = snamew2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ ret &= check_stream_list(tctx, cli, fname, 4, four);
+
+ smbcli_close(cli->tree, fnum1);
+ smbcli_close(cli->tree, fnum2);
+ smbcli_close(cli->tree, fnum3);
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_stream_list(tctx, cli, fname, 4, four);
+
+ for (i=0; i < 4; i++) {
+ NTTIME write_time;
+ uint64_t stream_size;
+ char *path = talloc_asprintf(tctx, "%s%s",
+ fname, four[i]);
+
+ char *rpath = talloc_strdup(path, path);
+ char *p = strrchr(rpath, ':');
+ /* eat :$DATA */
+ *p = 0;
+ p--;
+ if (*p == ':') {
+ /* eat ::$DATA */
+ *p = 0;
+ }
+ printf("(%s): i[%u][%s]\n", __location__, i, path);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.fname = path;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ stinfo.generic.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_NTTIME(stinfo.all_info.out.create_time,
+ finfo.all_info.out.create_time);
+ CHECK_NTTIME(stinfo.all_info.out.access_time,
+ finfo.all_info.out.access_time);
+ CHECK_NTTIME(stinfo.all_info.out.write_time,
+ finfo.all_info.out.write_time);
+ CHECK_NTTIME(stinfo.all_info.out.change_time,
+ finfo.all_info.out.change_time);
+ }
+ CHECK_VALUE(stinfo.all_info.out.attrib,
+ finfo.all_info.out.attrib);
+ CHECK_VALUE(stinfo.all_info.out.size,
+ finfo.all_info.out.size);
+ CHECK_VALUE(stinfo.all_info.out.delete_pending,
+ finfo.all_info.out.delete_pending);
+ CHECK_VALUE(stinfo.all_info.out.directory,
+ finfo.all_info.out.directory);
+ CHECK_VALUE(stinfo.all_info.out.ea_size,
+ finfo.all_info.out.ea_size);
+
+ stinfo.generic.level = RAW_FILEINFO_NAME_INFO;
+ stinfo.generic.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_STR(stinfo.name_info.out.fname.s, rpath);
+ }
+
+ write_time = finfo.all_info.out.write_time;
+ write_time += i*1000000;
+ write_time /= 1000000;
+ write_time *= 1000000;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
+ sinfo.basic_info.in.file.fnum = fnum1;
+ sinfo.basic_info.in.write_time = write_time;
+ sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ stream_size = i*8192;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO;
+ sinfo.end_of_file_info.in.file.fnum = fnum1;
+ sinfo.end_of_file_info.in.size = stream_size;
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ stinfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ stinfo.generic.in.file.fnum = fnum1;
+ status = smb_raw_fileinfo(cli->tree, tctx, &stinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_NTTIME(stinfo.all_info.out.write_time,
+ write_time);
+ CHECK_VALUE(stinfo.all_info.out.attrib,
+ finfo.all_info.out.attrib);
+ }
+ CHECK_VALUE(stinfo.all_info.out.size,
+ stream_size);
+ CHECK_VALUE(stinfo.all_info.out.delete_pending,
+ finfo.all_info.out.delete_pending);
+ CHECK_VALUE(stinfo.all_info.out.directory,
+ finfo.all_info.out.directory);
+ CHECK_VALUE(stinfo.all_info.out.ea_size,
+ finfo.all_info.out.ea_size);
+
+ ret &= check_stream_list(tctx, cli, fname, 4, four);
+
+ smbcli_close(cli->tree, fnum1);
+ talloc_free(path);
+ }
+
+ printf("(%s): testing stream renames\n", __location__);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.fname = snamer1;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ ret &= check_stream_list(tctx, cli, fname, 5, five1);
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.fnum = fnum1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_stream_list(tctx, cli, fname, 5, five2);
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.fnum = fnum1;
+ sinfo.rename_information.in.overwrite = false;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ ret &= check_stream_list(tctx, cli, fname, 5, five2);
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.fnum = fnum1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ if (torture_setting_bool(tctx, "samba4", false) ||
+ torture_setting_bool(tctx, "samba3", false)) {
+ /* why should this rename be considered invalid?? */
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ret &= check_stream_list(tctx, cli, fname, 4, four);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ ret &= check_stream_list(tctx, cli, fname, 5, five2);
+ }
+
+
+ /* TODO: we need to test more rename combinations */
+
+done:
+ if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
+ if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
+ if (fnum3 != -1) smbcli_close(cli->tree, fnum3);
+ status = smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test stream names
+*/
+static bool test_stream_names2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream_names2.txt";
+ bool ret = true;
+ int fnum1 = -1;
+ uint8_t i;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("(%s) testing stream names\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum1 = io.ntcreatex.out.file.fnum;
+
+ for (i=0x01; i < 0x7F; i++) {
+ char *path = talloc_asprintf(tctx, "%s:Stream%c0x%02X:$DATA",
+ fname, i, i);
+ NTSTATUS expected;
+
+ switch (i) {
+ case '/':/*0x2F*/
+ case ':':/*0x3A*/
+ case '\\':/*0x5C*/
+ expected = NT_STATUS_OBJECT_NAME_INVALID;
+ break;
+ default:
+ expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ break;
+ }
+
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.fname = path;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, expected)) {
+ printf("(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
+ __location__, fname, isprint(i)?(char)i:' ', i,
+ isprint(i)?"":" (not printable)",
+ nt_errstr(expected));
+ }
+ CHECK_STATUS(status, expected);
+
+ talloc_free(path);
+ }
+
+done:
+ if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
+ status = smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+#define CHECK_CALL_FNUM(call, rightstatus) do { \
+ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
+ sfinfo.generic.in.file.fnum = fnum; \
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo); \
+ if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = false; \
+ } \
+ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \
+ finfo1.generic.in.file.fnum = fnum; \
+ status2 = smb_raw_fileinfo(cli->tree, tctx, &finfo1); \
+ if (!NT_STATUS_IS_OK(status2)) { \
+ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \
+ ret = false; \
+ }} while (0)
+
+/*
+ test stream renames
+*/
+static bool test_stream_rename(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status, status2;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream_rename.txt";
+ const char *sname1, *sname2;
+ union smb_fileinfo finfo1;
+ union smb_setfileinfo sfinfo;
+ bool ret = true;
+ int fnum = -1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "Stream One");
+ sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
+
+ printf("(%s) testing stream renames\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+
+ /* Create two streams. */
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ if (fnum != -1) smbcli_close(cli->tree, fnum);
+
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ if (fnum != -1) smbcli_close(cli->tree, fnum);
+
+ /*
+ * Open the second stream.
+ */
+
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /*
+ * Now rename the second stream onto the first.
+ */
+
+ ZERO_STRUCT(sfinfo);
+
+ sfinfo.rename_information.in.overwrite = 1;
+ sfinfo.rename_information.in.root_fid = 0;
+ sfinfo.rename_information.in.new_name = ":Stream One";
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+
+done:
+ if (fnum != -1) smbcli_close(cli->tree, fnum);
+ status = smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+static bool test_stream_rename2(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname1 = BASEDIR "\\stream.txt";
+ const char *fname2 = BASEDIR "\\stream2.txt";
+ const char *stream_name1 = ":Stream One:$DATA";
+ const char *stream_name2 = ":Stream Two:$DATA";
+ const char *stream_name_default = "::$DATA";
+ const char *sname1;
+ const char *sname2;
+ bool ret = true;
+ int fnum = -1;
+ union smb_setfileinfo sinfo;
+ union smb_rename rio;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream One");
+ sname2 = talloc_asprintf(tctx, "%s:%s", fname1, "Stream Two");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_STD_DELETE|SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE);
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+
+ /* Open/create new stream. */
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /*
+ * Check raw rename with <base>:<stream>.
+ */
+ printf("(%s) Checking NTRENAME of a stream using <base>:<stream>\n",
+ __location__);
+ rio.generic.level = RAW_RENAME_NTRENAME;
+ rio.ntrename.in.old_name = sname1;
+ rio.ntrename.in.new_name = sname2;
+ rio.ntrename.in.attrib = 0;
+ rio.ntrename.in.cluster_size = 0;
+ rio.ntrename.in.flags = RENAME_FLAG_RENAME;
+ status = smb_raw_rename(cli->tree, &rio);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Check raw rename to the default stream using :<stream>.
+ */
+ printf("(%s) Checking NTRENAME to default stream using :<stream>\n",
+ __location__);
+ rio.ntrename.in.new_name = stream_name_default;
+ status = smb_raw_rename(cli->tree, &rio);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ /*
+ * Check raw rename using :<stream>.
+ */
+ printf("(%s) Checking NTRENAME of a stream using :<stream>\n",
+ __location__);
+ rio.ntrename.in.new_name = stream_name2;
+ status = smb_raw_rename(cli->tree, &rio);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Check raw rename of a stream to a file.
+ */
+ printf("(%s) Checking NTRENAME of a stream to a file\n",
+ __location__);
+ rio.ntrename.in.old_name = sname2;
+ rio.ntrename.in.new_name = fname2;
+ status = smb_raw_rename(cli->tree, &rio);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Check raw rename of a file to a stream.
+ */
+ printf("(%s) Checking NTRENAME of a file to a stream\n",
+ __location__);
+
+ /* Create the file. */
+ io.ntcreatex.in.fname = fname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Try the rename. */
+ rio.ntrename.in.old_name = fname2;
+ rio.ntrename.in.new_name = sname1;
+ status = smb_raw_rename(cli->tree, &rio);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ /*
+ * Reopen the stream for trans2 renames.
+ */
+ io.ntcreatex.in.fname = sname2;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /*
+ * Check trans2 rename of a stream using :<stream>.
+ */
+ printf("(%s) Checking trans2 rename of a stream using :<stream>\n",
+ __location__);
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.fnum = fnum;
+ sinfo.rename_information.in.overwrite = 1;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = stream_name1;
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Check trans2 rename of an overwriting stream using :<stream>.
+ */
+ printf("(%s) Checking trans2 rename of an overwriting stream using "
+ ":<stream>\n", __location__);
+
+ /* Create second stream. */
+ io.ntcreatex.in.fname = sname2;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+
+ /* Rename the first stream onto the second. */
+ sinfo.rename_information.in.file.fnum = fnum;
+ sinfo.rename_information.in.new_name = stream_name2;
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ /*
+ * Reopen the stream with the new name.
+ */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /*
+ * Check trans2 rename of a stream using <base>:<stream>.
+ */
+ printf("(%s) Checking trans2 rename of a stream using "
+ "<base>:<stream>\n", __location__);
+ sinfo.rename_information.in.file.fnum = fnum;
+ sinfo.rename_information.in.new_name = sname1;
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_NOT_SUPPORTED);
+
+ /*
+ * Samba3 doesn't currently support renaming a stream to the default
+ * stream. This test does pass on windows.
+ */
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ goto done;
+ }
+
+ /*
+ * Check trans2 rename to the default stream using :<stream>.
+ */
+ printf("(%s) Checking trans2 rename to defaualt stream using "
+ ":<stream>\n", __location__);
+ sinfo.rename_information.in.file.fnum = fnum;
+ sinfo.rename_information.in.new_name = stream_name_default;
+ status = smb_raw_setfileinfo(cli->tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ done:
+ smbcli_close(cli->tree, fnum);
+ status = smbcli_unlink(cli->tree, fname1);
+ status = smbcli_unlink(cli->tree, fname2);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test stream renames
+*/
+static bool test_stream_rename3(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status, status2;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream_rename.txt";
+ const char *sname1, *sname2;
+ union smb_fileinfo finfo1;
+ union smb_setfileinfo sfinfo;
+ bool ret = true;
+ int fnum = -1;
+ int fnum2 = -1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ sname1 = talloc_asprintf(tctx, "%s:%s", fname, "MStream Two:$DATA");
+ sname2 = talloc_asprintf(tctx, "%s:%s:$DaTa", fname, "Second Stream");
+
+ printf("(%s) testing stream renames\n", __location__);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = sname1;
+
+ /* Create two streams. */
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+ if (fnum != -1) smbcli_close(cli->tree, fnum);
+
+ io.ntcreatex.in.fname = sname2;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ if (fnum != -1) smbcli_close(cli->tree, fnum);
+
+ /* open the second stream. */
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Keep a handle to the first stream open. */
+ io.ntcreatex.in.fname = sname1;
+ io.ntcreatex.in.access_mask = SEC_STD_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = io.ntcreatex.out.file.fnum;
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.rename_information.in.overwrite = 1;
+ sfinfo.rename_information.in.root_fid = 0;
+ sfinfo.rename_information.in.new_name = ":MStream Two:$DATA";
+ if (torture_setting_bool(tctx, "samba4", false) ||
+ torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_CALL_FNUM(RENAME_INFORMATION, NT_STATUS_OK);
+ } else {
+ CHECK_CALL_FNUM(RENAME_INFORMATION,
+ NT_STATUS_INVALID_PARAMETER);
+ }
+
+
+done:
+ if (fnum != -1) smbcli_close(cli->tree, fnum);
+ if (fnum2 != -1) smbcli_close(cli->tree, fnum2);
+ status = smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+static bool create_file_with_stream(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *stream)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+
+ ZERO_STRUCT(io);
+
+ /* Create a file with a stream */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = stream;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ return ret;
+}
+
+/* Test how streams interact with create dispositions */
+static bool test_stream_create_disposition(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream;
+ const char *default_stream_name = "::$DATA";
+ const char *stream_list[2];
+ bool ret = false;
+ int fnum = -1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
+
+ stream_list[0] = talloc_asprintf(tctx, ":%s", stream);
+ stream_list[1] = default_stream_name;
+
+ if (!create_file_with_stream(tctx, cli, fname_stream)) {
+ goto done;
+ }
+
+ /* Open the base file with OPEN */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /*
+ * check ntcreatex open: sanity check
+ */
+ printf("(%s) Checking ntcreatex disp: open\n", __location__);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
+ goto done;
+ }
+
+ /*
+ * check ntcreatex overwrite
+ */
+ printf("(%s) Checking ntcreatex disp: overwrite\n", __location__);
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
+ goto done;
+ }
+
+ /*
+ * check ntcreatex overwrite_if
+ */
+ printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
+ smbcli_unlink(cli->tree, fname);
+ if (!create_file_with_stream(tctx, cli, fname_stream)) {
+ goto done;
+ }
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
+ goto done;
+ }
+
+ /*
+ * check ntcreatex supersede
+ */
+ printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
+ smbcli_unlink(cli->tree, fname);
+ if (!create_file_with_stream(tctx, cli, fname_stream)) {
+ goto done;
+ }
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_SUPERSEDE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
+ goto done;
+ }
+
+ /*
+ * check ntcreatex overwrite_if on a stream.
+ */
+ printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
+ __location__);
+ smbcli_unlink(cli->tree, fname);
+ if (!create_file_with_stream(tctx, cli, fname_stream)) {
+ goto done;
+ }
+
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.ntcreatex.in.fname = fname_stream;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+ if (!check_stream_list(tctx, cli, fname, 2, stream_list)) {
+ goto done;
+ }
+
+ /*
+ * check openx overwrite_if
+ */
+ printf("(%s) Checking openx disp: overwrite_if\n", __location__);
+ smbcli_unlink(cli->tree, fname);
+ if (!create_file_with_stream(tctx, cli, fname_stream)) {
+ goto done;
+ }
+
+ io.openx.level = RAW_OPEN_OPENX;
+ io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPEN_FLAGS_DENY_NONE;
+ io.openx.in.search_attrs = 0;
+ io.openx.in.file_attrs = 0;
+ io.openx.in.write_time = 0;
+ io.openx.in.size = 1024*1024;
+ io.openx.in.timeout = 0;
+ io.openx.in.fname = fname;
+
+ io.openx.in.open_func = OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE;
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, io.openx.out.file.fnum);
+ if (!check_stream_list(tctx, cli, fname, 1, &default_stream_name)) {
+ goto done;
+ }
+
+ ret = true;
+
+ done:
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+#if 0
+/* Test streaminfo with enough streams on a file to fill up the buffer. */
+static bool test_stream_large_streaminfo(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+#define LONG_STREAM_SIZE 2
+ char *lstream_name;
+ const char *fname = BASEDIR "\\stream.txt";
+ const char *fname_stream;
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+ union smb_fileinfo finfo;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ lstream_name = talloc_array(tctx, char, LONG_STREAM_SIZE);
+
+ for (i = 0; i < LONG_STREAM_SIZE - 1; i++) {
+ lstream_name[i] = (char)('a' + i%26);
+ }
+ lstream_name[LONG_STREAM_SIZE - 1] = '\0';
+
+ torture_comment(tctx, "(%s) Creating a file with a lot of streams\n", __location__);
+ for (i = 0; i < 10000; i++) {
+ fname_stream = talloc_asprintf(tctx, "%s:%s%d", fname,
+ lstream_name, i);
+ ret = create_file_with_stream(tctx, cli, fname_stream);
+ if (!ret) {
+ goto done;
+ }
+ }
+
+ finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
+ finfo.generic.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, STATUS_BUFFER_OVERFLOW);
+
+ done:
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+#endif
+
+/* Test the effect of setting attributes on a stream. */
+static bool test_stream_attributes(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream_attr.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream;
+ int fnum = -1;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sfinfo;
+ time_t basetime = (time(NULL) - 86400) & ~1;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "(%s) testing attribute setting on stream\n", __location__);
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
+
+ /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
+ ret = create_file_with_stream(tctx, cli, fname_stream);
+ if (!ret) {
+ goto done;
+ }
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
+
+ /* Now open the stream name. */
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL|SEC_FILE_WRITE_ATTRIBUTE);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname_stream;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Change the attributes + time on the stream fnum. */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
+
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.generic.in.file.fnum = fnum;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_setfileinfo failed");
+
+ smbcli_close(cli->tree, fnum);
+ fnum = -1;
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, done, "smb_raw_pathinfo failed");
+
+ torture_assert_int_equal_goto(tctx, finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, FILE_ATTRIBUTE_READONLY, ret, done, "attrib incorrect");
+
+ torture_assert_int_equal_goto(tctx, nt_time_to_unix(finfo.all_info.out.write_time), basetime, ret, done, "time incorrect");
+
+ done:
+
+ if (fnum != -1) {
+ smbcli_close(cli->tree, fnum);
+ }
+ smbcli_unlink(cli->tree, fname);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * A rough approximation of how a windows client creates the streams for use
+ * in the summary tab.
+ */
+static bool test_stream_summary_tab(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream_summary.txt";
+ const char *stream = ":\005SummaryInformation:$DATA";
+ const char *fname_stream = NULL;
+ const char *tmp_stream = ":Updt_\005SummaryInformation:$DATA";
+ const char *fname_tmp_stream = NULL;
+ int fnum = -1;
+ union smb_fileinfo finfo;
+ union smb_rename rio;
+ ssize_t retsize;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ fname_stream = talloc_asprintf(tctx, "%s%s", fname, stream);
+ fname_tmp_stream = talloc_asprintf(tctx, "%s%s", fname,
+ tmp_stream);
+
+ /* Create summary info stream */
+ ret = create_file_with_stream(tctx, cli, fname_stream);
+ if (!ret) {
+ goto done;
+ }
+
+ /* Create summary info tmp update stream */
+ ret = create_file_with_stream(tctx, cli, fname_tmp_stream);
+ if (!ret) {
+ goto done;
+ }
+
+ /* Open tmp stream and write to it */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname_tmp_stream;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = io.ntcreatex.out.file.fnum;
+
+ retsize = smbcli_write(cli->tree, fnum, 0, "test data", 0, 9);
+ CHECK_VALUE(retsize, 9);
+
+ /* close the tmp stream. */
+ smbcli_close(cli->tree, fnum);
+ fnum = -1;
+
+ /* Delete the current stream */
+ smbcli_unlink(cli->tree, fname_stream);
+
+ /* Do the rename. */
+ rio.generic.level = RAW_RENAME_RENAME;
+ rio.rename.in.pattern1 = fname_tmp_stream;
+ rio.rename.in.pattern2 = stream;
+ rio.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+ status = smb_raw_rename(cli->tree, &rio);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to open the tmp stream that we just renamed away. */
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* Query the base file to make sure it's still there. */
+ finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
+ finfo.generic.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+
+ if (fnum != -1) {
+ smbcli_close(cli->tree, fnum);
+ }
+ smbcli_unlink(cli->tree, fname);
+
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/* Test how streams interact with base file permissions */
+/* Regression test for bug:
+ https://bugzilla.samba.org/show_bug.cgi?id=10229
+ bug #10229 - No access check verification on stream files.
+*/
+static bool test_stream_permissions(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ const char *fname = BASEDIR "\\stream_permissions.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sfinfo;
+ int fnum = -1;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_ace ace = {};
+ struct security_descriptor *sd;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
+ "Failed to setup up test directory: " BASEDIR);
+
+ torture_comment(tctx, "(%s) testing permissions on streams\n", __location__);
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream);
+
+ /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
+ ret = create_file_with_stream(tctx, cli, fname_stream);
+ if (!ret) {
+ goto done;
+ }
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_BASIC_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_assert_int_equal_goto(tctx,
+ finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect");
+
+ /* Change the attributes on the base file name. */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_SETATTR;
+ sfinfo.generic.in.file.path = fname;
+ sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY;
+
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try and open the stream name for WRITE_DATA. Should
+ fail with ACCESS_DENIED. */
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname_stream;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ /* Change the attributes on the base file back. */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_SETATTR;
+ sfinfo.generic.in.file.path = fname;
+ sfinfo.setattr.in.attrib = 0;
+
+ status = smb_raw_setpathinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Re-open the file name. */
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC|
+ SEC_FILE_WRITE_ATTRIBUTE);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fnum = io.ntcreatex.out.file.fnum;
+
+ /* Get the existing security descriptor. */
+ ZERO_STRUCT(q);
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.fnum = fnum;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb_raw_fileinfo(cli->tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd = q.query_secdesc.out.sd;
+
+ /* Now add a DENY WRITE security descriptor for Everyone. */
+ torture_comment(tctx, "add a new ACE to the DACL\n");
+
+ ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
+ ace.flags = 0;
+ ace.access_mask = SEC_FILE_WRITE_DATA;
+ ace.trustee = global_sid_World;
+
+ status = security_descriptor_dacl_add(sd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* security_descriptor_dacl_add adds to the *end* of
+ the ace array, we need it at the start. Swap.. */
+ ace = sd->dacl->aces[0];
+ sd->dacl->aces[0] = sd->dacl->aces[sd->dacl->num_aces-1];
+ sd->dacl->aces[sd->dacl->num_aces-1] = ace;
+
+ ZERO_STRUCT(set);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.fnum = fnum;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb_raw_setfileinfo(cli->tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+ fnum = -1;
+
+ /* Try and open the stream name for WRITE_DATA. Should
+ fail with ACCESS_DENIED. */
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.share_access = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname_stream;
+
+ status = smb_raw_open(cli->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ done:
+
+ if (fnum != -1) {
+ smbcli_close(cli->tree, fnum);
+ }
+ smbcli_unlink(cli->tree, fname);
+
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of streams calls
+*/
+struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx)
+{
+ struct torture_suite *suite = torture_suite_create(tctx, "streams");
+
+ torture_suite_add_1smb_test(suite, "dir", test_stream_dir);
+ torture_suite_add_1smb_test(suite, "io", test_stream_io);
+ torture_suite_add_1smb_test(suite, "sharemodes", test_stream_sharemodes);
+ torture_suite_add_1smb_test(suite, "delete", test_stream_delete);
+ torture_suite_add_1smb_test(suite, "names", test_stream_names);
+ torture_suite_add_1smb_test(suite, "names2", test_stream_names2);
+ torture_suite_add_1smb_test(suite, "rename", test_stream_rename);
+ torture_suite_add_1smb_test(suite, "rename2", test_stream_rename2);
+ torture_suite_add_1smb_test(suite, "rename3", test_stream_rename3);
+ torture_suite_add_1smb_test(suite, "createdisp",
+ test_stream_create_disposition);
+ torture_suite_add_1smb_test(suite, "attr", test_stream_attributes);
+ torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab);
+ torture_suite_add_1smb_test(suite, "perms", test_stream_permissions);
+
+#if 0
+ torture_suite_add_1smb_test(suite, "LARGESTREAMINFO",
+ test_stream_large_streaminfo);
+#endif
+
+ return suite;
+}
diff --git a/source4/torture/raw/tconrate.c b/source4/torture/raw/tconrate.c
new file mode 100644
index 0000000..e514e7a
--- /dev/null
+++ b/source4/torture/raw/tconrate.c
@@ -0,0 +1,208 @@
+/*
+ SMB tree connection rate test
+
+ Copyright (C) 2006-2007 James Peach
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/smbtorture.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+
+#include "system/filesys.h"
+#include "system/shmem.h"
+#include "torture/raw/proto.h"
+
+#define TIME_LIMIT_SECS 30
+#define usec_to_sec(s) ((s) / 1000000)
+
+/* Map a shared memory buffer of at least nelem counters. */
+static void * map_count_buffer(unsigned nelem, size_t elemsz)
+{
+ void * buf;
+ size_t bufsz;
+ size_t pagesz = getpagesize();
+
+ bufsz = nelem * elemsz;
+ bufsz = (bufsz + pagesz) % pagesz; /* round up to pagesz */
+
+#ifdef MAP_ANON
+ /* BSD */
+ buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED,
+ -1 /* fd */, 0 /* offset */);
+#else
+ buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
+ open("/dev/zero", O_RDWR), 0 /* offset */);
+#endif
+
+ if (buf == MAP_FAILED) {
+ printf("failed to map count buffer: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ return buf;
+
+}
+
+static int fork_tcon_client(struct torture_context *tctx,
+ int *tcon_count, unsigned tcon_timelimit,
+ const char *host, const char *share)
+{
+ pid_t child;
+ struct smbcli_state *cli;
+ struct timeval end;
+ struct timeval now;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ child = fork();
+ if (child == -1) {
+ printf("failed to fork child: %s\n,", strerror(errno));
+ return -1;
+ } else if (child != 0) {
+ /* Parent, just return. */
+ return 0;
+ }
+
+ /* Child. Just make as many connections as possible within the
+ * time limit. Don't bother synchronising the child start times
+ * because it's probably not work the effort, and a bit of startup
+ * jitter is probably a more realistic test.
+ */
+
+
+ end = timeval_current();
+ now = timeval_current();
+ end.tv_sec += tcon_timelimit;
+ *tcon_count = 0;
+
+ while (timeval_compare(&now, &end) == -1) {
+ NTSTATUS status;
+
+ status = smbcli_full_connection(NULL, &cli,
+ host, lpcfg_smb_ports(tctx->lp_ctx), share,
+ NULL, lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("failed to connect to //%s/%s: %s\n",
+ host, share, nt_errstr(status));
+ goto done;
+ }
+
+ smbcli_tdis(cli);
+ talloc_free(cli);
+
+ *tcon_count = *tcon_count + 1;
+ now = timeval_current();
+ }
+
+done:
+ exit(0);
+}
+
+static bool children_remain(void)
+{
+ bool res;
+
+ /* Reap as many children as possible. */
+ for (;;) {
+ pid_t ret = waitpid(-1, NULL, WNOHANG);
+ if (ret == 0) {
+ /* no children ready */
+ res = true;
+ break;
+ }
+ if (ret == -1) {
+ /* no children left. maybe */
+ res = errno != ECHILD;
+ break;
+ }
+ }
+ return res;
+}
+
+static double rate_convert_secs(unsigned count,
+ const struct timeval *start, const struct timeval *end)
+{
+ return (double)count /
+ usec_to_sec((double)usec_time_diff(end, start));
+}
+
+/* Test the rate at which the server will accept connections. */
+bool torture_bench_treeconnect(struct torture_context *tctx)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+
+ int timelimit = torture_setting_int(tctx, "timelimit",
+ TIME_LIMIT_SECS);
+ int nprocs = torture_setting_int(tctx, "nprocs", 4);
+
+ int *curr_counts = map_count_buffer(nprocs, sizeof(int));
+ int *last_counts = talloc_zero_array(tctx, int, nprocs);
+
+ struct timeval now, last, start;
+ int i, delta;
+
+ torture_assert(tctx, nprocs > 0, "bad proc count");
+ torture_assert(tctx, timelimit > 0, "bad timelimit");
+ torture_assert(tctx, curr_counts, "allocation failure");
+ torture_assert(tctx, last_counts, "allocation failure");
+
+ start = last = timeval_current();
+ for (i = 0; i < nprocs; ++i) {
+ fork_tcon_client(tctx, &curr_counts[i], timelimit, host, share);
+ }
+
+ while (children_remain()) {
+
+ sleep(1);
+ now = timeval_current();
+
+ for (i = 0, delta = 0; i < nprocs; ++i) {
+ delta += curr_counts[i] - last_counts[i];
+ }
+
+ printf("%u connections/sec\n",
+ (unsigned)rate_convert_secs(delta, &last, &now));
+
+ memcpy(last_counts, curr_counts, nprocs * sizeof(int));
+ last = timeval_current();
+ }
+
+ now = timeval_current();
+
+ for (i = 0, delta = 0; i < nprocs; ++i) {
+ delta += curr_counts[i];
+ }
+
+ printf("TOTAL: %u connections/sec over %u secs\n",
+ (unsigned)rate_convert_secs(delta, &start, &now),
+ timelimit);
+ return true;
+}
+
+/* vim: set sts=8 sw=8 : */
diff --git a/source4/torture/raw/unlink.c b/source4/torture/raw/unlink.c
new file mode 100644
index 0000000..53059aa
--- /dev/null
+++ b/source4/torture/raw/unlink.c
@@ -0,0 +1,470 @@
+/*
+ Unix SMB/CIFS implementation.
+ unlink test suite
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "system/filesys.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ printf("(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define BASEDIR "\\testunlink"
+
+/*
+ test unlink ops
+*/
+static bool test_unlink(struct torture_context *tctx, struct smbcli_state *cli)
+{
+ union smb_unlink io;
+ NTSTATUS status;
+ bool ret = true;
+ const char *fname = BASEDIR "\\test.txt";
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ printf("Trying non-existent file\n");
+ io.unlink.in.pattern = fname;
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
+
+ io.unlink.in.pattern = fname;
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Trying a hidden file\n");
+ smbcli_close(cli->tree, smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE));
+ torture_set_file_attribute(cli->tree, fname, FILE_ATTRIBUTE_HIDDEN);
+
+ io.unlink.in.pattern = fname;
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_NO_SUCH_FILE);
+
+ io.unlink.in.pattern = fname;
+ io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.unlink.in.pattern = fname;
+ io.unlink.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ printf("Trying a directory\n");
+ io.unlink.in.pattern = BASEDIR;
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+
+ io.unlink.in.pattern = BASEDIR;
+ io.unlink.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+
+ printf("Trying a bad path\n");
+ io.unlink.in.pattern = "..";
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ io.unlink.in.pattern = "\\..";
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ io.unlink.in.pattern = BASEDIR "\\..\\..";
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+
+ io.unlink.in.pattern = BASEDIR "\\..";
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test delete on close
+*/
+static bool test_delete_on_close(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_open op;
+ union smb_unlink io;
+ struct smb_rmdir dio;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum, fnum2;
+ const char *fname = BASEDIR "\\test.txt";
+ const char *dname = BASEDIR "\\test.dir";
+ const char *inside = BASEDIR "\\test.dir\\test.txt";
+ union smb_setfileinfo sfinfo;
+
+ torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
+
+ dio.in.path = dname;
+
+ io.unlink.in.pattern = fname;
+ io.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ printf("Testing with delete_on_close 0\n");
+ fnum = create_complex_file(cli, tctx, fname);
+
+ sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 0;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Testing with delete_on_close 1\n");
+ fnum = create_complex_file(cli, tctx, fname);
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_unlink(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+
+ printf("Testing with directory and delete_on_close 0\n");
+ status = create_directory_handle(cli->tree, dname, &fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 0;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ printf("Testing with directory delete_on_close 1\n");
+ status = create_directory_handle(cli->tree, dname, &fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+
+ /*
+ * Known deficiency, also skipped in base-delete.
+ */
+
+ printf("Testing with non-empty directory delete_on_close\n");
+ status = create_directory_handle(cli->tree, dname, &fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fnum2 = create_complex_file(cli, tctx, inside);
+
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
+
+ sfinfo.disposition_info.in.file.fnum = fnum2;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
+
+ smbcli_close(cli->tree, fnum2);
+
+ status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ }
+
+ printf("Testing open dir with delete_on_close\n");
+ status = create_directory_handle(cli->tree, dname, &fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+ fnum2 = create_complex_file(cli, tctx, inside);
+ smbcli_close(cli->tree, fnum2);
+
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
+
+ smbcli_deltree(cli->tree, dname);
+
+ printf("Testing double open dir with second delete_on_close\n");
+ status = create_directory_handle(cli->tree, dname, &fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smbcli_close(cli->tree, fnum);
+
+ fnum2 = create_complex_file(cli, tctx, inside);
+ smbcli_close(cli->tree, fnum2);
+
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = op.ntcreatex.out.file.fnum;
+
+ smbcli_close(cli->tree, fnum2);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
+
+ smbcli_deltree(cli->tree, dname);
+
+ printf("Testing pre-existing open dir with second delete_on_close\n");
+ status = create_directory_handle(cli->tree, dname, &fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smbcli_close(cli->tree, fnum);
+
+ fnum = create_complex_file(cli, tctx, inside);
+ smbcli_close(cli->tree, fnum);
+
+ /* we have a dir with a file in it, no handles open */
+
+ op.generic.level = RAW_OPEN_NTCREATEX;
+ op.ntcreatex.in.root_fid.fnum = 0;
+ op.ntcreatex.in.flags = 0;
+ op.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY |NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ op.ntcreatex.in.alloc_size = 0;
+ op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ op.ntcreatex.in.security_flags = 0;
+ op.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum = op.ntcreatex.out.file.fnum;
+
+ /* open without delete on close */
+ op.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ status = smb_raw_open(cli->tree, tctx, &op);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fnum2 = op.ntcreatex.out.file.fnum;
+
+ /* close 2nd file handle */
+ smbcli_close(cli->tree, fnum2);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
+
+
+ smbcli_close(cli->tree, fnum);
+
+ status = smb_raw_rmdir(cli->tree, &dio);
+ CHECK_STATUS(status, NT_STATUS_DIRECTORY_NOT_EMPTY);
+
+done:
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+struct unlink_defer_cli_state {
+ struct torture_context *tctx;
+ struct smbcli_state *cli1;
+};
+
+/*
+ * A handler function for oplock break requests. Ack it as a break to none
+ */
+static bool oplock_handler_ack_to_none(struct smbcli_transport *transport,
+ uint16_t tid, uint16_t fnum,
+ uint8_t level, void *private_data)
+{
+ struct unlink_defer_cli_state *ud_cli_state =
+ (struct unlink_defer_cli_state *)private_data;
+ union smb_setfileinfo sfinfo;
+ bool ret;
+ struct smbcli_request *req = NULL;
+
+ torture_comment(ud_cli_state->tctx, "delete the file before sending "
+ "the ack.");
+
+ /* cli1: set delete on close */
+ sfinfo.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
+ sfinfo.disposition_info.in.file.fnum = fnum;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ req = smb_raw_setfileinfo_send(ud_cli_state->cli1->tree, &sfinfo);
+ if (!req) {
+ torture_comment(ud_cli_state->tctx, "smb_raw_setfileinfo_send "
+ "failed.");
+ }
+
+ smbcli_close(ud_cli_state->cli1->tree, fnum);
+
+ torture_comment(ud_cli_state->tctx, "Acking the oplock to NONE\n");
+
+ ret = smbcli_oplock_ack(ud_cli_state->cli1->tree, fnum,
+ OPLOCK_BREAK_TO_NONE);
+
+ return ret;
+}
+
+static bool test_unlink_defer(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ const char *fname = BASEDIR "\\test_unlink_defer.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_unlink unl;
+ struct unlink_defer_cli_state ud_cli_state = {};
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+
+ /* cleanup */
+ smbcli_unlink(cli1->tree, fname);
+
+ ud_cli_state.tctx = tctx;
+ ud_cli_state.cli1 = cli1;
+
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none,
+ &ud_cli_state);
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = fname;
+
+ /* cli1: open file with a batch oplock. */
+ io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+ NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cli2: Try to unlink it, but block on the oplock */
+ torture_comment(tctx, "Try an unlink (should defer the open\n");
+ unl.unlink.in.pattern = fname;
+ unl.unlink.in.attrib = 0;
+ status = smb_raw_unlink(cli2->tree, &unl);
+
+done:
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of unlink calls
+*/
+struct torture_suite *torture_raw_unlink(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "unlink");
+
+ torture_suite_add_1smb_test(suite, "unlink", test_unlink);
+ torture_suite_add_1smb_test(suite, "delete_on_close", test_delete_on_close);
+ torture_suite_add_2smb_test(suite, "unlink-defer", test_unlink_defer);
+
+ return suite;
+}
diff --git a/source4/torture/raw/write.c b/source4/torture/raw/write.c
new file mode 100644
index 0000000..e47225a
--- /dev/null
+++ b/source4/torture/raw/write.c
@@ -0,0 +1,799 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for various write operations
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/raw/proto.h"
+#include "libcli/raw/raw_proto.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_fail(tctx, talloc_asprintf(tctx, "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct))); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_fail(tctx, talloc_asprintf(tctx, "(%s) Incorrect value %s=%d - should be %d\n", \
+ __location__, #v, v, correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_BUFFER(buf, seed, len) do { \
+ if (!check_buffer(tctx, buf, seed, len, __location__)) { \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_ALL_INFO(v, field) do { \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
+ finfo.all_info.in.file.path = fname; \
+ status = smb_raw_pathinfo(cli->tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if ((v) != finfo.all_info.out.field) { \
+ torture_comment(tctx, "(%s) wrong value for field %s %.0f - %.0f\n", \
+ __location__, #field, (double)v, (double)finfo.all_info.out.field); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+
+#define BASEDIR "\\testwrite"
+
+
+/*
+ setup a random buffer based on a seed
+*/
+static void setup_buffer(uint8_t *buf, unsigned int seed, int len)
+{
+ int i;
+ srandom(seed);
+ for (i=0;i<len;i++) buf[i] = random();
+}
+
+/*
+ check a random buffer based on a seed
+*/
+static bool check_buffer(struct torture_context *tctx,
+ uint8_t *buf, unsigned int seed, int len, const char *location)
+{
+ int i;
+ srandom(seed);
+ for (i=0;i<len;i++) {
+ uint8_t v = random();
+ if (buf[i] != v) {
+ torture_fail(tctx, talloc_asprintf(tctx, "Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
+ location, i, buf[i], v));
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ test write ops
+*/
+static bool test_write(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_write io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned int seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ torture_fail(tctx, "failed to setup basedir");
+ }
+
+ torture_comment(tctx, "Testing RAW_WRITE_WRITE\n");
+ io.generic.level = RAW_WRITE_WRITE;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ ret = false;
+ torture_fail_goto(tctx, done,
+ talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
+ }
+
+ torture_comment(tctx, "Trying zero write\n");
+ io.write.in.file.fnum = fnum;
+ io.write.in.count = 0;
+ io.write.in.offset = 0;
+ io.write.in.remaining = 0;
+ io.write.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.write.out.nwritten, 0);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying small write\n");
+ io.write.in.count = 9;
+ io.write.in.offset = 4;
+ io.write.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying large write\n");
+ io.write.in.count = 4000;
+ io.write.in.offset = 0;
+ io.write.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.write.out.nwritten, 4000);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ torture_comment(tctx, "Trying bad fnum\n");
+ io.write.in.file.fnum = fnum+1;
+ io.write.in.count = 4000;
+ io.write.in.offset = 0;
+ io.write.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "Setting file as sparse\n");
+ status = torture_set_sparse(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ torture_comment(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.write.in.file.fnum = fnum;
+ io.write.in.count = 4000;
+ io.write.in.offset = 0xFFFFFFFF - 2000;
+ io.write.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.write.out.nwritten, 4000);
+ CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test writex ops
+*/
+static bool test_writex(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_write io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum, i;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned int seed = time(NULL);
+ union smb_fileinfo finfo;
+ int max_bits=63;
+
+ if (!torture_setting_bool(tctx, "dangerous", false)) {
+ max_bits=33;
+ torture_comment(tctx, "dangerous not set - limiting range of test to 2^%d\n", max_bits);
+ }
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ if (!cli->transport->negotiate.lockread_supported) {
+ torture_comment(tctx, "Server does not support writeunlock - skipping\n");
+ return true;
+ }
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ torture_fail(tctx, "failed to setup basedir");
+ }
+
+ torture_comment(tctx, "Testing RAW_WRITE_WRITEX\n");
+ io.generic.level = RAW_WRITE_WRITEX;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
+ }
+
+ torture_comment(tctx, "Trying zero write\n");
+ io.writex.in.file.fnum = fnum;
+ io.writex.in.offset = 0;
+ io.writex.in.wmode = 0;
+ io.writex.in.remaining = 0;
+ io.writex.in.count = 0;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, 0);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying small write\n");
+ io.writex.in.count = 9;
+ io.writex.in.offset = 4;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying large write\n");
+ io.writex.in.count = 4000;
+ io.writex.in.offset = 0;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, 4000);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ torture_comment(tctx, "Trying bad fnum\n");
+ io.writex.in.file.fnum = fnum+1;
+ io.writex.in.count = 4000;
+ io.writex.in.offset = 0;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "Testing wmode\n");
+ io.writex.in.file.fnum = fnum;
+ io.writex.in.count = 1;
+ io.writex.in.offset = 0;
+ io.writex.in.wmode = 1;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
+
+ io.writex.in.wmode = 2;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
+
+
+ torture_comment(tctx, "Trying locked region\n");
+ cli->session->pid++;
+ if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to lock file at %s\n", __location__));
+ }
+ cli->session->pid--;
+ io.writex.in.wmode = 0;
+ io.writex.in.count = 4;
+ io.writex.in.offset = 0;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+ torture_comment(tctx, "Setting file as sparse\n");
+ status = torture_set_sparse(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
+ }
+
+ torture_comment(tctx, "Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.writex.in.file.fnum = fnum;
+ io.writex.in.count = 4000;
+ io.writex.in.offset = 0xFFFFFFFF - 2000;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, 4000);
+ CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ for (i=33;i<max_bits;i++) {
+ torture_comment(tctx, "Trying 2^%d offset\n", i);
+ setup_buffer(buf, seed+1, maxsize);
+ io.writex.in.file.fnum = fnum;
+ io.writex.in.count = 4000;
+ io.writex.in.offset = ((uint64_t)1) << i;
+ io.writex.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ if (i>33 &&
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ break;
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writex.out.nwritten, 4000);
+ CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed+1, 4000);
+ }
+ torture_comment(tctx, "limit is 2^%d\n", i);
+
+ setup_buffer(buf, seed, maxsize);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test write unlock ops
+*/
+static bool test_writeunlock(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_write io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned int seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ if (!cli->transport->negotiate.lockread_supported) {
+ torture_skip(tctx, "Server does not support writeunlock - skipping\n");
+ }
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ torture_fail(tctx, "failed to setup basedir");
+ }
+
+ torture_comment(tctx, "Testing RAW_WRITE_WRITEUNLOCK\n");
+ io.generic.level = RAW_WRITE_WRITEUNLOCK;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
+ }
+
+ torture_comment(tctx, "Trying zero write\n");
+ io.writeunlock.in.file.fnum = fnum;
+ io.writeunlock.in.count = 0;
+ io.writeunlock.in.offset = 0;
+ io.writeunlock.in.remaining = 0;
+ io.writeunlock.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying small write\n");
+ io.writeunlock.in.count = 9;
+ io.writeunlock.in.offset = 4;
+ io.writeunlock.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+ smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
+ 0, WRITE_LOCK);
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying large write\n");
+ io.writeunlock.in.count = 4000;
+ io.writeunlock.in.offset = 0;
+ io.writeunlock.in.data = buf;
+ smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
+ 0, WRITE_LOCK);
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
+
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ torture_comment(tctx, "Trying bad fnum\n");
+ io.writeunlock.in.file.fnum = fnum+1;
+ io.writeunlock.in.count = 4000;
+ io.writeunlock.in.offset = 0;
+ io.writeunlock.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "Setting file as sparse\n");
+ status = torture_set_sparse(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
+ }
+
+ torture_comment(tctx, "Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.writeunlock.in.file.fnum = fnum;
+ io.writeunlock.in.count = 4000;
+ io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
+ io.writeunlock.in.data = buf;
+ smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
+ 0, WRITE_LOCK);
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
+ CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+
+/*
+ test write close ops
+*/
+static bool test_writeclose(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ union smb_write io;
+ NTSTATUS status;
+ bool ret = true;
+ int fnum;
+ uint8_t *buf;
+ const int maxsize = 90000;
+ const char *fname = BASEDIR "\\test.txt";
+ unsigned int seed = time(NULL);
+ union smb_fileinfo finfo;
+
+ buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+ if (!torture_setting_bool(tctx, "writeclose_support", true)) {
+ torture_skip(tctx, "Server does not support writeclose - skipping\n");
+ }
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ torture_fail(tctx, "failed to setup basedir");
+ }
+
+ torture_comment(tctx, "Testing RAW_WRITE_WRITECLOSE\n");
+ io.generic.level = RAW_WRITE_WRITECLOSE;
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
+ }
+
+ torture_comment(tctx, "Trying zero write\n");
+ io.writeclose.in.file.fnum = fnum;
+ io.writeclose.in.count = 0;
+ io.writeclose.in.offset = 0;
+ io.writeclose.in.mtime = 0;
+ io.writeclose.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
+
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying small write\n");
+ io.writeclose.in.count = 9;
+ io.writeclose.in.offset = 4;
+ io.writeclose.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.file.fnum = fnum;
+
+ if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.file.fnum = fnum;
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf+4, seed, 9);
+ CHECK_VALUE(IVAL(buf,0), 0);
+
+ setup_buffer(buf, seed, maxsize);
+
+ torture_comment(tctx, "Trying large write\n");
+ io.writeclose.in.count = 4000;
+ io.writeclose.in.offset = 0;
+ io.writeclose.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeclose.out.nwritten, 4000);
+
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.file.fnum = fnum;
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+ torture_comment(tctx, "Trying bad fnum\n");
+ io.writeclose.in.file.fnum = fnum+1;
+ io.writeclose.in.count = 4000;
+ io.writeclose.in.offset = 0;
+ io.writeclose.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
+
+ torture_comment(tctx, "Setting file as sparse\n");
+ status = torture_set_sparse(cli->tree, fnum);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
+ }
+
+ torture_comment(tctx, "Trying 2^32 offset\n");
+ setup_buffer(buf, seed, maxsize);
+ io.writeclose.in.file.fnum = fnum;
+ io.writeclose.in.count = 4000;
+ io.writeclose.in.offset = 0xFFFFFFFF - 2000;
+ io.writeclose.in.data = buf;
+ status = smb_raw_write(cli->tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(io.writeclose.out.nwritten, 4000);
+ CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+ io.writeclose.in.file.fnum = fnum;
+
+ memset(buf, 0, maxsize);
+ if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
+ ret = false;
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
+ }
+ CHECK_BUFFER(buf, seed, 4000);
+
+done:
+ smbcli_close(cli->tree, fnum);
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test a deliberately bad SMB1 write.
+*/
+static bool test_bad_write(struct torture_context *tctx,
+ struct smbcli_state *cli)
+{
+ bool ret = false;
+ int fnum = -1;
+ struct smbcli_request *req = NULL;
+ const char *fname = BASEDIR "\\badwrite.txt";
+ bool ok = false;
+
+ if (!torture_setup_dir(cli, BASEDIR)) {
+ torture_fail(tctx, "failed to setup basedir");
+ }
+
+ torture_comment(tctx, "Testing RAW_BAD_WRITE\n");
+
+ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+ if (fnum == -1) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "Failed to create %s - %s\n",
+ fname,
+ smbcli_errstr(cli->tree)));
+ }
+
+ req = smbcli_request_setup(cli->tree,
+ SMBwrite,
+ 5,
+ 0);
+ if (req == NULL) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx, "talloc fail\n"));
+ }
+
+ SSVAL(req->out.vwv, VWV(0), fnum);
+ SSVAL(req->out.vwv, VWV(1), 65535); /* bad write length. */
+ SIVAL(req->out.vwv, VWV(2), 0); /* offset */
+ SSVAL(req->out.vwv, VWV(4), 0); /* remaining. */
+
+ if (!smbcli_request_send(req)) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx, "Send failed\n"));
+ }
+
+ if (!smbcli_request_receive(req)) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx, "Receive failed\n"));
+ }
+
+ /*
+ * Check for expected error codes.
+ * ntvfs returns NT_STATUS_UNSUCCESSFUL.
+ */
+ ok = (NT_STATUS_EQUAL(req->status, NT_STATUS_INVALID_PARAMETER) ||
+ NT_STATUS_EQUAL(req->status, NT_STATUS_UNSUCCESSFUL));
+
+ if (!ok) {
+ torture_fail_goto(tctx,
+ done,
+ talloc_asprintf(tctx,
+ "Should have returned "
+ "NT_STATUS_INVALID_PARAMETER or "
+ "NT_STATUS_UNSUCCESSFUL "
+ "got %s\n",
+ nt_errstr(req->status)));
+ }
+
+ ret = true;
+
+done:
+ if (req != NULL) {
+ smbcli_request_destroy(req);
+ }
+ if (fnum != -1) {
+ smbcli_close(cli->tree, fnum);
+ }
+ smb_raw_exit(cli->session);
+ smbcli_deltree(cli->tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of write calls
+*/
+struct torture_suite *torture_raw_write(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "write");
+
+ torture_suite_add_1smb_test(suite, "write", test_write);
+ torture_suite_add_1smb_test(suite, "write unlock", test_writeunlock);
+ torture_suite_add_1smb_test(suite, "write close", test_writeclose);
+ torture_suite_add_1smb_test(suite, "writex", test_writex);
+ torture_suite_add_1smb_test(suite, "bad-write", test_bad_write);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/alter_context.c b/source4/torture/rpc/alter_context.c
new file mode 100644
index 0000000..9b69727
--- /dev/null
+++ b/source4/torture/rpc/alter_context.c
@@ -0,0 +1,112 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for dcerpc alter_context operations
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_dssetup.h"
+#include "torture/rpc/torture_rpc.h"
+
+bool torture_rpc_alter_context(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p, *p2, *p3;
+ struct policy_handle *handle;
+ struct ndr_interface_table tmptbl;
+ bool ret = true;
+
+ torture_comment(torture, "opening LSA connection\n");
+ status = torture_rpc_connection(torture, &p, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(torture, status, "connecting");
+
+ torture_comment(torture, "Testing change of primary context\n");
+ status = dcerpc_alter_context(p, torture, &p->syntax, &p->transfer_syntax);
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_alter_context failed");
+
+ if (!test_lsa_OpenPolicy2(p->binding_handle, torture, &handle)) {
+ ret = false;
+ }
+
+ torture_comment(torture, "Testing change of primary context\n");
+ status = dcerpc_alter_context(p, torture, &p->syntax, &p->transfer_syntax);
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_alter_context failed");
+
+ torture_comment(torture, "Opening secondary DSSETUP context\n");
+ status = dcerpc_secondary_context(p, &p2, &ndr_table_dssetup);
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_alter_context failed");
+
+ torture_comment(torture, "Testing change of primary context\n");
+ status = dcerpc_alter_context(p2, torture, &p2->syntax, &p2->transfer_syntax);
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_alter_context failed");
+
+ tmptbl = ndr_table_dssetup;
+ tmptbl.syntax_id.if_version += 100;
+ torture_comment(torture, "Opening bad secondary connection\n");
+ status = dcerpc_secondary_context(p, &p3, &tmptbl);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX,
+ "dcerpc_alter_context with wrong version should fail");
+
+ torture_comment(torture, "Testing DSSETUP pipe operations\n");
+ ret &= test_DsRoleGetPrimaryDomainInformation(torture, p2);
+
+ if (handle) {
+ ret &= test_lsa_Close(p->binding_handle, torture, handle);
+ }
+
+ torture_comment(torture, "Testing change of primary context\n");
+ status = dcerpc_alter_context(p, torture, &p->syntax, &p->transfer_syntax);
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_alter_context failed");
+
+ ret &= test_lsa_OpenPolicy2(p->binding_handle, torture, &handle);
+
+ if (handle) {
+ ret &= test_lsa_Close(p->binding_handle, torture, handle);
+ }
+
+ torture_comment(torture, "Testing change of primary context\n");
+ status = dcerpc_alter_context(p, torture, &p2->syntax, &p2->transfer_syntax);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+
+ ret &= test_lsa_OpenPolicy2_ex(p->binding_handle, torture, &handle,
+ NT_STATUS_CONNECTION_DISCONNECTED,
+ NT_STATUS_CONNECTION_RESET);
+
+ torture_assert(torture, !dcerpc_binding_handle_is_connected(p->binding_handle),
+ "dcerpc disconnected");
+
+ return ret;
+ }
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_alter_context failed");
+
+ torture_comment(torture, "Testing DSSETUP pipe operations - should fault\n");
+ ret &= test_DsRoleGetPrimaryDomainInformation_ext(torture, p, NT_STATUS_RPC_BAD_STUB_DATA);
+
+ ret &= test_lsa_OpenPolicy2(p->binding_handle, torture, &handle);
+
+ if (handle) {
+ ret &= test_lsa_Close(p->binding_handle, torture, handle);
+ }
+
+ torture_comment(torture, "Testing DSSETUP pipe operations\n");
+
+ ret &= test_DsRoleGetPrimaryDomainInformation(torture, p2);
+
+ return ret;
+}
diff --git a/source4/torture/rpc/async_bind.c b/source4/torture/rpc/async_bind.c
new file mode 100644
index 0000000..e86d0ab
--- /dev/null
+++ b/source4/torture/rpc/async_bind.c
@@ -0,0 +1,86 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc torture tests
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Rafal Szczesniak 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+
+/*
+ This test initiates multiple rpc bind requests and verifies
+ whether all of them are served.
+*/
+
+
+bool torture_async_bind(struct torture_context *torture)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ int i;
+ const char *binding_string;
+ struct cli_credentials *creds;
+ extern int torture_numasync;
+
+ struct composite_context **bind_req;
+ struct dcerpc_pipe **pipes;
+ const struct ndr_interface_table **table;
+
+ if (!torture_setting_bool(torture, "async", false)) {
+ printf("async bind test disabled - enable async tests to use\n");
+ return true;
+ }
+
+ binding_string = torture_setting_string(torture, "binding", NULL);
+
+ /* talloc context */
+ mem_ctx = talloc_init("torture_async_bind");
+ if (mem_ctx == NULL) return false;
+
+ bind_req = talloc_array(torture, struct composite_context*, torture_numasync);
+ if (bind_req == NULL) return false;
+ pipes = talloc_array(torture, struct dcerpc_pipe*, torture_numasync);
+ if (pipes == NULL) return false;
+ table = talloc_array(torture, const struct ndr_interface_table*, torture_numasync);
+ if (table == NULL) return false;
+
+ /* credentials */
+ creds = samba_cmdline_get_creds();
+
+ /* send bind requests */
+ for (i = 0; i < torture_numasync; i++) {
+ table[i] = &ndr_table_lsarpc;
+ bind_req[i] = dcerpc_pipe_connect_send(mem_ctx, binding_string,
+ table[i], creds, torture->ev, torture->lp_ctx);
+ }
+
+ /* recv bind requests */
+ for (i = 0; i < torture_numasync; i++) {
+ status = dcerpc_pipe_connect_recv(bind_req[i], mem_ctx, &pipes[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("async rpc connection failed: %s\n", nt_errstr(status));
+ return false;
+ }
+ }
+
+ talloc_free(mem_ctx);
+ return true;
+}
diff --git a/source4/torture/rpc/atsvc.c b/source4/torture/rpc/atsvc.c
new file mode 100644
index 0000000..729a7ca
--- /dev/null
+++ b/source4/torture/rpc/atsvc.c
@@ -0,0 +1,138 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for atsvc rpc operations
+
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_atsvc_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+static bool test_JobGetInfo(struct dcerpc_pipe *p, struct torture_context *tctx, uint32_t job_id)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct atsvc_JobGetInfo r;
+ struct atsvc_JobInfo *info = talloc(tctx, struct atsvc_JobInfo);
+ if (!info) {
+ return false;
+ }
+
+ r.in.servername = dcerpc_server_name(p);
+ r.in.job_id = job_id;
+ r.out.job_info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_atsvc_JobGetInfo_r(b, tctx, &r),
+ "JobGetInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "JobGetInfo failed");
+
+ return true;
+}
+
+static bool test_JobDel(struct dcerpc_pipe *p, struct torture_context *tctx, uint32_t min_job_id,
+ uint32_t max_job_id)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct atsvc_JobDel r;
+
+ r.in.servername = dcerpc_server_name(p);
+ r.in.min_job_id = min_job_id;
+ r.in.max_job_id = max_job_id;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_atsvc_JobDel_r(b, tctx, &r),
+ "JobDel failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "JobDel failed");
+
+ return true;
+}
+
+static bool test_JobEnum(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct atsvc_JobEnum r;
+ struct atsvc_enum_ctr ctr;
+ uint32_t resume_handle = 0, i, total_entries = 0;
+
+ bool ret = true;
+
+ r.in.servername = dcerpc_server_name(p);
+ ctr.entries_read = 0;
+ ctr.first_entry = NULL;
+ r.in.ctr = r.out.ctr = &ctr;
+ r.in.preferred_max_len = 0xffffffff;
+ r.in.resume_handle = r.out.resume_handle = &resume_handle;
+ r.out.total_entries = &total_entries;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_atsvc_JobEnum_r(b, tctx, &r),
+ "JobEnum failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "JobEnum failed");
+
+ for (i = 0; i < r.out.ctr->entries_read; i++) {
+ if (!test_JobGetInfo(p, tctx, r.out.ctr->first_entry[i].job_id)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_JobAdd(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct atsvc_JobAdd r;
+ struct atsvc_JobInfo info;
+
+ r.in.servername = dcerpc_server_name(p);
+ info.job_time = 0x050ae4c0; /* 11:30pm */
+ info.days_of_month = 0; /* n/a */
+ info.days_of_week = 0x02; /* Tuesday */
+ info.flags = 0x11; /* periodic, non-interactive */
+ info.command = "foo.exe";
+ r.in.job_info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_atsvc_JobAdd_r(b, tctx, &r),
+ "JobAdd failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "JobAdd failed");
+
+ /* Run EnumJobs again in case there were no jobs to begin with */
+
+ if (!test_JobEnum(tctx, p)) {
+ return false;
+ }
+
+ if (!test_JobGetInfo(p, tctx, *r.out.job_id)) {
+ return false;
+ }
+
+ if (!test_JobDel(p, tctx, *r.out.job_id, *r.out.job_id)) {
+ return false;
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_atsvc(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "atsvc");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "atsvc", &ndr_table_atsvc);
+
+ torture_rpc_tcase_add_test(tcase, "JobEnum", test_JobEnum);
+ torture_rpc_tcase_add_test(tcase, "JobAdd", test_JobAdd);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c
new file mode 100644
index 0000000..71cdf0f
--- /dev/null
+++ b/source4/torture/rpc/backupkey.c
@@ -0,0 +1,2431 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for backupkey remote protocol rpc operations
+
+ Copyright (C) Matthieu Patou 2010-2011
+ Copyright (C) Andreas Schneider <asn@samba.org> 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../libcli/security/security.h"
+
+#include "torture/rpc/torture_rpc.h"
+#include "torture/ndr/ndr.h"
+
+#include "librpc/gen_ndr/ndr_backupkey_c.h"
+#include "librpc/gen_ndr/ndr_backupkey.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/auth/proto.h"
+#include <system/network.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+
+enum test_wrong {
+ WRONG_MAGIC,
+ WRONG_R2,
+ WRONG_PAYLOAD_LENGTH,
+ WRONG_CIPHERTEXT_LENGTH,
+ SHORT_PAYLOAD_LENGTH,
+ SHORT_CIPHERTEXT_LENGTH,
+ ZERO_PAYLOAD_LENGTH,
+ ZERO_CIPHERTEXT_LENGTH,
+ RIGHT_KEY,
+ WRONG_KEY,
+ WRONG_SID,
+};
+
+/* Our very special and valued secret */
+/* No need to put const as we cast the array in uint8_t
+ * we will get a warning about the discarded const
+ */
+static const char secret[] = "tata yoyo mais qu'est ce qu'il y a sous ton grand chapeau ?";
+
+/* Get the SID from a user */
+static struct dom_sid *get_user_sid(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const char *user)
+{
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 r;
+ struct lsa_Close c;
+ NTSTATUS status;
+ struct policy_handle handle;
+ struct lsa_LookupNames l;
+ struct lsa_TransSidArray sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String lsa_name;
+ uint32_t count = 0;
+ struct dom_sid *result;
+ TALLOC_CTX *tmp_ctx;
+ struct dcerpc_pipe *p2;
+ struct dcerpc_binding_handle *b;
+
+ const char *domain = cli_credentials_get_domain(
+ samba_cmdline_get_creds());
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_lsarpc),
+ "could not open lsarpc pipe");
+ b = p2->binding_handle;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ return NULL;
+ }
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = "\\";
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ status = dcerpc_lsa_OpenPolicy2_r(b, tmp_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx,
+ "OpenPolicy2 failed - %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx,
+ "OpenPolicy2_ failed - %s\n",
+ nt_errstr(r.out.result));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ lsa_name.string = talloc_asprintf(tmp_ctx, "%s\\%s", domain, user);
+
+ l.in.handle = &handle;
+ l.in.num_names = 1;
+ l.in.names = &lsa_name;
+ l.in.sids = &sids;
+ l.in.level = 1;
+ l.in.count = &count;
+ l.out.count = &count;
+ l.out.sids = &sids;
+ l.out.domains = &domains;
+
+ status = dcerpc_lsa_LookupNames_r(b, tmp_ctx, &l);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx,
+ "LookupNames of %s failed - %s\n",
+ lsa_name.string,
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (domains->count == 0) {
+ return NULL;
+ }
+
+ result = dom_sid_add_rid(mem_ctx,
+ domains->domains[0].sid,
+ l.out.sids->sids[0].rid);
+ c.in.handle = &handle;
+ c.out.handle = &handle;
+
+ status = dcerpc_lsa_Close_r(b, tmp_ctx, &c);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx,
+ "dcerpc_lsa_Close failed - %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(c.out.result)) {
+ torture_comment(tctx,
+ "dcerpc_lsa_Close failed - %s\n",
+ nt_errstr(c.out.result));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ talloc_free(p2);
+
+ torture_comment(tctx, "Get_user_sid finished\n");
+ return result;
+}
+
+/*
+ * Create a bkrp_encrypted_secret_vX structure
+ * the version depends on the version parameter
+ * the structure is returned as a blob.
+ * The broken flag is to indicate if we want
+ * to create a non conform to specification structure
+ */
+static DATA_BLOB *create_unencryptedsecret(TALLOC_CTX *mem_ctx,
+ bool broken,
+ int version)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB);
+ enum ndr_err_code ndr_err;
+
+ if (version == 2) {
+ struct bkrp_encrypted_secret_v2 unenc_sec;
+
+ ZERO_STRUCT(unenc_sec);
+ unenc_sec.secret_len = sizeof(secret);
+ unenc_sec.secret = discard_const_p(uint8_t, secret);
+ generate_random_buffer(unenc_sec.payload_key,
+ sizeof(unenc_sec.payload_key));
+
+ ndr_err = ndr_push_struct_blob(blob, blob, &unenc_sec,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_encrypted_secret_v2);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NULL;
+ }
+
+ if (broken) {
+ /* The magic value is correctly set by the NDR push
+ * but we want to test the behavior of the server
+ * if a different value is provided
+ */
+ ((uint8_t*)blob->data)[4] = 79; /* A great year !!! */
+ }
+ }
+
+ if (version == 3) {
+ struct bkrp_encrypted_secret_v3 unenc_sec;
+
+ ZERO_STRUCT(unenc_sec);
+ unenc_sec.secret_len = sizeof(secret);
+ unenc_sec.secret = discard_const_p(uint8_t, secret);
+ generate_random_buffer(unenc_sec.payload_key,
+ sizeof(unenc_sec.payload_key));
+
+ ndr_err = ndr_push_struct_blob(blob, blob, &unenc_sec,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_encrypted_secret_v3);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NULL;
+ }
+
+ if (broken) {
+ /*
+ * The magic value is correctly set by the NDR push
+ * but we want to test the behavior of the server
+ * if a different value is provided
+ */
+ ((uint8_t*)blob->data)[4] = 79; /* A great year !!! */
+ }
+ }
+ talloc_free(tmp_ctx);
+ return blob;
+}
+
+/*
+ * Create an access check structure, the format depends on the version parameter.
+ * If broken is specified then we create a structure that isn't conform to the
+ * specification.
+ *
+ * If the structure can't be created then NULL is returned.
+ */
+static DATA_BLOB *create_access_check(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ const char *user,
+ bool broken,
+ uint32_t version)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ DATA_BLOB *blob = NULL;
+ enum ndr_err_code ndr_err;
+ const struct dom_sid *sid = NULL;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ sid = get_user_sid(tctx, tmp_ctx, user);
+ if (sid == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (blob == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (version == 2) {
+ struct bkrp_access_check_v2 access_struct;
+ gnutls_hash_hd_t dig_ctx;
+ uint8_t nonce[32];
+ int rc;
+
+ ZERO_STRUCT(access_struct);
+ generate_random_buffer(nonce, sizeof(nonce));
+ access_struct.nonce_len = sizeof(nonce);
+ access_struct.nonce = nonce;
+ access_struct.sid = *sid;
+
+ ndr_err = ndr_push_struct_blob(blob, blob, &access_struct,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_access_check_v2);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(blob);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ /*
+ * We pushed the whole structure including a null hash
+ * but the hash need to be calculated only up to the hash field
+ * so we reduce the size of what has to be calculated
+ */
+
+ rc = gnutls_hash_init(&dig_ctx, GNUTLS_DIG_SHA1);
+ if (rc != GNUTLS_E_SUCCESS) {
+ talloc_free(blob);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ rc = gnutls_hash(dig_ctx,
+ blob->data,
+ blob->length - sizeof(access_struct.hash));
+ gnutls_hash_deinit(dig_ctx,
+ blob->data + blob->length - sizeof(access_struct.hash));
+ if (rc != GNUTLS_E_SUCCESS) {
+ talloc_free(blob);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ /* Altering the SHA */
+ if (broken) {
+ blob->data[blob->length - 1]++;
+ }
+ }
+
+ if (version == 3) {
+ struct bkrp_access_check_v3 access_struct;
+ gnutls_hash_hd_t dig_ctx;
+ uint8_t nonce[32];
+ int rc;
+
+ ZERO_STRUCT(access_struct);
+ generate_random_buffer(nonce, sizeof(nonce));
+ access_struct.nonce_len = sizeof(nonce);
+ access_struct.nonce = nonce;
+ access_struct.sid = *sid;
+
+ ndr_err = ndr_push_struct_blob(blob, blob, &access_struct,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_access_check_v3);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(blob);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ /*We pushed the whole structure including a null hash
+ * but the hash need to be calculated only up to the hash field
+ * so we reduce the size of what has to be calculated
+ */
+
+ rc = gnutls_hash_init(&dig_ctx, GNUTLS_DIG_SHA512);
+ if (rc != GNUTLS_E_SUCCESS) {
+ talloc_free(blob);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ rc = gnutls_hash(dig_ctx,
+ blob->data,
+ blob->length - sizeof(access_struct.hash));
+ gnutls_hash_deinit(dig_ctx,
+ blob->data + blob->length - sizeof(access_struct.hash));
+ if (rc != GNUTLS_E_SUCCESS) {
+ talloc_free(blob);
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ /* Altering the SHA */
+ if (broken) {
+ blob->data[blob->length -1]++;
+ }
+ }
+ talloc_free(tmp_ctx);
+ return blob;
+}
+
+
+static DATA_BLOB *encrypt_blob(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key,
+ DATA_BLOB *iv,
+ DATA_BLOB *to_encrypt,
+ gnutls_cipher_algorithm_t cipher_algo)
+{
+ gnutls_cipher_hd_t cipher_handle = { 0 };
+ gnutls_datum_t gkey = {
+ .data = key->data,
+ .size = key->length,
+ };
+ gnutls_datum_t giv = {
+ .data = iv->data,
+ .size = iv->length,
+ };
+ DATA_BLOB *blob;
+ int rc;
+
+ blob = talloc(mem_ctx, DATA_BLOB);
+ if (blob == NULL) {
+ return NULL;
+ }
+
+ *blob = data_blob_talloc_zero(mem_ctx, to_encrypt->length);
+ if (blob->data == NULL) {
+ talloc_free(blob);
+ return NULL;
+ }
+
+ rc = gnutls_cipher_init(&cipher_handle,
+ cipher_algo,
+ &gkey,
+ &giv);
+ if (rc != GNUTLS_E_SUCCESS) {
+ torture_comment(tctx,
+ "gnutls_cipher_init failed: %s\n",
+ gnutls_strerror(rc));
+ talloc_free(blob);
+ return NULL;
+ }
+
+ rc = gnutls_cipher_encrypt2(cipher_handle,
+ to_encrypt->data,
+ to_encrypt->length,
+ blob->data,
+ blob->length);
+ gnutls_cipher_deinit(cipher_handle);
+ if (rc != GNUTLS_E_SUCCESS) {
+ torture_comment(tctx,
+ "gnutls_cipher_decrypt2 failed: %s\n",
+ gnutls_strerror(rc));
+ return NULL;
+ }
+
+ return blob;
+}
+
+/*
+ * Certs used for this protocol have a GUID in the issuer_uniq_id field.
+ * This function fetch it.
+ */
+static struct GUID *get_cert_guid(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *cert_data,
+ uint32_t cert_len)
+{
+ gnutls_x509_crt_t x509_cert = NULL;
+ gnutls_datum_t x509_crt_data = {
+ .data = cert_data,
+ .size = cert_len,
+ };
+ uint8_t dummy[1] = {0};
+ DATA_BLOB issuer_unique_id = {
+ .data = dummy,
+ .length = 0,
+ };
+ struct GUID *guid = talloc_zero(mem_ctx, struct GUID);
+ NTSTATUS status;
+ int rc;
+
+ rc = gnutls_x509_crt_init(&x509_cert);
+ if (rc != GNUTLS_E_SUCCESS) {
+ torture_comment(tctx,
+ "gnutls_x509_crt_init failed - %s",
+ gnutls_strerror(rc));
+ return NULL;
+ }
+
+ rc = gnutls_x509_crt_import(x509_cert,
+ &x509_crt_data,
+ GNUTLS_X509_FMT_DER);
+ if (rc != GNUTLS_E_SUCCESS) {
+ torture_comment(tctx,
+ "gnutls_x509_crt_import failed - %s",
+ gnutls_strerror(rc));
+ gnutls_x509_crt_deinit(x509_cert);
+ return NULL;
+ }
+
+ /* Get the buffer size */
+ rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+ (char *)issuer_unique_id.data,
+ &issuer_unique_id.length);
+ if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER ||
+ issuer_unique_id.length == 0) {
+ gnutls_x509_crt_deinit(x509_cert);
+ return NULL;
+ }
+
+ issuer_unique_id = data_blob_talloc_zero(mem_ctx,
+ issuer_unique_id.length);
+ if (issuer_unique_id.data == NULL) {
+ gnutls_x509_crt_deinit(x509_cert);
+ return NULL;
+ }
+
+ rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+ (char *)issuer_unique_id.data,
+ &issuer_unique_id.length);
+ gnutls_x509_crt_deinit(x509_cert);
+ if (rc != GNUTLS_E_SUCCESS) {
+ torture_comment(tctx,
+ "gnutls_x509_crt_get_issuer_unique_id failed - %s",
+ gnutls_strerror(rc));
+ return NULL;
+ }
+
+ status = GUID_from_data_blob(&issuer_unique_id, guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return guid;
+}
+
+/*
+ * Encrypt a blob with the private key of the certificate
+ * passed as a parameter.
+ */
+static DATA_BLOB *encrypt_blob_pk(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *cert_data,
+ uint32_t cert_len,
+ DATA_BLOB *to_encrypt)
+{
+ gnutls_x509_crt_t x509_cert;
+ gnutls_datum_t x509_crt_data = {
+ .data = cert_data,
+ .size = cert_len,
+ };
+ gnutls_pubkey_t pubkey;
+ gnutls_datum_t plaintext = {
+ .data = to_encrypt->data,
+ .size = to_encrypt->length,
+ };
+ gnutls_datum_t ciphertext = {
+ .data = NULL,
+ };
+ DATA_BLOB *blob;
+ int rc;
+
+ rc = gnutls_x509_crt_init(&x509_cert);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return NULL;
+ }
+
+ rc = gnutls_x509_crt_import(x509_cert,
+ &x509_crt_data,
+ GNUTLS_X509_FMT_DER);
+ if (rc != GNUTLS_E_SUCCESS) {
+ gnutls_x509_crt_deinit(x509_cert);
+ return NULL;
+ }
+
+ rc = gnutls_pubkey_init(&pubkey);
+ if (rc != GNUTLS_E_SUCCESS) {
+ gnutls_x509_crt_deinit(x509_cert);
+ return NULL;
+ }
+
+ rc = gnutls_pubkey_import_x509(pubkey,
+ x509_cert,
+ 0);
+ gnutls_x509_crt_deinit(x509_cert);
+ if (rc != GNUTLS_E_SUCCESS) {
+ gnutls_pubkey_deinit(pubkey);
+ return NULL;
+ }
+
+ rc = gnutls_pubkey_encrypt_data(pubkey,
+ 0,
+ &plaintext,
+ &ciphertext);
+ gnutls_pubkey_deinit(pubkey);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return NULL;
+ }
+
+ blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (blob == NULL) {
+ gnutls_pubkey_deinit(pubkey);
+ return NULL;
+ }
+
+ *blob = data_blob_talloc(blob, ciphertext.data, ciphertext.size);
+ gnutls_free(ciphertext.data);
+ if (blob->data == NULL) {
+ gnutls_pubkey_deinit(pubkey);
+ return NULL;
+ }
+
+ return blob;
+}
+
+static struct bkrp_BackupKey *createRetrieveBackupKeyGUIDStruct(struct torture_context *tctx,
+ struct dcerpc_pipe *p, int version, DATA_BLOB *out)
+{
+ struct dcerpc_binding *binding;
+ struct bkrp_client_side_wrapped data;
+ struct GUID *g = talloc(tctx, struct GUID);
+ struct bkrp_BackupKey *r = talloc_zero(tctx, struct bkrp_BackupKey);
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ NTSTATUS status;
+
+ if (r == NULL) {
+ return NULL;
+ }
+
+ binding = dcerpc_binding_dup(tctx, p->binding);
+ if (binding == NULL) {
+ return NULL;
+ }
+
+ status = dcerpc_binding_set_flags(binding, DCERPC_SEAL|DCERPC_AUTH_SPNEGO, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ ZERO_STRUCT(data);
+ status = GUID_from_string(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, g);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ r->in.guidActionAgent = g;
+ data.version = version;
+ ndr_err = ndr_push_struct_blob(&blob, tctx, &data,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_client_side_wrapped);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NULL;
+ }
+ r->in.data_in = blob.data;
+ r->in.data_in_len = blob.length;
+ r->out.data_out = &out->data;
+ r->out.data_out_len = talloc(r, uint32_t);
+ return r;
+}
+
+static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tctx,
+ struct dcerpc_pipe *p, int version, DATA_BLOB *out,
+ bool norevert,
+ bool broken_version,
+ bool broken_user,
+ bool broken_magic_secret,
+ bool broken_magic_access,
+ bool broken_hash_access,
+ bool broken_cert_guid)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct bkrp_client_side_wrapped data;
+ DATA_BLOB *xs;
+ DATA_BLOB *sec;
+ DATA_BLOB *enc_sec = NULL;
+ DATA_BLOB *enc_xs = NULL;
+ DATA_BLOB *blob2;
+ DATA_BLOB enc_sec_reverted;
+ DATA_BLOB key;
+ DATA_BLOB iv;
+ DATA_BLOB out_blob;
+ struct GUID *guid, *g;
+ int t;
+ uint32_t size;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+ const char *user;
+ gnutls_cipher_algorithm_t cipher_algo;
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, version, &out_blob);
+ if (r == NULL) {
+ return NULL;
+ }
+
+ if (broken_user) {
+ /* we take a fake user*/
+ user = "guest";
+ } else {
+ user = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ }
+
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ "Get GUID");
+ torture_assert_werr_ok(tctx, r->out.result,
+ "Get GUID");
+
+ /*
+ * We have to set it outside of the function createRetrieveBackupKeyGUIDStruct
+ * the len of the blob, this is due to the fact that they don't have the
+ * same size (one is 32bits the other 64bits)
+ */
+ out_blob.length = *r->out.data_out_len;
+
+ sec = create_unencryptedsecret(tctx, broken_magic_secret, version);
+ if (sec == NULL) {
+ return NULL;
+ }
+
+ xs = create_access_check(tctx, p, tctx, user, broken_hash_access, version);
+ if (xs == NULL) {
+ return NULL;
+ }
+
+ if (broken_magic_access){
+ /* The start of the access_check structure contains the
+ * GUID of the certificate
+ */
+ xs->data[0]++;
+ }
+
+ enc_sec = encrypt_blob_pk(tctx, tctx, out_blob.data, out_blob.length, sec);
+ if (!enc_sec) {
+ return NULL;
+ }
+ enc_sec_reverted.data = talloc_array(tctx, uint8_t, enc_sec->length);
+ if (enc_sec_reverted.data == NULL) {
+ return NULL;
+ }
+ enc_sec_reverted.length = enc_sec->length;
+
+ /*
+ * We DO NOT revert the array on purpose it's in order to check that
+ * when the server is not able to decrypt then it answer the correct error
+ */
+ if (norevert) {
+ for(t=0; t< enc_sec->length; t++) {
+ enc_sec_reverted.data[t] = ((uint8_t*)enc_sec->data)[t];
+ }
+ } else {
+ for(t=0; t< enc_sec->length; t++) {
+ enc_sec_reverted.data[t] = ((uint8_t*)enc_sec->data)[enc_sec->length - t -1];
+ }
+ }
+
+ size = sec->length;
+ switch (version) {
+ case 2:
+ cipher_algo = GNUTLS_CIPHER_3DES_CBC;
+ break;
+ case 3:
+ cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
+ break;
+ default:
+ return NULL;
+ }
+ iv.length = gnutls_cipher_get_iv_size(cipher_algo);
+ iv.data = sec->data + (size - iv.length);
+
+ key.length = gnutls_cipher_get_key_size(cipher_algo);
+ key.data = sec->data + (size - (key.length + iv.length));
+
+ enc_xs = encrypt_blob(tctx, tctx, &key, &iv, xs, cipher_algo);
+ if (!enc_xs) {
+ return NULL;
+ }
+
+ /* To cope with the fact that heimdal do padding at the end for the moment */
+ enc_xs->length = xs->length;
+
+ guid = get_cert_guid(tctx, tctx, out_blob.data, out_blob.length);
+ if (guid == NULL) {
+ return NULL;
+ }
+
+ if (broken_version) {
+ data.version = 1;
+ } else {
+ data.version = version;
+ }
+
+ data.guid = *guid;
+ data.encrypted_secret = enc_sec_reverted.data;
+ data.access_check = enc_xs->data;
+ data.encrypted_secret_len = enc_sec->length;
+ data.access_check_len = enc_xs->length;
+
+ /* We want the blob to persist after this function so we don't
+ * allocate it in the stack
+ */
+ blob2 = talloc(tctx, DATA_BLOB);
+ if (blob2 == NULL) {
+ return NULL;
+ }
+
+ ndr_err = ndr_push_struct_blob(blob2, tctx, &data,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_client_side_wrapped);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NULL;
+ }
+
+ if (broken_cert_guid) {
+ blob2->data[12]++;
+ }
+
+ ZERO_STRUCT(*r);
+
+ g = talloc(tctx, struct GUID);
+ if (g == NULL) {
+ return NULL;
+ }
+
+ status = GUID_from_string(BACKUPKEY_RESTORE_GUID, g);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ r->in.guidActionAgent = g;
+ r->in.data_in = blob2->data;
+ r->in.data_in_len = blob2->length;
+ r->in.param = 0;
+ r->out.data_out = &(out->data);
+ r->out.data_out_len = talloc(r, uint32_t);
+ return r;
+}
+
+/* Check that we are able to receive the certificate of the DCs
+ * used for client wrap version of the backup key protocol
+ */
+static bool test_RetrieveBackupKeyGUID(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ if (r == NULL) {
+ return false;
+ }
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ "Get GUID");
+
+ out_blob.length = *r->out.data_out_len;
+ torture_assert_werr_equal(tctx,
+ r->out.result,
+ WERR_OK,
+ "Wrong dce/rpc error code");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED,
+ "Get GUID");
+ }
+ return true;
+}
+
+/* Test to check the failure to recover a secret because the
+ * secret blob is not reversed
+ */
+static bool test_RestoreGUID_ko(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+ true, false, false, false, false, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAMETER, "Wrong error code");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_wrongversion(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+ false, true, false, false, false, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAMETER, "Wrong error code on wrong version");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_wronguser(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+ false, false, true, false, false, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_ACCESS, "Restore GUID");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_v3(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+ false, false, false, false, false, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 1, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_OK, "Restore GUID");
+ torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+ false, false, false, false, false, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ torture_assert_werr_equal(tctx, r->out.result, WERR_OK, "Restore GUID");
+ torture_assert_ndr_err_equal(tctx,
+ ndr_pull_struct_blob(&out_blob, tctx, &resp,
+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped),
+ NDR_ERR_SUCCESS,
+ "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_badmagiconsecret(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+ false, false, false, true, false, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Wrong error code while providing bad magic in secret");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_emptyrequest(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+ false, false, false, true, false, false, true);
+
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ r->in.data_in = talloc(tctx, uint8_t);
+ r->in.data_in_len = 0;
+ r->in.param = 0;
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAMETER, "Bad error code on wrong has in access check");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_badcertguid(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob,
+ false, false, false, false, false, false, true);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct() failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+
+ /*
+ * Windows 2012R2 has, presumably, a programming error
+ * returning an NTSTATUS code on this interface
+ */
+ if (W_ERROR_V(r->out.result) != NT_STATUS_V(NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
+ }
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_badmagicaccesscheck(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+ false, false, false, false, true, false, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_RestoreGUID_badhashaccesscheck(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum ndr_err_code ndr_err;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_client_side_unwrapped resp;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob,
+ false, false, false, false, false, true, false);
+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed");
+ torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID");
+ out_blob.length = *r->out.data_out_len;
+ ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped);
+ torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped");
+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check");
+ } else {
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED, "Get GUID");
+ }
+
+ return true;
+}
+
+/*
+ * Check that the RSA modulus in the certificate of the DCs has 2048 bits.
+ */
+static bool test_RetrieveBackupKeyGUID_validate(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB out_blob;
+ struct bkrp_BackupKey *r = createRetrieveBackupKeyGUIDStruct(tctx, p, 2, &out_blob);
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ torture_assert(tctx, r != NULL, "test_RetrieveBackupKeyGUID_validate failed");
+
+ if (r == NULL) {
+ return false;
+ }
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ gnutls_x509_crt_t x509_cert = NULL;
+ gnutls_pubkey_t pubkey = NULL;
+ gnutls_datum_t x509_crt_data;
+ gnutls_pk_algorithm_t pubkey_algo;
+ uint8_t dummy[1] = {0};
+ DATA_BLOB subject_unique_id = {
+ .data = dummy,
+ .length = 0,
+ };
+ DATA_BLOB issuer_unique_id = {
+ .data = dummy,
+ .length = 0,
+ };
+ DATA_BLOB reversed = {
+ .data = dummy,
+ .length = 0,
+ };
+ DATA_BLOB serial_number;
+ unsigned int RSA_returned_bits = 0;
+ int version;
+ size_t i;
+ int cmp;
+ int rc;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ "Get GUID");
+
+ torture_assert_werr_ok(tctx, r->out.result,
+ "Get GUID");
+
+ out_blob.length = *r->out.data_out_len;
+
+ x509_crt_data.data = out_blob.data;
+ x509_crt_data.size = out_blob.length;
+
+ rc = gnutls_x509_crt_init(&x509_cert);
+ if (rc != GNUTLS_E_SUCCESS) {
+ return NULL;
+ }
+
+ rc = gnutls_x509_crt_import(x509_cert,
+ &x509_crt_data,
+ GNUTLS_X509_FMT_DER);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_x509_crt_import failed");
+
+ /* Compare unique ids */
+
+ /* Get buffer size */
+ rc = gnutls_x509_crt_get_subject_unique_id(x509_cert,
+ (char *)subject_unique_id.data,
+ &subject_unique_id.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SHORT_MEMORY_BUFFER,
+ "gnutls_x509_crt_get_subject_unique_id "
+ "get buffer size failed");
+
+ subject_unique_id = data_blob_talloc_zero(tctx,
+ subject_unique_id.length);
+
+ rc = gnutls_x509_crt_get_subject_unique_id(x509_cert,
+ (char *)subject_unique_id.data,
+ &subject_unique_id.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_x509_crt_get_subject_unique_id failed");
+
+ rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+ (char *)issuer_unique_id.data,
+ &issuer_unique_id.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SHORT_MEMORY_BUFFER,
+ "gnutls_x509_crt_get_issuer_unique_id "
+ "get buffer size failed");
+
+ issuer_unique_id = data_blob_talloc_zero(tctx,
+ issuer_unique_id.length);
+
+ rc = gnutls_x509_crt_get_issuer_unique_id(x509_cert,
+ (char *)issuer_unique_id.data,
+ &issuer_unique_id.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_x509_crt_get_issuer_unique_id failed");
+
+ cmp = data_blob_cmp(&subject_unique_id, &issuer_unique_id);
+ torture_assert(tctx,
+ cmp == 0,
+ "The GUID to identify the public key is not "
+ "identical");
+
+ rc = gnutls_x509_crt_get_serial(x509_cert,
+ reversed.data,
+ &reversed.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SHORT_MEMORY_BUFFER,
+ "gnutls_x509_crt_get_serial "
+ "get buffer size failed");
+
+ reversed = data_blob_talloc_zero(tctx,
+ reversed.length);
+
+ rc = gnutls_x509_crt_get_serial(x509_cert,
+ reversed.data,
+ &reversed.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_x509_crt_get_serial failed");
+
+ /*
+ * Heimdal sometimes adds a leading byte to the data buffer of
+ * the serial number. So lets uses the subject_unique_id size
+ * and ignore the leading byte.
+ */
+ serial_number = data_blob_talloc_zero(tctx,
+ subject_unique_id.length);
+
+ for (i = 0; i < serial_number.length; i++) {
+ serial_number.data[i] = reversed.data[reversed.length - i - 1];
+ }
+
+ cmp = data_blob_cmp(&subject_unique_id, &serial_number);
+ torture_assert(tctx,
+ cmp == 0,
+ "The GUID to identify the public key is not "
+ "identical");
+
+ /* Check certificate version */
+ version = gnutls_x509_crt_get_version(x509_cert);
+ torture_assert_int_equal(tctx,
+ version,
+ 3,
+ "Invalid certificate version");
+
+ /* Get the public key */
+ rc = gnutls_pubkey_init(&pubkey);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_pubkey_init failed");
+
+ rc = gnutls_pubkey_import_x509(pubkey,
+ x509_cert,
+ 0);
+ gnutls_x509_crt_deinit(x509_cert);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_pubkey_import_x509 failed");
+
+ pubkey_algo = gnutls_pubkey_get_pk_algorithm(pubkey,
+ &RSA_returned_bits);
+ gnutls_pubkey_deinit(pubkey);
+ torture_assert_int_equal(tctx,
+ pubkey_algo,
+ GNUTLS_PK_RSA,
+ "gnutls_pubkey_get_pk_algorithm did "
+ "not return a RSA key");
+ torture_assert_int_equal(tctx,
+ RSA_returned_bits,
+ 2048,
+ "RSA Key doesn't have 2048 bits");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, r),
+ NT_STATUS_ACCESS_DENIED,
+ "Get GUID");
+ }
+
+ return true;
+}
+
+static bool test_ServerWrap_encrypt_decrypt(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct bkrp_BackupKey r;
+ struct GUID guid;
+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+ DATA_BLOB encrypted;
+ uint32_t enclen;
+ DATA_BLOB decrypted;
+ uint32_t declen;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ ZERO_STRUCT(r);
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ /* Encrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = plaintext.data;
+ r.in.data_in_len = plaintext.length;
+ r.in.param = 0;
+ r.out.data_out = &encrypted.data;
+ r.out.data_out_len = &enclen;
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "encrypt");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_ACCESS_DENIED,
+ "encrypt");
+ return true;
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "encrypt");
+ encrypted.length = *r.out.data_out_len;
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = encrypted.data;
+ r.in.data_in_len = encrypted.length;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "decrypt");
+ decrypted.length = *r.out.data_out_len;
+
+ /* Compare */
+ torture_assert_data_blob_equal(tctx, plaintext, decrypted, "Decrypt failed");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = encrypted.data;
+ r.in.data_in_len = encrypted.length;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "decrypt");
+ decrypted.length = *r.out.data_out_len;
+
+ /* Compare */
+ torture_assert_data_blob_equal(tctx, plaintext, decrypted, "Decrypt failed");
+ return true;
+}
+
+static bool test_ServerWrap_decrypt_wrong_keyGUID(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct bkrp_BackupKey r;
+ struct GUID guid;
+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+ DATA_BLOB encrypted;
+ uint32_t enclen;
+ DATA_BLOB decrypted;
+ uint32_t declen;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum ndr_err_code ndr_err;
+ struct bkrp_server_side_wrapped server_side_wrapped;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ ZERO_STRUCT(r);
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ /* Encrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = plaintext.data;
+ r.in.data_in_len = plaintext.length;
+ r.in.param = 0;
+ r.out.data_out = &encrypted.data;
+ r.out.data_out_len = &enclen;
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "encrypt");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_ACCESS_DENIED,
+ "encrypt");
+ return true;
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "encrypt");
+ encrypted.length = *r.out.data_out_len;
+
+ ndr_err = ndr_pull_struct_blob(&encrypted, tctx, &server_side_wrapped,
+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "pull of server_side_wrapped");
+
+ /* Change the GUID */
+ server_side_wrapped.guid = GUID_random();
+
+ ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = encrypted.data;
+ r.in.data_in_len = encrypted.length;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_DATA,
+ "decrypt should fail with WERR_INVALID_DATA");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = encrypted.data;
+ r.in.data_in_len = encrypted.length;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_DATA,
+ "decrypt should fail with WERR_INVALID_DATA");
+
+ return true;
+}
+
+static bool test_ServerWrap_decrypt_empty_request(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct bkrp_BackupKey r;
+ struct GUID guid;
+ DATA_BLOB decrypted;
+ uint32_t declen;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t short_request[4] = { 1, 0, 0, 0 };
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ ZERO_STRUCT(r);
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = short_request;
+ r.in.data_in_len = 0;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "encrypt");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_ACCESS_DENIED,
+ "encrypt");
+ return true;
+ }
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "decrypt should fail with WERR_INVALID_PARAMETER");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = short_request;
+ r.in.data_in_len = 0;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "decrypt should fail with WERR_INVALID_PARAMETER");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = NULL;
+ r.in.data_in_len = 0;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_INVALID_PARAMETER_MIX,
+ "decrypt");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = NULL;
+ r.in.data_in_len = 0;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_INVALID_PARAMETER_MIX,
+ "decrypt");
+
+ return true;
+}
+
+
+static bool test_ServerWrap_decrypt_short_request(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct bkrp_BackupKey r;
+ struct GUID guid;
+ DATA_BLOB decrypted;
+ uint32_t declen;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t short_request[4] = { 1, 0, 0, 0 };
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ ZERO_STRUCT(r);
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = short_request;
+ r.in.data_in_len = 4;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "encrypt");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_ACCESS_DENIED,
+ "encrypt");
+ return true;
+ }
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "decrypt should fail with WERR_INVALID_PARM");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = short_request;
+ r.in.data_in_len = 4;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "decrypt should fail with WERR_INVALID_PARAMETER");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = short_request;
+ r.in.data_in_len = 1;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "decrypt should fail with WERR_INVALID_PARAMETER");
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = short_request;
+ r.in.data_in_len = 1;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "decrypt should fail with WERR_INVALID_PARAMETER");
+
+ return true;
+}
+
+static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx,
+ struct bkrp_server_side_wrapped *server_side_wrapped,
+ enum test_wrong wrong)
+{
+ char *lsa_binding_string = NULL;
+ struct dcerpc_binding *lsa_binding = NULL;
+ struct dcerpc_pipe *lsa_p = NULL;
+ struct dcerpc_binding_handle *lsa_b = NULL;
+ struct lsa_OpenSecret r_secret;
+ struct lsa_QuerySecret r_query_secret;
+ struct policy_handle *handle, sec_handle;
+ struct bkrp_BackupKey r;
+ struct GUID preferred_key_guid;
+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+ DATA_BLOB preferred_key, preferred_key_clear, session_key,
+ decrypt_key, decrypt_key_clear, encrypted_blob,
+ sid_blob;
+ struct bkrp_dc_serverwrap_key server_key;
+ struct lsa_DATA_BUF_PTR bufp1;
+ char *key_guid_string;
+ struct bkrp_rc4encryptedpayload rc4payload;
+ struct dom_sid *caller_sid;
+ uint8_t symkey[20]; /* SHA-1 hash len */
+ uint8_t mackey[20]; /* SHA-1 hash len */
+ uint8_t mac[20]; /* SHA-1 hash len */
+ gnutls_hmac_hd_t hmac_hnd;
+ gnutls_cipher_hd_t cipher_hnd;
+ gnutls_datum_t cipher_key;
+ int rc;
+
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(r_secret);
+ ZERO_STRUCT(r_query_secret);
+
+ /* Now read BCKUPKEY_P and prove we can do a matching decrypt and encrypt */
+
+ /* lsa_OpenSecret only works with ncacn_np and AUTH_LEVEL_NONE */
+ lsa_binding_string = talloc_asprintf(tctx, "ncacn_np:%s",
+ torture_setting_string(tctx, "host", NULL));
+ torture_assert(tctx, lsa_binding_string != NULL, "lsa_binding_string");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_parse_binding(tctx, lsa_binding_string, &lsa_binding),
+ "Failed to parse dcerpc binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &lsa_p,
+ lsa_binding, &ndr_table_lsarpc,
+ samba_cmdline_get_creds(),
+ tctx->ev, tctx->lp_ctx),
+ "Opening LSA pipe");
+ lsa_b = lsa_p->binding_handle;
+
+ torture_assert(tctx, test_lsa_OpenPolicy2(lsa_b, tctx, &handle), "OpenPolicy failed");
+ r_secret.in.name.string = "G$BCKUPKEY_P";
+
+ r_secret.in.handle = handle;
+ r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r_secret.out.sec_handle = &sec_handle;
+
+ torture_comment(tctx, "Testing OpenSecret\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret),
+ "OpenSecret failed");
+ torture_assert_ntstatus_ok(tctx, r_secret.out.result,
+ "OpenSecret failed");
+
+ r_query_secret.in.sec_handle = &sec_handle;
+ r_query_secret.in.new_val = &bufp1;
+ bufp1.buf = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(lsa_b, tctx, &r_query_secret),
+ "QuerySecret failed");
+ torture_assert_ntstatus_ok(tctx, r_query_secret.out.result,
+ "QuerySecret failed");
+
+
+ preferred_key.data = r_query_secret.out.new_val->buf->data;
+ preferred_key.length = r_query_secret.out.new_val->buf->size;
+ torture_assert_ntstatus_ok(tctx, dcerpc_fetch_session_key(lsa_p, &session_key),
+ "dcerpc_fetch_session_key failed");
+
+ torture_assert_ntstatus_ok(tctx,
+ sess_decrypt_blob(tctx,
+ &preferred_key, &session_key, &preferred_key_clear),
+ "sess_decrypt_blob failed");
+
+ torture_assert_ntstatus_ok(tctx, GUID_from_ndr_blob(&preferred_key_clear, &preferred_key_guid),
+ "GUID parse failed");
+
+ torture_assert_guid_equal(tctx, server_side_wrapped->guid,
+ preferred_key_guid,
+ "GUID didn't match value pointed at by G$BCKUPKEY_P");
+
+ /* And read BCKUPKEY_<guid> and get the actual key */
+
+ key_guid_string = GUID_string(tctx, &server_side_wrapped->guid);
+ r_secret.in.name.string = talloc_asprintf(tctx, "G$BCKUPKEY_%s", key_guid_string);
+
+ r_secret.in.handle = handle;
+ r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r_secret.out.sec_handle = &sec_handle;
+
+ torture_comment(tctx, "Testing OpenSecret\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret),
+ "OpenSecret failed");
+ torture_assert_ntstatus_ok(tctx, r_secret.out.result,
+ "OpenSecret failed");
+
+ r_query_secret.in.sec_handle = &sec_handle;
+ r_query_secret.in.new_val = &bufp1;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(lsa_b, tctx, &r_query_secret),
+ "QuerySecret failed");
+ torture_assert_ntstatus_ok(tctx, r_query_secret.out.result,
+ "QuerySecret failed");
+
+
+ decrypt_key.data = r_query_secret.out.new_val->buf->data;
+ decrypt_key.length = r_query_secret.out.new_val->buf->size;
+
+ torture_assert_ntstatus_ok(tctx,
+ sess_decrypt_blob(tctx,
+ &decrypt_key, &session_key, &decrypt_key_clear),
+ "sess_decrypt_blob failed");
+
+ torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&decrypt_key_clear, tctx, &server_key,
+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key),
+ NDR_ERR_SUCCESS, "Failed to parse server_key");
+
+ torture_assert_int_equal(tctx, server_key.magic, 1, "Failed to correctly decrypt server key");
+
+ /*
+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+ * BACKUPKEY_BACKUP_GUID, it really is the whole key
+ */
+ gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_SHA1,
+ server_key.key,
+ sizeof(server_key.key));
+ gnutls_hmac(hmac_hnd,
+ server_side_wrapped->r2,
+ sizeof(server_side_wrapped->r2));
+ gnutls_hmac_output(hmac_hnd, symkey);
+
+ /* rc4 decrypt sid and secret using sym key */
+ cipher_key.data = symkey;
+ cipher_key.size = sizeof(symkey);
+
+ encrypted_blob = data_blob_talloc(tctx, server_side_wrapped->rc4encryptedpayload,
+ server_side_wrapped->ciphertext_length);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &cipher_key,
+ NULL);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_cipher_init failed");
+ rc = gnutls_cipher_encrypt2(cipher_hnd,
+ encrypted_blob.data,
+ encrypted_blob.length,
+ encrypted_blob.data,
+ encrypted_blob.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_cipher_encrypt failed");
+ gnutls_cipher_deinit(cipher_hnd);
+
+ torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&encrypted_blob, tctx, &rc4payload,
+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload),
+ NDR_ERR_SUCCESS, "Failed to parse rc4encryptedpayload");
+
+ torture_assert_int_equal(tctx, rc4payload.secret_data.length,
+ server_side_wrapped->payload_length,
+ "length of decrypted payload not the length declared in surrounding structure");
+
+ /*
+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1
+ * BACKUPKEY_BACKUP_GUID, it really is the whole key
+ */
+ gnutls_hmac(hmac_hnd,
+ rc4payload.r3,
+ sizeof(rc4payload.r3));
+ gnutls_hmac_deinit(hmac_hnd, mackey);
+
+ torture_assert_ndr_err_equal(tctx, ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid),
+ NDR_ERR_SUCCESS, "unable to push SID");
+
+ gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_SHA1,
+ mackey,
+ sizeof(mackey));
+ /* SID field */
+ gnutls_hmac(hmac_hnd,
+ sid_blob.data,
+ sid_blob.length);
+ /* Secret field */
+ gnutls_hmac(hmac_hnd,
+ rc4payload.secret_data.data,
+ rc4payload.secret_data.length);
+ gnutls_hmac_output(hmac_hnd, mac);
+
+ torture_assert_mem_equal(tctx, mac, rc4payload.mac, sizeof(mac), "mac not correct");
+ torture_assert_int_equal(tctx, rc4payload.secret_data.length,
+ plaintext.length, "decrypted data is not correct length");
+ torture_assert_mem_equal(tctx, rc4payload.secret_data.data,
+ plaintext.data, plaintext.length,
+ "decrypted data is not correct");
+
+ /* Not strictly correct all the time, but good enough for this test */
+ caller_sid = get_user_sid(tctx, tctx,
+ cli_credentials_get_username(
+ samba_cmdline_get_creds()));
+
+ torture_assert_sid_equal(tctx, &rc4payload.sid, caller_sid, "Secret saved with wrong SID");
+
+
+ /* RE-encrypt */
+
+ if (wrong == WRONG_SID) {
+ rc4payload.sid.sub_auths[rc4payload.sid.num_auths - 1] = DOMAIN_RID_KRBTGT;
+ }
+
+ dump_data_pw("mackey: \n", mackey, sizeof(mackey));
+
+ torture_assert_ndr_err_equal(tctx,
+ ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid),
+ NDR_ERR_SUCCESS,
+ "push of sid failed");
+
+ /* SID field */
+ gnutls_hmac(hmac_hnd,
+ sid_blob.data,
+ sid_blob.length);
+ /* Secret field */
+ gnutls_hmac(hmac_hnd,
+ rc4payload.secret_data.data,
+ rc4payload.secret_data.length);
+ gnutls_hmac_deinit(hmac_hnd, rc4payload.mac);
+
+ dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac));
+
+ torture_assert_ndr_err_equal(tctx,
+ ndr_push_struct_blob(&encrypted_blob, tctx, &rc4payload,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_rc4encryptedpayload),
+ NDR_ERR_SUCCESS,
+ "push of rc4payload failed");
+
+ if (wrong == WRONG_KEY) {
+ symkey[0] = 78;
+ symkey[1] = 78;
+ symkey[2] = 78;
+ }
+
+ /* rc4 encrypt sid and secret using sym key */
+ cipher_key.data = symkey;
+ cipher_key.size = sizeof(symkey);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &cipher_key,
+ NULL);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_cipher_init failed");
+ rc = gnutls_cipher_encrypt2(cipher_hnd,
+ encrypted_blob.data,
+ encrypted_blob.length,
+ encrypted_blob.data,
+ encrypted_blob.length);
+ torture_assert_int_equal(tctx,
+ rc,
+ GNUTLS_E_SUCCESS,
+ "gnutls_cipher_encrypt failed");
+ gnutls_cipher_deinit(cipher_hnd);
+
+
+ /* re-create server wrap structure */
+
+ torture_assert_int_equal(tctx, encrypted_blob.length,
+ server_side_wrapped->ciphertext_length,
+ "expected encrypted length not to change");
+ if (wrong == RIGHT_KEY) {
+ torture_assert_mem_equal(tctx, server_side_wrapped->rc4encryptedpayload,
+ encrypted_blob.data,
+ encrypted_blob.length,
+ "expected encrypted data not to change");
+ }
+
+ server_side_wrapped->payload_length = rc4payload.secret_data.length;
+ server_side_wrapped->ciphertext_length = encrypted_blob.length;
+ server_side_wrapped->rc4encryptedpayload = encrypted_blob.data;
+
+ return true;
+}
+
+
+static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ enum test_wrong wrong)
+{
+ struct bkrp_BackupKey r;
+ struct GUID guid;
+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret));
+ DATA_BLOB encrypted;
+ uint32_t enclen;
+ DATA_BLOB decrypted;
+ uint32_t declen;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum ndr_err_code ndr_err;
+ struct bkrp_server_side_wrapped server_side_wrapped;
+ bool repush = false;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ ZERO_STRUCT(r);
+
+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level);
+
+ /* Encrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = plaintext.data;
+ r.in.data_in_len = plaintext.length;
+ r.in.param = 0;
+ r.out.data_out = &encrypted.data;
+ r.out.data_out_len = &enclen;
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "encrypt");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ NT_STATUS_ACCESS_DENIED,
+ "encrypt");
+ return true;
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "encrypt");
+ encrypted.length = *r.out.data_out_len;
+
+ ndr_err = ndr_pull_struct_blob(&encrypted, tctx, &server_side_wrapped,
+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "pull of server_side_wrapped");
+
+ torture_assert_int_equal(tctx, server_side_wrapped.payload_length, plaintext.length,
+ "wrong payload length");
+
+ switch (wrong) {
+ case WRONG_MAGIC:
+ /* Change the magic. Forced by our NDR layer, so do it raw */
+ SIVAL(encrypted.data, 0, 78); /* valid values are 1-3 */
+ break;
+ case WRONG_R2:
+ server_side_wrapped.r2[0] = 78;
+ server_side_wrapped.r2[1] = 78;
+ server_side_wrapped.r2[2] = 78;
+ repush = true;
+ break;
+ case WRONG_PAYLOAD_LENGTH:
+ server_side_wrapped.payload_length = UINT32_MAX - 8;
+ repush = true;
+ break;
+ case WRONG_CIPHERTEXT_LENGTH:
+ /*
+ * Change the ciphertext len. We can't push this if
+ * we have it wrong, so do it raw
+ */
+ SIVAL(encrypted.data, 8, UINT32_MAX - 8); /* valid values are 1-3 */
+ break;
+ case SHORT_PAYLOAD_LENGTH:
+ server_side_wrapped.payload_length = server_side_wrapped.payload_length - 8;
+ repush = true;
+ break;
+ case SHORT_CIPHERTEXT_LENGTH:
+ /*
+ * Change the ciphertext len. We can't push this if
+ * we have it wrong, so do it raw
+ */
+ SIVAL(encrypted.data, 8, server_side_wrapped.ciphertext_length - 8); /* valid values are 1-3 */
+ break;
+ case ZERO_PAYLOAD_LENGTH:
+ server_side_wrapped.payload_length = 0;
+ repush = true;
+ break;
+ case ZERO_CIPHERTEXT_LENGTH:
+ /*
+ * Change the ciphertext len. We can't push this if
+ * we have it wrong, so do it raw
+ */
+ SIVAL(encrypted.data, 8, 0); /* valid values are 1-3 */
+ break;
+
+ case RIGHT_KEY:
+ case WRONG_KEY:
+ case WRONG_SID:
+ torture_assert(tctx,
+ test_ServerWrap_encrypt_decrypt_manual(tctx, &server_side_wrapped, wrong),
+ "test_ServerWrap_encrypt_decrypt_manual failed");
+ repush = true;
+ break;
+ }
+
+ if (repush) {
+ ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped,
+ (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped);
+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped");
+ }
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = encrypted.data;
+ r.in.data_in_len = encrypted.length;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+
+ if ((wrong == WRONG_R2 || wrong == WRONG_KEY)
+ && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_SID,
+ "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAMETER");
+ } else if (wrong == RIGHT_KEY) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_OK,
+ "decrypt should succeed!");
+ } else if (wrong == WRONG_SID) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_ACCESS,
+ "decrypt should fail with WERR_INVALID_ACCESS");
+ } else {
+ if (!W_ERROR_EQUAL(r.out.result, WERR_INVALID_ACCESS)
+ && !W_ERROR_EQUAL(r.out.result, WERR_INVALID_PARAMETER)) {
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_INVALID_DATA,
+ "decrypt should fail with WERR_INVALID_ACCESS, WERR_INVALID_PARAMETER or WERR_INVALID_DATA");
+ }
+ }
+
+ /* Decrypt */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid),
+ "obtain GUID");
+
+ r.in.guidActionAgent = &guid;
+ r.in.data_in = encrypted.data;
+ r.in.data_in_len = encrypted.length;
+ r.in.param = 0;
+ r.out.data_out = &(decrypted.data);
+ r.out.data_out_len = &declen;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_bkrp_BackupKey_r(b, tctx, &r),
+ "decrypt");
+
+ if ((wrong == WRONG_R2 || wrong == WRONG_KEY)
+ && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_SID,
+ "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAMETER");
+ } else if (wrong == RIGHT_KEY) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_OK,
+ "decrypt should succeed!");
+ } else if (wrong == WRONG_SID) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_ACCESS,
+ "decrypt should fail with WERR_INVALID_ACCESS");
+ } else {
+ if (!W_ERROR_EQUAL(r.out.result, WERR_INVALID_ACCESS)
+ && !W_ERROR_EQUAL(r.out.result, WERR_INVALID_PARAMETER)) {
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_INVALID_DATA,
+ "decrypt should fail with WERR_INVALID_ACCESS, WERR_INVALID_PARAMETER or WERR_INVALID_DATA");
+ }
+ }
+
+ return true;
+}
+
+static bool test_ServerWrap_decrypt_wrong_magic(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_MAGIC);
+}
+
+static bool test_ServerWrap_decrypt_wrong_r2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_R2);
+}
+
+static bool test_ServerWrap_decrypt_wrong_payload_length(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_PAYLOAD_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_short_payload_length(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, SHORT_PAYLOAD_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_zero_payload_length(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_PAYLOAD_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_wrong_ciphertext_length(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_CIPHERTEXT_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_short_ciphertext_length(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, SHORT_CIPHERTEXT_LENGTH);
+}
+
+static bool test_ServerWrap_decrypt_zero_ciphertext_length(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_CIPHERTEXT_LENGTH);
+}
+
+static bool test_ServerWrap_encrypt_decrypt_remote_key(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, RIGHT_KEY);
+}
+
+static bool test_ServerWrap_encrypt_decrypt_wrong_key(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_KEY);
+}
+
+static bool test_ServerWrap_encrypt_decrypt_wrong_sid(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_SID);
+}
+
+struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "backupkey");
+
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "backupkey",
+ &ndr_table_backupkey);
+
+ torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid",
+ test_RetrieveBackupKeyGUID);
+
+ torture_rpc_tcase_add_test(tcase, "restore_guid",
+ test_RestoreGUID);
+
+ torture_rpc_tcase_add_test(tcase, "restore_guid version 3",
+ test_RestoreGUID_v3);
+
+/* We double the test in order to be sure that we don't mess stuff (ie. freeing static stuff) */
+
+ torture_rpc_tcase_add_test(tcase, "restore_guid_2nd",
+ test_RestoreGUID);
+
+ torture_rpc_tcase_add_test(tcase, "unable_to_decrypt_secret",
+ test_RestoreGUID_ko);
+
+ torture_rpc_tcase_add_test(tcase, "wrong_user_restore_guid",
+ test_RestoreGUID_wronguser);
+
+ torture_rpc_tcase_add_test(tcase, "wrong_version_restore_guid",
+ test_RestoreGUID_wrongversion);
+
+ torture_rpc_tcase_add_test(tcase, "bad_magic_on_secret_restore_guid",
+ test_RestoreGUID_badmagiconsecret);
+
+ torture_rpc_tcase_add_test(tcase, "bad_hash_on_secret_restore_guid",
+ test_RestoreGUID_badhashaccesscheck);
+
+ torture_rpc_tcase_add_test(tcase, "bad_magic_on_accesscheck_restore_guid",
+ test_RestoreGUID_badmagicaccesscheck);
+
+ torture_rpc_tcase_add_test(tcase, "bad_cert_guid_restore_guid",
+ test_RestoreGUID_badcertguid);
+
+ torture_rpc_tcase_add_test(tcase, "empty_request_restore_guid",
+ test_RestoreGUID_emptyrequest);
+
+ torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid_validate",
+ test_RetrieveBackupKeyGUID_validate);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt",
+ test_ServerWrap_encrypt_decrypt);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_keyGUID",
+ test_ServerWrap_decrypt_wrong_keyGUID);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_empty_request",
+ test_ServerWrap_decrypt_empty_request);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_request",
+ test_ServerWrap_decrypt_short_request);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_magic",
+ test_ServerWrap_decrypt_wrong_magic);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_r2",
+ test_ServerWrap_decrypt_wrong_r2);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_payload_length",
+ test_ServerWrap_decrypt_wrong_payload_length);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_payload_length",
+ test_ServerWrap_decrypt_short_payload_length);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_payload_length",
+ test_ServerWrap_decrypt_zero_payload_length);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_ciphertext_length",
+ test_ServerWrap_decrypt_wrong_ciphertext_length);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_ciphertext_length",
+ test_ServerWrap_decrypt_short_ciphertext_length);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_ciphertext_length",
+ test_ServerWrap_decrypt_zero_ciphertext_length);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_remote_key",
+ test_ServerWrap_encrypt_decrypt_remote_key);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_key",
+ test_ServerWrap_encrypt_decrypt_wrong_key);
+
+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_sid",
+ test_ServerWrap_encrypt_decrypt_wrong_sid);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/bench.c b/source4/torture/rpc/bench.c
new file mode 100644
index 0000000..88825c5
--- /dev/null
+++ b/source4/torture/rpc/bench.c
@@ -0,0 +1,152 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ simple RPC benchmark
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+/**************************/
+/* srvsvc_NetShare */
+/**************************/
+static bool test_NetShareEnumAll(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareEnumAll r;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr0 c0;
+ struct srvsvc_NetShareCtr1 c1;
+ struct srvsvc_NetShareCtr2 c2;
+ struct srvsvc_NetShareCtr501 c501;
+ struct srvsvc_NetShareCtr502 c502;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0, 1, 2, 501, 502};
+ int i;
+ bool ret = true;
+ uint32_t resume_handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = &resume_handle;
+ r.out.resume_handle = &resume_handle;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ resume_handle = 0;
+ info_ctr.level = levels[i];
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ case 2:
+ ZERO_STRUCT(c2);
+ info_ctr.ctr.ctr2 = &c2;
+ break;
+ case 501:
+ ZERO_STRUCT(c501);
+ info_ctr.ctr.ctr501 = &c501;
+ break;
+ case 502:
+ ZERO_STRUCT(c502);
+ info_ctr.ctr.ctr502 = &c502;
+ break;
+ }
+
+ status = dcerpc_srvsvc_NetShareEnumAll_r(b, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("NetShareEnumAll level %u failed - %s\n", info_ctr.level, nt_errstr(status));
+ ret = false;
+ continue;
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ printf("NetShareEnumAll level %u failed - %s\n", info_ctr.level, win_errstr(r.out.result));
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ benchmark srvsvc netshareenumall queries
+*/
+static bool bench_NetShareEnumAll(struct torture_context *tctx, struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+{
+ struct timeval tv = timeval_current();
+ bool ret = true;
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ int count=0;
+
+ printf("Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (!test_NetShareEnumAll(p, tmp_ctx)) break;
+ talloc_free(tmp_ctx);
+ count++;
+ if (count % 50 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ printf("%.1f queries per second \r",
+ count / timeval_elapsed(&tv));
+ }
+ }
+ }
+
+ printf("%.1f queries per second \n", count / timeval_elapsed(&tv));
+
+ return ret;
+}
+
+
+bool torture_bench_rpc(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+
+ mem_ctx = talloc_init("torture_rpc_srvsvc");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_srvsvc);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ if (!bench_NetShareEnumAll(torture, p, mem_ctx)) {
+ ret = false;
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/rpc/bind.c b/source4/torture/rpc/bind.c
new file mode 100644
index 0000000..7c0d5e4
--- /dev/null
+++ b/source4/torture/rpc/bind.c
@@ -0,0 +1,245 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for rpc bind operations
+
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_epmapper_c.h"
+#include "lib/cmdline/cmdline.h"
+
+static bool test_openpolicy(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle *handle;
+
+ torture_assert(tctx,
+ test_lsa_OpenPolicy2(b, tctx, &handle),
+ "failed to open policy");
+
+ torture_assert(tctx,
+ test_lsa_Close(b, tctx, handle),
+ "failed to close policy");
+
+ return true;
+}
+
+static bool test_bind(struct torture_context *tctx,
+ const void *private_data)
+{
+ struct dcerpc_binding *binding;
+ struct dcerpc_pipe *p;
+ NTSTATUS status;
+ const uint32_t *flags = (const uint32_t *)private_data;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "failed to parse binding string");
+
+ status = dcerpc_binding_set_flags(binding, *flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p, binding,
+ &ndr_table_lsarpc,
+ samba_cmdline_get_creds(),
+ tctx->ev,
+ tctx->lp_ctx),
+ "failed to connect pipe");
+
+ torture_assert(tctx,
+ test_openpolicy(tctx, p),
+ "failed to test openpolicy");
+
+ talloc_free(p);
+
+ return true;
+}
+
+/**
+ * Verifies a handle created in a connection is available on
+ * a second connection when the same association group is
+ * requested in the bind operation. The LSA interface can't be
+ * used because it runs in preforking mode in the selftests.
+ * Association groups should work when binding to interfaces
+ * running in the same process.
+ */
+static bool test_assoc_group_handles_external(struct torture_context *tctx,
+ const void *private_data)
+{
+ struct dcerpc_binding *binding1 = NULL;
+ struct dcerpc_binding *binding2 = NULL;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
+ struct epm_Lookup r;
+ struct epm_LookupHandleFree f;
+ struct policy_handle handle;
+ uint32_t assoc_group_id;
+ uint32_t num_ents = 0;
+
+ ZERO_STRUCT(handle);
+
+ /* Open first pipe and open a policy handle */
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding1),
+ "failed to parse binding string");
+ dcerpc_binding_set_transport(binding1, NCACN_IP_TCP);
+ dcerpc_binding_set_string_option(binding1, "endpoint", "135");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p1, binding1,
+ &ndr_table_epmapper,
+ samba_cmdline_get_creds(),
+ tctx->ev,
+ tctx->lp_ctx),
+ "failed to connect first pipe");
+
+ r.in.inquiry_type = RPC_C_EP_ALL_ELTS;
+ r.in.object = NULL;
+ r.in.interface_id = NULL;
+ r.in.vers_option = RPC_C_VERS_ALL;
+
+ r.in.entry_handle = &handle;
+ r.in.max_ents = 1;
+
+ r.out.entry_handle = &handle;
+ r.out.num_ents = &num_ents;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_epm_Lookup_r(p1->binding_handle, tctx, &r),
+ "failed EPM Lookup");
+ torture_assert_int_equal(tctx,
+ r.out.result,
+ EPMAPPER_STATUS_OK,
+ "failed EPM Lookup");
+
+ /* Open second pipe, different association group. Handle not found */
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding2),
+ "failed to parse binding string");
+ dcerpc_binding_set_transport(binding2, NCACN_IP_TCP);
+ dcerpc_binding_set_string_option(binding2, "endpoint", "135");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, binding2,
+ &ndr_table_epmapper,
+ samba_cmdline_get_creds(),
+ tctx->ev,
+ tctx->lp_ctx),
+ "failed to connect second pipe");
+
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_epm_Lookup_r(p2->binding_handle, tctx, &r),
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "Unexpected EPM Lookup success");
+
+ /* Open second pipe, same association group. Handle is found */
+ assoc_group_id = dcerpc_binding_get_assoc_group_id(p1->binding);
+ dcerpc_binding_set_assoc_group_id(binding2, assoc_group_id);
+
+ TALLOC_FREE(p2);
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, binding2,
+ &ndr_table_epmapper,
+ samba_cmdline_get_creds(),
+ tctx->ev,
+ tctx->lp_ctx),
+ "failed to connect second pipe");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_epm_Lookup_r(p2->binding_handle, tctx, &r),
+ "failed EPM Lookup");
+
+ torture_assert_int_equal(tctx,
+ r.out.result,
+ EPMAPPER_STATUS_OK,
+ "failed EPM Lookup");
+
+ /* Cleanup */
+ f.in.entry_handle = &handle;
+ f.out.entry_handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_epm_LookupHandleFree_r(p1->binding_handle, tctx, &f),
+ "failed EPM LookupHandleFree");
+
+ torture_assert_int_equal(tctx,
+ r.out.result,
+ EPMAPPER_STATUS_OK,
+ "failed EPM LookupHandleFree");
+
+ TALLOC_FREE(p1);
+ TALLOC_FREE(p2);
+ TALLOC_FREE(binding2);
+ TALLOC_FREE(binding1);
+
+ return true;
+}
+
+static void test_bind_op(struct torture_suite *suite,
+ const char *name,
+ uint32_t flags)
+{
+ uint32_t *flags_p = talloc(suite, uint32_t);
+
+ *flags_p = flags;
+
+ torture_suite_add_simple_tcase_const(suite, name, test_bind, flags_p);
+}
+
+
+struct torture_suite *torture_rpc_bind(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "bind");
+ struct {
+ const char *test_name;
+ uint32_t flags;
+ } tests[] = {
+ {
+ .test_name = "ntlm,sign",
+ .flags = DCERPC_AUTH_NTLM | DCERPC_SIGN
+ },{
+ .test_name = "ntlm,sign,seal",
+ .flags = DCERPC_AUTH_NTLM | DCERPC_SIGN | DCERPC_SEAL
+ },{
+ .test_name = "spnego,sign",
+ .flags = DCERPC_AUTH_SPNEGO | DCERPC_SIGN
+ },{
+ .test_name = "spnego,sign,seal",
+ .flags = DCERPC_AUTH_SPNEGO | DCERPC_SIGN | DCERPC_SEAL
+ }
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+ test_bind_op(suite, tests[i].test_name, tests[i].flags);
+ }
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+ test_bind_op(suite, talloc_asprintf(suite, "bigendian,%s", tests[i].test_name), tests[i].flags | DCERPC_PUSH_BIGENDIAN);
+ }
+
+ torture_suite_add_simple_tcase_const(suite,
+ "assoc_group_handles_external",
+ test_assoc_group_handles_external,
+ NULL);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/browser.c b/source4/torture/rpc/browser.c
new file mode 100644
index 0000000..2fbcd4e
--- /dev/null
+++ b/source4/torture/rpc/browser.c
@@ -0,0 +1,124 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for browser rpc operations
+
+ Copyright (C) Stefan Metzmacher 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_browser_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+bool test_BrowserrQueryOtherDomains(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct BrowserrQueryOtherDomains r;
+ struct BrowserrSrvInfo info;
+ struct BrowserrSrvInfo100Ctr ctr100;
+ struct srvsvc_NetSrvInfo100 entries100[1];
+ struct BrowserrSrvInfo101Ctr ctr101;
+ struct srvsvc_NetSrvInfo101 entries101[1];
+ uint32_t total_entries;
+ NTSTATUS status;
+
+ torture_comment(tctx, "dcerpc_BrowserrQueryOtherDomains\n");
+
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(info);
+ ZERO_STRUCT(ctr100);
+ ZERO_STRUCT(entries100);
+ ZERO_STRUCT(ctr101);
+ ZERO_STRUCT(entries101);
+ total_entries = 0;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.info = &info;
+ r.out.info = &info;
+ r.out.total_entries = &total_entries;
+
+ info.level = 100;
+ info.info.info100 = &ctr100;
+
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_ok(tctx, r.out.result, "BrowserrQueryOtherDomains failed");
+ torture_assert_int_equal(tctx, *r.out.total_entries, 0, "BrowserrQueryOtherDomains");
+
+ info.info.info100 = &ctr100;
+ ctr100.entries_read = ARRAY_SIZE(entries100);
+ ctr100.entries = entries100;
+
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_ok(tctx, r.out.result, "BrowserrQueryOtherDomains failed");
+ torture_assert_int_equal(tctx, *r.out.total_entries, 0, "BrowserrQueryOtherDomains");
+
+ info.info.info100 = NULL;
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_equal(tctx, WERR_INVALID_PARAMETER, r.out.result,
+ "BrowserrQueryOtherDomains failed");
+
+ info.level = 101;
+ info.info.info101 = &ctr101;
+
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_equal(tctx, WERR_INVALID_LEVEL, r.out.result,
+ "BrowserrQueryOtherDomains");
+
+ info.info.info101 = &ctr101;
+ ctr101.entries_read = ARRAY_SIZE(entries101);
+ ctr101.entries = entries101;
+
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_equal(tctx, WERR_INVALID_LEVEL, r.out.result,
+ "BrowserrQueryOtherDomains");
+
+ info.info.info101 = NULL;
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_equal(tctx, WERR_INVALID_LEVEL, r.out.result,
+ "BrowserrQueryOtherDomains");
+
+ info.level = 102;
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_equal(tctx, WERR_INVALID_LEVEL, r.out.result,
+ "BrowserrQueryOtherDomains");
+
+ info.level = 0;
+ status = dcerpc_BrowserrQueryOtherDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "BrowserrQueryOtherDomains failed");
+ torture_assert_werr_equal(tctx, WERR_INVALID_LEVEL, r.out.result,
+ "BrowserrQueryOtherDomains");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_browser(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "browser");
+ struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite, "browser", &ndr_table_browser);
+
+ torture_rpc_tcase_add_test(tcase, "BrowserrQueryOtherDomains", test_BrowserrQueryOtherDomains);
+
+ return suite;
+}
+
diff --git a/source4/torture/rpc/clusapi.c b/source4/torture/rpc/clusapi.c
new file mode 100644
index 0000000..183ff54
--- /dev/null
+++ b/source4/torture/rpc/clusapi.c
@@ -0,0 +1,4185 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for clusapi rpc operations
+
+ Copyright (C) Günther Deschner 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_clusapi_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "libcli/registry/util_reg.h"
+
+struct torture_clusapi_context {
+ struct dcerpc_pipe *p;
+ const char *NodeName;
+ const char *ClusterName;
+ uint16_t lpwMajorVersion;
+ uint16_t lpwMinorVersion;
+ uint16_t lpwBuildNumber;
+};
+
+static bool test_OpenCluster_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenCluster r;
+ WERROR Status;
+
+ r.out.Status = &Status;
+ r.out.Cluster = Cluster;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenCluster_r(b, tctx, &r),
+ "OpenCluster failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenCluster failed");
+
+ return true;
+}
+
+static bool test_OpenClusterEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenClusterEx r;
+ uint32_t lpdwGrantedAccess;
+ WERROR Status;
+
+ r.in.dwDesiredAccess = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.lpdwGrantedAccess = &lpdwGrantedAccess;
+ r.out.Status = &Status;
+ r.out.hCluster = Cluster;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenClusterEx_r(b, tctx, &r),
+ "OpenClusterEx failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenClusterEx failed");
+
+ return true;
+}
+
+static bool test_CloseCluster_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseCluster r;
+
+ r.in.Cluster = Cluster;
+ r.out.Cluster = Cluster;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseCluster_r(b, tctx, &r),
+ "CloseCluster failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseCluster failed");
+
+ torture_assert(tctx,
+ ndr_policy_handle_empty(Cluster),
+ "policy_handle non empty after CloseCluster");
+
+ return true;
+}
+
+static bool test_OpenCluster(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle Cluster;
+
+ if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ test_CloseCluster_int(tctx, t->p, &Cluster);
+
+ return true;
+}
+
+static bool test_OpenClusterEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle Cluster;
+
+ if (!test_OpenClusterEx_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ test_CloseCluster_int(tctx, t->p, &Cluster);
+
+ return true;
+}
+
+static bool test_CloseCluster(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle Cluster;
+
+ if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ return test_CloseCluster_int(tctx, t->p, &Cluster);
+}
+
+static bool test_GetClusterName_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char **ClusterName)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetClusterName r;
+ const char *NodeName;
+
+ r.out.ClusterName = ClusterName;
+ r.out.NodeName = &NodeName;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetClusterName_r(b, tctx, &r),
+ "GetClusterName failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetClusterName failed");
+
+ return true;
+}
+
+static bool test_SetClusterName(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_SetClusterName r;
+ const char *NewClusterName;
+ WERROR rpc_status;
+
+ torture_assert(tctx,
+ test_GetClusterName_int(tctx, t->p, &NewClusterName),
+ "failed to query old ClusterName");
+
+ r.in.NewClusterName = NewClusterName;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_SetClusterName_r(b, tctx, &r),
+ "SetClusterName failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_RESOURCE_PROPERTIES_STORED,
+ "SetClusterName failed");
+
+ return true;
+}
+
+static bool test_GetClusterName(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ const char *ClusterName;
+
+ return test_GetClusterName_int(tctx, t->p, &ClusterName);
+}
+
+static bool test_GetClusterVersion(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_GetClusterVersion r;
+ uint16_t lpwMajorVersion;
+ uint16_t lpwMinorVersion;
+ uint16_t lpwBuildNumber;
+ const char *lpszVendorId;
+ const char *lpszCSDVersion;
+
+ r.out.lpwMajorVersion = &lpwMajorVersion;
+ r.out.lpwMinorVersion = &lpwMinorVersion;
+ r.out.lpwBuildNumber = &lpwBuildNumber;
+ r.out.lpszVendorId = &lpszVendorId;
+ r.out.lpszCSDVersion = &lpszCSDVersion;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetClusterVersion_r(b, tctx, &r),
+ "GetClusterVersion failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CALL_NOT_IMPLEMENTED,
+ "GetClusterVersion failed");
+
+ return true;
+}
+
+static bool test_GetClusterVersion2(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_GetClusterVersion2 r;
+ uint16_t lpwMajorVersion;
+ uint16_t lpwMinorVersion;
+ uint16_t lpwBuildNumber;
+ const char *lpszVendorId;
+ const char *lpszCSDVersion;
+ struct CLUSTER_OPERATIONAL_VERSION_INFO *ppClusterOpVerInfo;
+ WERROR rpc_status;
+
+ r.out.lpwMajorVersion = &lpwMajorVersion;
+ r.out.lpwMinorVersion = &lpwMinorVersion;
+ r.out.lpwBuildNumber = &lpwBuildNumber;
+ r.out.lpszVendorId = &lpszVendorId;
+ r.out.lpszCSDVersion = &lpszCSDVersion;
+ r.out.ppClusterOpVerInfo = &ppClusterOpVerInfo;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetClusterVersion2_r(b, tctx, &r),
+ "GetClusterVersion2 failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetClusterVersion2 failed");
+
+ return true;
+}
+
+static bool test_CreateEnum(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType[] = {
+ CLUSTER_ENUM_NODE,
+ CLUSTER_ENUM_RESTYPE,
+ CLUSTER_ENUM_RESOURCE,
+ CLUSTER_ENUM_GROUP,
+ CLUSTER_ENUM_NETWORK,
+ CLUSTER_ENUM_NETINTERFACE,
+ CLUSTER_ENUM_INTERNAL_NETWORK,
+ CLUSTER_ENUM_SHARED_VOLUME_RESOURCE
+ };
+ uint32_t dwType_invalid[] = {
+ 0x00000040,
+ 0x00000080,
+ 0x00000100 /* and many more ... */
+ };
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(dwType); i++) {
+
+ r.in.dwType = dwType[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+ }
+
+ for (i=0; i < ARRAY_SIZE(dwType_invalid); i++) {
+
+ r.in.dwType = dwType_invalid[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "CreateEnum failed");
+ }
+
+ return true;
+}
+
+static bool test_CreateEnumEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CreateEnumEx r;
+ uint32_t dwType[] = {
+ CLUSTER_ENUM_NODE,
+ CLUSTER_ENUM_RESTYPE,
+ CLUSTER_ENUM_RESOURCE,
+ CLUSTER_ENUM_GROUP,
+ CLUSTER_ENUM_NETWORK,
+ CLUSTER_ENUM_NETINTERFACE,
+ CLUSTER_ENUM_INTERNAL_NETWORK,
+ CLUSTER_ENUM_SHARED_VOLUME_RESOURCE
+ };
+ uint32_t dwType_invalid[] = {
+ 0x00000040,
+ 0x00000080,
+ 0x00000100 /* and many more ... */
+ };
+ struct ENUM_LIST *ReturnIdEnum;
+ struct ENUM_LIST *ReturnNameEnum;
+ WERROR rpc_status;
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(dwType); i++) {
+
+ r.in.hCluster = *Cluster;
+ r.in.dwType = dwType[i];
+ r.in.dwOptions = 0;
+ r.out.ReturnIdEnum = &ReturnIdEnum;
+ r.out.ReturnNameEnum = &ReturnNameEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnumEx_r(b, tctx, &r),
+ "CreateEnumEx failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnumEx failed");
+ }
+
+ for (i=0; i < ARRAY_SIZE(dwType_invalid); i++) {
+
+ r.in.hCluster = *Cluster;
+ r.in.dwType = dwType_invalid[i];
+ r.in.dwOptions = 0;
+ r.out.ReturnIdEnum = &ReturnIdEnum;
+ r.out.ReturnNameEnum = &ReturnNameEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnumEx_r(b, tctx, &r),
+ "CreateEnumEx failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "CreateEnumEx failed");
+ }
+
+ return true;
+}
+
+static bool test_CreateEnumEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle Cluster;
+ bool ret;
+
+ if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ ret = test_CreateEnumEx_int(tctx, t->p, &Cluster);
+
+ test_CloseCluster_int(tctx, t->p, &Cluster);
+
+ return ret;
+}
+
+
+static bool test_GetQuorumResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_GetQuorumResource r;
+ const char *lpszResourceName;
+ const char *lpszDeviceName;
+ uint32_t pdwMaxQuorumLogSize;
+ WERROR rpc_status;
+
+ r.out.lpszResourceName = &lpszResourceName;
+ r.out.lpszDeviceName = &lpszDeviceName;
+ r.out.pdwMaxQuorumLogSize = &pdwMaxQuorumLogSize;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetQuorumResource_r(b, tctx, &r),
+ "GetQuorumResource failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetQuorumResource failed");
+
+ return true;
+}
+
+static bool test_SetQuorumResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_SetQuorumResource r;
+ const char *lpszDeviceName = "";
+ uint32_t dwMaxQuorumLogSize = 0;
+ WERROR rpc_status;
+ struct policy_handle hResource;
+
+ /* we need to figure out how this call works and what we provide as
+ devicename and resource handle - gd
+ */
+
+ torture_skip(tctx, "skipping SetQuorumResource test");
+
+ ZERO_STRUCT(hResource);
+
+ r.in.hResource = hResource;
+ r.in.lpszDeviceName = lpszDeviceName;
+ r.in.dwMaxQuorumLogSize = dwMaxQuorumLogSize;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_SetQuorumResource_r(b, tctx, &r),
+ "SetQuorumResource failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "SetQuorumResource failed");
+
+ return true;
+}
+
+static bool test_OpenResource_int_exp(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszResourceName,
+ struct policy_handle *hResource,
+ WERROR expected_Status,
+ WERROR expected_rpc_status)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenResource r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszResourceName = lpszResourceName;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hResource = hResource;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenResource_r(b, tctx, &r),
+ "OpenResource failed");
+ torture_assert_werr_equal(tctx,
+ *r.out.Status, expected_Status,
+ "OpenResource failed");
+ torture_assert_werr_equal(tctx,
+ *r.out.rpc_status, expected_rpc_status,
+ "OpenResource failed");
+
+ return true;
+}
+
+bool test_OpenResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszResourceName,
+ struct policy_handle *hResource)
+{
+ return test_OpenResource_int_exp(tctx, p,
+ lpszResourceName,
+ hResource,
+ WERR_OK, WERR_OK);
+}
+
+static bool test_OpenResourceEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszResourceName,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenResourceEx r;
+ uint32_t lpdwGrantedAccess;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszResourceName = lpszResourceName;
+ r.in.dwDesiredAccess = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.lpdwGrantedAccess = &lpdwGrantedAccess;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hResource = hResource;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenResourceEx_r(b, tctx, &r),
+ "OpenResourceEx failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenResourceEx failed");
+
+ return true;
+}
+
+bool test_CloseResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseResource r;
+
+ r.in.Resource = hResource;
+ r.out.Resource = hResource;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseResource_r(b, tctx, &r),
+ "CloseResource failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseResource failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(hResource),
+ "policy_handle non empty after CloseResource");
+
+ return true;
+}
+
+static bool test_OpenResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ if (!test_OpenResource_int_exp(tctx, t->p, "", &hResource, WERR_RESOURCE_NOT_FOUND, WERR_OK)) {
+ return false;
+ }
+
+ torture_assert(tctx,
+ ndr_policy_handle_empty(&hResource),
+ "expected empty policy handle");
+
+ if (!test_OpenResource_int_exp(tctx, t->p, "jfUF38fjSNcfn", &hResource, WERR_RESOURCE_NOT_FOUND, WERR_OK)) {
+ return false;
+ }
+
+ torture_assert(tctx,
+ ndr_policy_handle_empty(&hResource),
+ "expected empty policy handle");
+
+ return true;
+}
+
+static bool test_OpenResourceEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+
+ if (!test_OpenResourceEx_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return true;
+}
+
+
+static bool test_CloseResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ return test_CloseResource_int(tctx, t->p, &hResource);
+}
+
+static bool test_OpenGroup_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszGroupName,
+ struct policy_handle *hGroup);
+static bool test_CloseGroup_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Group);
+
+static bool test_CreateResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CreateResource r;
+ const char *lpszResourceName = "wurst";
+ const char *lpszResourceType = "Generic Service";
+ WERROR Status;
+ WERROR rpc_status;
+ struct policy_handle hGroup;
+
+ torture_assert(tctx,
+ test_OpenGroup_int(tctx, p, "Cluster Group", &hGroup),
+ "failed to open group");
+
+ r.in.hGroup = hGroup;
+ r.in.lpszResourceName = lpszResourceName;
+ r.in.lpszResourceType = lpszResourceType;
+ r.in.dwFlags = CLUSTER_RESOURCE_DEFAULT_MONITOR;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hResource = hResource;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateResource_r(b, tctx, &r),
+ "CreateResource failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "CreateResource failed");
+
+ test_CloseGroup_int(tctx, p, &hGroup);
+
+ return true;
+}
+
+static bool test_DeleteResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_DeleteResource r;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_DeleteResource_r(b, tctx, &r),
+ "DeleteResource failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "DeleteResource failed");
+
+ return true;
+}
+
+static bool test_CreateResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+
+ if (!test_CreateResource_int(tctx, t->p, &hResource)) {
+ return false;
+ }
+
+ test_DeleteResource_int(tctx, t->p, &hResource);
+
+ return true;
+}
+
+static bool test_DeleteResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+
+ if (!test_CreateResource_int(tctx, t->p, &hResource)) {
+ return false;
+ }
+
+ return test_DeleteResource_int(tctx, t->p, &hResource);
+}
+
+static bool test_SetResourceName_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_SetResourceName r;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.in.lpszResourceName = "wurst";
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_SetResourceName_r(b, tctx, &r),
+ "SetResourceName failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "SetResourceName failed");
+
+ return true;
+}
+
+static bool test_SetResourceName(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_CreateResource_int(tctx, t->p, &hResource)) {
+ return false;
+ }
+
+ ret = test_SetResourceName_int(tctx, t->p, &hResource);
+
+ test_DeleteResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_GetResourceState_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetResourceState r;
+ enum clusapi_ClusterResourceState State;
+ const char *NodeName;
+ const char *GroupName;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.State = &State;
+ r.out.NodeName = &NodeName;
+ r.out.GroupName = &GroupName;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetResourceState_r(b, tctx, &r),
+ "GetResourceState failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetResourceState failed");
+
+ return true;
+}
+
+static bool test_GetResourceState(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_GetResourceState_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_GetResourceId_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetResourceId r;
+ const char *pGuid;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.pGuid = &pGuid;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetResourceId_r(b, tctx, &r),
+ "GetResourceId failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetResourceId failed");
+
+ return true;
+}
+
+static bool test_GetResourceId(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_GetResourceId_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_GetResourceType_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetResourceType r;
+ const char *lpszResourceType;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.lpszResourceType = &lpszResourceType;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetResourceType_r(b, tctx, &r),
+ "GetResourceType failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetResourceType failed");
+
+ return true;
+}
+
+static bool test_GetResourceType(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_GetResourceType_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_FailResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_FailResource r;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_FailResource_r(b, tctx, &r),
+ "FailResource failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "FailResource failed");
+
+ return true;
+}
+
+static bool test_FailResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_FailResource_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+bool test_OnlineResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OnlineResource r;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OnlineResource_r(b, tctx, &r),
+ "OnlineResource failed");
+ if (!W_ERROR_IS_OK(r.out.result) &&
+ !W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "OnlineResource failed with %s",
+ win_errstr(r.out.result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_OnlineResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_OnlineResource_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+bool test_OfflineResource_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OfflineResource r;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OfflineResource_r(b, tctx, &r),
+ "OfflineResource failed");
+ if (!W_ERROR_IS_OK(r.out.result) &&
+ !W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "OfflineResource failed with %s",
+ win_errstr(r.out.result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_OfflineResource(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_OfflineResource_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_CreateResEnum_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CreateResEnum r;
+ uint32_t dwType = CLUSTER_ENUM_RESOURCE;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateResEnum_r(b, tctx, &r),
+ "CreateResEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateResEnum failed");
+
+ return true;
+}
+
+static bool test_CreateResEnum(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_CreateResEnum_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_GetResourceDependencyExpression_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetResourceDependencyExpression r;
+ const char *lpszDependencyExpression;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.lpszDependencyExpression = &lpszDependencyExpression;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetResourceDependencyExpression_r(b, tctx, &r),
+ "GetResourceDependencyExpression failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetResourceDependencyExpression failed");
+
+ return true;
+}
+
+static bool test_GetResourceDependencyExpression(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Cluster Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_GetResourceDependencyExpression_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_GetResourceNetworkName_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetResourceNetworkName r;
+ const char *lpszName;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.lpszName = &lpszName;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetResourceNetworkName_r(b, tctx, &r),
+ "GetResourceNetworkName failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetResourceNetworkName failed");
+
+ return true;
+}
+
+static bool test_GetResourceNetworkName(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hResource;
+ bool ret = true;
+
+ if (!test_OpenResource_int(tctx, t->p, "Network Name", &hResource)) {
+ return false;
+ }
+
+ ret = test_GetResourceNetworkName_int(tctx, t->p, &hResource);
+
+ test_CloseResource_int(tctx, t->p, &hResource);
+
+ return ret;
+}
+
+static bool test_ResourceTypeControl_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster,
+ const char *resource_type,
+ enum clusapi_ResourceTypeControlCode dwControlCode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_ResourceTypeControl r;
+ uint32_t lpBytesReturned;
+ uint32_t lpcbRequired;
+ WERROR rpc_status;
+
+ r.in.hCluster = *Cluster;
+ r.in.lpszResourceTypeName = resource_type;
+ r.in.dwControlCode = 0;
+ r.in.lpInBuffer = NULL;
+ r.in.nInBufferSize = 0;
+ r.in.nOutBufferSize = 0;
+ r.out.lpOutBuffer = NULL;
+ r.out.lpBytesReturned = &lpBytesReturned;
+ r.out.lpcbRequired = &lpcbRequired;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ResourceTypeControl_r(b, tctx, &r),
+ "ResourceTypeControl failed");
+
+ if (strequal(r.in.lpszResourceTypeName, "MSMQ") ||
+ strequal(r.in.lpszResourceTypeName, "MSMQTriggers")) {
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CLUSTER_RESTYPE_NOT_SUPPORTED,
+ "ResourceTypeControl failed");
+ return true;
+ }
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_FUNCTION,
+ "ResourceTypeControl failed");
+
+ r.in.dwControlCode = dwControlCode;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ResourceTypeControl_r(b, tctx, &r),
+ "ResourceTypeControl failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, *r.out.lpcbRequired);
+ r.in.nOutBufferSize = *r.out.lpcbRequired;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ResourceTypeControl_r(b, tctx, &r),
+ "ResourceTypeControl failed");
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "ResourceTypeControl failed");
+
+ /* now try what happens when we query with a buffer large enough to hold
+ * the entire packet */
+
+ r.in.nOutBufferSize = 0x4000;
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ResourceTypeControl_r(b, tctx, &r),
+ "ResourceTypeControl failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "ResourceTypeControl failed");
+ torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+ "lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
+ return true;
+}
+
+static bool test_ResourceTypeControl(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *resourcetype_name)
+{
+ struct policy_handle Cluster;
+ bool ret = true;
+ uint32_t control_codes[] = {
+ CLUSCTL_RESOURCE_TYPE_GET_CLASS_INFO,
+ CLUSCTL_RESOURCE_TYPE_GET_CHARACTERISTICS,
+ CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES,
+ CLUSCTL_RESOURCE_TYPE_GET_RO_COMMON_PROPERTIES,
+ CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_PROPERTIES
+ };
+ int i;
+
+ if (!test_OpenCluster_int(tctx, p, &Cluster)) {
+ return false;
+ }
+
+ for (i=0; i < ARRAY_SIZE(control_codes); i++) {
+ ret = test_ResourceTypeControl_int(tctx, p, &Cluster,
+ resourcetype_name,
+ control_codes[i]);
+ if (!ret) {
+ goto done;
+ }
+ }
+
+ done:
+ test_CloseCluster_int(tctx, p, &Cluster);
+
+ return ret;
+}
+
+
+
+static bool test_one_resourcetype(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *resourcetype_name)
+{
+ torture_assert(tctx,
+ test_ResourceTypeControl(tctx, p, resourcetype_name),
+ "failed to query ResourceTypeControl");
+
+ return true;
+}
+
+static bool test_one_resource(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *resource_name)
+{
+ struct policy_handle hResource;
+
+ torture_assert(tctx,
+ test_OpenResource_int(tctx, p, resource_name, &hResource),
+ "failed to open resource");
+ test_CloseResource_int(tctx, p, &hResource);
+
+ torture_assert(tctx,
+ test_OpenResourceEx_int(tctx, p, resource_name, &hResource),
+ "failed to openex resource");
+
+ torture_assert(tctx,
+ test_GetResourceType_int(tctx, p, &hResource),
+ "failed to query resource type");
+ torture_assert(tctx,
+ test_GetResourceId_int(tctx, p, &hResource),
+ "failed to query resource id");
+ torture_assert(tctx,
+ test_GetResourceState_int(tctx, p, &hResource),
+ "failed to query resource state");
+ torture_assert(tctx,
+ test_CreateResEnum_int(tctx, p, &hResource),
+ "failed to query resource enum");
+ torture_assert(tctx,
+ test_GetResourceDependencyExpression_int(tctx, p, &hResource),
+ "failed to query resource dependency expression");
+ torture_assert(tctx,
+ test_GetResourceNetworkName_int(tctx, p, &hResource),
+ "failed to query resource network name");
+
+ test_CloseResource_int(tctx, p, &hResource);
+
+ return true;
+}
+
+static bool test_all_resources(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType = CLUSTER_ENUM_RESOURCE;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert_int_equal(tctx, e.Type, CLUSTER_ENUM_RESOURCE, "type mismatch");
+
+ torture_assert(tctx,
+ test_one_resource(tctx, t->p, e.Name),
+ "failed to test one resource");
+ }
+
+ return true;
+}
+
+static bool test_all_resourcetypes(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType = CLUSTER_ENUM_RESTYPE;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert_int_equal(tctx, e.Type, CLUSTER_ENUM_RESTYPE, "type mismatch");
+
+ torture_assert(tctx,
+ test_one_resourcetype(tctx, t->p, e.Name),
+ "failed to test one resourcetype");
+ }
+
+ return true;
+}
+
+
+static bool test_OpenNode_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszNodeName,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenNode r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszNodeName = lpszNodeName;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hNode= hNode;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenNode_r(b, tctx, &r),
+ "OpenNode failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenNode failed");
+
+ return true;
+}
+
+static bool test_OpenNodeEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszNodeName,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenNodeEx r;
+ uint32_t lpdwGrantedAccess;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszNodeName = lpszNodeName;
+ r.in.dwDesiredAccess = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.lpdwGrantedAccess = &lpdwGrantedAccess;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hNode= hNode;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenNodeEx_r(b, tctx, &r),
+ "OpenNodeEx failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenNodeEx failed");
+
+ return true;
+}
+
+
+static bool test_CloseNode_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Node)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseNode r;
+
+ r.in.Node = Node;
+ r.out.Node = Node;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseNode_r(b, tctx, &r),
+ "CloseNode failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseNode failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(Node),
+ "policy_handle non empty after CloseNode");
+
+ return true;
+}
+
+static bool test_OpenNode(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return true;
+}
+
+static bool test_OpenNodeEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+
+ if (!test_OpenNodeEx_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return true;
+}
+
+static bool test_CloseNode(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ return test_CloseNode_int(tctx, t->p, &hNode);
+}
+
+static bool test_GetNodeState_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetNodeState r;
+ enum clusapi_ClusterNodeState State;
+ WERROR rpc_status;
+
+ r.in.hNode = *hNode;
+ r.out.State = &State;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetNodeState_r(b, tctx, &r),
+ "GetNodeState failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetNodeState failed");
+
+ return true;
+}
+
+static bool test_GetNodeState(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+ bool ret = true;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ ret = test_GetNodeState_int(tctx, t->p, &hNode);
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return ret;
+}
+
+static bool test_GetNodeId_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetNodeId r;
+ const char *pGuid;
+ WERROR rpc_status;
+
+ r.in.hNode = *hNode;
+ r.out.pGuid = &pGuid;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetNodeId_r(b, tctx, &r),
+ "GetNodeId failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetNodeId failed");
+
+ return true;
+}
+
+static bool test_GetNodeId(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+ bool ret = true;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ ret = test_GetNodeId_int(tctx, t->p, &hNode);
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return ret;
+}
+
+static bool test_NodeControl_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNode,
+ enum clusapi_NodeControlCode dwControlCode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_NodeControl r;
+ uint32_t lpBytesReturned;
+ uint32_t lpcbRequired;
+ WERROR rpc_status;
+
+ r.in.hNode = *hNode;
+ r.in.dwControlCode = 0;
+ r.in.lpInBuffer = NULL;
+ r.in.nInBufferSize = 0;
+ r.in.nOutBufferSize = 0;
+ r.out.lpOutBuffer = NULL;
+ r.out.lpBytesReturned = &lpBytesReturned;
+ r.out.lpcbRequired = &lpcbRequired;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+ "NodeControl failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_FUNCTION,
+ "NodeControl failed");
+
+ r.in.dwControlCode = dwControlCode;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+ "NodeControl failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, *r.out.lpcbRequired);
+ r.in.nOutBufferSize = *r.out.lpcbRequired;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+ "NodeControl failed");
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "NodeControl failed");
+
+ /* now try what happens when we query with a buffer large enough to hold
+ * the entire packet */
+
+ r.in.nOutBufferSize = 0x4000;
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_NodeControl_r(b, tctx, &r),
+ "NodeControl failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "NodeControl failed");
+ torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+ "lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
+ if (dwControlCode == CLUSCTL_NODE_GET_ID) {
+ const char *str;
+ DATA_BLOB blob = data_blob_const(r.out.lpOutBuffer, *r.out.lpBytesReturned);
+
+ torture_assert(tctx, *r.out.lpBytesReturned >= 4, "must be at least 4 bytes long");
+ torture_assert(tctx, (*r.out.lpBytesReturned % 2) == 0, "must be a multiple of 2");
+
+ torture_assert(tctx,
+ pull_reg_sz(tctx, &blob, &str),
+ "failed to pull unicode string");
+
+ torture_comment(tctx, "got this node id: '%s'", str);
+ }
+
+ return true;
+}
+
+static bool test_NodeControl(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+ bool ret = true;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ ret = test_NodeControl_int(tctx, t->p, &hNode, CLUSCTL_NODE_GET_RO_COMMON_PROPERTIES);
+ if (!ret) {
+ return false;
+ }
+
+ ret = test_NodeControl_int(tctx, t->p, &hNode, CLUSCTL_NODE_GET_ID);
+ if (!ret) {
+ return false;
+ }
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return ret;
+}
+
+static bool test_PauseNode_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_PauseNode r;
+ WERROR rpc_status;
+
+ r.in.hNode = *hNode;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_PauseNode_r(b, tctx, &r),
+ "PauseNode failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "PauseNode failed");
+
+ return true;
+}
+
+static bool test_PauseNode(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+ bool ret = true;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ ret = test_PauseNode_int(tctx, t->p, &hNode);
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return ret;
+}
+
+static bool test_ResumeNode_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_ResumeNode r;
+ WERROR rpc_status;
+
+ r.in.hNode = *hNode;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ResumeNode_r(b, tctx, &r),
+ "ResumeNode failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CLUSTER_NODE_NOT_PAUSED,
+ "ResumeNode gave unexpected result");
+
+ return true;
+}
+
+static bool test_ResumeNode(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+ bool ret = true;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ ret = test_ResumeNode_int(tctx, t->p, &hNode);
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return ret;
+}
+
+static bool test_EvictNode_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_EvictNode r;
+ WERROR rpc_status;
+
+ r.in.hNode = *hNode;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_EvictNode_r(b, tctx, &r),
+ "EvictNode failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "EvictNode failed");
+
+ return true;
+}
+
+static bool test_EvictNode(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNode;
+ bool ret = true;
+
+ if (!test_OpenNode_int(tctx, t->p, t->NodeName, &hNode)) {
+ return false;
+ }
+
+ ret = test_EvictNode_int(tctx, t->p, &hNode);
+
+ test_CloseNode_int(tctx, t->p, &hNode);
+
+ return ret;
+}
+
+static bool test_one_node(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *node_name)
+{
+ struct policy_handle hNode;
+
+ torture_assert(tctx,
+ test_OpenNode_int(tctx, p, node_name, &hNode),
+ "failed to open node");
+ test_CloseNode_int(tctx, p, &hNode);
+
+ torture_assert(tctx,
+ test_OpenNodeEx_int(tctx, p, node_name, &hNode),
+ "failed to openex node");
+
+ torture_assert(tctx,
+ test_GetNodeId_int(tctx, p, &hNode),
+ "failed to query node id");
+ torture_assert(tctx,
+ test_GetNodeState_int(tctx, p, &hNode),
+ "failed to query node id");
+
+ test_CloseNode_int(tctx, p, &hNode);
+
+ return true;
+}
+
+static bool test_all_nodes(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType = CLUSTER_ENUM_NODE;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert_int_equal(tctx, e.Type, CLUSTER_ENUM_NODE, "type mismatch");
+
+ torture_assert(tctx,
+ test_one_node(tctx, t->p, e.Name),
+ "failed to test one node");
+ }
+
+ return true;
+}
+
+static bool test_OpenGroup_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszGroupName,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenGroup r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszGroupName = lpszGroupName;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hGroup= hGroup;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenGroup_r(b, tctx, &r),
+ "OpenGroup failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenGroup failed");
+
+ return true;
+}
+
+static bool test_OpenGroupEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszGroupName,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenGroupEx r;
+ uint32_t lpdwGrantedAccess;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszGroupName = lpszGroupName;
+ r.in.dwDesiredAccess = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.lpdwGrantedAccess = &lpdwGrantedAccess;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hGroup= hGroup;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenGroupEx_r(b, tctx, &r),
+ "OpenGroupEx failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenGroupEx failed");
+
+ return true;
+}
+
+static bool test_CloseGroup_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Group)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseGroup r;
+
+ r.in.Group = Group;
+ r.out.Group = Group;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseGroup_r(b, tctx, &r),
+ "CloseGroup failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseGroup failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(Group),
+ "policy_handle non empty after CloseGroup");
+
+ return true;
+}
+
+static bool test_OpenGroup(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return true;
+}
+
+static bool test_OpenGroupEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+
+ if (!test_OpenGroupEx_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return true;
+}
+
+static bool test_CloseGroup(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ return test_CloseGroup_int(tctx, t->p, &hGroup);
+}
+
+static bool test_GetGroupState_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetGroupState r;
+ enum clusapi_ClusterGroupState State;
+ const char *NodeName;
+ WERROR rpc_status;
+
+ r.in.hGroup = *hGroup;
+ r.out.State = &State;
+ r.out.NodeName = &NodeName;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetGroupState_r(b, tctx, &r),
+ "GetGroupState failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetGroupState failed");
+
+ return true;
+}
+
+static bool test_GetGroupState(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+ bool ret = true;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ ret = test_GetGroupState_int(tctx, t->p, &hGroup);
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return ret;
+}
+
+static bool test_GetGroupId_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetGroupId r;
+ const char *pGuid;
+ WERROR rpc_status;
+
+ r.in.hGroup = *hGroup;
+ r.out.pGuid = &pGuid;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetGroupId_r(b, tctx, &r),
+ "GetGroupId failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetGroupId failed");
+
+ return true;
+}
+
+static bool test_GetGroupId(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+ bool ret = true;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ ret = test_GetGroupId_int(tctx, t->p, &hGroup);
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return ret;
+}
+
+static bool test_GroupControl_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hGroup,
+ enum clusapi_GroupControlCode dwControlCode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GroupControl r;
+ uint32_t lpBytesReturned;
+ uint32_t lpcbRequired;
+ WERROR rpc_status;
+
+ r.in.hGroup = *hGroup;
+ r.in.dwControlCode = 0;
+ r.in.lpInBuffer = NULL;
+ r.in.nInBufferSize = 0;
+ r.in.nOutBufferSize = 0;
+ r.out.lpOutBuffer = NULL;
+ r.out.lpBytesReturned = &lpBytesReturned;
+ r.out.lpcbRequired = &lpcbRequired;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+ "GroupControl failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_FUNCTION,
+ "GroupControl failed");
+
+ r.in.dwControlCode = dwControlCode;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+ "GroupControl failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, *r.out.lpcbRequired);
+ r.in.nOutBufferSize = *r.out.lpcbRequired;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+ "GroupControl failed");
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GroupControl failed");
+
+ /* now try what happens when we query with a buffer large enough to hold
+ * the entire packet */
+
+ r.in.nOutBufferSize = 0x400;
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GroupControl_r(b, tctx, &r),
+ "GroupControl failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GroupControl failed");
+ torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+ "lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
+ return true;
+}
+
+static bool test_CreateGroupResourceEnum_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CreateGroupResourceEnum r;
+ uint32_t dwType[] = {
+ CLUSTER_GROUP_ENUM_CONTAINS,
+ CLUSTER_GROUP_ENUM_NODES
+ };
+ uint32_t dwType_invalid[] = {
+ 0x00000040,
+ 0x00000080,
+ 0x00000100 /* and many more ... */
+ };
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.hGroup = *hGroup;
+
+ for (i=0; i < ARRAY_SIZE(dwType); i++) {
+
+ r.in.hGroup = *hGroup;
+ r.in.dwType = dwType[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateGroupResourceEnum_r(b, tctx, &r),
+ "CreateGroupResourceEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateGroupResourceEnum failed");
+ }
+
+ for (i=0; i < ARRAY_SIZE(dwType_invalid); i++) {
+
+ r.in.dwType = dwType_invalid[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateGroupResourceEnum_r(b, tctx, &r),
+ "CreateGroupResourceEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateGroupResourceEnum failed");
+ }
+
+ return true;
+}
+
+
+static bool test_GroupControl(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+ bool ret = true;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ ret = test_GroupControl_int(tctx, t->p, &hGroup, CLUSCTL_GROUP_GET_CHARACTERISTICS);
+ if (!ret) {
+ return false;
+ }
+
+ ret = test_GroupControl_int(tctx, t->p, &hGroup, CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES);
+ if (!ret) {
+ return false;
+ }
+
+ ret = test_GroupControl_int(tctx, t->p, &hGroup, CLUSCTL_GROUP_GET_FLAGS);
+ if (!ret) {
+ return false;
+ }
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return ret;
+}
+
+static bool test_OnlineGroup_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OnlineGroup r;
+ WERROR rpc_status;
+
+ r.in.hGroup = *hGroup;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OnlineGroup_r(b, tctx, &r),
+ "OnlineGroup failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "OnlineGroup failed");
+
+ return true;
+}
+
+static bool test_OnlineGroup(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+ bool ret = true;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ ret = test_OnlineGroup_int(tctx, t->p, &hGroup);
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return ret;
+}
+
+static bool test_OfflineGroup_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hGroup)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OfflineGroup r;
+ WERROR rpc_status;
+
+ r.in.hGroup = *hGroup;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OfflineGroup_r(b, tctx, &r),
+ "OfflineGroup failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "OfflineGroup failed");
+
+ return true;
+}
+
+static bool test_OfflineGroup(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroup;
+ bool ret = true;
+
+ if (!test_OpenGroup_int(tctx, t->p, "Cluster Group", &hGroup)) {
+ return false;
+ }
+
+ ret = test_OfflineGroup_int(tctx, t->p, &hGroup);
+
+ test_CloseGroup_int(tctx, t->p, &hGroup);
+
+ return ret;
+}
+
+static bool test_one_group(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *group_name)
+{
+ struct policy_handle hGroup;
+
+ torture_assert(tctx,
+ test_OpenGroup_int(tctx, p, group_name, &hGroup),
+ "failed to open group");
+ test_CloseGroup_int(tctx, p, &hGroup);
+
+ torture_assert(tctx,
+ test_OpenGroupEx_int(tctx, p, group_name, &hGroup),
+ "failed to openex group");
+
+ torture_assert(tctx,
+ test_GetGroupId_int(tctx, p, &hGroup),
+ "failed to query group id");
+ torture_assert(tctx,
+ test_GetGroupState_int(tctx, p, &hGroup),
+ "failed to query group id");
+
+ torture_assert(tctx,
+ test_GroupControl_int(tctx, p, &hGroup, CLUSCTL_GROUP_GET_FLAGS),
+ "failed to query group control");
+
+ torture_assert(tctx,
+ test_CreateGroupResourceEnum_int(tctx, p, &hGroup),
+ "failed to query resource enum");
+
+ test_CloseGroup_int(tctx, p, &hGroup);
+
+ return true;
+}
+
+static bool test_all_groups(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType = CLUSTER_ENUM_GROUP;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert_int_equal(tctx, e.Type, CLUSTER_ENUM_GROUP, "type mismatch");
+
+ torture_assert(tctx,
+ test_one_group(tctx, t->p, e.Name),
+ "failed to test one group");
+ }
+
+ return true;
+}
+
+static bool test_BackupClusterDatabase(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_BackupClusterDatabase r;
+ WERROR rpc_status;
+
+ r.in.lpszPathName = "c:\\cluster_backup";
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_BackupClusterDatabase_r(b, tctx, &r),
+ "BackupClusterDatabase failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CALL_NOT_IMPLEMENTED,
+ "BackupClusterDatabase failed");
+
+ return true;
+}
+
+static bool test_SetServiceAccountPassword(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_SetServiceAccountPassword r;
+ uint32_t SizeReturned;
+ uint32_t ExpectedBufferSize;
+
+ r.in.lpszNewPassword = "P@ssw0rd!";
+ r.in.dwFlags = IDL_CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES;
+ r.in.ReturnStatusBufferSize = 1024;
+ r.out.ReturnStatusBufferPtr = NULL;
+ r.out.SizeReturned = &SizeReturned;
+ r.out.ExpectedBufferSize = &ExpectedBufferSize;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_SetServiceAccountPassword_r(b, tctx, &r),
+ "SetServiceAccountPassword failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CALL_NOT_IMPLEMENTED,
+ "SetServiceAccountPassword failed");
+
+ return true;
+}
+
+static bool test_ClusterControl_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster,
+ enum clusapi_ClusterControlCode dwControlCode)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_ClusterControl r;
+ uint32_t lpBytesReturned;
+ uint32_t lpcbRequired;
+ WERROR rpc_status;
+
+ r.in.hCluster = *Cluster;
+ r.in.dwControlCode = 0;
+ r.in.lpInBuffer = NULL;
+ r.in.nInBufferSize = 0;
+ r.in.nOutBufferSize = 0;
+ r.out.lpOutBuffer = NULL;
+ r.out.lpBytesReturned = &lpBytesReturned;
+ r.out.lpcbRequired = &lpcbRequired;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ClusterControl_r(b, tctx, &r),
+ "ClusterControl failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_FUNCTION,
+ "ClusterControl failed");
+
+ r.in.dwControlCode = dwControlCode;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ClusterControl_r(b, tctx, &r),
+ "ClusterControl failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, *r.out.lpcbRequired);
+ r.in.nOutBufferSize = *r.out.lpcbRequired;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ClusterControl_r(b, tctx, &r),
+ "ClusterControl failed");
+ }
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "ClusterControl failed");
+
+ /* now try what happens when we query with a buffer large enough to hold
+ * the entire packet */
+
+ r.in.nOutBufferSize = 0xffff;
+ r.out.lpOutBuffer = talloc_zero_array(tctx, uint8_t, r.in.nOutBufferSize);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_ClusterControl_r(b, tctx, &r),
+ "ClusterControl failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "ClusterControl failed");
+ torture_assert(tctx, *r.out.lpBytesReturned < r.in.nOutBufferSize,
+ "lpBytesReturned expected to be smaller than input size nOutBufferSize");
+
+ return true;
+}
+
+static bool test_ClusterControl(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle Cluster;
+ bool ret = true;
+ uint32_t control_codes[] = {
+ CLUSCTL_CLUSTER_GET_COMMON_PROPERTIES,
+ CLUSCTL_CLUSTER_GET_RO_COMMON_PROPERTIES,
+ CLUSCTL_CLUSTER_GET_FQDN,
+ CLUSCTL_CLUSTER_GET_PRIVATE_PROPERTIES,
+ CLUSCTL_CLUSTER_CHECK_VOTER_DOWN
+ };
+ int i;
+
+ if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ for (i=0; i < ARRAY_SIZE(control_codes); i++) {
+ ret = test_ClusterControl_int(tctx, t->p, &Cluster,
+ control_codes[i]);
+ if (!ret) {
+ goto done;
+ }
+ }
+
+ done:
+ test_CloseCluster_int(tctx, t->p, &Cluster);
+
+ return ret;
+}
+
+static bool test_CreateResTypeEnum(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateResTypeEnum r;
+ uint32_t dwType[] = {
+ CLUSTER_RESOURCE_TYPE_ENUM_NODES,
+ CLUSTER_RESOURCE_TYPE_ENUM_RESOURCES
+ };
+ uint32_t dwType_invalid[] = {
+ 0x00000040,
+ 0x00000080,
+ 0x00000100 /* and many more ... */
+ };
+ const char *valid_names[] = {
+ "Physical Disk",
+ "Storage Pool"
+ };
+ const char *invalid_names[] = {
+ "INVALID_TYPE_XXXX"
+ };
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i, s;
+
+ for (s = 0; s < ARRAY_SIZE(valid_names); s++) {
+
+ r.in.lpszTypeName = valid_names[s];
+
+ for (i=0; i < ARRAY_SIZE(dwType); i++) {
+
+ r.in.dwType = dwType[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateResTypeEnum_r(b, tctx, &r),
+ "CreateResTypeEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateResTypeEnum failed");
+ }
+
+ for (i=0; i < ARRAY_SIZE(dwType_invalid); i++) {
+
+ r.in.dwType = dwType_invalid[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateResTypeEnum_r(b, tctx, &r),
+ "CreateResTypeEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateResTypeEnum failed");
+ }
+ }
+
+ for (s = 0; s < ARRAY_SIZE(invalid_names); s++) {
+
+ r.in.lpszTypeName = invalid_names[s];
+
+ for (i=0; i < ARRAY_SIZE(dwType); i++) {
+
+ r.in.dwType = dwType[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateResTypeEnum_r(b, tctx, &r),
+ "CreateResTypeEnum failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CLUSTER_RESOURCE_TYPE_NOT_FOUND,
+ "CreateResTypeEnum failed");
+ }
+
+ for (i=0; i < ARRAY_SIZE(dwType_invalid); i++) {
+
+ r.in.dwType = dwType_invalid[i];
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateResTypeEnum_r(b, tctx, &r),
+ "CreateResTypeEnum failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_CLUSTER_RESOURCE_TYPE_NOT_FOUND,
+ "CreateResTypeEnum failed");
+ }
+ }
+
+
+ return true;
+}
+
+static bool test_CreateGroupEnum_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Cluster,
+ const char **multi_sz,
+ const char **multi_sz_ro)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CreateGroupEnum r;
+ struct GROUP_ENUM_LIST *pResultList;
+ WERROR rpc_status;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB blob_ro = data_blob_null;
+
+ r.in.hCluster = *Cluster;
+ r.in.pProperties = blob.data;
+ r.in.cbProperties = blob.length;
+ r.in.pRoProperties = blob_ro.data;
+ r.in.cbRoProperties = blob_ro.length;
+ r.out.ppResultList = &pResultList;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateGroupEnum_r(b, tctx, &r),
+ "CreateGroupEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateGroupEnum failed");
+
+ if (!push_reg_multi_sz(tctx, &blob, multi_sz)) {
+ return false;
+ }
+
+ if (!push_reg_multi_sz(tctx, &blob_ro, multi_sz_ro)) {
+ return false;
+ }
+
+ r.in.pProperties = blob.data;
+ r.in.cbProperties = blob.length;
+
+ r.in.pRoProperties = blob_ro.data;
+ r.in.cbRoProperties = blob_ro.length;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateGroupEnum_r(b, tctx, &r),
+ "CreateGroupEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateGroupEnum failed");
+
+#if 0
+ {
+ int i;
+ enum ndr_err_code ndr_err;
+
+ for (i=0; i < pResultList->EntryCount; i++) {
+ struct clusapi_PROPERTY_LIST list;
+ torture_comment(tctx, "entry #%d\n", i);
+
+ blob = data_blob_const(pResultList->Entry[i].Properties,
+ pResultList->Entry[i].cbProperties);
+
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, &list,
+ (ndr_pull_flags_fn_t)ndr_pull_clusapi_PROPERTY_LIST);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(clusapi_PROPERTY_LIST, &list);
+ }
+
+ blob_ro = data_blob_const(pResultList->Entry[i].RoProperties,
+ pResultList->Entry[i].cbRoProperties);
+
+ ndr_err = ndr_pull_struct_blob(&blob_ro, tctx, &list,
+ (ndr_pull_flags_fn_t)ndr_pull_clusapi_PROPERTY_LIST);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(clusapi_PROPERTY_LIST, &list);
+ }
+ }
+ }
+#endif
+
+ return true;
+}
+
+static bool test_CreateGroupEnum(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle Cluster;
+ bool ret;
+ const char *multi_sz[] = {
+ "Priority", NULL,
+ };
+ const char *multi_sz_ro[] = {
+ "GroupType", NULL,
+ };
+
+ if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ ret = test_CreateGroupEnum_int(tctx, t->p, &Cluster,
+ multi_sz, multi_sz_ro);
+ if (!ret) {
+ goto done;
+ }
+
+ done:
+ test_CloseCluster_int(tctx, t->p, &Cluster);
+
+ return ret;
+}
+
+static bool test_OpenNetwork_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszNetworkName,
+ struct policy_handle *hNetwork)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenNetwork r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszNetworkName = lpszNetworkName;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hNetwork = hNetwork ;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenNetwork_r(b, tctx, &r),
+ "OpenNetwork failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenNetwork failed");
+
+ return true;
+}
+
+static bool test_OpenNetworkEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszNetworkName,
+ struct policy_handle *hNetwork)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenNetworkEx r;
+ uint32_t lpdwGrantedAccess;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszNetworkName = lpszNetworkName;
+ r.in.dwDesiredAccess = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.lpdwGrantedAccess = &lpdwGrantedAccess;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hNetwork = hNetwork ;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenNetworkEx_r(b, tctx, &r),
+ "OpenNetworkEx failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenNetworkEx failed");
+
+ return true;
+}
+
+static bool test_CloseNetwork_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *Network)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseNetwork r;
+
+ r.in.Network = Network;
+ r.out.Network = Network;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseNetwork_r(b, tctx, &r),
+ "CloseNetwork failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseNetwork failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(Network),
+ "policy_handle non empty after CloseNetwork");
+
+ return true;
+}
+
+static bool test_OpenNetwork(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetwork;
+
+ if (!test_OpenNetwork_int(tctx, t->p, "Cluster Network 1", &hNetwork)) {
+ return false;
+ }
+
+ test_CloseNetwork_int(tctx, t->p, &hNetwork);
+
+ return true;
+}
+
+static bool test_OpenNetworkEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetwork;
+
+ if (!test_OpenNetworkEx_int(tctx, t->p, "Cluster Network 1", &hNetwork)) {
+ return false;
+ }
+
+ test_CloseNetwork_int(tctx, t->p, &hNetwork);
+
+ return true;
+}
+
+static bool test_CloseNetwork(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetwork;
+
+ if (!test_OpenNetwork_int(tctx, t->p, "Cluster Network 1", &hNetwork)) {
+ return false;
+ }
+
+ return test_CloseNetwork_int(tctx, t->p, &hNetwork);
+}
+
+static bool test_GetNetworkState_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNetwork)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetNetworkState r;
+ enum clusapi_ClusterNetworkState State;
+ WERROR rpc_status;
+
+ r.in.hNetwork = *hNetwork;
+ r.out.State = &State;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetNetworkState_r(b, tctx, &r),
+ "GetNetworkState failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetNetworkState failed");
+
+ return true;
+}
+
+static bool test_GetNetworkState(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetwork;
+ bool ret = true;
+
+ if (!test_OpenNetwork_int(tctx, t->p, "Cluster Network 1", &hNetwork)) {
+ return false;
+ }
+
+ ret = test_GetNetworkState_int(tctx, t->p, &hNetwork);
+
+ test_CloseNetwork_int(tctx, t->p, &hNetwork);
+
+ return ret;
+}
+
+static bool test_GetNetworkId_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNetwork)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetNetworkId r;
+ const char *pGuid;
+ WERROR rpc_status;
+
+ r.in.hNetwork = *hNetwork;
+ r.out.pGuid = &pGuid;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetNetworkId_r(b, tctx, &r),
+ "GetNetworkId failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetNetworkId failed");
+
+ return true;
+}
+
+static bool test_GetNetworkId(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetwork;
+ bool ret = true;
+
+ if (!test_OpenNetwork_int(tctx, t->p, "Cluster Network 1", &hNetwork)) {
+ return false;
+ }
+
+ ret = test_GetNetworkId_int(tctx, t->p, &hNetwork);
+
+ test_CloseNetwork_int(tctx, t->p, &hNetwork);
+
+ return ret;
+}
+
+static bool test_one_network(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *network_name)
+{
+ struct policy_handle hNetwork;
+
+ torture_assert(tctx,
+ test_OpenNetwork_int(tctx, p, network_name, &hNetwork),
+ "failed to open network");
+ test_CloseNetwork_int(tctx, p, &hNetwork);
+
+ torture_assert(tctx,
+ test_OpenNetworkEx_int(tctx, p, network_name, &hNetwork),
+ "failed to openex network");
+
+ torture_assert(tctx,
+ test_GetNetworkId_int(tctx, p, &hNetwork),
+ "failed to query network id");
+ torture_assert(tctx,
+ test_GetNetworkState_int(tctx, p, &hNetwork),
+ "failed to query network id");
+
+ test_CloseNetwork_int(tctx, p, &hNetwork);
+
+ return true;
+}
+
+static bool test_all_networks(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType = CLUSTER_ENUM_NETWORK;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert_int_equal(tctx, e.Type, CLUSTER_ENUM_NETWORK, "type mismatch");
+
+ torture_assert(tctx,
+ test_one_network(tctx, t->p, e.Name),
+ "failed to test one network");
+ }
+
+ return true;
+}
+
+static bool test_OpenNetInterface_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszNetInterfaceName,
+ struct policy_handle *hNetInterface)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenNetInterface r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszNetInterfaceName = lpszNetInterfaceName;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hNetInterface = hNetInterface;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenNetInterface_r(b, tctx, &r),
+ "OpenNetInterface failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenNetInterface failed");
+
+ return true;
+}
+
+static bool test_OpenNetInterfaceEx_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszNetInterfaceName,
+ struct policy_handle *hNetInterface)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenNetInterfaceEx r;
+ uint32_t lpdwGrantedAccess;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszNetInterfaceName = lpszNetInterfaceName;
+ r.in.dwDesiredAccess = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.lpdwGrantedAccess = &lpdwGrantedAccess;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hNetInterface = hNetInterface;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenNetInterfaceEx_r(b, tctx, &r),
+ "OpenNetInterfaceEx failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenNetInterfaceEx failed");
+
+ return true;
+}
+
+static bool test_CloseNetInterface_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *NetInterface)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseNetInterface r;
+
+ r.in.NetInterface = NetInterface;
+ r.out.NetInterface = NetInterface;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseNetInterface_r(b, tctx, &r),
+ "CloseNetInterface failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseNetInterface failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(NetInterface),
+ "policy_handle non empty after CloseNetInterface");
+
+ return true;
+}
+
+static bool test_OpenNetInterface(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetInterface;
+
+ if (!test_OpenNetInterface_int(tctx, t->p, "node1 - Ethernet", &hNetInterface)) {
+ return false;
+ }
+
+ test_CloseNetInterface_int(tctx, t->p, &hNetInterface);
+
+ return true;
+}
+
+static bool test_OpenNetInterfaceEx(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetInterface;
+
+ if (!test_OpenNetInterfaceEx_int(tctx, t->p, "node1 - Ethernet", &hNetInterface)) {
+ return false;
+ }
+
+ test_CloseNetInterface_int(tctx, t->p, &hNetInterface);
+
+ return true;
+}
+
+static bool test_CloseNetInterface(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetInterface;
+
+ if (!test_OpenNetInterface_int(tctx, t->p, "node1 - Ethernet", &hNetInterface)) {
+ return false;
+ }
+
+ return test_CloseNetInterface_int(tctx, t->p, &hNetInterface);
+}
+
+static bool test_GetNetInterfaceState_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNetInterface)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetNetInterfaceState r;
+ enum clusapi_ClusterNetInterfaceState State;
+ WERROR rpc_status;
+
+ r.in.hNetInterface = *hNetInterface;
+ r.out.State = &State;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetNetInterfaceState_r(b, tctx, &r),
+ "GetNetInterfaceState failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetNetInterfaceState failed");
+
+ return true;
+}
+
+static bool test_GetNetInterfaceState(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetInterface;
+ bool ret = true;
+
+ if (!test_OpenNetInterface_int(tctx, t->p, "node1 - Ethernet", &hNetInterface)) {
+ return false;
+ }
+
+ ret = test_GetNetInterfaceState_int(tctx, t->p, &hNetInterface);
+
+ test_CloseNetInterface_int(tctx, t->p, &hNetInterface);
+
+ return ret;
+}
+
+static bool test_GetNetInterfaceId_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hNetInterface)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetNetInterfaceId r;
+ const char *pGuid;
+ WERROR rpc_status;
+
+ r.in.hNetInterface = *hNetInterface;
+ r.out.pGuid = &pGuid;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetNetInterfaceId_r(b, tctx, &r),
+ "GetNetInterfaceId failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetNetInterfaceId failed");
+
+ return true;
+}
+
+static bool test_GetNetInterfaceId(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hNetInterface;
+ bool ret = true;
+
+ if (!test_OpenNetInterface_int(tctx, t->p, "node1 - Ethernet", &hNetInterface)) {
+ return false;
+ }
+
+ ret = test_GetNetInterfaceId_int(tctx, t->p, &hNetInterface);
+
+ test_CloseNetInterface_int(tctx, t->p, &hNetInterface);
+
+ return ret;
+}
+
+static bool test_one_netinterface(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *netinterface_name)
+{
+ struct policy_handle hNetInterface;
+
+ torture_assert(tctx,
+ test_OpenNetInterface_int(tctx, p, netinterface_name, &hNetInterface),
+ "failed to open netinterface");
+ test_CloseNetInterface_int(tctx, p, &hNetInterface);
+
+ torture_assert(tctx,
+ test_OpenNetInterfaceEx_int(tctx, p, netinterface_name, &hNetInterface),
+ "failed to openex netinterface");
+
+ torture_assert(tctx,
+ test_GetNetInterfaceId_int(tctx, p, &hNetInterface),
+ "failed to query netinterface id");
+ torture_assert(tctx,
+ test_GetNetInterfaceState_int(tctx, p, &hNetInterface),
+ "failed to query netinterface id");
+
+ test_CloseNetInterface_int(tctx, p, &hNetInterface);
+
+ return true;
+}
+
+static bool test_all_netinterfaces(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateEnum r;
+ uint32_t dwType = CLUSTER_ENUM_NETINTERFACE;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ int i;
+
+ r.in.dwType = dwType;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "CreateEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateEnum failed");
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert_int_equal(tctx, e.Type, CLUSTER_ENUM_NETINTERFACE, "type mismatch");
+
+ torture_assert(tctx,
+ test_one_netinterface(tctx, t->p, e.Name),
+ "failed to test one netinterface");
+ }
+
+ return true;
+}
+
+static bool test_CloseKey_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *pKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseKey r;
+
+ r.in.pKey = pKey;
+ r.out.pKey = pKey;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseKey_r(b, tctx, &r),
+ "CloseKey failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseKey failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(pKey),
+ "policy_handle non empty after CloseKey");
+
+ return true;
+}
+
+static bool test_GetRootKey_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *phKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetRootKey r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.samDesired = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.Status = &Status;
+ r.out.rpc_status = &rpc_status;
+ r.out.phKey = phKey;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetRootKey_r(b, tctx, &r),
+ "GetRootKey failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "GetRootKey failed");
+
+ return true;
+}
+
+static bool test_EnumKey_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_EnumKey r;
+ const char *KeyName;
+ NTTIME lpftLastWriteTime;
+ WERROR rpc_status;
+
+ r.in.hKey = *hKey;
+ r.in.dwIndex = 0;
+ r.out.KeyName = &KeyName;
+ r.out.lpftLastWriteTime = &lpftLastWriteTime;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_EnumKey_r(b, tctx, &r),
+ "EnumKey failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "EnumKey failed");
+
+ return true;
+}
+
+static bool test_OpenKey_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey,
+ const char *lpSubKey,
+ struct policy_handle *phKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenKey r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.hKey = *hKey;
+ r.in.lpSubKey = lpSubKey;
+ r.in.samDesired = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.Status = &Status;
+ r.out.rpc_status = &rpc_status;
+ r.out.phKey = phKey;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenKey_r(b, tctx, &r),
+ "OpenKey failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenKey failed");
+
+ return true;
+}
+
+static bool test_EnumValue_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_EnumValue r;
+ const char *lpValueName;
+ uint32_t lpType;
+ uint32_t TotalSize;
+ WERROR rpc_status;
+ int i = 0;
+
+ do {
+ uint32_t lpcbData = 2048;
+
+ r.in.hKey = *hKey;
+ r.in.dwIndex = i++;
+ r.in.lpcbData = &lpcbData;
+ r.out.lpValueName = &lpValueName;
+ r.out.lpType = &lpType;
+ r.out.lpData = talloc_array(tctx, uint8_t, lpcbData);
+ r.out.TotalSize = &TotalSize;
+ r.out.rpc_status = &rpc_status;
+ r.out.lpcbData = &lpcbData;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_EnumValue_r(b, tctx, &r),
+ "EnumValue failed");
+
+ } while (W_ERROR_IS_OK(r.out.result));
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_NO_MORE_ITEMS,
+ "EnumValue failed");
+
+ return true;
+}
+
+static bool test_QueryInfoKey_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_QueryInfoKey r;
+ uint32_t lpcSubKeys;
+ uint32_t lpcbMaxSubKeyLen;
+ uint32_t lpcValues;
+ uint32_t lpcbMaxValueNameLen;
+ uint32_t lpcbMaxValueLen;
+ uint32_t lpcbSecurityDescriptor;
+ NTTIME lpftLastWriteTime;
+ WERROR rpc_status;
+
+ r.in.hKey = *hKey;
+ r.out.lpcSubKeys = &lpcSubKeys;
+ r.out.lpcbMaxSubKeyLen = &lpcbMaxSubKeyLen;
+ r.out.lpcValues = &lpcValues;
+ r.out.lpcbMaxValueNameLen = &lpcbMaxValueNameLen;
+ r.out.lpcbMaxValueLen = &lpcbMaxValueLen;
+ r.out.lpcbSecurityDescriptor = &lpcbSecurityDescriptor;
+ r.out.lpftLastWriteTime = &lpftLastWriteTime;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_QueryInfoKey_r(b, tctx, &r),
+ "QueryInfoKey failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "QueryInfoKey failed");
+
+ return true;
+}
+
+static bool test_GetKeySecurity_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetKeySecurity r;
+ uint32_t SecurityInformation = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP;
+ struct RPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor;
+ WERROR rpc_status;
+
+ ZERO_STRUCT(pRpcSecurityDescriptor);
+
+ r.in.hKey = *hKey;
+ r.in.SecurityInformation = SecurityInformation;
+ r.in.pRpcSecurityDescriptor = &pRpcSecurityDescriptor;
+ r.out.rpc_status = &rpc_status;
+ r.out.pRpcSecurityDescriptor = &pRpcSecurityDescriptor;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetKeySecurity_r(b, tctx, &r),
+ "GetKeySecurity failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ pRpcSecurityDescriptor.lpSecurityDescriptor = talloc_array(tctx,
+ uint8_t, pRpcSecurityDescriptor.cbInSecurityDescriptor);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetKeySecurity_r(b, tctx, &r),
+ "GetKeySecurity failed");
+ }
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetKeySecurity failed");
+
+ return true;
+}
+
+static bool test_GetRootKey(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hKey;
+
+ if (!test_GetRootKey_int(tctx, t->p, &hKey)) {
+ return false;
+ }
+
+ test_CloseKey_int(tctx, t->p, &hKey);
+
+ return true;
+}
+
+static bool test_CloseKey(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hKey;
+
+ if (!test_GetRootKey_int(tctx, t->p, &hKey)) {
+ return false;
+ }
+
+ return test_CloseKey_int(tctx, t->p, &hKey);
+}
+
+static bool test_EnumKey(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hKey;
+ bool ret = true;
+
+ if (!test_GetRootKey_int(tctx, t->p, &hKey)) {
+ return false;
+ }
+
+ ret = test_EnumKey_int(tctx, t->p, &hKey);
+
+ test_CloseKey_int(tctx, t->p, &hKey);
+
+ return ret;
+}
+
+static bool test_QueryValue_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey,
+ const char *ValueName)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_QueryValue r;
+ uint32_t lpValueType;
+ uint32_t lpcbRequired;
+ WERROR rpc_status;
+
+ r.in.hKey = *hKey;
+ r.in.lpValueName = ValueName;
+ r.in.cbData = 0;
+ r.out.lpValueType = &lpValueType;
+ r.out.lpData = NULL;
+ r.out.lpcbRequired = &lpcbRequired;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+
+ r.in.cbData = lpcbRequired;
+ r.out.lpData = talloc_zero_array(tctx, uint8_t, r.in.cbData);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ }
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "QueryValue failed");
+
+ if (lpValueType == REG_SZ) {
+ const char *s;
+ DATA_BLOB blob = data_blob_const(r.out.lpData, lpcbRequired);
+ pull_reg_sz(tctx, &blob, &s);
+ torture_comment(tctx, "got: %s\n", s);
+ }
+
+ return true;
+}
+
+static bool test_QueryValue(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hKey;
+ bool ret = true;
+
+ if (!test_GetRootKey_int(tctx, t->p, &hKey)) {
+ return false;
+ }
+
+ ret = test_QueryValue_int(tctx, t->p, &hKey, "ClusterInstanceID");
+
+ test_CloseKey_int(tctx, t->p, &hKey);
+
+ return ret;
+}
+
+
+static bool test_one_key(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hKey,
+ const char *KeyName)
+{
+ struct policy_handle phKey;
+
+ torture_assert(tctx,
+ test_OpenKey_int(tctx, p, hKey, KeyName, &phKey),
+ "failed to open key");
+
+ torture_assert(tctx,
+ test_QueryInfoKey_int(tctx, p, &phKey),
+ "failed to enum values");
+ torture_assert(tctx,
+ test_GetKeySecurity_int(tctx, p, &phKey),
+ "failed to get key security");
+
+ torture_assert(tctx,
+ test_EnumValue_int(tctx, p, &phKey),
+ "failed to enum values");
+
+ torture_assert(tctx,
+ test_CloseKey_int(tctx, p, &phKey),
+ "failed to close key");
+
+ return true;
+}
+
+static bool test_all_keys(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct policy_handle hKey;
+ struct clusapi_EnumKey r;
+ const char *KeyName;
+ NTTIME lpftLastWriteTime;
+ WERROR rpc_status;
+ int i = 0;
+
+ if (!test_GetRootKey_int(tctx, t->p, &hKey)) {
+ return false;
+ }
+
+ do {
+ r.in.hKey = hKey;
+ r.in.dwIndex = i++;
+ r.out.KeyName = &KeyName;
+ r.out.lpftLastWriteTime = &lpftLastWriteTime;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_EnumKey_r(b, tctx, &r),
+ "EnumKey failed");
+
+ if (W_ERROR_IS_OK(r.out.result)) {
+ torture_assert(tctx,
+ test_one_key(tctx, t->p, &hKey, KeyName),
+ "failed to test one key");
+ }
+
+ } while (W_ERROR_IS_OK(r.out.result));
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_NO_MORE_ITEMS,
+ "EnumKey failed");
+
+ test_CloseKey_int(tctx, t->p, &hKey);
+
+ return true;
+}
+
+static bool test_OpenGroupSet_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *lpszGroupSetName,
+ struct policy_handle *hGroupSet)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_OpenGroupSet r;
+ WERROR Status;
+ WERROR rpc_status;
+
+ r.in.lpszGroupSetName = lpszGroupSetName;
+ r.out.rpc_status = &rpc_status;
+ r.out.Status = &Status;
+ r.out.hGroupSet = hGroupSet;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_OpenGroupSet_r(b, tctx, &r),
+ "OpenGroupSet failed");
+ torture_assert_werr_ok(tctx,
+ *r.out.Status,
+ "OpenGroupSet failed");
+
+ return true;
+}
+
+static bool test_CloseGroupSet_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *GroupSet)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_CloseGroupSet r;
+
+ r.in.GroupSet = GroupSet;
+ r.out.GroupSet = GroupSet;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CloseGroupSet_r(b, tctx, &r),
+ "CloseGroupSet failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CloseGroupSet failed");
+ torture_assert(tctx,
+ ndr_policy_handle_empty(GroupSet),
+ "policy_handle non empty after CloseGroupSet");
+
+ return true;
+}
+
+static bool test_OpenGroupSet(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroupSet;
+
+ if (t->lpwMajorVersion < 0x000a) {
+ torture_skip(tctx, "GroupSet fn not available on old clusters");
+ return true;
+ }
+
+ if (!test_OpenGroupSet_int(tctx, t->p, "Cluster Group", &hGroupSet)) {
+ return false;
+ }
+
+ test_CloseGroupSet_int(tctx, t->p, &hGroupSet);
+
+ return true;
+}
+
+static bool test_CloseGroupSet(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct policy_handle hGroupSet;
+
+ if (t->lpwMajorVersion < 0x000a) {
+ torture_skip(tctx, "GroupSet fn not available on old clusters");
+ return true;
+ }
+
+ if (!test_OpenGroupSet_int(tctx, t->p, "Cluster Group", &hGroupSet)) {
+ return false;
+ }
+
+ return test_CloseGroupSet_int(tctx, t->p, &hGroupSet);
+}
+
+static bool test_one_groupset(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *groupset_name)
+{
+ struct policy_handle hGroupSet;
+
+ torture_assert(tctx,
+ test_OpenGroupSet_int(tctx, p, groupset_name, &hGroupSet),
+ "failed to open groupset");
+
+ test_CloseGroupSet_int(tctx, p, &hGroupSet);
+
+ return true;
+}
+
+static bool test_all_groupsets(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_clusapi_context *t =
+ talloc_get_type_abort(data, struct torture_clusapi_context);
+ struct dcerpc_binding_handle *b = t->p->binding_handle;
+ struct clusapi_CreateGroupSetEnum r;
+ struct ENUM_LIST *ReturnEnum;
+ struct policy_handle Cluster;
+ WERROR rpc_status;
+ int i;
+
+ if (!test_OpenCluster_int(tctx, t->p, &Cluster)) {
+ return false;
+ }
+
+ r.in.hCluster = Cluster;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateGroupSetEnum_r(b, tctx, &r),
+ "CreateGroupSetEnum failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "CreateGroupSetEnum failed");
+
+ test_CloseCluster_int(tctx, t->p, &Cluster);
+
+ for (i=0; i < ReturnEnum->EntryCount; i++) {
+
+ struct ENUM_ENTRY e = ReturnEnum->Entry[i];
+
+ torture_assert(tctx,
+ test_one_groupset(tctx, t->p, e.Name),
+ "failed to test one groupset");
+ }
+
+ return true;
+}
+
+static bool torture_rpc_clusapi_setup_common(struct torture_context *tctx,
+ struct torture_clusapi_context *t)
+{
+ struct dcerpc_binding_handle *b;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &t->p, &ndr_table_clusapi),
+ "Error connecting to server");
+
+ b = t->p->binding_handle;
+
+ {
+ struct clusapi_GetClusterName r;
+
+ r.out.ClusterName = &t->ClusterName;
+ r.out.NodeName = &t->NodeName;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetClusterName_r(b, tctx, &r),
+ "GetClusterName failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetClusterName failed");
+ }
+ {
+ struct clusapi_GetClusterVersion2 r;
+ const char *lpszVendorId;
+ const char *lpszCSDVersion;
+ struct CLUSTER_OPERATIONAL_VERSION_INFO *ppClusterOpVerInfo;
+ WERROR rpc_status;
+
+ r.out.lpwMajorVersion = &t->lpwMajorVersion;
+ r.out.lpwMinorVersion = &t->lpwMinorVersion;
+ r.out.lpwBuildNumber = &t->lpwBuildNumber;
+ r.out.lpszVendorId = &lpszVendorId;
+ r.out.lpszCSDVersion = &lpszCSDVersion;
+ r.out.ppClusterOpVerInfo = &ppClusterOpVerInfo;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetClusterVersion2_r(b, tctx, &r),
+ "GetClusterVersion2 failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetClusterVersion2 failed");
+ }
+
+ return true;
+}
+
+static bool torture_rpc_clusapi_setup(struct torture_context *tctx,
+ void **data)
+{
+ struct torture_clusapi_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_clusapi_context);
+
+ return torture_rpc_clusapi_setup_common(tctx, t);
+}
+
+static bool torture_rpc_clusapi_teardown(struct torture_context *tctx,
+ void *data)
+{
+ talloc_free(data);
+
+ return true;
+}
+
+void torture_tcase_cluster(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "OpenCluster",
+ test_OpenCluster);
+ torture_tcase_add_simple_test(tcase, "OpenClusterEx",
+ test_OpenClusterEx);
+ torture_tcase_add_simple_test(tcase, "CloseCluster",
+ test_CloseCluster);
+ torture_tcase_add_simple_test(tcase, "SetClusterName",
+ test_SetClusterName);
+ torture_tcase_add_simple_test(tcase, "GetClusterName",
+ test_GetClusterName);
+ torture_tcase_add_simple_test(tcase, "GetClusterVersion",
+ test_GetClusterVersion);
+ torture_tcase_add_simple_test(tcase, "CreateEnum",
+ test_CreateEnum);
+ torture_tcase_add_simple_test(tcase, "CreateEnumEx",
+ test_CreateEnumEx);
+ torture_tcase_add_simple_test(tcase, "GetClusterVersion2",
+ test_GetClusterVersion2);
+ torture_tcase_add_simple_test(tcase, "BackupClusterDatabase",
+ test_BackupClusterDatabase);
+ torture_tcase_add_simple_test(tcase, "SetServiceAccountPassword",
+ test_SetServiceAccountPassword);
+ torture_tcase_add_simple_test(tcase, "ClusterControl",
+ test_ClusterControl);
+ torture_tcase_add_simple_test(tcase, "CreateResTypeEnum",
+ test_CreateResTypeEnum);
+ torture_tcase_add_simple_test(tcase, "CreateGroupEnum",
+ test_CreateGroupEnum);
+
+}
+
+void torture_tcase_resource(struct torture_tcase *tcase)
+{
+ struct torture_test *test;
+
+ torture_tcase_add_simple_test(tcase, "GetQuorumResource",
+ test_GetQuorumResource);
+ torture_tcase_add_simple_test(tcase, "SetQuorumResource",
+ test_SetQuorumResource);
+ torture_tcase_add_simple_test(tcase, "OpenResource",
+ test_OpenResource);
+ torture_tcase_add_simple_test(tcase, "OpenResourceEx",
+ test_OpenResourceEx);
+ torture_tcase_add_simple_test(tcase, "CloseResource",
+ test_CloseResource);
+ torture_tcase_add_simple_test(tcase, "CreateResource",
+ test_CreateResource);
+ torture_tcase_add_simple_test(tcase, "DeleteResource",
+ test_DeleteResource);
+ torture_tcase_add_simple_test(tcase, "SetResourceName",
+ test_SetResourceName);
+ torture_tcase_add_simple_test(tcase, "GetResourceState",
+ test_GetResourceState);
+ torture_tcase_add_simple_test(tcase, "GetResourceId",
+ test_GetResourceId);
+ torture_tcase_add_simple_test(tcase, "GetResourceType",
+ test_GetResourceType);
+ torture_tcase_add_simple_test(tcase, "CreateResEnum",
+ test_CreateResEnum);
+ test = torture_tcase_add_simple_test(tcase, "FailResource",
+ test_FailResource);
+ test->dangerous = true;
+ torture_tcase_add_simple_test(tcase, "OnlineResource",
+ test_OnlineResource);
+ test = torture_tcase_add_simple_test(tcase, "OfflineResource",
+ test_OfflineResource);
+ test->dangerous = true;
+ torture_tcase_add_simple_test(tcase, "GetResourceDependencyExpression",
+ test_GetResourceDependencyExpression);
+ torture_tcase_add_simple_test(tcase, "GetResourceNetworkName",
+ test_GetResourceNetworkName);
+ torture_tcase_add_simple_test(tcase, "all_resources",
+ test_all_resources);
+}
+
+void torture_tcase_resourcetype(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "all_resourcetypes",
+ test_all_resourcetypes);
+}
+
+void torture_tcase_node(struct torture_tcase *tcase)
+{
+ struct torture_test *test;
+
+ torture_tcase_add_simple_test(tcase, "OpenNode",
+ test_OpenNode);
+ torture_tcase_add_simple_test(tcase, "OpenNodeEx",
+ test_OpenNodeEx);
+ torture_tcase_add_simple_test(tcase, "CloseNode",
+ test_CloseNode);
+ torture_tcase_add_simple_test(tcase, "GetNodeState",
+ test_GetNodeState);
+ torture_tcase_add_simple_test(tcase, "GetNodeId",
+ test_GetNodeId);
+ torture_tcase_add_simple_test(tcase, "NodeControl",
+ test_NodeControl);
+ test = torture_tcase_add_simple_test(tcase, "PauseNode",
+ test_PauseNode);
+ test->dangerous = true;
+ torture_tcase_add_simple_test(tcase, "ResumeNode",
+ test_ResumeNode);
+ test = torture_tcase_add_simple_test(tcase, "EvictNode",
+ test_EvictNode);
+ test->dangerous = true;
+ torture_tcase_add_simple_test(tcase, "all_nodes",
+ test_all_nodes);
+}
+
+void torture_tcase_group(struct torture_tcase *tcase)
+{
+ struct torture_test *test;
+
+ torture_tcase_add_simple_test(tcase, "OpenGroup",
+ test_OpenGroup);
+ torture_tcase_add_simple_test(tcase, "OpenGroupEx",
+ test_OpenGroupEx);
+ torture_tcase_add_simple_test(tcase, "CloseGroup",
+ test_CloseGroup);
+ torture_tcase_add_simple_test(tcase, "GetGroupState",
+ test_GetGroupState);
+ torture_tcase_add_simple_test(tcase, "GetGroupId",
+ test_GetGroupId);
+ torture_tcase_add_simple_test(tcase, "GroupControl",
+ test_GroupControl);
+ torture_tcase_add_simple_test(tcase, "OnlineGroup",
+ test_OnlineGroup);
+ test = torture_tcase_add_simple_test(tcase, "OfflineGroup",
+ test_OfflineGroup);
+ test->dangerous = true;
+ torture_tcase_add_simple_test(tcase, "all_groups",
+ test_all_groups);
+}
+
+void torture_tcase_network(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "OpenNetwork",
+ test_OpenNetwork);
+ torture_tcase_add_simple_test(tcase, "OpenNetworkEx",
+ test_OpenNetworkEx);
+ torture_tcase_add_simple_test(tcase, "CloseNetwork",
+ test_CloseNetwork);
+ torture_tcase_add_simple_test(tcase, "GetNetworkState",
+ test_GetNetworkState);
+ torture_tcase_add_simple_test(tcase, "GetNetworkId",
+ test_GetNetworkId);
+ torture_tcase_add_simple_test(tcase, "all_networks",
+ test_all_networks);
+}
+
+void torture_tcase_netinterface(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "OpenNetInterface",
+ test_OpenNetInterface);
+ torture_tcase_add_simple_test(tcase, "OpenNetInterfaceEx",
+ test_OpenNetInterfaceEx);
+ torture_tcase_add_simple_test(tcase, "CloseNetInterface",
+ test_CloseNetInterface);
+ torture_tcase_add_simple_test(tcase, "GetNetInterfaceState",
+ test_GetNetInterfaceState);
+ torture_tcase_add_simple_test(tcase, "GetNetInterfaceId",
+ test_GetNetInterfaceId);
+ torture_tcase_add_simple_test(tcase, "all_netinterfaces",
+ test_all_netinterfaces);
+}
+
+void torture_tcase_registry(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "GetRootKey",
+ test_GetRootKey);
+ torture_tcase_add_simple_test(tcase, "CloseKey",
+ test_CloseKey);
+ torture_tcase_add_simple_test(tcase, "EnumKey",
+ test_EnumKey);
+ torture_tcase_add_simple_test(tcase, "QueryValue",
+ test_QueryValue);
+ torture_tcase_add_simple_test(tcase, "all_keys",
+ test_all_keys);
+}
+
+void torture_tcase_groupset(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "OpenGroupSet",
+ test_OpenGroupSet);
+ torture_tcase_add_simple_test(tcase, "CloseGroupSet",
+ test_CloseGroupSet);
+ torture_tcase_add_simple_test(tcase, "all_groupsets",
+ test_all_groupsets);
+}
+
+struct torture_suite *torture_rpc_clusapi(TALLOC_CTX *mem_ctx)
+{
+ struct torture_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "clusapi");
+
+ tcase = torture_suite_add_tcase(suite, "cluster");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_cluster(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "resource");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_resource(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "resourcetype");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_resourcetype(tcase);
+
+
+ tcase = torture_suite_add_tcase(suite, "node");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_node(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "group");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_group(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "network");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_network(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "netinterface");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_netinterface(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "registry");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_registry(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "groupset");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_clusapi_setup,
+ torture_rpc_clusapi_teardown);
+
+ torture_tcase_groupset(tcase);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/countcalls.c b/source4/torture/rpc/countcalls.c
new file mode 100644
index 0000000..52be979
--- /dev/null
+++ b/source4/torture/rpc/countcalls.c
@@ -0,0 +1,131 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ count number of calls on an interface
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/ndr/ndr_table.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+
+
+bool count_calls(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *iface,
+ bool all)
+{
+ struct dcerpc_pipe *p;
+ DATA_BLOB stub_in, stub_out;
+ int i;
+ NTSTATUS status = torture_rpc_connection(tctx, &p, iface);
+ if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)
+ || NT_STATUS_IS_RPC(status)
+ || NT_STATUS_EQUAL(NT_STATUS_PORT_UNREACHABLE, status)
+ || NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
+ if (all) {
+ /* Not fatal if looking for all pipes */
+ return true;
+ } else {
+ printf("Failed to open '%s' to count calls - %s\n", iface->name, nt_errstr(status));
+ return false;
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to open '%s' to count calls - %s\n", iface->name, nt_errstr(status));
+ return false;
+ }
+
+ stub_in = data_blob_null;
+
+ printf("\nScanning pipe '%s'\n", iface->name);
+
+ for (i=0;i<500;i++) {
+ uint32_t out_flags = 0;
+
+ status = dcerpc_binding_handle_raw_call(p->binding_handle,
+ NULL, i,
+ 0, /* in_flags */
+ stub_in.data,
+ stub_in.length,
+ mem_ctx,
+ &stub_out.data,
+ &stub_out.length,
+ &out_flags);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ i--;
+ break;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ i--;
+ break;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
+ i--;
+ break;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ i--;
+ break;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)) {
+ i--;
+ break;
+ }
+ }
+
+ if (i==500) {
+ talloc_free(p);
+ printf("no limit on calls: %s!?\n", nt_errstr(status));
+ return false;
+ }
+
+ printf("Found %d calls\n", i);
+
+ talloc_free(p);
+
+ return true;
+
+}
+
+bool torture_rpc_countcalls(struct torture_context *torture)
+{
+ const struct ndr_interface_table *iface;
+ const char *iface_name;
+ bool ret = true;
+ const struct ndr_interface_list *l;
+ iface_name = lpcfg_parm_string(torture->lp_ctx, NULL, "countcalls", "interface");
+ if (iface_name != NULL) {
+ iface = ndr_table_by_name(iface_name);
+ if (!iface) {
+ printf("Unknown interface '%s'\n", iface_name);
+ return false;
+ }
+ return count_calls(torture, torture, iface, false);
+ }
+
+ for (l=ndr_table_list();l;l=l->next) {
+ TALLOC_CTX *loop_ctx;
+ loop_ctx = talloc_named(torture, 0, "torture_rpc_councalls loop context");
+ ret &= count_calls(torture, loop_ctx, l->table, true);
+ talloc_free(loop_ctx);
+ }
+ return ret;
+}
diff --git a/source4/torture/rpc/dfs.c b/source4/torture/rpc/dfs.c
new file mode 100644
index 0000000..14af288
--- /dev/null
+++ b/source4/torture/rpc/dfs.c
@@ -0,0 +1,651 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for rpc dfs operations
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_dfs_c.h"
+#include "libnet/libnet.h"
+#include "torture/util.h"
+#include "libcli/libcli.h"
+#include "lib/cmdline/cmdline.h"
+
+#define SMBTORTURE_DFS_SHARENAME "smbtorture_dfs_share"
+#define SMBTORTURE_DFS_DIRNAME "\\smbtorture_dfs_dir"
+#define SMBTORTURE_DFS_PATHNAME "C:"SMBTORTURE_DFS_DIRNAME
+
+#define IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(x,y)\
+ if (x == DFS_MANAGER_VERSION_W2K3) {\
+ if (!W_ERROR_EQUAL(y,WERR_NOT_SUPPORTED)) {\
+ printf("expected WERR_NOT_SUPPORTED\n");\
+ return false;\
+ }\
+ return true;\
+ }\
+
+static bool test_NetShareAdd(struct torture_context *tctx,
+ const char *host,
+ const char *sharename,
+ const char *dir)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareInfo2 i;
+ struct libnet_context* libnetctx;
+ struct libnet_AddShare r;
+
+ printf("Creating share %s\n", sharename);
+
+ if (!(libnetctx = libnet_context_init(tctx->ev, tctx->lp_ctx))) {
+ return false;
+ }
+
+ libnetctx->cred = samba_cmdline_get_creds();
+
+ i.name = sharename;
+ i.type = STYPE_DISKTREE;
+ i.path = dir;
+ i.max_users = (uint32_t) -1;
+ i.comment = "created by smbtorture";
+ i.password = NULL;
+ i.permissions = 0x0;
+ i.current_users = 0x0;
+
+ r.level = 2;
+ r.in.server_name = host;
+ r.in.share = i;
+
+ status = libnet_AddShare(libnetctx, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Failed to add new share: %s (%s)\n",
+ nt_errstr(status), r.out.error_string);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_NetShareDel(struct torture_context *tctx,
+ const char *host,
+ const char *sharename)
+{
+ NTSTATUS status;
+ struct libnet_context* libnetctx;
+ struct libnet_DelShare r;
+
+ torture_comment(tctx, "Deleting share %s\n", sharename);
+
+ if (!(libnetctx = libnet_context_init(tctx->ev, tctx->lp_ctx))) {
+ return false;
+ }
+
+ libnetctx->cred = samba_cmdline_get_creds();
+
+ r.in.share_name = sharename;
+ r.in.server_name = host;
+
+ status = libnet_DelShare(libnetctx, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Failed to delete share: %s (%s)\n",
+ nt_errstr(status), r.out.error_string);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_CreateDir(TALLOC_CTX *mem_ctx,
+ struct smbcli_state **cli,
+ struct torture_context *tctx,
+ const char *host,
+ const char *share,
+ const char *dir)
+{
+ printf("Creating directory %s\n", dir);
+
+ if (!torture_open_connection_share(mem_ctx, cli, tctx, host, share, tctx->ev)) {
+ return false;
+ }
+
+ if (!torture_setup_dir(*cli, dir)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_DeleteDir(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ const char *dir)
+{
+ torture_comment(tctx, "Deleting directory %s\n", dir);
+
+ if (smbcli_deltree(cli->tree, dir) == -1) {
+ printf("Unable to delete dir %s - %s\n", dir,
+ smbcli_errstr(cli->tree));
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_GetManagerVersion_opts(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ enum dfs_ManagerVersion *version_p)
+{
+ struct dfs_GetManagerVersion r;
+ enum dfs_ManagerVersion version;
+
+ r.out.version = &version;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_GetManagerVersion_r(b, tctx, &r),
+ "GetManagerVersion failed");
+
+ if (version_p) {
+ *version_p = version;
+ }
+
+ return true;
+}
+
+
+static bool test_GetManagerVersion(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ return test_GetManagerVersion_opts(tctx, b, NULL);
+}
+
+static bool test_ManagerInitialize(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ enum dfs_ManagerVersion version;
+ struct dfs_ManagerInitialize r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+
+ torture_comment(tctx, "Testing ManagerInitialize\n");
+
+ torture_assert(tctx,
+ test_GetManagerVersion_opts(tctx, b, &version),
+ "GetManagerVersion failed");
+
+ r.in.servername = host;
+ r.in.flags = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_ManagerInitialize_r(b, tctx, &r),
+ "ManagerInitialize failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_warning(tctx, "dfs_ManagerInitialize failed - %s\n",
+ win_errstr(r.out.result));
+ IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_GetInfoLevel(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint16_t level,
+ const char *root)
+{
+ struct dfs_GetInfo r;
+ union dfs_Info info;
+
+ torture_comment(tctx, "Testing GetInfo level %u on '%s'\n", level, root);
+
+ r.in.dfs_entry_path = root;
+ r.in.servername = NULL;
+ r.in.sharename = NULL;
+ r.in.level = level;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_GetInfo_r(b, tctx, &r),
+ "GetInfo failed");
+
+ if (!W_ERROR_IS_OK(r.out.result) &&
+ !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) {
+ torture_warning(tctx, "dfs_GetInfo failed - %s\n", win_errstr(r.out.result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_GetInfo(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *root)
+{
+ bool ret = true;
+ /* 103, 104, 105, 106 is only available on Set */
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 100, 101, 102, 103, 104, 105, 106};
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (!test_GetInfoLevel(tctx, b, levels[i], root)) {
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+static bool test_EnumLevelEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint16_t level,
+ const char *dfs_name)
+{
+ struct dfs_EnumEx rex;
+ uint32_t total=0;
+ struct dfs_EnumStruct e;
+ struct dfs_Info1 s;
+ struct dfs_EnumArray1 e1;
+ bool ret = true;
+
+ rex.in.level = level;
+ rex.in.bufsize = (uint32_t)-1;
+ rex.in.total = &total;
+ rex.in.info = &e;
+ rex.in.dfs_name = dfs_name;
+
+ e.level = rex.in.level;
+ e.e.info1 = &e1;
+ e.e.info1->count = 0;
+ e.e.info1->s = &s;
+ s.path = NULL;
+
+ torture_comment(tctx, "Testing EnumEx level %u on '%s'\n", level, dfs_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_EnumEx_r(b, tctx, &rex),
+ "EnumEx failed");
+ torture_assert_werr_ok(tctx, rex.out.result,
+ "EnumEx failed");
+
+ if (level == 1 && rex.out.total) {
+ int i;
+ for (i=0;i<*rex.out.total;i++) {
+ const char *root = rex.out.info->e.info1->s[i].path;
+ if (!test_GetInfo(tctx, b, root)) {
+ ret = false;
+ }
+ }
+ }
+
+ if (level == 300 && rex.out.total) {
+ int i,k;
+ for (i=0;i<*rex.out.total;i++) {
+ uint16_t levels[] = {1, 2, 3, 4, 200}; /* 300 */
+ const char *root = rex.out.info->e.info300->s[i].dom_root;
+ for (k=0;k<ARRAY_SIZE(levels);k++) {
+ if (!test_EnumLevelEx(tctx, b,
+ levels[k], root))
+ {
+ ret = false;
+ }
+ }
+ if (!test_GetInfo(tctx, b, root)) {
+ ret = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+static bool test_EnumLevel(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint16_t level)
+{
+ struct dfs_Enum r;
+ uint32_t total=0;
+ struct dfs_EnumStruct e;
+ struct dfs_Info1 s;
+ struct dfs_EnumArray1 e1;
+ bool ret = true;
+
+ r.in.level = level;
+ r.in.bufsize = (uint32_t)-1;
+ r.in.total = &total;
+ r.in.info = &e;
+
+ e.level = r.in.level;
+ e.e.info1 = &e1;
+ e.e.info1->count = 0;
+ e.e.info1->s = &s;
+ s.path = NULL;
+
+ torture_comment(tctx, "Testing Enum level %u\n", level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_Enum_r(b, tctx, &r),
+ "Enum failed");
+
+ if (!W_ERROR_IS_OK(r.out.result) &&
+ !W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, r.out.result)) {
+ torture_warning(tctx, "dfs_Enum failed - %s\n", win_errstr(r.out.result));
+ return false;
+ }
+
+ if (level == 1 && r.out.total) {
+ int i;
+ for (i=0;i<*r.out.total;i++) {
+ const char *root = r.out.info->e.info1->s[i].path;
+ if (!test_GetInfo(tctx, b, root)) {
+ ret = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+static bool test_Enum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (!test_EnumLevel(tctx, b, levels[i])) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_EnumEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 200, 300};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (!test_EnumLevelEx(tctx, b, levels[i], host)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_RemoveStdRoot(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host,
+ const char *sharename)
+{
+ struct dfs_RemoveStdRoot r;
+
+ torture_comment(tctx, "Testing RemoveStdRoot\n");
+
+ r.in.servername = host;
+ r.in.rootshare = sharename;
+ r.in.flags = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_RemoveStdRoot_r(b, tctx, &r),
+ "RemoveStdRoot failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "dfs_RemoveStdRoot failed");
+
+ return true;
+}
+
+static bool test_AddStdRoot(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host,
+ const char *sharename)
+{
+ struct dfs_AddStdRoot r;
+
+ torture_comment(tctx, "Testing AddStdRoot\n");
+
+ r.in.servername = host;
+ r.in.rootshare = sharename;
+ r.in.comment = "standard dfs standalone DFS root created by smbtorture (dfs_AddStdRoot)";
+ r.in.flags = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_AddStdRoot_r(b, tctx, &r),
+ "AddStdRoot failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AddStdRoot failed");
+
+ return true;
+}
+
+static bool test_AddStdRootForced(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host,
+ const char *sharename)
+{
+ struct dfs_AddStdRootForced r;
+ enum dfs_ManagerVersion version;
+
+ torture_comment(tctx, "Testing AddStdRootForced\n");
+
+ torture_assert(tctx,
+ test_GetManagerVersion_opts(tctx, b, &version),
+ "GetManagerVersion failed");
+
+ r.in.servername = host;
+ r.in.rootshare = sharename;
+ r.in.comment = "standard dfs forced standalone DFS root created by smbtorture (dfs_AddStdRootForced)";
+ r.in.store = SMBTORTURE_DFS_PATHNAME;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_AddStdRootForced_r(b, tctx, &r),
+ "AddStdRootForced failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_warning(tctx, "dfs_AddStdRootForced failed - %s\n",
+ win_errstr(r.out.result));
+ IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
+ return false;
+ }
+
+ return test_RemoveStdRoot(tctx, b, host, sharename);
+}
+
+static void test_cleanup_stdroot(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host,
+ const char *sharename,
+ const char *dir)
+{
+ struct smbcli_state *cli;
+
+ torture_comment(tctx, "Cleaning up StdRoot\n");
+
+ test_RemoveStdRoot(tctx, b, host, sharename);
+ test_NetShareDel(tctx, host, sharename);
+ if (torture_open_connection_share(tctx, &cli, tctx, host, "C$", tctx->ev)) {
+ test_DeleteDir(tctx, cli, dir);
+ torture_close_connection(cli);
+ }
+}
+
+static bool test_StdRoot(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ const char *sharename = SMBTORTURE_DFS_SHARENAME;
+ const char *dir = SMBTORTURE_DFS_DIRNAME;
+ const char *path = SMBTORTURE_DFS_PATHNAME;
+ struct smbcli_state *cli;
+ bool ret = true;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing StdRoot\n");
+
+ test_cleanup_stdroot(tctx, b, host, sharename, dir);
+
+ torture_assert(tctx,
+ test_CreateDir(tctx, &cli, tctx, host, "C$", dir),
+ "failed to connect C$ share and to create directory");
+ torture_assert(tctx,
+ test_NetShareAdd(tctx, host, sharename, path),
+ "failed to create new share");
+
+ ret &= test_AddStdRoot(tctx, b, host, sharename);
+ ret &= test_RemoveStdRoot(tctx, b, host, sharename);
+ ret &= test_AddStdRootForced(tctx, b, host, sharename);
+ ret &= test_NetShareDel(tctx, host, sharename);
+ ret &= test_DeleteDir(tctx, cli, dir);
+
+ torture_close_connection(cli);
+
+ return ret;
+}
+
+static bool test_GetDcAddress(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host)
+{
+ struct dfs_GetDcAddress r;
+ uint8_t is_root = 0;
+ uint32_t ttl = 0;
+ const char *ptr;
+
+ torture_comment(tctx, "Testing GetDcAddress\n");
+
+ ptr = host;
+
+ r.in.servername = host;
+ r.in.server_fullname = r.out.server_fullname = &ptr;
+ r.in.is_root = r.out.is_root = &is_root;
+ r.in.ttl = r.out.ttl = &ttl;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_GetDcAddress_r(b, tctx, &r),
+ "GetDcAddress failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "dfs_GetDcAddress failed");
+
+ return true;
+}
+
+static bool test_SetDcAddress(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host)
+{
+ struct dfs_SetDcAddress r;
+
+ torture_comment(tctx, "Testing SetDcAddress\n");
+
+ r.in.servername = host;
+ r.in.server_fullname = host;
+ r.in.flags = 0;
+ r.in.ttl = 1000;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_SetDcAddress_r(b, tctx, &r),
+ "SetDcAddress failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "dfs_SetDcAddress failed");
+
+ return true;
+}
+
+static bool test_DcAddress(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_GetDcAddress(tctx, b, host)) {
+ return false;
+ }
+
+ if (!test_SetDcAddress(tctx, b, host)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_FlushFtTable(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *host,
+ const char *sharename)
+{
+ struct dfs_FlushFtTable r;
+ enum dfs_ManagerVersion version;
+
+ torture_comment(tctx, "Testing FlushFtTable\n");
+
+ torture_assert(tctx,
+ test_GetManagerVersion_opts(tctx, b, &version),
+ "GetManagerVersion failed");
+
+ r.in.servername = host;
+ r.in.rootshare = sharename;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_dfs_FlushFtTable_r(b, tctx, &r),
+ "FlushFtTable failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_warning(tctx, "dfs_FlushFtTable failed - %s\n",
+ win_errstr(r.out.result));
+ IS_DFS_VERSION_UNSUPPORTED_CALL_W2K3(version, r.out.result);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_FtRoot(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ const char *sharename = SMBTORTURE_DFS_SHARENAME;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ return test_FlushFtTable(tctx, b, host, sharename);
+}
+
+struct torture_suite *torture_rpc_dfs(TALLOC_CTX *mem_ctx)
+{
+ struct torture_rpc_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "dfs");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "netdfs",
+ &ndr_table_netdfs);
+
+ torture_rpc_tcase_add_test(tcase, "GetManagerVersion", test_GetManagerVersion);
+ torture_rpc_tcase_add_test(tcase, "ManagerInitialize", test_ManagerInitialize);
+ torture_rpc_tcase_add_test(tcase, "Enum", test_Enum);
+ torture_rpc_tcase_add_test(tcase, "EnumEx", test_EnumEx);
+ torture_rpc_tcase_add_test(tcase, "StdRoot", test_StdRoot);
+ torture_rpc_tcase_add_test(tcase, "FtRoot", test_FtRoot);
+ torture_rpc_tcase_add_test(tcase, "DcAddress", test_DcAddress);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/drsuapi.c b/source4/torture/rpc/drsuapi.c
new file mode 100644
index 0000000..4c7e2fc
--- /dev/null
+++ b/source4/torture/rpc/drsuapi.c
@@ -0,0 +1,1049 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUapi tests
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/security/dom_sid.h"
+#include "param/param.h"
+
+#define TEST_MACHINE_NAME "torturetest"
+
+static bool test_DsBind(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *bind_handle,
+ struct drsuapi_DsBindInfo28 *srv_info28)
+{
+ NTSTATUS status;
+ struct drsuapi_DsBind r;
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfo28 *bind_info28;
+ struct drsuapi_DsBindInfoCtr bind_info_ctr;
+
+ ZERO_STRUCT(bind_info_ctr);
+ bind_info_ctr.length = 28;
+
+ bind_info28 = &bind_info_ctr.info.info28;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
+ bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
+
+ r.in.bind_guid = &bind_guid;
+ r.in.bind_info = &bind_info_ctr;
+ r.out.bind_handle = bind_handle;
+
+ torture_comment(tctx, "Testing DsBind\n");
+
+ status = dcerpc_drsuapi_DsBind_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");
+
+ if (srv_info28 != NULL) {
+ *srv_info28 = r.out.bind_info->info.info28;
+ }
+
+ return true;
+}
+
+static bool test_DsGetDomainControllerInfo(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsGetDomainControllerInfo r;
+ union drsuapi_DsGetDCInfoCtr ctr;
+ union drsuapi_DsGetDCInfoRequest req;
+ int32_t level_out = 0;
+ bool found = false;
+ int i, j, k;
+
+ struct {
+ const char *name;
+ WERROR expected;
+ } names[] = {
+ {
+ .name = torture_join_dom_netbios_name(priv->join),
+ .expected = WERR_OK
+ },
+ {
+ .name = torture_join_dom_dns_name(priv->join),
+ .expected = WERR_OK
+ },
+ {
+ .name = "__UNKNOWN_DOMAIN__",
+ .expected = WERR_DS_OBJ_NOT_FOUND
+ },
+ {
+ .name = "unknown.domain.samba.example.com",
+ .expected = WERR_DS_OBJ_NOT_FOUND
+ },
+ };
+ int levels[] = {1, 2};
+ int level;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+ for (j=0; j < ARRAY_SIZE(names); j++) {
+ level = levels[i];
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+
+ r.in.req->req1.domain_name = names[j].name;
+ r.in.req->req1.level = level;
+
+ r.out.ctr = &ctr;
+ r.out.level_out = &level_out;
+
+ torture_comment(tctx,
+ "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
+ r.in.req->req1.level, r.in.req->req1.domain_name);
+
+ status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result, names[j].expected,
+ "DsGetDomainControllerInfo level with dns domain failed");
+
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ /* If this was an error, we can't read the result structure */
+ continue;
+ }
+
+ torture_assert_int_equal(tctx,
+ r.in.req->req1.level, *r.out.level_out,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo in/out level differs");
+
+ switch (level) {
+ case 1:
+ for (k=0; k < r.out.ctr->ctr1.count; k++) {
+ if (strcasecmp_m(r.out.ctr->ctr1.array[k].netbios_name,
+ torture_join_netbios_name(priv->join)) == 0) {
+ found = true;
+ break;
+ }
+ }
+ break;
+ case 2:
+ for (k=0; k < r.out.ctr->ctr2.count; k++) {
+ if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
+ torture_join_netbios_name(priv->join)) == 0) {
+ found = true;
+ priv->dcinfo = r.out.ctr->ctr2.array[k];
+ break;
+ }
+ }
+ break;
+ }
+ torture_assert(tctx, found,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
+ }
+ }
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+
+ r.out.ctr = &ctr;
+ r.out.level_out = &level_out;
+
+ r.in.req->req1.domain_name = "__UNKNOWN_DOMAIN__"; /* This is clearly ignored for this level */
+ r.in.req->req1.level = -1;
+
+ torture_comment(tctx, "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
+ r.in.req->req1.level, r.in.req->req1.domain_name);
+
+ status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "DsGetDomainControllerInfo with dns domain failed");
+
+ {
+ const char *dc_account = talloc_asprintf(tctx, "%s\\%s$",
+ torture_join_dom_netbios_name(priv->join),
+ priv->dcinfo.netbios_name);
+ torture_comment(tctx, "%s: Enum active LDAP sessions searching for %s\n", __func__, dc_account);
+ for (k=0; k < r.out.ctr->ctr01.count; k++) {
+ if (strcasecmp_m(r.out.ctr->ctr01.array[k].client_account,
+ dc_account)) {
+ found = true;
+ break;
+ }
+ }
+ torture_assert(tctx, found,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo level: Failed to find the domain controller in last logon records");
+ }
+
+
+ return true;
+}
+
+static bool test_DsWriteAccountSpn(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsWriteAccountSpn r;
+ union drsuapi_DsWriteAccountSpnRequest req;
+ struct drsuapi_DsNameString names[2];
+ union drsuapi_DsWriteAccountSpnResult res;
+ uint32_t level_out;
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+
+ torture_comment(tctx, "Testing DsWriteAccountSpn\n");
+
+ r.in.req->req1.operation = DRSUAPI_DS_SPN_OPERATION_ADD;
+ r.in.req->req1.unknown1 = 0;
+ r.in.req->req1.object_dn = priv->dcinfo.computer_dn;
+ r.in.req->req1.count = 2;
+ r.in.req->req1.spn_names = names;
+ names[0].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.netbios_name);
+ names[1].str = talloc_asprintf(tctx, "smbtortureSPN/%s",priv->dcinfo.dns_name);
+
+ r.out.res = &res;
+ r.out.level_out = &level_out;
+
+ status = dcerpc_drsuapi_DsWriteAccountSpn_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
+
+ r.in.req->req1.operation = DRSUAPI_DS_SPN_OPERATION_DELETE;
+ r.in.req->req1.unknown1 = 0;
+
+ status = dcerpc_drsuapi_DsWriteAccountSpn_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsWriteAccountSpn");
+
+ return true;
+}
+
+static bool test_DsReplicaGetInfo(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsReplicaGetInfo r;
+ union drsuapi_DsReplicaGetInfoRequest req;
+ union drsuapi_DsReplicaInfo info;
+ enum drsuapi_DsReplicaInfoType info_type;
+ int i;
+ struct {
+ int32_t level;
+ int32_t infotype;
+ const char *obj_dn;
+ } array[] = {
+ {
+ DRSUAPI_DS_REPLICA_GET_INFO,
+ DRSUAPI_DS_REPLICA_INFO_NEIGHBORS,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO,
+ DRSUAPI_DS_REPLICA_INFO_PENDING_OPS,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS2,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS3,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_REPSTO,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS,
+ "__IGNORED__"
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1,
+ NULL
+ },{
+ DRSUAPI_DS_REPLICA_GET_INFO2,
+ DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS,
+ NULL
+ }
+ };
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping DsReplicaGetInfo test against Samba4\n");
+ return true;
+ }
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.req = &req;
+
+ for (i=0; i < ARRAY_SIZE(array); i++) {
+ const char *object_dn;
+
+ torture_comment(tctx, "Testing DsReplicaGetInfo level %d infotype %d\n",
+ array[i].level, array[i].infotype);
+
+ object_dn = (array[i].obj_dn ? array[i].obj_dn : priv->domain_obj_dn);
+
+ r.in.level = array[i].level;
+ switch(r.in.level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO:
+ r.in.req->req1.info_type = array[i].infotype;
+ r.in.req->req1.object_dn = object_dn;
+ ZERO_STRUCT(r.in.req->req1.source_dsa_guid);
+ break;
+ case DRSUAPI_DS_REPLICA_GET_INFO2:
+ r.in.req->req2.info_type = array[i].infotype;
+ r.in.req->req2.object_dn = object_dn;
+ ZERO_STRUCT(r.in.req->req2.source_dsa_guid);
+ r.in.req->req2.flags = 0;
+ r.in.req->req2.attribute_name = NULL;
+ r.in.req->req2.value_dn_str = NULL;
+ r.in.req->req2.enumeration_context = 0;
+ break;
+ }
+
+ r.out.info = &info;
+ r.out.info_type = &info_type;
+
+ status = dcerpc_drsuapi_DsReplicaGetInfo_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
+ torture_comment(tctx,
+ "DsReplicaGetInfo level %d and/or infotype %d not supported by server\n",
+ array[i].level, array[i].infotype);
+ } else {
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
+ }
+ }
+
+ return true;
+}
+
+static bool test_DsReplicaSync(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ int i;
+ struct drsuapi_DsReplicaSync r;
+ union drsuapi_DsReplicaSyncRequest sync_req;
+ struct drsuapi_DsReplicaObjectIdentifier nc;
+ struct dom_sid null_sid;
+ struct {
+ int32_t level;
+ } array[] = {
+ {
+ 1
+ }
+ };
+
+ if (!torture_setting_bool(tctx, "dangerous", false)) {
+ torture_comment(tctx, "DsReplicaSync disabled - enable dangerous tests to use\n");
+ return true;
+ }
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping DsReplicaSync test against Samba4\n");
+ return true;
+ }
+
+ ZERO_STRUCT(null_sid);
+
+ r.in.bind_handle = &priv->bind_handle;
+
+ for (i=0; i < ARRAY_SIZE(array); i++) {
+ torture_comment(tctx, "Testing DsReplicaSync level %d\n",
+ array[i].level);
+
+ r.in.level = array[i].level;
+ switch(r.in.level) {
+ case 1:
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+ nc.dn = priv->domain_obj_dn?priv->domain_obj_dn:"";
+
+ sync_req.req1.naming_context = &nc;
+ sync_req.req1.source_dsa_guid = priv->dcinfo.ntds_guid;
+ sync_req.req1.source_dsa_dns = NULL;
+ sync_req.req1.options = 16;
+
+ r.in.req = &sync_req;
+ break;
+ }
+
+ status = dcerpc_drsuapi_DsReplicaSync_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaSync");
+ }
+
+ return true;
+}
+
+static bool test_DsReplicaUpdateRefs(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsReplicaUpdateRefs r;
+ struct drsuapi_DsReplicaObjectIdentifier nc;
+ struct GUID dest_dsa_guid;
+ const char *dest_dsa_guid_str;
+ struct dom_sid null_sid;
+
+ ZERO_STRUCT(null_sid);
+ dest_dsa_guid = GUID_random();
+ dest_dsa_guid_str = GUID_string(tctx, &dest_dsa_guid);
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1; /* Only version 1 is defined presently */
+
+ /* setup NC */
+ nc.guid = priv->domain_obj_dn ? GUID_zero():priv->domain_guid;
+ nc.sid = null_sid;
+ nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
+
+ /* default setup for request */
+ r.in.req.req1.naming_context = &nc;
+ r.in.req.req1.dest_dsa_dns_name = talloc_asprintf(tctx, "%s._msdn.%s",
+ dest_dsa_guid_str,
+ priv->domain_dns_name);
+ r.in.req.req1.dest_dsa_guid = dest_dsa_guid;
+
+ /* 1. deleting replica dest should fail */
+ torture_comment(tctx, "delete: %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_DS_DRA_REF_NOT_FOUND, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ /* 2. hopefully adding random replica dest should succeed */
+ torture_comment(tctx, "add : %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_ADD_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_OK, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ /* 3. try adding same replica dest - should fail */
+ torture_comment(tctx, "add : %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_ADD_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_DS_DRA_REF_ALREADY_EXISTS, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ /* 4. try resetting same replica dest - should succeed */
+ torture_comment(tctx, "reset : %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_OK, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ /* 5. delete random replicate added at step 2. */
+ torture_comment(tctx, "delete : %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_OK, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ /* 6. try replace on non-existing replica dest - should succeed */
+ torture_comment(tctx, "replace: %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_DEL_REF | DRSUAPI_DRS_ADD_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_OK, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ /* 7. delete random replicate added at step 6. */
+ torture_comment(tctx, "delete : %s\n", r.in.req.req1.dest_dsa_dns_name);
+ r.in.req.req1.options = DRSUAPI_DRS_DEL_REF;
+ status = dcerpc_drsuapi_DsReplicaUpdateRefs_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call_werr(tctx, p,
+ status, WERR_OK, &r,
+ "dcerpc_drsuapi_DsReplicaUpdateRefs");
+
+ return true;
+}
+
+static bool test_DsGetNCChanges(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ int i;
+ struct drsuapi_DsGetNCChanges r;
+ union drsuapi_DsGetNCChangesRequest req;
+ union drsuapi_DsGetNCChangesCtr ctr;
+ struct drsuapi_DsReplicaObjectIdentifier nc;
+ struct dom_sid null_sid;
+ uint32_t level_out;
+ struct {
+ uint32_t level;
+ } array[] = {
+ {
+ 5
+ },
+ {
+ 8
+ }
+ };
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping DsGetNCChanges test against Samba4\n");
+ return true;
+ }
+
+ ZERO_STRUCT(null_sid);
+
+ for (i=0; i < ARRAY_SIZE(array); i++) {
+ torture_comment(tctx,
+ "Testing DsGetNCChanges level %d\n",
+ array[i].level);
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = array[i].level;
+ r.out.level_out = &level_out;
+ r.out.ctr = &ctr;
+
+ switch (r.in.level) {
+ case 5:
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+ nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
+
+ r.in.req = &req;
+ r.in.req->req5.destination_dsa_guid = GUID_random();
+ r.in.req->req5.source_dsa_invocation_id = GUID_zero();
+ r.in.req->req5.naming_context = &nc;
+ r.in.req->req5.highwatermark.tmp_highest_usn = 0;
+ r.in.req->req5.highwatermark.reserved_usn = 0;
+ r.in.req->req5.highwatermark.highest_usn = 0;
+ r.in.req->req5.uptodateness_vector = NULL;
+ r.in.req->req5.replica_flags = 0;
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
+ r.in.req->req5.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
+ }
+ r.in.req->req5.max_object_count = 0;
+ r.in.req->req5.max_ndr_size = 0;
+ r.in.req->req5.extended_op = DRSUAPI_EXOP_NONE;
+ r.in.req->req5.fsmo_info = 0;
+
+ break;
+ case 8:
+ nc.guid = GUID_zero();
+ nc.sid = null_sid;
+ nc.dn = priv->domain_obj_dn ? priv->domain_obj_dn : "";
+
+ r.in.req = &req;
+ r.in.req->req8.destination_dsa_guid = GUID_random();
+ r.in.req->req8.source_dsa_invocation_id = GUID_zero();
+ r.in.req->req8.naming_context = &nc;
+ r.in.req->req8.highwatermark.tmp_highest_usn = 0;
+ r.in.req->req8.highwatermark.reserved_usn = 0;
+ r.in.req->req8.highwatermark.highest_usn = 0;
+ r.in.req->req8.uptodateness_vector = NULL;
+ r.in.req->req8.replica_flags = 0;
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "compression", false)) {
+ r.in.req->req8.replica_flags |= DRSUAPI_DRS_USE_COMPRESSION;
+ }
+ if (lpcfg_parm_bool(tctx->lp_ctx, NULL, "drsuapi", "neighbour_writeable", true)) {
+ r.in.req->req8.replica_flags |= DRSUAPI_DRS_WRIT_REP;
+ }
+ r.in.req->req8.replica_flags |= DRSUAPI_DRS_INIT_SYNC
+ | DRSUAPI_DRS_PER_SYNC
+ | DRSUAPI_DRS_GET_ANC
+ | DRSUAPI_DRS_NEVER_SYNCED
+ ;
+ r.in.req->req8.max_object_count = 402;
+ r.in.req->req8.max_ndr_size = 402116;
+ r.in.req->req8.extended_op = DRSUAPI_EXOP_NONE;
+ r.in.req->req8.fsmo_info = 0;
+ r.in.req->req8.partial_attribute_set = NULL;
+ r.in.req->req8.partial_attribute_set_ex = NULL;
+ r.in.req->req8.mapping_ctr.num_mappings = 0;
+ r.in.req->req8.mapping_ctr.mappings = NULL;
+
+ break;
+ }
+
+ status = dcerpc_drsuapi_DsGetNCChanges_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsGetNCChanges");
+ }
+
+ return true;
+}
+
+bool test_QuerySitesByCost(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_QuerySitesByCost r;
+ union drsuapi_QuerySitesByCostRequest req;
+
+ const char *my_site = "Default-First-Site-Name";
+ const char *remote_site1 = "smbtorture-nonexisting-site1";
+ const char *remote_site2 = "smbtorture-nonexisting-site2";
+
+ req.req1.site_from = talloc_strdup(tctx, my_site);
+ req.req1.num_req = 2;
+ req.req1.site_to = talloc_zero_array(tctx, const char *, 2);
+ req.req1.site_to[0] = talloc_strdup(tctx, remote_site1);
+ req.req1.site_to[1] = talloc_strdup(tctx, remote_site2);
+ req.req1.flags = 0;
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+
+ status = dcerpc_drsuapi_QuerySitesByCost_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_QuerySitesByCost");
+
+ if (W_ERROR_IS_OK(r.out.result)) {
+ torture_assert_werr_equal(tctx,
+ r.out.ctr->ctr1.info[0].error_code, WERR_DS_OBJ_NOT_FOUND,
+ "dcerpc_drsuapi_QuerySitesByCost");
+ torture_assert_werr_equal(tctx,
+ r.out.ctr->ctr1.info[1].error_code, WERR_DS_OBJ_NOT_FOUND,
+ "dcerpc_drsuapi_QuerySitesByCost expected error_code WERR_DS_OBJ_NOT_FOUND");
+
+ torture_assert_int_equal(tctx,
+ r.out.ctr->ctr1.info[0].site_cost, -1,
+ "dcerpc_drsuapi_QuerySitesByCost");
+ torture_assert_int_equal(tctx,
+ r.out.ctr->ctr1.info[1].site_cost, -1,
+ "dcerpc_drsuapi_QuerySitesByCost expected site cost");
+ }
+
+ return true;
+
+
+}
+
+bool test_DsUnbind(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ struct drsuapi_DsUnbind r;
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.out.bind_handle = &priv->bind_handle;
+
+ torture_comment(tctx, "Testing DsUnbind\n");
+
+ status = dcerpc_drsuapi_DsUnbind_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsUnbind");
+
+ return true;
+}
+
+
+/**
+ * Helper func to collect DC information for testing purposes.
+ * This function is almost identical to test_DsGetDomainControllerInfo
+ */
+bool torture_rpc_drsuapi_get_dcinfo(struct torture_context *torture,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ int32_t level_out = 0;
+ struct drsuapi_DsGetDomainControllerInfo r;
+ union drsuapi_DsGetDCInfoCtr ctr;
+ int j, k;
+ const char *names[] = {
+ torture_join_dom_netbios_name(priv->join),
+ torture_join_dom_dns_name(priv->join)};
+
+ for (j=0; j < ARRAY_SIZE(names); j++) {
+ union drsuapi_DsGetDCInfoRequest req;
+ struct dcerpc_binding_handle *b = priv->drs_pipe->binding_handle;
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+
+ r.in.req->req1.domain_name = names[j];
+ r.in.req->req1.level = 2;
+
+ r.out.ctr = &ctr;
+ r.out.level_out = &level_out;
+
+ status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(b, torture, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ continue;
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ /* If this was an error, we can't read the result structure */
+ continue;
+ }
+
+ for (k=0; k < r.out.ctr->ctr2.count; k++) {
+ if (strcasecmp_m(r.out.ctr->ctr2.array[k].netbios_name,
+ torture_join_netbios_name(priv->join)) == 0) {
+ priv->dcinfo = r.out.ctr->ctr2.array[k];
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Common test case setup function to be used
+ * in DRS suit of test when appropriate
+ */
+bool torture_drsuapi_tcase_setup_common(struct torture_context *tctx, struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ int rnd = rand() % 1000;
+ char *name = talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, rnd);
+
+ torture_assert(tctx, priv, "Invalid argument");
+
+ priv->admin_credentials = samba_cmdline_get_creds();
+
+ torture_comment(tctx, "Create DRSUAPI pipe\n");
+ status = torture_rpc_connection(tctx,
+ &priv->drs_pipe,
+ &ndr_table_drsuapi);
+ torture_assert(tctx, NT_STATUS_IS_OK(status), "Unable to connect to DRSUAPI pipe");
+
+ torture_comment(tctx, "About to join domain with name %s\n", name);
+ priv->join = torture_join_domain(tctx, name, ACB_SVRTRUST,
+ &priv->dc_credentials);
+ torture_assert(tctx, priv->join, "Failed to join as BDC");
+
+ if (!test_DsBind(priv->drs_pipe, tctx,
+ &priv->bind_handle,
+ &priv->srv_bind_info))
+ {
+ /* clean up */
+ torture_drsuapi_tcase_teardown_common(tctx, priv);
+ torture_fail(tctx, "Failed execute test_DsBind()");
+ }
+
+ /* try collect some information for testing */
+ torture_rpc_drsuapi_get_dcinfo(tctx, priv);
+
+ return true;
+}
+
+/**
+ * Common test case teardown function to be used
+ * in DRS suit of test when appropriate
+ */
+bool torture_drsuapi_tcase_teardown_common(struct torture_context *tctx, struct DsPrivate *priv)
+{
+ if (priv->join) {
+ torture_leave_domain(tctx, priv->join);
+ }
+
+ return true;
+}
+
+/**
+ * Test case setup for DRSUAPI test case
+ */
+static bool torture_drsuapi_tcase_setup(struct torture_context *tctx, void **data)
+{
+ struct DsPrivate *priv;
+
+ *data = priv = talloc_zero(tctx, struct DsPrivate);
+
+ return torture_drsuapi_tcase_setup_common(tctx, priv);
+}
+
+/**
+ * Test case tear-down for DRSUAPI test case
+ */
+static bool torture_drsuapi_tcase_teardown(struct torture_context *tctx, void *data)
+{
+ bool ret;
+ struct DsPrivate *priv = talloc_get_type(data, struct DsPrivate);
+
+ ret = torture_drsuapi_tcase_teardown_common(tctx, priv);
+
+ talloc_free(priv);
+ return ret;
+}
+
+static bool __test_DsBind_assoc_group(struct torture_context *tctx,
+ const char *testname,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ NTSTATUS status;
+ const char *err_msg;
+ struct drsuapi_DsCrackNames r;
+ union drsuapi_DsNameRequest req;
+ uint32_t level_out;
+ union drsuapi_DsNameCtr ctr;
+ struct drsuapi_DsNameString names[1];
+ const char *dom_sid = NULL;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
+ TALLOC_CTX *mem_ctx = priv;
+ struct dcerpc_binding *binding = NULL;
+ struct policy_handle ds_bind_handle = { .handle_type = 0, };
+
+ torture_comment(tctx, "%s: starting...\n", testname);
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "torture_rpc_binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx,
+ &p1,
+ binding,
+ &ndr_table_drsuapi,
+ creds,
+ tctx->ev,
+ tctx->lp_ctx),
+ "connect p1");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx,
+ &p2,
+ p1->binding,
+ &ndr_table_drsuapi,
+ creds,
+ tctx->ev,
+ tctx->lp_ctx),
+ "connect p2");
+
+ torture_assert(tctx, test_DsBind(p1, tctx, &ds_bind_handle, NULL), "DsBind");
+
+ ZERO_STRUCT(r);
+ r.in.bind_handle = &ds_bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+ r.in.req->req1.codepage = 1252; /* german */
+ r.in.req->req1.language = 0x00000407; /* german */
+ r.in.req->req1.count = 1;
+ r.in.req->req1.names = names;
+ r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
+
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+
+ r.out.level_out = &level_out;
+ r.out.ctr = &ctr;
+
+ dom_sid = dom_sid_string(mem_ctx, torture_join_sid(priv->join));
+
+ names[0].str = dom_sid;
+
+ torture_comment(tctx, "Testing DsCrackNames on p1 with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p1->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ torture_comment(tctx, "Testing DsCrackNames on p2 with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ TALLOC_FREE(p1);
+
+ torture_comment(tctx, "Testing DsCrackNames on p2 (with p1 closed) with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ torture_comment(tctx, "%s: ... finished\n", testname);
+ return true;
+}
+
+static bool test_DsBindAssocGroupAdmin(struct torture_context *tctx,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ return __test_DsBind_assoc_group(tctx, __func__, priv,
+ priv->admin_credentials);
+}
+
+static bool test_DsBindAssocGroupDC(struct torture_context *tctx,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ return __test_DsBind_assoc_group(tctx, __func__, priv,
+ priv->dc_credentials);
+}
+
+static bool test_DsBindAssocGroupWS(struct torture_context *tctx,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ struct test_join *wks_join = NULL;
+ struct cli_credentials *wks_credentials = NULL;
+ int rnd = rand() % 1000;
+ char *wks_name = talloc_asprintf(tctx, "WKS%s%d", TEST_MACHINE_NAME, rnd);
+ bool ret;
+
+ torture_comment(tctx, "%s: About to join workstation with name %s\n",
+ __func__, wks_name);
+ wks_join = torture_join_domain(tctx, wks_name, ACB_WSTRUST,
+ &wks_credentials);
+ torture_assert(tctx, wks_join, "Failed to join as WORKSTATION");
+ ret = __test_DsBind_assoc_group(tctx, __func__, priv,
+ wks_credentials);
+ torture_leave_domain(tctx, wks_join);
+ return ret;
+}
+
+/**
+ * DRSUAPI test case implementation
+ */
+void torture_rpc_drsuapi_tcase(struct torture_suite *suite)
+{
+ typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
+
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "drsuapi");
+
+ torture_tcase_set_fixture(tcase, torture_drsuapi_tcase_setup,
+ torture_drsuapi_tcase_teardown);
+
+#if 0
+ test = torture_tcase_add_simple_test(tcase, "QuerySitesByCost", (run_func)test_QuerySitesByCost);
+#endif
+
+ torture_tcase_add_simple_test(tcase, "DsGetDomainControllerInfo", (run_func)test_DsGetDomainControllerInfo);
+
+ torture_tcase_add_simple_test(tcase, "DsCrackNames", (run_func)test_DsCrackNames);
+
+ torture_tcase_add_simple_test(tcase, "DsWriteAccountSpn", (run_func)test_DsWriteAccountSpn);
+
+ torture_tcase_add_simple_test(tcase, "DsReplicaGetInfo", (run_func)test_DsReplicaGetInfo);
+
+ torture_tcase_add_simple_test(tcase, "DsReplicaSync", (run_func)test_DsReplicaSync);
+
+ torture_tcase_add_simple_test(tcase, "DsReplicaUpdateRefs", (run_func)test_DsReplicaUpdateRefs);
+
+ torture_tcase_add_simple_test(tcase, "DsGetNCChanges", (run_func)test_DsGetNCChanges);
+
+ torture_tcase_add_simple_test(tcase, "DsBindAssocGroupAdmin", (run_func)test_DsBindAssocGroupAdmin);
+ torture_tcase_add_simple_test(tcase, "DsBindAssocGroupDC", (run_func)test_DsBindAssocGroupDC);
+ torture_tcase_add_simple_test(tcase, "DsBindAssocGroupWS", (run_func)test_DsBindAssocGroupWS);
+}
diff --git a/source4/torture/rpc/drsuapi.h b/source4/torture/rpc/drsuapi.h
new file mode 100644
index 0000000..3cc4be4
--- /dev/null
+++ b/source4/torture/rpc/drsuapi.h
@@ -0,0 +1,94 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUapi tests
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "librpc/gen_ndr/drsuapi.h"
+
+/**
+ * Data structure common for most of DRSUAPI tests
+ */
+struct DsPrivate {
+ struct cli_credentials *admin_credentials;
+ struct dcerpc_pipe *drs_pipe;
+ struct policy_handle bind_handle;
+ struct drsuapi_DsBindInfo28 srv_bind_info;
+
+ const char *domain_obj_dn;
+ const char *domain_guid_str;
+ const char *domain_dns_name;
+ struct GUID domain_guid;
+ struct drsuapi_DsGetDCInfo2 dcinfo;
+ struct test_join *join;
+ struct cli_credentials *dc_credentials;
+};
+
+/**
+ * Data structure of DRSUAPI W2K8 tests
+ * W2K8 Clients use different versions of structs
+ */
+struct DsPrivate_w2k8 {
+ struct dcerpc_pipe *drs_pipe;
+ struct policy_handle bind_handle;
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfoCtr srv_bind_info;
+
+ const char *domain_obj_dn;
+ const char *domain_guid_str;
+ const char *domain_dns_name;
+ struct GUID domain_guid;
+ struct drsuapi_DsGetDCInfo3 dcinfo;
+ struct test_join *join;
+};
+
+
+/**
+ * Custom torture macro to check dcerpc_drsuapi_ call
+ * return values printing more friendly messages
+ * \param _tctx torture context
+ * \param _p DCERPC pipe handle
+ * \param _ntstatus NTSTATUS for dcerpc_drsuapi_ call
+ * \param _werr_expected Expected windows error to be returned
+ * \param _pr in/out DCEPRC request structure - pointer
+ * \param _msg error message prefix
+ */
+#define torture_drsuapi_assert_call_werr(_tctx, _p, _ntstat, _werr_expected, _pr, _msg) \
+ do { \
+ NTSTATUS __nt = _ntstat; \
+ if (!NT_STATUS_IS_OK(__nt)) { \
+ const char *errstr = nt_errstr(__nt); \
+ torture_fail(tctx, talloc_asprintf(_tctx, "%s failed - %s", _msg, errstr)); \
+ } \
+ torture_assert_werr_equal(_tctx, (_pr)->out.result, _werr_expected, _msg); \
+ } while(0)
+
+/**
+ * Custom torture macro to check dcerpc_drsuapi_ call
+ * return values printing more friendly messages
+ * \param _tctx torture context
+ * \param _p DCERPC pipe handle
+ * \param _ntstatus NTSTATUS for dcerpc_drsuapi_ call
+ * \param _pr in/out DCEPRC request structure
+ * \param _msg error message prefix
+ */
+#define torture_drsuapi_assert_call(_tctx, _p, _ntstat, _pr, _msg) \
+ torture_drsuapi_assert_call_werr(_tctx, _p, _ntstat, WERR_OK, _pr, _msg)
+
diff --git a/source4/torture/rpc/drsuapi_cracknames.c b/source4/torture/rpc/drsuapi_cracknames.c
new file mode 100644
index 0000000..0cbccda
--- /dev/null
+++ b/source4/torture/rpc/drsuapi_cracknames.c
@@ -0,0 +1,1087 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUapi tests
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include <ldb.h>
+#include "libcli/security/security.h"
+
+#undef strcasecmp
+
+struct DsCrackNamesPrivate {
+ struct DsPrivate base;
+
+ /* following names are used in Crack Names Matrix test */
+ const char *fqdn_name;
+ const char *user_principal_name;
+ const char *service_principal_name;
+};
+
+static bool test_DsCrackNamesMatrix(struct torture_context *tctx,
+ struct DsPrivate *priv, const char *dn,
+ const char *user_principal_name, const char *service_principal_name)
+{
+ NTSTATUS status;
+ const char *err_msg;
+ struct drsuapi_DsCrackNames r;
+ union drsuapi_DsNameRequest req;
+ uint32_t level_out;
+ union drsuapi_DsNameCtr ctr;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ TALLOC_CTX *mem_ctx = priv;
+
+ enum drsuapi_DsNameFormat formats[] = {
+ DRSUAPI_DS_NAME_FORMAT_UNKNOWN,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+ DRSUAPI_DS_NAME_FORMAT_GUID,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN
+ };
+ struct drsuapi_DsNameString names[ARRAY_SIZE(formats)];
+ int i, j;
+
+ const char *n_matrix[ARRAY_SIZE(formats)][ARRAY_SIZE(formats)];
+ const char *n_from[ARRAY_SIZE(formats)];
+
+ ZERO_STRUCT(r);
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+ r.in.req->req1.codepage = 1252; /* german */
+ r.in.req->req1.language = 0x00000407; /* german */
+ r.in.req->req1.count = 1;
+ r.in.req->req1.names = names;
+ r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
+
+ r.out.level_out = &level_out;
+ r.out.ctr = &ctr;
+
+ n_matrix[0][0] = dn;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+ r.in.req->req1.format_desired = formats[i];
+ names[0].str = dn;
+ torture_comment(tctx, "Testing DsCrackNames (matrix prep) with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx,
+ "testing DsCrackNames (matrix prep) with name '%s' from format: %d desired format:%d failed - %s",
+ names[0].str, r.in.req->req1.format_offered, r.in.req->req1.format_desired, errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "testing DsCrackNames (matrix prep) with name '%s' from format: %d desired format:%d failed - %s",
+ names[0].str, r.in.req->req1.format_offered, r.in.req->req1.format_desired, win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ }
+
+ switch (formats[i]) {
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
+ if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "Unexpected error (%d): This name lookup should fail",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+ torture_comment(tctx, __location__ ": (expected) error\n");
+ break;
+ case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
+ if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_NO_MAPPING) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "Unexpected error (%d): This name lookup should fail",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+ torture_comment(tctx, __location__ ": (expected) error\n");
+ break;
+ case DRSUAPI_DS_NAME_FORMAT_UNKNOWN: /* should fail as we ask server to convert to Unknown format */
+ case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN:
+ if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "Unexpected error (%d): This name lookup should fail",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+ torture_comment(tctx, __location__ ": (expected) error\n");
+ break;
+ default:
+ if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames error: %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+ break;
+ }
+
+ switch (formats[i]) {
+ case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
+ n_from[i] = user_principal_name;
+ break;
+ case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
+ n_from[i] = service_principal_name;
+ break;
+ case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
+ case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN:
+ n_from[i] = NULL;
+ break;
+ default:
+ n_from[i] = r.out.ctr->ctr1->array[0].result_name;
+ printf("%s\n", n_from[i]);
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ for (j = 0; j < ARRAY_SIZE(formats); j++) {
+ r.in.req->req1.format_offered = formats[i];
+ r.in.req->req1.format_desired = formats[j];
+ if (!n_from[i]) {
+ n_matrix[i][j] = NULL;
+ continue;
+ }
+ names[0].str = n_from[i];
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx,
+ "testing DsCrackNames (matrix) with name '%s' from format: %d desired format:%d failed - %s",
+ names[0].str, r.in.req->req1.format_offered, r.in.req->req1.format_desired, errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "testing DsCrackNames (matrix) with name '%s' from format: %d desired format:%d failed - %s",
+ names[0].str, r.in.req->req1.format_offered, r.in.req->req1.format_desired,
+ win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ }
+
+ if (r.out.ctr->ctr1->array[0].status == DRSUAPI_DS_NAME_STATUS_OK) {
+ n_matrix[i][j] = r.out.ctr->ctr1->array[0].result_name;
+ } else {
+ n_matrix[i][j] = NULL;
+ }
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ for (j = 0; j < ARRAY_SIZE(formats); j++) {
+ torture_comment(tctx, "Converting %s (format %d)"
+ " to %d gave %s\n",
+ n_from[i] == NULL ? "NULL" : n_from[i],
+ formats[i], formats[j],
+ n_matrix[i][j] == NULL ?
+ "NULL" : n_matrix[i][j]);
+
+ if (n_matrix[i][j] == n_from[j]) {
+
+ /* We don't have a from name for these yet (and we can't map to them to find it out) */
+ } else if (n_matrix[i][j] == NULL && n_from[i] == NULL) {
+
+ /* we can't map to these two */
+ } else if (n_matrix[i][j] == NULL && formats[j] == DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL) {
+ } else if (n_matrix[i][j] == NULL && formats[j] == DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL) {
+ } else if (n_matrix[i][j] == NULL && n_from[j] != NULL) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "dcerpc_drsuapi_DsCrackNames mismatch - from %d to %d: should be %s",
+ formats[i], formats[j], n_from[j]);
+ torture_fail(tctx, err_msg);
+ } else if (n_matrix[i][j] != NULL && n_from[j] == NULL) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "dcerpc_drsuapi_DsCrackNames mismatch - from %d to %d: should be %s",
+ formats[i], formats[j], n_matrix[i][j]);
+ torture_fail(tctx, err_msg);
+ } else if (strcmp(n_matrix[i][j], n_from[j]) != 0) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "dcerpc_drsuapi_DsCrackNames mismatch - from %d to %d: %s should be %s",
+ formats[i], formats[j], n_matrix[i][j], n_from[j]);
+ torture_fail(tctx, err_msg);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool test_DsCrackNames(struct torture_context *tctx,
+ struct DsPrivate *priv)
+{
+ NTSTATUS status;
+ const char *err_msg;
+ struct drsuapi_DsCrackNames r;
+ union drsuapi_DsNameRequest req;
+ uint32_t level_out;
+ union drsuapi_DsNameCtr ctr;
+ struct drsuapi_DsNameString names[1];
+ const char *dns_domain;
+ const char *nt4_domain;
+ const char *FQDN_1779_name;
+ struct ldb_context *ldb;
+ struct ldb_dn *FQDN_1779_dn;
+ struct ldb_dn *realm_dn;
+ const char *realm_dn_str;
+ const char *realm_canonical;
+ const char *realm_canonical_ex;
+ const char *user_principal_name;
+ char *user_principal_name_short;
+ const char *service_principal_name;
+ const char *canonical_name;
+ const char *canonical_ex_name;
+ const char *dom_sid;
+ const char *test_dc = torture_join_netbios_name(priv->join);
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ TALLOC_CTX *mem_ctx = priv;
+
+ ZERO_STRUCT(r);
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+ r.in.req->req1.codepage = 1252; /* german */
+ r.in.req->req1.language = 0x00000407; /* german */
+ r.in.req->req1.count = 1;
+ r.in.req->req1.names = names;
+ r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
+
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+
+ r.out.level_out = &level_out;
+ r.out.ctr = &ctr;
+
+ dom_sid = dom_sid_string(mem_ctx, torture_join_sid(priv->join));
+
+ names[0].str = dom_sid;
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ dns_domain = r.out.ctr->ctr1->array[0].dns_domain_name;
+ nt4_domain = r.out.ctr->ctr1->array[0].result_name;
+
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_GUID;
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ priv->domain_dns_name = r.out.ctr->ctr1->array[0].dns_domain_name;
+ priv->domain_guid_str = r.out.ctr->ctr1->array[0].result_name;
+ GUID_from_string(priv->domain_guid_str, &priv->domain_guid);
+
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ ldb = ldb_init(mem_ctx, tctx->ev);
+
+ realm_dn_str = r.out.ctr->ctr1->array[0].result_name;
+ realm_dn = ldb_dn_new(mem_ctx, ldb, realm_dn_str);
+ realm_canonical = ldb_dn_canonical_string(mem_ctx, realm_dn);
+
+ if (strcmp(realm_canonical,
+ talloc_asprintf(mem_ctx, "%s/", dns_domain))!= 0) {
+ err_msg = talloc_asprintf(mem_ctx, "local Round trip on canonical name failed: %s != %s!",
+ realm_canonical,
+ talloc_asprintf(mem_ctx, "%s/", dns_domain));
+ torture_fail(tctx, err_msg);
+ };
+
+ realm_canonical_ex = ldb_dn_canonical_ex_string(mem_ctx, realm_dn);
+
+ if (strcmp(realm_canonical_ex,
+ talloc_asprintf(mem_ctx, "%s\n", dns_domain))!= 0) {
+ err_msg = talloc_asprintf(mem_ctx, "local Round trip on canonical ex name failed: %s != %s!",
+ realm_canonical_ex,
+ talloc_asprintf(mem_ctx, "%s\n", dns_domain));
+ torture_fail(tctx, err_msg);
+ };
+
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+ names[0].str = nt4_domain;
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ priv->domain_obj_dn = r.out.ctr->ctr1->array[0].result_name;
+
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+ names[0].str = talloc_asprintf(mem_ctx, "%s%s$", nt4_domain, test_dc);
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ FQDN_1779_name = r.out.ctr->ctr1->array[0].result_name;
+
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_GUID;
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+ names[0].str = priv->domain_guid_str;
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ if (strcmp(priv->domain_dns_name, r.out.ctr->ctr1->array[0].dns_domain_name) != 0) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames failed to return same DNS name - expected %s got %s",
+ priv->domain_dns_name, r.out.ctr->ctr1->array[0].dns_domain_name);
+ torture_fail(tctx, err_msg);
+ }
+
+ FQDN_1779_dn = ldb_dn_new(mem_ctx, ldb, FQDN_1779_name);
+
+ canonical_name = ldb_dn_canonical_string(mem_ctx, FQDN_1779_dn);
+ canonical_ex_name = ldb_dn_canonical_ex_string(mem_ctx, FQDN_1779_dn);
+
+ user_principal_name = talloc_asprintf(mem_ctx, "%s$@%s", test_dc, dns_domain);
+
+ /* form up a user@DOMAIN */
+ user_principal_name_short = talloc_asprintf(mem_ctx, "%s$@%s", test_dc, nt4_domain);
+ /* variable nt4_domain includes a trailing \ */
+ user_principal_name_short[strlen(user_principal_name_short) - 1] = '\0';
+
+ service_principal_name = talloc_asprintf(mem_ctx, "HOST/%s", test_dc);
+ {
+
+ struct {
+ enum drsuapi_DsNameFormat format_offered;
+ enum drsuapi_DsNameFormat format_desired;
+ const char *comment;
+ const char *str;
+ const char *expected_str;
+ const char *expected_dns;
+ enum drsuapi_DsNameStatus status;
+ enum drsuapi_DsNameStatus alternate_status;
+ enum drsuapi_DsNameFlags flags;
+ bool skip;
+ } crack[] = {
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = user_principal_name,
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = user_principal_name_short,
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = service_principal_name,
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "cifs/%s.%s", test_dc, dns_domain),
+ .comment = "ServicePrincipal Name",
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ .str = FQDN_1779_name,
+ .expected_str = canonical_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = canonical_name,
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ .str = FQDN_1779_name,
+ .expected_str = canonical_ex_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = canonical_ex_name,
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ .str = FQDN_1779_name,
+ .comment = "DN to cannoical syntactial only",
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .expected_str = canonical_name,
+ .flags = DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ .str = FQDN_1779_name,
+ .comment = "DN to cannoical EX syntactial only",
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .expected_str = canonical_ex_name,
+ .flags = DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+ .str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .str = priv->domain_guid_str,
+ .comment = "Domain GUID to NT4 ACCOUNT",
+ .expected_str = nt4_domain,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+ .str = priv->domain_guid_str,
+ .comment = "Domain GUID to Canonical",
+ .expected_str = talloc_asprintf(mem_ctx, "%s/", dns_domain),
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+ .str = priv->domain_guid_str,
+ .comment = "Domain GUID to Canonical EX",
+ .expected_str = talloc_asprintf(mem_ctx, "%s\n", dns_domain),
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = "CN=Microsoft Corporation,L=Redmond,S=Washington,C=US",
+ .comment = "display name for Microsoft Support Account",
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE,
+ .skip = torture_setting_bool(tctx, "samba4", false)
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = GUID_string2(mem_ctx, torture_join_user_guid(priv->join)),
+ .comment = "Account GUID -> DN",
+ .expected_str = FQDN_1779_name,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .str = GUID_string2(mem_ctx, torture_join_user_guid(priv->join)),
+ .comment = "Account GUID -> NT4 Account",
+ .expected_str = talloc_asprintf(mem_ctx, "%s%s$", nt4_domain, test_dc),
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = GUID_string2(mem_ctx, &priv->dcinfo.site_guid),
+ .comment = "Site GUID",
+ .expected_str = priv->dcinfo.site_dn,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = GUID_string2(mem_ctx, &priv->dcinfo.computer_guid),
+ .comment = "Computer GUID",
+ .expected_str = priv->dcinfo.computer_dn,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .str = GUID_string2(mem_ctx, &priv->dcinfo.computer_guid),
+ .comment = "Computer GUID -> NT4 Account",
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = GUID_string2(mem_ctx, &priv->dcinfo.server_guid),
+ .comment = "Server GUID",
+ .expected_str = priv->dcinfo.server_dn,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = GUID_string2(mem_ctx, &priv->dcinfo.ntds_guid),
+ .comment = "NTDS GUID",
+ .expected_str = priv->dcinfo.ntds_dn,
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .skip = GUID_all_zero(&priv->dcinfo.ntds_guid)
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = test_dc,
+ .comment = "DISPLAY NAME search for DC short name",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "krbtgt/%s", dns_domain),
+ .comment = "Looking for KRBTGT as a service principal",
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY,
+ .expected_dns = dns_domain
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "bogus/%s", dns_domain),
+ .comment = "Looking for bogus service principal",
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY,
+ .expected_dns = dns_domain
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "bogus/%s.%s", test_dc, dns_domain),
+ .comment = "Looking for bogus service on test DC",
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY,
+ .expected_dns = talloc_asprintf(mem_ctx, "%s.%s", test_dc, dns_domain)
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "krbtgt"),
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Looking for the kadmin/changepw service as a service principal",
+ .str = talloc_asprintf(mem_ctx, "kadmin/changepw"),
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .expected_str = talloc_asprintf(mem_ctx, "CN=krbtgt,CN=Users,%s", realm_dn_str),
+ .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "cifs/%s.%s@%s",
+ test_dc, dns_domain,
+ dns_domain),
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "cifs/%s.%s@%s",
+ test_dc, dns_domain,
+ "BOGUS"),
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY,
+ .expected_dns = "BOGUS"
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "cifs/%s.%s@%s",
+ test_dc, "REALLY",
+ "BOGUS"),
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY,
+ .expected_dns = "BOGUS"
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "cifs/%s.%s",
+ test_dc, dns_domain),
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = talloc_asprintf(mem_ctx, "cifs/%s",
+ test_dc),
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = "NOT A GUID",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = "NOT A SID",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = "NOT AN NT4 NAME",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .comment = "Unparsable DN",
+ .str = "NOT A DN",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Unparsable user principal",
+ .str = "NOT A PRINCIPAL",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Unparsable service principal",
+ .str = "NOT A SERVICE PRINCIPAL",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "BIND GUID (ie, not in the directory)",
+ .str = DRSUAPI_DS_BIND_GUID,
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Unqualified Machine account as user principal",
+ .str = talloc_asprintf(mem_ctx, "%s$", test_dc),
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Machine account as service principal",
+ .str = talloc_asprintf(mem_ctx, "%s$", test_dc),
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Full Machine account as service principal",
+ .str = user_principal_name,
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Realm as an NT4 domain lookup",
+ .str = talloc_asprintf(mem_ctx, "%s\\", dns_domain),
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "BUILTIN\\ -> DN",
+ .str = "BUILTIN\\",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "NT AUTHORITY\\ -> DN",
+ .str = "NT AUTHORITY\\",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "NT AUTHORITY\\ANONYMOUS LOGON -> DN",
+ .str = "NT AUTHORITY\\ANONYMOUS LOGON",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "NT AUTHORITY\\SYSTEM -> DN",
+ .str = "NT AUTHORITY\\SYSTEM",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .comment = "BUILTIN SID -> NT4 account",
+ .str = SID_BUILTIN,
+ .status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING,
+ .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = SID_BUILTIN,
+ .comment = "Builtin Domain SID -> DN",
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .expected_str = talloc_asprintf(mem_ctx, "CN=Builtin,%s", realm_dn_str),
+ .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .str = SID_BUILTIN_ADMINISTRATORS,
+ .comment = "Builtin Administrors SID -> DN",
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .str = SID_BUILTIN_ADMINISTRATORS,
+ .comment = "Builtin Administrors SID -> NT4 Account",
+ .status = DRSUAPI_DS_NAME_STATUS_OK,
+ .alternate_status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .str = SID_NT_ANONYMOUS,
+ .comment = "NT Anonymous SID -> NT4 Account",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .str = SID_NT_SYSTEM,
+ .comment = "NT SYSTEM SID -> NT4 Account",
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "Domain SID -> DN",
+ .str = dom_sid,
+ .expected_str = realm_dn_str,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+ .comment = "Domain SID -> NT4 account",
+ .str = dom_sid,
+ .expected_str = nt4_domain,
+ .status = DRSUAPI_DS_NAME_STATUS_OK
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "invalid user principal name",
+ .str = "foo@bar",
+ .status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY,
+ .expected_dns = "bar"
+ },
+ {
+ .format_offered = DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+ .format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+ .comment = "invalid user principal name in valid domain",
+ .str = talloc_asprintf(mem_ctx, "invalidusername@%s", dns_domain),
+ .status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
+ }
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(crack); i++) {
+ const char *comment;
+
+ torture_comment(tctx, "Testing DsCrackNames with name '%s'"
+ " offered format: %d desired format:%d\n",
+ crack[i].str,
+ crack[i].format_offered,
+ crack[i].format_desired);
+
+ r.in.req->req1.format_flags = crack[i].flags;
+ r.in.req->req1.format_offered = crack[i].format_offered;
+ r.in.req->req1.format_desired = crack[i].format_desired;
+ names[0].str = crack[i].str;
+
+ if (crack[i].comment) {
+ comment = talloc_asprintf(mem_ctx,
+ "'%s' with name '%s' offered format:%d desired format:%d\n",
+ crack[i].comment, names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ } else {
+ comment = talloc_asprintf(mem_ctx, "'%s' offered format:%d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ }
+ if (crack[i].skip) {
+ torture_comment(tctx, "skipping: %s", comment);
+ continue;
+ }
+ status = dcerpc_drsuapi_DsCrackNames_r(p->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != crack[i].status) {
+ if (crack[i].alternate_status) {
+ if (r.out.ctr->ctr1->array[0].status != crack[i].alternate_status) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames unexpected status %d, wanted %d or %d on: %s",
+ r.out.ctr->ctr1->array[0].status,
+ crack[i].status,
+ crack[i].alternate_status,
+ comment);
+ torture_fail(tctx, err_msg);
+ }
+ } else {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames unexpected status %d, wanted %d on: %s\n",
+ r.out.ctr->ctr1->array[0].status,
+ crack[i].status,
+ comment);
+ torture_fail(tctx, err_msg);
+ }
+ } else if (crack[i].expected_str &&
+ (!r.out.ctr->ctr1->count ||
+ !r.out.ctr->ctr1->array[0].result_name))
+ {
+ if (!r.out.ctr->ctr1->count) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames failed - got 0 entries, expected %s on %s",
+ crack[i].expected_str, comment);
+ torture_fail(tctx, err_msg);
+ } else {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames failed - got NULL pointer, expected %s on %s",
+ crack[i].expected_str, comment);
+ torture_fail(tctx, err_msg);
+ }
+ } else if (crack[i].expected_str
+ && (strcmp(r.out.ctr->ctr1->array[0].result_name,
+ crack[i].expected_str) != 0))
+ {
+ if (strcasecmp(r.out.ctr->ctr1->array[0].result_name,
+ crack[i].expected_str) != 0) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames failed - got %s, expected %s on %s",
+ r.out.ctr->ctr1->array[0].result_name,
+ crack[i].expected_str, comment);
+ torture_fail(tctx, err_msg);
+ } else {
+ torture_comment(tctx,
+ "(warning) DsCrackNames returned different case - got %s, expected %s on %s\n",
+ r.out.ctr->ctr1->array[0].result_name,
+ crack[i].expected_str, comment);
+ }
+ } else if (crack[i].expected_dns
+ && (strcmp(r.out.ctr->ctr1->array[0].dns_domain_name,
+ crack[i].expected_dns) != 0)) {
+ err_msg = talloc_asprintf(mem_ctx,
+ "DsCrackNames failed - got DNS name %s, expected %s on %s",
+ r.out.ctr->ctr1->array[0].result_name,
+ crack[i].expected_str, comment);
+ torture_fail(tctx, err_msg);
+ }
+
+ torture_comment(tctx, "Testing DsCrackNames got %s\n", r.out.ctr->ctr1->array[0].result_name);
+ }
+ }
+
+ return test_DsCrackNamesMatrix(tctx, priv, FQDN_1779_name,
+ user_principal_name, service_principal_name);
+}
+
+/**
+ * Test case setup for CrackNames
+ */
+static bool torture_drsuapi_cracknames_setup(struct torture_context *tctx, void **data)
+{
+ struct DsCrackNamesPrivate *priv;
+
+ *data = priv = talloc_zero(tctx, struct DsCrackNamesPrivate);
+
+ return torture_drsuapi_tcase_setup_common(tctx, &priv->base);
+}
+
+/**
+ * Test case tear-down for CrackNames
+ */
+static bool torture_drsuapi_cracknames_teardown(struct torture_context *tctx, void *data)
+{
+ struct DsCrackNamesPrivate *priv = talloc_get_type(data, struct DsCrackNamesPrivate);
+
+ return torture_drsuapi_tcase_teardown_common(tctx, &priv->base);
+}
+
+/**
+ * CRACKNAMES test suite implementation
+ */
+void torture_rpc_drsuapi_cracknames_tcase(struct torture_suite *suite)
+{
+ typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
+
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "cracknames");
+
+ torture_tcase_set_fixture(tcase,
+ torture_drsuapi_cracknames_setup,
+ torture_drsuapi_cracknames_teardown);
+
+ torture_tcase_add_simple_test(tcase, "cracknames-test", (run_func)test_DsCrackNames);
+}
diff --git a/source4/torture/rpc/drsuapi_w2k8.c b/source4/torture/rpc/drsuapi_w2k8.c
new file mode 100644
index 0000000..9ff37ed
--- /dev/null
+++ b/source4/torture/rpc/drsuapi_w2k8.c
@@ -0,0 +1,334 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DRSUapi tests
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+#define TEST_MACHINE_NAME "torturetest"
+
+/*
+ * DsBind as sent from W2K8 Client.
+ * This should work regardless of functional level, and accept
+ * any info <=48
+ */
+bool test_DsBind_w2k8(struct torture_context *tctx,
+ struct DsPrivate_w2k8 *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsBind r;
+ struct drsuapi_DsBindInfo48 *bind_info48;
+ struct drsuapi_DsBindInfoCtr bind_info_ctr;
+
+ /* We send info48 */
+ ZERO_STRUCT(bind_info_ctr);
+ bind_info_ctr.length = 48;
+
+ bind_info48 = &bind_info_ctr.info.info48;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
+ bind_info48->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
+
+ /*
+ * We wish for DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2,
+ * needed for DsGetDomainControllerInfo level 3
+ */
+ bind_info48->supported_extensions_ext |= DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2;
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &priv->bind_guid);
+
+ r.in.bind_guid = &priv->bind_guid;
+ r.in.bind_info = &bind_info_ctr;
+ r.out.bind_handle = &priv->bind_handle;
+
+ torture_comment(tctx, "Testing DsBind W2K8\n");
+
+ status = dcerpc_drsuapi_DsBind_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");
+
+ torture_assert_not_null(tctx, r.out.bind_info,
+ "DsBind with info48 results in NULL");
+
+ /* cache server supported extensions, i.e. bind_info */
+ priv->srv_bind_info = *r.out.bind_info;
+
+ /*
+ * We do not check for length here, because it should be valid to return
+ * any valid info
+ */
+
+ return true;
+}
+
+static bool test_DsGetDomainControllerInfo_w2k8(struct torture_context *tctx,
+ struct DsPrivate_w2k8 *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsGetDomainControllerInfo r;
+ union drsuapi_DsGetDCInfoCtr ctr;
+ int32_t level_out = 0;
+ uint32_t supported_extensions_ext = 0;
+ bool found = false;
+ int j, k;
+
+ struct {
+ const char *name;
+ WERROR expected;
+ } names[] = {
+ {
+ .name = torture_join_dom_netbios_name(priv->join),
+ .expected = WERR_OK
+ },
+ {
+ .name = torture_join_dom_dns_name(priv->join),
+ .expected = WERR_OK
+ },
+ {
+ .name = "__UNKNOWN_DOMAIN__",
+ .expected = WERR_DS_OBJ_NOT_FOUND
+ },
+ {
+ .name = "unknown.domain.samba.example.com",
+ .expected = WERR_DS_OBJ_NOT_FOUND
+ },
+ };
+
+ /* Levels 1 and 2 are tested in standard drsuapi tests */
+ int level = 3;
+
+ /* Do Bind first. */
+ if (!test_DsBind_w2k8(tctx, priv)) {
+ return false;
+ }
+
+ /*
+ * We used DsBind_w2k8, so DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2
+ * should mean support for level 3
+ */
+
+ /*
+ * We are looking for an extension found in info32 and later
+ */
+ switch (priv->srv_bind_info.length) {
+ case 32:
+ supported_extensions_ext = priv->srv_bind_info.info.info32.supported_extensions_ext;
+ break;
+ case 48:
+ supported_extensions_ext = priv->srv_bind_info.info.info48.supported_extensions_ext;
+ break;
+ default:
+ supported_extensions_ext = 0;
+ break;
+ }
+
+ supported_extensions_ext &= DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2;
+ torture_assert(tctx, (supported_extensions_ext > 0),
+ "Server does not support DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2");
+
+ for (j=0; j < ARRAY_SIZE(names); j++) {
+ union drsuapi_DsGetDCInfoRequest req;
+ r.in.bind_handle = &priv->bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+
+ r.in.req->req1.domain_name = names[j].name;
+ r.in.req->req1.level = level;
+
+ r.out.ctr = &ctr;
+ r.out.level_out = &level_out;
+
+ torture_comment(tctx,
+ "Testing DsGetDomainControllerInfo level %d on domainname '%s'\n",
+ r.in.req->req1.level, r.in.req->req1.domain_name);
+
+ status = dcerpc_drsuapi_DsGetDomainControllerInfo_r(p->binding_handle, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo with dns domain failed");
+ torture_assert_werr_equal(tctx, r.out.result, names[j].expected,
+ "DsGetDomainControllerInfo level with dns domain failed");
+
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ /* If this was an error, we can't read the result structure */
+ continue;
+ }
+
+ torture_assert_int_equal(tctx, r.in.req->req1.level, *r.out.level_out,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo in/out level differs");
+
+ for (k=0; k < r.out.ctr->ctr3.count; k++) {
+ if (strcasecmp_m(r.out.ctr->ctr3.array[k].netbios_name,
+ torture_join_netbios_name(priv->join)) == 0) {
+ found = true;
+ priv->dcinfo = r.out.ctr->ctr3.array[k];
+ break;
+ }
+ }
+ break;
+
+ torture_assert(tctx, found,
+ "dcerpc_drsuapi_DsGetDomainControllerInfo: Failed to find the domain controller we just created during the join");
+ }
+
+ return true;
+}
+
+
+bool test_DsUnbind_w2k8(struct torture_context *tctx,
+ struct DsPrivate_w2k8 *priv)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = priv->drs_pipe;
+ struct drsuapi_DsUnbind r;
+
+ r.in.bind_handle = &priv->bind_handle;
+ r.out.bind_handle = &priv->bind_handle;
+
+ torture_comment(tctx, "Testing DsUnbind W2K8\n");
+
+ status = dcerpc_drsuapi_DsUnbind_r(p->binding_handle, tctx, &r);
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsUnbind");
+
+ return true;
+}
+
+/**
+ * Common test case setup function to be used
+ * in DRS suit of test when appropriate
+ */
+bool torture_drsuapi_w2k8_tcase_setup_common(struct torture_context *tctx,
+ struct DsPrivate_w2k8 *priv)
+{
+ NTSTATUS status;
+ int rnd = rand() % 1000;
+ char *name = talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, rnd);
+ struct cli_credentials *machine_credentials;
+
+ torture_assert(tctx, priv, "Invalid argument");
+
+ torture_comment(tctx, "Create DRSUAPI pipe\n");
+ status = torture_rpc_connection(tctx,
+ &priv->drs_pipe,
+ &ndr_table_drsuapi);
+ torture_assert(tctx, NT_STATUS_IS_OK(status), "Unable to connect to DRSUAPI pipe");
+
+ torture_comment(tctx, "About to join domain with name %s\n", name);
+ priv->join = torture_join_domain(tctx, name, ACB_SVRTRUST,
+ &machine_credentials);
+ torture_assert(tctx, priv->join, "Failed to join as BDC");
+
+ /*
+ * After that every test should use DsBind and DsGetDomainControllerInfo
+ */
+ if (!test_DsBind_w2k8(tctx, priv)) {
+ /* clean up */
+ torture_drsuapi_w2k8_tcase_teardown_common(tctx, priv);
+ torture_fail(tctx, "Failed execute test_DsBind_w2k8()");
+ }
+
+
+ return true;
+}
+
+/**
+ * Common test case teardown function to be used
+ * in DRS suit of test when appropriate
+ */
+bool torture_drsuapi_w2k8_tcase_teardown_common(struct torture_context *tctx,
+ struct DsPrivate_w2k8 *priv)
+{
+ if (priv->join) {
+ torture_leave_domain(tctx, priv->join);
+ }
+
+ return true;
+}
+
+/**
+ * Test case setup for DRSUAPI test case
+ */
+static bool torture_drsuapi_w2k8_tcase_setup(struct torture_context *tctx, void **data)
+{
+ struct DsPrivate_w2k8 *priv;
+
+ *data = priv = talloc_zero(tctx, struct DsPrivate_w2k8);
+
+ return torture_drsuapi_w2k8_tcase_setup_common(tctx, priv);
+}
+
+/**
+ * Test case tear-down for DRSUAPI test case
+ */
+static bool torture_drsuapi_w2k8_tcase_teardown(struct torture_context *tctx, void *data)
+{
+ bool ret;
+ struct DsPrivate_w2k8 *priv = talloc_get_type(data, struct DsPrivate_w2k8);
+
+ ret = torture_drsuapi_w2k8_tcase_teardown_common(tctx, priv);
+
+ talloc_free(priv);
+ return ret;
+}
+
+/**
+ * DRSUAPI test case implementation
+ */
+void torture_rpc_drsuapi_w2k8_tcase(struct torture_suite *suite)
+{
+ typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
+
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "drsuapi_w2k8");
+
+ torture_tcase_set_fixture(tcase, torture_drsuapi_w2k8_tcase_setup,
+ torture_drsuapi_w2k8_tcase_teardown);
+
+ torture_tcase_add_simple_test(tcase, "DsBind_W2K8", (run_func)test_DsBind_w2k8);
+ torture_tcase_add_simple_test(tcase, "DsGetDomainControllerInfo_W2K8", (run_func)test_DsGetDomainControllerInfo_w2k8);
+}
diff --git a/source4/torture/rpc/dsgetinfo.c b/source4/torture/rpc/dsgetinfo.c
new file mode 100644
index 0000000..b47d6ee
--- /dev/null
+++ b/source4/torture/rpc/dsgetinfo.c
@@ -0,0 +1,452 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ DsGetReplInfo test. Based on code from dssync.c
+
+ Copyright (C) Erick Nogueira do Nascimento 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "libcli/cldap/cldap.h"
+#include "torture/torture.h"
+#include "../libcli/drsuapi/drsuapi.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/drs/proto.h"
+#include "lib/util/util_paths.h"
+
+
+struct DsGetinfoBindInfo {
+ struct dcerpc_pipe *drs_pipe;
+ struct dcerpc_binding_handle *drs_handle;
+ struct drsuapi_DsBind req;
+ struct GUID bind_guid;
+ struct drsuapi_DsBindInfoCtr our_bind_info_ctr;
+ struct drsuapi_DsBindInfo28 our_bind_info28;
+ struct drsuapi_DsBindInfo28 peer_bind_info28;
+ struct policy_handle bind_handle;
+};
+
+struct DsGetinfoTest {
+ struct dcerpc_binding *drsuapi_binding;
+
+ const char *ldap_url;
+ const char *site_name;
+
+ const char *domain_dn;
+
+ /* what we need to do as 'Administrator' */
+ struct {
+ struct cli_credentials *credentials;
+ struct DsGetinfoBindInfo drsuapi;
+ } admin;
+};
+
+
+
+/*
+ return the default DN for a ldap server given a connected RPC pipe to the
+ server
+ */
+static const char *torture_get_ldap_base_dn(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ const char *hostname = dcerpc_binding_get_string_option(p->binding, "host");
+ struct ldb_context *ldb;
+ const char *ldap_url = talloc_asprintf(p, "ldap://%s", hostname);
+ const char *attrs[] = { "defaultNamingContext", NULL };
+ const char *dnstr;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ int ret;
+ struct ldb_result *res;
+
+ ldb = ldb_init(tmp_ctx, tctx->ev);
+ if (ldb == NULL) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (ldb_set_opaque(ldb, "loadparm", tctx->lp_ctx)) {
+ talloc_free(ldb);
+ return NULL;
+ }
+
+ ldb_set_modules_dir(ldb,
+ modules_path(ldb, "ldb"));
+
+ ret = ldb_connect(ldb, ldap_url, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ torture_comment(tctx, "Failed to make LDB connection to target");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ ret = dsdb_search_dn(ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, ldb, ""),
+ attrs, 0);
+ if (ret != LDB_SUCCESS) {
+ torture_comment(tctx, "Failed to get defaultNamingContext");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ dnstr = ldb_msg_find_attr_as_string(res->msgs[0], "defaultNamingContext", NULL);
+ dnstr = talloc_strdup(tctx, dnstr);
+ talloc_free(tmp_ctx);
+ return dnstr;
+}
+
+
+static struct DsGetinfoTest *test_create_context(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct DsGetinfoTest *ctx;
+ struct drsuapi_DsBindInfo28 *our_bind_info28;
+ struct drsuapi_DsBindInfoCtr *our_bind_info_ctr;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ ctx = talloc_zero(tctx, struct DsGetinfoTest);
+ if (!ctx) return NULL;
+
+ status = dcerpc_parse_binding(ctx, binding, &ctx->drsuapi_binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Bad binding string %s\n", binding);
+ return NULL;
+ }
+ status = dcerpc_binding_set_flags(ctx->drsuapi_binding, DCERPC_SIGN | DCERPC_SEAL, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("dcerpc_binding_set_flags - %s\n", nt_errstr(status));
+ return NULL;
+ }
+
+ /* ctx->admin ...*/
+ ctx->admin.credentials = samba_cmdline_get_creds();
+
+ our_bind_info28 = &ctx->admin.drsuapi.our_bind_info28;
+ our_bind_info28->supported_extensions = 0xFFFFFFFF;
+ our_bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3;
+ our_bind_info28->site_guid = GUID_zero();
+ our_bind_info28->pid = 0;
+ our_bind_info28->repl_epoch = 1;
+
+ our_bind_info_ctr = &ctx->admin.drsuapi.our_bind_info_ctr;
+ our_bind_info_ctr->length = 28;
+ our_bind_info_ctr->info.info28 = *our_bind_info28;
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &ctx->admin.drsuapi.bind_guid);
+
+ ctx->admin.drsuapi.req.in.bind_guid = &ctx->admin.drsuapi.bind_guid;
+ ctx->admin.drsuapi.req.in.bind_info = our_bind_info_ctr;
+ ctx->admin.drsuapi.req.out.bind_handle = &ctx->admin.drsuapi.bind_handle;
+
+ return ctx;
+}
+
+static bool _test_DsBind(struct torture_context *tctx,
+ struct DsGetinfoTest *ctx, struct cli_credentials *credentials, struct DsGetinfoBindInfo *b)
+{
+ NTSTATUS status;
+ bool ret = true;
+
+ status = dcerpc_pipe_connect_b(ctx,
+ &b->drs_pipe, ctx->drsuapi_binding,
+ &ndr_table_drsuapi,
+ credentials, tctx->ev, tctx->lp_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect to server as a BDC: %s\n", nt_errstr(status));
+ return false;
+ }
+ b->drs_handle = b->drs_pipe->binding_handle;
+
+ status = dcerpc_drsuapi_DsBind_r(b->drs_handle, ctx, &b->req);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr);
+ ret = false;
+ } else if (!W_ERROR_IS_OK(b->req.out.result)) {
+ printf("DsBind failed - %s\n", win_errstr(b->req.out.result));
+ ret = false;
+ }
+
+ ZERO_STRUCT(b->peer_bind_info28);
+ if (b->req.out.bind_info) {
+ switch (b->req.out.bind_info->length) {
+ case 24: {
+ struct drsuapi_DsBindInfo24 *info24;
+ info24 = &b->req.out.bind_info->info.info24;
+ b->peer_bind_info28.supported_extensions= info24->supported_extensions;
+ b->peer_bind_info28.site_guid = info24->site_guid;
+ b->peer_bind_info28.pid = info24->pid;
+ b->peer_bind_info28.repl_epoch = 0;
+ break;
+ }
+ case 28: {
+ b->peer_bind_info28 = b->req.out.bind_info->info.info28;
+ break;
+ }
+ case 32: {
+ struct drsuapi_DsBindInfo32 *info32;
+ info32 = &b->req.out.bind_info->info.info32;
+ b->peer_bind_info28.supported_extensions= info32->supported_extensions;
+ b->peer_bind_info28.site_guid = info32->site_guid;
+ b->peer_bind_info28.pid = info32->pid;
+ b->peer_bind_info28.repl_epoch = info32->repl_epoch;
+ break;
+ }
+ case 48: {
+ struct drsuapi_DsBindInfo48 *info48;
+ info48 = &b->req.out.bind_info->info.info48;
+ b->peer_bind_info28.supported_extensions= info48->supported_extensions;
+ b->peer_bind_info28.site_guid = info48->site_guid;
+ b->peer_bind_info28.pid = info48->pid;
+ b->peer_bind_info28.repl_epoch = info48->repl_epoch;
+ break;
+ }
+ case 52: {
+ struct drsuapi_DsBindInfo52 *info52;
+ info52 = &b->req.out.bind_info->info.info52;
+ b->peer_bind_info28.supported_extensions= info52->supported_extensions;
+ b->peer_bind_info28.site_guid = info52->site_guid;
+ b->peer_bind_info28.pid = info52->pid;
+ b->peer_bind_info28.repl_epoch = info52->repl_epoch;
+ break;
+ }
+ default:
+ printf("DsBind - warning: unknown BindInfo length: %u\n",
+ b->req.out.bind_info->length);
+ }
+ }
+
+ return ret;
+}
+
+
+static bool test_getinfo(struct torture_context *tctx,
+ struct DsGetinfoTest *ctx)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = ctx->admin.drsuapi.drs_pipe;
+ struct dcerpc_binding_handle *b = ctx->admin.drsuapi.drs_handle;
+ struct drsuapi_DsReplicaGetInfo r;
+ union drsuapi_DsReplicaGetInfoRequest req;
+ union drsuapi_DsReplicaInfo info;
+ enum drsuapi_DsReplicaInfoType info_type;
+ int i;
+ bool no_invalid_levels = true;
+ struct {
+ int32_t level;
+ int32_t infotype;
+ const char *obj_dn;
+ const char *attribute_name;
+ uint32_t flags;
+ } array[] = {
+ {
+ .level = DRSUAPI_DS_REPLICA_GET_INFO,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_CURSORS
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_PENDING_OPS
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_CURSORS2
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_CURSORS3
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2,
+ .obj_dn = "CN=Domain Admins,CN=Users,",
+ .flags = 0
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2,
+ .obj_dn = "CN=Domain Admins,CN=Users,",
+ .flags = DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_REPSTO
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1
+ },{
+ .level = DRSUAPI_DS_REPLICA_GET_INFO2,
+ .infotype = DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS
+ }
+ };
+
+ ctx->domain_dn = torture_get_ldap_base_dn(tctx, p);
+ torture_assert(tctx, ctx->domain_dn != NULL, "Cannot get domain_dn");
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping DsReplicaGetInfo test against Samba4\n");
+ return true;
+ }
+
+ r.in.bind_handle = &ctx->admin.drsuapi.bind_handle;
+ r.in.req = &req;
+
+ for (i=0; i < ARRAY_SIZE(array); i++) {
+ const char *object_dn;
+
+ torture_comment(tctx, "Testing DsReplicaGetInfo level %d infotype %d\n",
+ array[i].level, array[i].infotype);
+
+ if (array[i].obj_dn) {
+ object_dn = array[i].obj_dn;
+ if (object_dn[strlen(object_dn)-1] == ',') {
+ /* add the domain DN on the end */
+ object_dn = talloc_asprintf(tctx, "%s%s", object_dn, ctx->domain_dn);
+ }
+ } else {
+ object_dn = ctx->domain_dn;
+ }
+
+ r.in.level = array[i].level;
+ switch(r.in.level) {
+ case DRSUAPI_DS_REPLICA_GET_INFO:
+ r.in.req->req1.info_type = array[i].infotype;
+ r.in.req->req1.object_dn = object_dn;
+ ZERO_STRUCT(r.in.req->req1.source_dsa_guid);
+ break;
+ case DRSUAPI_DS_REPLICA_GET_INFO2:
+ r.in.req->req2.info_type = array[i].infotype;
+ r.in.req->req2.object_dn = object_dn;
+ ZERO_STRUCT(r.in.req->req2.source_dsa_guid);
+ r.in.req->req2.flags = 0;
+ r.in.req->req2.attribute_name = NULL;
+ r.in.req->req2.value_dn_str = NULL;
+ r.in.req->req2.enumeration_context = 0;
+ break;
+ }
+
+ /* Construct a different request for some of the infoTypes */
+ if (array[i].attribute_name != NULL) {
+ r.in.req->req2.attribute_name = array[i].attribute_name;
+ }
+ if (array[i].flags != 0) {
+ r.in.req->req2.flags |= array[i].flags;
+ }
+
+ r.out.info = &info;
+ r.out.info_type = &info_type;
+
+ status = dcerpc_drsuapi_DsReplicaGetInfo_r(b, tctx, &r);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
+ torture_comment(tctx,
+ "DsReplicaGetInfo level %d and/or infotype %d not supported by server\n",
+ array[i].level, array[i].infotype);
+ continue;
+ }
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx,
+ "DsReplicaGetInfo level %d and/or infotype %d failed\n",
+ array[i].level, array[i].infotype));
+ if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
+ /* this is a not yet supported level */
+ torture_comment(tctx,
+ "DsReplicaGetInfo level %d and/or infotype %d not yet supported by server\n",
+ array[i].level, array[i].infotype);
+ no_invalid_levels = false;
+ continue;
+ }
+
+ torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsReplicaGetInfo");
+ }
+
+ return no_invalid_levels;
+}
+
+/**
+ * DSGETINFO test case setup
+ */
+static bool torture_dsgetinfo_tcase_setup(struct torture_context *tctx, void **data)
+{
+ bool bret;
+ struct DsGetinfoTest *ctx;
+
+ *data = ctx = test_create_context(tctx);
+ torture_assert(tctx, ctx, "test_create_context() failed");
+
+ bret = _test_DsBind(tctx, ctx, ctx->admin.credentials, &ctx->admin.drsuapi);
+ torture_assert(tctx, bret, "_test_DsBind() failed");
+
+ return true;
+}
+
+/**
+ * DSGETINFO test case cleanup
+ */
+static bool torture_dsgetinfo_tcase_teardown(struct torture_context *tctx, void *data)
+{
+ struct DsGetinfoTest *ctx;
+ struct drsuapi_DsUnbind r;
+ struct policy_handle bind_handle;
+
+ ctx = talloc_get_type(data, struct DsGetinfoTest);
+
+ ZERO_STRUCT(r);
+ r.out.bind_handle = &bind_handle;
+
+ /* Unbing admin handle */
+ r.in.bind_handle = &ctx->admin.drsuapi.bind_handle;
+ if (ctx->admin.drsuapi.drs_handle) {
+ dcerpc_drsuapi_DsUnbind_r(ctx->admin.drsuapi.drs_handle,
+ ctx, &r);
+ }
+
+ talloc_free(ctx);
+
+ return true;
+}
+
+/**
+ * DSGETINFO test case implementation
+ */
+void torture_drs_rpc_dsgetinfo_tcase(struct torture_suite *suite)
+{
+ typedef bool (*run_func) (struct torture_context *test, void *tcase_data);
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "dsgetinfo");
+
+ torture_tcase_set_fixture(tcase,
+ torture_dsgetinfo_tcase_setup,
+ torture_dsgetinfo_tcase_teardown);
+
+ torture_tcase_add_simple_test(tcase, "DsGetReplicaInfo", (run_func)test_getinfo);
+}
+
diff --git a/source4/torture/rpc/dssetup.c b/source4/torture/rpc/dssetup.c
new file mode 100644
index 0000000..9a61199
--- /dev/null
+++ b/source4/torture/rpc/dssetup.c
@@ -0,0 +1,64 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for dssetup rpc operations
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_dssetup_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+
+bool test_DsRoleGetPrimaryDomainInformation_ext(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ NTSTATUS ext_status)
+{
+ struct dssetup_DsRoleGetPrimaryDomainInformation r;
+ NTSTATUS status;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=DS_ROLE_BASIC_INFORMATION; i <= DS_ROLE_OP_STATUS; i++) {
+ r.in.level = i;
+ torture_comment(tctx, "dcerpc_dssetup_DsRoleGetPrimaryDomainInformation level %d\n", i);
+
+ status = dcerpc_dssetup_DsRoleGetPrimaryDomainInformation_r(b, tctx, &r);
+ torture_assert_ntstatus_equal(tctx, ext_status, status, "DsRoleGetPrimaryDomainInformation failed");
+ if (NT_STATUS_IS_OK(ext_status)) {
+ torture_assert_werr_ok(tctx, r.out.result, "DsRoleGetPrimaryDomainInformation failed");
+ }
+ }
+
+ return true;
+}
+
+bool test_DsRoleGetPrimaryDomainInformation(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_DsRoleGetPrimaryDomainInformation_ext(tctx, p, NT_STATUS_OK);
+}
+
+struct torture_suite *torture_rpc_dssetup(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "dssetup");
+ struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite, "dssetup", &ndr_table_dssetup);
+
+ torture_rpc_tcase_add_test(tcase, "DsRoleGetPrimaryDomainInformation", test_DsRoleGetPrimaryDomainInformation);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/echo.c b/source4/torture/rpc/echo.c
new file mode 100644
index 0000000..93fd408
--- /dev/null
+++ b/source4/torture/rpc/echo.c
@@ -0,0 +1,474 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for echo rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2005
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "lib/events/events.h"
+#include "librpc/gen_ndr/ndr_echo_c.h"
+
+
+/*
+ test the AddOne interface
+*/
+#define TEST_ADDONE(tctx, value) do { \
+ n = i = value; \
+ r.in.in_data = n; \
+ r.out.out_data = &n; \
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_AddOne_r(b, tctx, &r), \
+ talloc_asprintf(tctx, "AddOne(%d) failed", i)); \
+ torture_assert (tctx, n == i+1, talloc_asprintf(tctx, "%d + 1 != %u (should be %u)\n", i, n, i+1)); \
+ torture_comment (tctx, "%d + 1 = %u\n", i, n); \
+} while(0)
+
+static bool test_addone(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ uint32_t i;
+ uint32_t n;
+ struct echo_AddOne r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0;i<10;i++) {
+ TEST_ADDONE(tctx, i);
+ }
+
+ TEST_ADDONE(tctx, 0x7FFFFFFE);
+ TEST_ADDONE(tctx, 0xFFFFFFFE);
+ TEST_ADDONE(tctx, 0xFFFFFFFF);
+ TEST_ADDONE(tctx, random() & 0xFFFFFFFF);
+ return true;
+}
+
+/*
+ test the EchoData interface
+*/
+static bool test_echodata(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ int i;
+ uint8_t *data_in, *data_out;
+ int len;
+ struct echo_EchoData r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "quick", false) &&
+ (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
+ len = 1 + (random() % 500);
+ } else {
+ len = 1 + (random() % 5000);
+ }
+
+ data_in = talloc_array(tctx, uint8_t, len);
+ data_out = talloc_array(tctx, uint8_t, len);
+ for (i=0;i<len;i++) {
+ data_in[i] = i;
+ }
+
+ r.in.len = len;
+ r.in.in_data = data_in;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_EchoData_r(b, tctx, &r),
+ talloc_asprintf(tctx, "EchoData(%d) failed\n", len));
+
+ data_out = r.out.out_data;
+
+ for (i=0;i<len;i++) {
+ if (data_in[i] != data_out[i]) {
+ torture_comment(tctx, "Bad data returned for len %d at offset %d\n",
+ len, i);
+ torture_comment(tctx, "in:\n");
+ dump_data(0, data_in+i, MIN(len-i, 16));
+ torture_comment(tctx, "out:\n");
+ dump_data(0, data_out+i, MIN(len-1, 16));
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ test the SourceData interface
+*/
+static bool test_sourcedata(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ int i;
+ int len;
+ struct echo_SourceData r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "quick", false) &&
+ (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
+ len = 100 + (random() % 500);
+ } else {
+ len = 200000 + (random() % 5000);
+ }
+
+ r.in.len = len;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_SourceData_r(b, tctx, &r),
+ talloc_asprintf(tctx, "SourceData(%d) failed", len));
+
+ for (i=0;i<len;i++) {
+ uint8_t *v = (uint8_t *)r.out.data;
+ torture_assert(tctx, v[i] == (i & 0xFF),
+ talloc_asprintf(tctx,
+ "bad data 0x%x at %d\n", (uint8_t)r.out.data[i], i));
+ }
+ return true;
+}
+
+/*
+ test the SinkData interface
+*/
+static bool test_sinkdata(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ int i;
+ uint8_t *data_in;
+ int len;
+ struct echo_SinkData r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "quick", false) &&
+ (p->conn->flags & DCERPC_DEBUG_VALIDATE_BOTH)) {
+ len = 100 + (random() % 5000);
+ } else {
+ len = 200000 + (random() % 5000);
+ }
+
+ data_in = talloc_array(tctx, uint8_t, len);
+ for (i=0;i<len;i++) {
+ data_in[i] = i+1;
+ }
+
+ r.in.len = len;
+ r.in.data = data_in;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_SinkData_r(b, tctx, &r),
+ talloc_asprintf(tctx, "SinkData(%d) failed", len));
+
+ torture_comment(tctx, "sunk %d bytes\n", len);
+ return true;
+}
+
+
+/*
+ test the testcall interface
+*/
+static bool test_testcall(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct echo_TestCall r;
+ const char *s = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.s1 = "input string";
+ r.out.s2 = &s;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestCall_r(b, tctx, &r),
+ "TestCall failed");
+
+ torture_assert_str_equal(tctx, s, "input string", "Didn't receive back same string");
+
+ return true;
+}
+
+/*
+ test the testcall interface
+*/
+static bool test_testcall2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct echo_TestCall2 r;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=1;i<=7;i++) {
+ r.in.level = i;
+ r.out.info = talloc(tctx, union echo_Info);
+
+ torture_comment(tctx, "Testing TestCall2 level %d\n", i);
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestCall2_r(b, tctx, &r),
+ "TestCall2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "TestCall2 failed");
+ }
+ return true;
+}
+
+static void test_sleep_done(struct tevent_req *subreq)
+{
+ bool *done1 = (bool *)tevent_req_callback_data_void(subreq);
+ *done1 = true;
+}
+
+/*
+ test the TestSleep interface
+*/
+static bool test_sleep(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ int i;
+#define ASYNC_COUNT 3
+ struct tevent_req *req[ASYNC_COUNT];
+ struct echo_TestSleep r[ASYNC_COUNT];
+ bool done1[ASYNC_COUNT];
+ bool done2[ASYNC_COUNT];
+ struct timeval snd[ASYNC_COUNT];
+ struct timeval rcv[ASYNC_COUNT];
+ struct timeval diff[ASYNC_COUNT];
+ int total_done = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_transport_t transport;
+ uint32_t assoc_group_id;
+ struct dcerpc_pipe *p2 = NULL;
+ NTSTATUS status;
+
+ if (torture_setting_bool(tctx, "quick", false)) {
+ torture_skip(tctx, "TestSleep disabled - use \"torture:quick=no\" to enable\n");
+ }
+ torture_comment(tctx, "Testing TestSleep - use \"torture:quick=yes\" to disable\n");
+
+ transport = dcerpc_binding_get_transport(p->binding);
+ assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
+
+ torture_comment(tctx, "connect echo connection 2 with "
+ "DCERPC_CONCURRENT_MULTIPLEX\n");
+ status = torture_rpc_connection_transport(tctx, &p2,
+ &ndr_table_rpcecho,
+ transport,
+ assoc_group_id,
+ DCERPC_CONCURRENT_MULTIPLEX);
+ torture_assert_ntstatus_ok(tctx, status, "opening echo connection 2");
+ b = p2->binding_handle;
+
+ for (i=0;i<ASYNC_COUNT;i++) {
+ done1[i] = false;
+ done2[i] = false;
+ snd[i] = timeval_current();
+ rcv[i] = timeval_zero();
+ r[i].in.seconds = ASYNC_COUNT-i;
+ req[i] = dcerpc_echo_TestSleep_r_send(tctx, tctx->ev, b, &r[i]);
+ torture_assert(tctx, req[i], "Failed to send async sleep request\n");
+ tevent_req_set_callback(req[i], test_sleep_done, &done1[i]);
+ }
+
+ while (total_done < ASYNC_COUNT) {
+ torture_assert(tctx, tevent_loop_once(tctx->ev) == 0,
+ "Event context loop failed");
+ for (i=0;i<ASYNC_COUNT;i++) {
+ if (done2[i] == false && done1[i] == true) {
+ int rounded_tdiff;
+ total_done++;
+ done2[i] = true;
+ rcv[i] = timeval_current();
+ diff[i] = timeval_until(&snd[i], &rcv[i]);
+ rounded_tdiff = (int)(0.5 + diff[i].tv_sec + (1.0e-6*diff[i].tv_usec));
+ torture_comment(tctx, "rounded_tdiff=%d\n", rounded_tdiff);
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_echo_TestSleep_r_recv(req[i], tctx),
+ talloc_asprintf(tctx, "TestSleep(%d) failed", i));
+ torture_assert(tctx, r[i].out.result == r[i].in.seconds,
+ talloc_asprintf(tctx, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)",
+ r[i].out.result, r[i].in.seconds, (unsigned int)diff[i].tv_sec));
+ torture_assert(tctx, r[i].out.result <= rounded_tdiff,
+ talloc_asprintf(tctx, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)",
+ r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
+ if (r[i].out.result+1 == rounded_tdiff) {
+ torture_comment(tctx, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n",
+ r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
+ } else if (r[i].out.result == rounded_tdiff) {
+ torture_comment(tctx, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n",
+ r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec);
+ } else {
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)\n",
+ r[i].out.result, (unsigned int)diff[i].tv_sec, (unsigned int)diff[i].tv_usec));
+ }
+ }
+ }
+ }
+ torture_comment(tctx, "\n");
+ return true;
+}
+
+/*
+ test enum handling
+*/
+static bool test_enum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct echo_TestEnum r;
+ enum echo_Enum1 v = ECHO_ENUM1;
+ struct echo_Enum2 e2;
+ union echo_Enum3 e3;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.foo1 = &v;
+ r.in.foo2 = &e2;
+ r.in.foo3 = &e3;
+ r.out.foo1 = &v;
+ r.out.foo2 = &e2;
+ r.out.foo3 = &e3;
+
+ e2.e1 = 76;
+ e2.e2 = ECHO_ENUM1_32;
+ e3.e1 = ECHO_ENUM2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestEnum_r(b, tctx, &r),
+ "TestEnum failed");
+ return true;
+}
+
+/*
+ test surrounding conformant array handling
+*/
+static bool test_surrounding(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct echo_TestSurrounding r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+ r.in.data = talloc(tctx, struct echo_Surrounding);
+
+ r.in.data->x = 20;
+ r.in.data->surrounding = talloc_zero_array(tctx, uint16_t, r.in.data->x);
+
+ r.out.data = talloc(tctx, struct echo_Surrounding);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestSurrounding_r(b, tctx, &r),
+ "TestSurrounding failed");
+
+ torture_assert(tctx, r.out.data->x == 2 * r.in.data->x,
+ "TestSurrounding did not make the array twice as large");
+
+ return true;
+}
+
+/*
+ test multiple levels of pointers
+*/
+static bool test_doublepointer(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct echo_TestDoublePointer r;
+ uint16_t value = 12;
+ uint16_t *pvalue = &value;
+ uint16_t **ppvalue = &pvalue;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+ r.in.data = &ppvalue;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_echo_TestDoublePointer_r(b, tctx, &r),
+ "TestDoublePointer failed");
+
+ torture_assert_int_equal(tctx, value, r.out.result,
+ "TestDoublePointer did not return original value");
+ return true;
+}
+
+
+/*
+ test request timeouts
+*/
+#if 0 /* this test needs fixing to work over ncacn_np */
+static bool test_timeout(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct rpc_request *req;
+ struct echo_TestSleep r;
+ int timeout_saved = p->request_timeout;
+
+ if (torture_setting_bool(tctx, "quick", false)) {
+ torture_skip(tctx, "timeout testing disabled - use \"torture:quick=no\" to enable\n");
+ }
+
+ torture_comment(tctx, "testing request timeouts\n");
+ r.in.seconds = 2;
+ p->request_timeout = 1;
+
+ req = dcerpc_echo_TestSleep_send(p, tctx, &r);
+ if (!req) {
+ torture_comment(tctx, "Failed to send async sleep request\n");
+ goto failed;
+ }
+ req->ignore_timeout = true;
+
+ status = dcerpc_echo_TestSleep_recv(req);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT,
+ "request should have timed out");
+
+ torture_comment(tctx, "testing request destruction\n");
+ req = dcerpc_echo_TestSleep_send(p, tctx, &r);
+ if (!req) {
+ torture_comment(tctx, "Failed to send async sleep request\n");
+ goto failed;
+ }
+ talloc_free(req);
+
+ req = dcerpc_echo_TestSleep_send(p, tctx, &r);
+ if (!req) {
+ torture_comment(tctx, "Failed to send async sleep request\n");
+ goto failed;
+ }
+ req->ignore_timeout = true;
+ status = dcerpc_echo_TestSleep_recv(req);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_IO_TIMEOUT,
+ "request should have timed out");
+
+ p->request_timeout = timeout_saved;
+
+ return test_addone(tctx, p);
+
+failed:
+ p->request_timeout = timeout_saved;
+ return false;
+}
+#endif
+
+struct torture_suite *torture_rpc_echo(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "echo");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "echo",
+ &ndr_table_rpcecho);
+
+ torture_rpc_tcase_add_test(tcase, "addone", test_addone);
+ torture_rpc_tcase_add_test(tcase, "sinkdata", test_sinkdata);
+ torture_rpc_tcase_add_test(tcase, "echodata", test_echodata);
+ torture_rpc_tcase_add_test(tcase, "sourcedata", test_sourcedata);
+ torture_rpc_tcase_add_test(tcase, "testcall", test_testcall);
+ torture_rpc_tcase_add_test(tcase, "testcall2", test_testcall2);
+ torture_rpc_tcase_add_test(tcase, "enum", test_enum);
+ torture_rpc_tcase_add_test(tcase, "surrounding", test_surrounding);
+ torture_rpc_tcase_add_test(tcase, "doublepointer", test_doublepointer);
+ torture_rpc_tcase_add_test(tcase, "sleep", test_sleep);
+#if 0 /* this test needs fixing to work over ncacn_np */
+ torture_rpc_tcase_add_test(tcase, "timeout", test_timeout);
+#endif
+
+ return suite;
+}
diff --git a/source4/torture/rpc/epmapper.c b/source4/torture/rpc/epmapper.c
new file mode 100644
index 0000000..d1202c2
--- /dev/null
+++ b/source4/torture/rpc/epmapper.c
@@ -0,0 +1,679 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for epmapper rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_epmapper_c.h"
+#include "librpc/ndr/ndr_table.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "torture/rpc/torture_rpc.h"
+#include "lib/util/util_net.h"
+#include "librpc/rpc/rpc_common.h"
+
+/*
+ display any protocol tower
+ */
+static void display_tower(struct torture_context *tctx, struct epm_tower *twr)
+{
+ int i;
+
+ for (i = 0; i < twr->num_floors; i++) {
+ torture_comment(tctx,
+ " %s",
+ epm_floor_string(tctx, &twr->floors[i]));
+ }
+ torture_comment(tctx, "\n");
+}
+
+static bool test_Insert(struct torture_context *tctx,
+ struct dcerpc_binding_handle *h,
+ struct ndr_syntax_id object,
+ const char *annotation,
+ const struct dcerpc_binding *b)
+{
+ struct epm_Insert r;
+ NTSTATUS status;
+
+ r.in.num_ents = 1;
+ r.in.entries = talloc_array(tctx, struct epm_entry_t, 1);
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "Skip Insert test against Samba4");
+ }
+
+ /* FIXME zero */
+ ZERO_STRUCT(r.in.entries[0].object);
+ r.in.entries[0].annotation = annotation;
+
+ r.in.entries[0].tower = talloc(tctx, struct epm_twr_t);
+
+ status = dcerpc_binding_build_tower(tctx,
+ b,
+ &r.in.entries[0].tower->tower);
+
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "Unable to build tower from binding struct");
+ r.in.replace = 0;
+
+ /* shoot! */
+ status = dcerpc_epm_Insert_r(h, tctx, &r);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx,
+ "epm_Insert failed - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ if (r.out.result != EPMAPPER_STATUS_OK) {
+ torture_comment(tctx,
+ "epm_Insert failed - internal error: 0x%.4x\n",
+ r.out.result);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_Delete(struct torture_context *tctx,
+ struct dcerpc_binding_handle *h,
+ const char *annotation,
+ const struct dcerpc_binding *b)
+{
+ NTSTATUS status;
+ struct epm_Delete r;
+
+ r.in.num_ents = 1;
+ r.in.entries = talloc_array(tctx, struct epm_entry_t, 1);
+
+ ZERO_STRUCT(r.in.entries[0].object);
+ r.in.entries[0].annotation = annotation;
+
+ r.in.entries[0].tower = talloc(tctx, struct epm_twr_t);
+
+ status = dcerpc_binding_build_tower(tctx,
+ b,
+ &r.in.entries[0].tower->tower);
+
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "Unable to build tower from binding struct");
+ r.in.num_ents = 1;
+
+ status = dcerpc_epm_Delete_r(h, tctx, &r);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx,
+ "epm_Delete failed - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ if (r.out.result != EPMAPPER_STATUS_OK) {
+ torture_comment(tctx,
+ "epm_Delete failed - internal error: 0x%.4x\n",
+ r.out.result);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_Map_tcpip(struct torture_context *tctx,
+ struct dcerpc_binding_handle *h,
+ struct ndr_syntax_id map_syntax)
+{
+ struct epm_Map r;
+ struct GUID uuid;
+ struct policy_handle entry_handle;
+ struct ndr_syntax_id syntax;
+ struct dcerpc_binding *map_binding;
+ struct epm_twr_t map_tower;
+ struct epm_twr_p_t towers[20];
+ struct epm_tower t;
+ uint32_t num_towers;
+ uint32_t port;
+ uint32_t i;
+ long int p;
+ const char *tmp;
+ const char *ip;
+ char *ptr;
+ NTSTATUS status;
+
+ torture_comment(tctx, "Testing epm_Map\n");
+
+ ZERO_STRUCT(uuid);
+ ZERO_STRUCT(entry_handle);
+
+ r.in.object = &uuid;
+ r.in.map_tower = &map_tower;
+ r.in.entry_handle = &entry_handle;
+ r.out.entry_handle = &entry_handle;
+ r.in.max_towers = 10;
+ r.out.towers = towers;
+ r.out.num_towers = &num_towers;
+
+ /* Create map tower */
+ status = dcerpc_parse_binding(tctx, "ncacn_ip_tcp:[135]", &map_binding);
+ torture_assert_ntstatus_ok(tctx, status,
+ "epm_Map_tcpip failed: can't create map_binding");
+
+ status = dcerpc_binding_set_abstract_syntax(map_binding, &map_syntax);
+ torture_assert_ntstatus_ok(tctx, status,
+ "epm_Map_tcpip failed: set map_syntax");
+
+ status = dcerpc_binding_build_tower(tctx, map_binding,
+ &map_tower.tower);
+ torture_assert_ntstatus_ok(tctx, status,
+ "epm_Map_tcpip failed: can't create map_tower");
+
+ torture_comment(tctx,
+ "epm_Map request for '%s':\n",
+ ndr_interface_name(&map_syntax.uuid, map_syntax.if_version));
+ display_tower(tctx, &r.in.map_tower->tower);
+
+ status = dcerpc_epm_Map_r(h, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "epm_Map_simple failed");
+ torture_assert(tctx, r.out.result == EPMAPPER_STATUS_OK,
+ "epm_Map_tcpip failed: result is not EPMAPPER_STATUS_OK");
+
+ /* Check the result */
+ t = r.out.towers[0].twr->tower;
+
+ /* Check if we got the correct RPC interface identifier */
+ dcerpc_floor_get_uuid_full(&t.floors[0], &syntax);
+ torture_assert(tctx, ndr_syntax_id_equal(&syntax, &map_syntax),
+ "epm_Map_tcpip failed: Interface identifier mismatch");
+
+ torture_comment(tctx,
+ "epm_Map_tcpip response for '%s':\n",
+ ndr_interface_name(&syntax.uuid, syntax.if_version));
+
+ dcerpc_floor_get_uuid_full(&t.floors[1], &syntax);
+ torture_assert(tctx, ndr_syntax_id_equal(&syntax, &ndr_transfer_syntax_ndr),
+ "epm_Map_tcpip failed: floor 2 is not NDR encoded");
+
+ torture_assert(tctx, t.floors[2].lhs.protocol == EPM_PROTOCOL_NCACN,
+ "epm_Map_tcpip failed: floor 3 is not NCACN_IP_TCP");
+
+ tmp = dcerpc_floor_get_rhs_data(tctx, &t.floors[3]);
+ p = strtol(tmp, &ptr, 10);
+ port = p & 0xffff;
+ torture_assert(tctx, port > 1024 && port < 65535, "epm_Map_tcpip failed");
+
+ ip = dcerpc_floor_get_rhs_data(tctx, &t.floors[4]);
+ torture_assert(tctx, is_ipaddress(ip), "epm_Map_tcpip failed");
+
+ for (i = 0; i < *r.out.num_towers; i++) {
+ if (r.out.towers[i].twr) {
+ display_tower(tctx, &t);
+ }
+ }
+
+ return true;
+}
+
+static bool test_Map_full(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ const struct ndr_syntax_id obj = {
+ { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
+ 2
+ };
+ struct dcerpc_binding_handle *h = p->binding_handle;
+ const char *annotation = "SMBTORTURE";
+ struct dcerpc_binding *b;
+ NTSTATUS status;
+ bool ok;
+
+ status = dcerpc_parse_binding(tctx, "ncacn_ip_tcp:216.83.154.106[41768]", &b);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "Unable to generate dcerpc_binding struct");
+ status = dcerpc_binding_set_abstract_syntax(b, &obj);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_binding_set_abstract_syntax");
+
+ ok = test_Insert(tctx, h, obj, annotation, b);
+ torture_assert(tctx, ok, "test_Insert failed");
+
+ ok = test_Map_tcpip(tctx, h, obj);
+ torture_assert(tctx, ok, "test_Map_tcpip failed");
+
+ ok = test_Delete(tctx, h, annotation, b);
+ torture_assert(tctx, ok, "test_Delete failed");
+
+ return true;
+}
+
+static bool test_Map_display(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct epm_entry_t *entry)
+
+{
+ NTSTATUS status;
+ struct epm_twr_t *twr = entry->tower;
+ struct epm_Map r;
+ struct GUID uuid = entry->object;
+ struct policy_handle handle;
+ struct ndr_syntax_id syntax;
+ uint32_t num_towers;
+ uint32_t i;
+
+ ZERO_STRUCT(handle);
+
+ r.in.object = &uuid;
+ r.in.map_tower = twr;
+ r.in.entry_handle = &handle;
+ r.out.entry_handle = &handle;
+ r.in.max_towers = 10;
+ r.out.num_towers = &num_towers;
+
+ dcerpc_floor_get_uuid_full(&twr->tower.floors[0], &syntax);
+
+ torture_comment(tctx,
+ "epm_Map results for '%s':\n",
+ ndr_interface_name(&syntax.uuid, syntax.if_version));
+
+ status = dcerpc_epm_Map_r(b, tctx, &r);
+ if (NT_STATUS_IS_OK(status) && r.out.result == 0) {
+ for (i=0;i<*r.out.num_towers;i++) {
+ if (r.out.towers[i].twr) {
+ display_tower(tctx, &r.out.towers[i].twr->tower);
+ }
+ }
+ }
+
+ /* RPC protocol identifier */
+ twr->tower.floors[2].lhs.protocol = EPM_PROTOCOL_NCACN;
+ twr->tower.floors[2].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[2].rhs.ncacn.minor_version = 0;
+
+ /* Port address */
+ twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
+ twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[3].rhs.tcp.port = 0;
+
+ /* Transport */
+ twr->tower.floors[4].lhs.protocol = EPM_PROTOCOL_IP;
+ twr->tower.floors[4].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[4].rhs.ip.ipaddr = "0.0.0.0";
+
+ status = dcerpc_epm_Map_r(b, tctx, &r);
+ if (NT_STATUS_IS_OK(status) && r.out.result == 0) {
+ for (i=0;i<*r.out.num_towers;i++) {
+ if (r.out.towers[i].twr) {
+ display_tower(tctx, &r.out.towers[i].twr->tower);
+ }
+ }
+ }
+
+ twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_HTTP;
+ twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[3].rhs.http.port = 0;
+
+ status = dcerpc_epm_Map_r(b, tctx, &r);
+ if (NT_STATUS_IS_OK(status) && r.out.result == 0) {
+ for (i=0;i<*r.out.num_towers;i++) {
+ if (r.out.towers[i].twr) {
+ display_tower(tctx, &r.out.towers[i].twr->tower);
+ }
+ }
+ }
+
+ twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_UDP;
+ twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[3].rhs.udp.port = 0;
+
+ status = dcerpc_epm_Map_r(b, tctx, &r);
+ if (NT_STATUS_IS_OK(status) && r.out.result == 0) {
+ for (i=0;i<*r.out.num_towers;i++) {
+ if (r.out.towers[i].twr) {
+ display_tower(tctx, &r.out.towers[i].twr->tower);
+ }
+ }
+ }
+
+ twr->tower.floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
+ twr->tower.floors[3].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[3].rhs.smb.unc = "";
+
+ twr->tower.floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
+ twr->tower.floors[4].lhs.lhs_data = data_blob(NULL, 0);
+ twr->tower.floors[4].rhs.netbios.name = "";
+
+ status = dcerpc_epm_Map_r(b, tctx, &r);
+ if (NT_STATUS_IS_OK(status) && r.out.result == 0) {
+ for (i = 0; i < *r.out.num_towers; i++) {
+ if (r.out.towers[i].twr) {
+ display_tower(tctx, &r.out.towers[i].twr->tower);
+ }
+ }
+ }
+
+ /* FIXME: Extend to do other protocols as well (ncacn_unix_stream, ncalrpc) */
+
+ return true;
+}
+
+static bool test_Map_simple(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct epm_Lookup r;
+ struct policy_handle entry_handle;
+ uint32_t num_ents = 0;
+ struct dcerpc_binding_handle *h = p->binding_handle;
+
+ ZERO_STRUCT(entry_handle);
+
+ torture_comment(tctx, "Testing epm_Map\n");
+
+ /* get all elements */
+ r.in.inquiry_type = RPC_C_EP_ALL_ELTS;
+ r.in.object = NULL;
+ r.in.interface_id = NULL;
+ r.in.vers_option = RPC_C_VERS_ALL;
+
+ r.in.entry_handle = &entry_handle;
+ r.in.max_ents = 10;
+
+ r.out.entry_handle = &entry_handle;
+ r.out.num_ents = &num_ents;
+
+ do {
+ int i;
+
+ status = dcerpc_epm_Lookup_r(h, tctx, &r);
+ if (!NT_STATUS_IS_OK(status) ||
+ r.out.result != EPMAPPER_STATUS_OK) {
+ break;
+ }
+
+ for (i = 0; i < *r.out.num_ents; i++) {
+ if (r.out.entries[i].tower->tower.num_floors == 5) {
+ test_Map_display(h, tctx, &r.out.entries[i]);
+ }
+ }
+ } while (NT_STATUS_IS_OK(status) &&
+ r.out.result == EPMAPPER_STATUS_OK &&
+ *r.out.num_ents == r.in.max_ents &&
+ !ndr_policy_handle_empty(&entry_handle));
+
+ torture_assert_ntstatus_ok(tctx, status, "epm_Map_simple failed");
+
+ torture_assert(tctx,
+ ndr_policy_handle_empty(&entry_handle),
+ "epm_Map_simple failed - The policy handle should be empty.");
+
+ return true;
+}
+
+static bool test_LookupHandleFree(struct torture_context *tctx,
+ struct dcerpc_binding_handle *h,
+ struct policy_handle *entry_handle) {
+ NTSTATUS status;
+ struct epm_LookupHandleFree r;
+
+ if (ndr_policy_handle_empty(entry_handle)) {
+ torture_comment(tctx,
+ "epm_LookupHandleFree failed - empty policy_handle\n");
+ return false;
+ }
+
+ r.in.entry_handle = entry_handle;
+ r.out.entry_handle = entry_handle;
+
+ status = dcerpc_epm_LookupHandleFree_r(h, tctx, &r);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx,
+ "epm_LookupHandleFree failed - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ if (r.out.result != EPMAPPER_STATUS_OK) {
+ torture_comment(tctx,
+ "epm_LookupHandleFree failed - internal error: "
+ "0x%.4x\n",
+ r.out.result);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_Lookup_simple(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct epm_Lookup r;
+ struct policy_handle entry_handle;
+ uint32_t num_ents = 0;
+ struct dcerpc_binding_handle *h = p->binding_handle;
+
+ ZERO_STRUCT(entry_handle);
+
+ torture_comment(tctx, "Testing epm_Lookup\n");
+
+ /* get all elements */
+ r.in.inquiry_type = RPC_C_EP_ALL_ELTS;
+ r.in.object = NULL;
+ r.in.interface_id = NULL;
+ r.in.vers_option = RPC_C_VERS_ALL;
+
+ r.in.entry_handle = &entry_handle;
+ r.in.max_ents = 10;
+
+ r.out.entry_handle = &entry_handle;
+ r.out.num_ents = &num_ents;
+
+ do {
+ int i;
+
+ status = dcerpc_epm_Lookup_r(h, tctx, &r);
+ if (!NT_STATUS_IS_OK(status) ||
+ r.out.result != EPMAPPER_STATUS_OK) {
+ break;
+ }
+
+ torture_comment(tctx,
+ "epm_Lookup returned %d events, entry_handle: %s\n",
+ *r.out.num_ents,
+ GUID_string(tctx, &entry_handle.uuid));
+
+ for (i = 0; i < *r.out.num_ents; i++) {
+ torture_comment(tctx,
+ "\n Found '%s' Object[%s]\n",
+ r.out.entries[i].annotation,
+ GUID_string(tctx, &r.out.entries[i].object));
+
+ display_tower(tctx, &r.out.entries[i].tower->tower);
+ }
+ } while (NT_STATUS_IS_OK(status) &&
+ r.out.result == EPMAPPER_STATUS_OK &&
+ *r.out.num_ents == r.in.max_ents &&
+ !ndr_policy_handle_empty(&entry_handle));
+
+ torture_assert_ntstatus_ok(tctx, status, "epm_Lookup failed");
+ torture_assert(tctx, r.out.result == EPMAPPER_STATUS_NO_MORE_ENTRIES, "epm_Lookup failed");
+
+ torture_assert(tctx,
+ ndr_policy_handle_empty(&entry_handle),
+ "epm_Lookup failed - The policy handle should be empty.");
+
+ return true;
+}
+
+/*
+ * This test starts a epm_Lookup request, but doesn't finish the
+ * call terminates the search. So it will call epm_LookupHandleFree.
+ */
+static bool test_Lookup_terminate_search(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ bool ok;
+ NTSTATUS status;
+ struct epm_Lookup r;
+ struct policy_handle entry_handle;
+ uint32_t i, num_ents = 0;
+ struct dcerpc_binding_handle *h = p->binding_handle;
+
+ ZERO_STRUCT(entry_handle);
+
+ torture_comment(tctx, "Testing epm_Lookup and epm_LookupHandleFree\n");
+
+ /* get all elements */
+ r.in.inquiry_type = RPC_C_EP_ALL_ELTS;
+ r.in.object = NULL;
+ r.in.interface_id = NULL;
+ r.in.vers_option = RPC_C_VERS_ALL;
+
+ r.in.entry_handle = &entry_handle;
+ r.in.max_ents = 2;
+
+ r.out.entry_handle = &entry_handle;
+ r.out.num_ents = &num_ents;
+
+ status = dcerpc_epm_Lookup_r(h, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "epm_Lookup failed");
+ torture_assert(tctx, r.out.result == EPMAPPER_STATUS_OK, "epm_Lookup failed");
+
+ torture_comment(tctx,
+ "epm_Lookup returned %d events, entry_handle: %s\n",
+ *r.out.num_ents,
+ GUID_string(tctx, &entry_handle.uuid));
+
+ for (i = 0; i < *r.out.num_ents; i++) {
+ torture_comment(tctx,
+ "\n Found '%s'\n",
+ r.out.entries[i].annotation);
+ }
+
+ ok = test_LookupHandleFree(tctx,
+ h,
+ &entry_handle);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_Insert_noreplace(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ bool ok;
+ NTSTATUS status;
+ struct epm_Insert r;
+ struct dcerpc_binding *b;
+ struct dcerpc_binding_handle *h = p->binding_handle;
+
+ torture_comment(tctx, "Testing epm_Insert(noreplace) and epm_Delete\n");
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "Skip Insert test against Samba4");
+ }
+
+ r.in.num_ents = 1;
+ r.in.entries = talloc_array(tctx, struct epm_entry_t, 1);
+
+ ZERO_STRUCT(r.in.entries[0].object);
+ r.in.entries[0].annotation = "smbtorture endpoint";
+
+ status = dcerpc_parse_binding(tctx, "ncalrpc:[SMBTORTURE]", &b);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "Unable to generate dcerpc_binding struct");
+
+ r.in.entries[0].tower = talloc(tctx, struct epm_twr_t);
+
+ status = dcerpc_binding_build_tower(tctx,
+ b,
+ &r.in.entries[0].tower->tower);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "Unable to build tower from binding struct");
+ r.in.replace = 0;
+
+ status = dcerpc_epm_Insert_r(h, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "epm_Insert failed");
+
+ torture_assert(tctx, r.out.result == 0, "epm_Insert failed");
+
+ ok = test_Delete(tctx, h, "smbtorture", b);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+#if 0
+/*
+ * The MS-RPCE documentation states that this function isn't implemented and
+ * SHOULD NOT be called by a client.
+ */
+static bool test_InqObject(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct epm_InqObject r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.epm_object = talloc(tctx, struct GUID);
+ *r.in.epm_object = ndr_table_epmapper.syntax_id.uuid;
+
+ status = dcerpc_epm_InqObject_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "InqObject failed");
+
+ return true;
+}
+#endif
+
+struct torture_suite *torture_rpc_epmapper(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "epmapper");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite,
+ "epmapper",
+ &ndr_table_epmapper);
+
+ /* This is a stack */
+ torture_rpc_tcase_add_test(tcase,
+ "Map_simple",
+ test_Map_simple);
+ torture_rpc_tcase_add_test(tcase,
+ "Map_full",
+ test_Map_full);
+ torture_rpc_tcase_add_test(tcase,
+ "Lookup_simple",
+ test_Lookup_simple);
+ torture_rpc_tcase_add_test(tcase,
+ "Lookup_terminate_search",
+ test_Lookup_terminate_search);
+ torture_rpc_tcase_add_test(tcase,
+ "Insert_noreplace",
+ test_Insert_noreplace);
+
+ return suite;
+}
+
+/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */
diff --git a/source4/torture/rpc/eventlog.c b/source4/torture/rpc/eventlog.c
new file mode 100644
index 0000000..87dc6a2
--- /dev/null
+++ b/source4/torture/rpc/eventlog.c
@@ -0,0 +1,501 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for eventlog rpc operations
+
+ Copyright (C) Tim Potter 2003,2005
+ Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_eventlog.h"
+#include "librpc/gen_ndr/ndr_eventlog_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+#define TEST_BACKUP_NAME "samrtorturetest"
+
+static void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+ name->length = 2*strlen_m(s);
+ name->size = name->length;
+}
+
+static bool get_policy_handle(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct eventlog_OpenEventLogW r;
+ struct eventlog_OpenUnknown0 unknown0;
+ struct lsa_String logname, servername;
+
+ unknown0.unknown0 = 0x005c;
+ unknown0.unknown1 = 0x0001;
+
+ r.in.unknown0 = &unknown0;
+ init_lsa_String(&logname, "dns server");
+ init_lsa_String(&servername, NULL);
+ r.in.logname = &logname;
+ r.in.servername = &servername;
+ r.in.major_version = 0x00000001;
+ r.in.minor_version = 0x00000001;
+ r.out.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_OpenEventLogW_r(b, tctx, &r),
+ "OpenEventLog failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "OpenEventLog failed");
+
+ return true;
+}
+
+
+
+static bool test_GetNumRecords(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct eventlog_GetNumRecords r;
+ struct eventlog_CloseEventLog cr;
+ struct policy_handle handle;
+ uint32_t number = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ ZERO_STRUCT(r);
+ r.in.handle = &handle;
+ r.out.number = &number;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_GetNumRecords_r(b, tctx, &r),
+ "GetNumRecords failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "GetNumRecords failed");
+ torture_comment(tctx, "%d records\n", *r.out.number);
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+ return true;
+}
+
+static bool test_ReadEventLog(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct eventlog_ReadEventLogW r;
+ struct eventlog_CloseEventLog cr;
+ struct policy_handle handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint32_t sent_size = 0;
+ uint32_t real_size = 0;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ ZERO_STRUCT(r);
+ r.in.offset = 0;
+ r.in.handle = &handle;
+ r.in.flags = 0;
+ r.out.data = NULL;
+ r.out.sent_size = &sent_size;
+ r.out.real_size = &real_size;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_ReadEventLogW_r(b, tctx, &r),
+ "ReadEventLog failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER,
+ "ReadEventLog failed");
+
+ while (1) {
+ struct EVENTLOGRECORD rec;
+ enum ndr_err_code ndr_err;
+ uint32_t size = 0;
+ uint32_t pos = 0;
+
+ /* Read first for number of bytes in record */
+
+ r.in.number_of_bytes = 0;
+ r.in.flags = EVENTLOG_BACKWARDS_READ|EVENTLOG_SEQUENTIAL_READ;
+ r.out.data = NULL;
+ r.out.sent_size = &sent_size;
+ r.out.real_size = &real_size;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_ReadEventLogW_r(b, tctx, &r),
+ "ReadEventLogW failed");
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_END_OF_FILE)) {
+ /* FIXME: still need to decode then */
+ break;
+ }
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_BUFFER_TOO_SMALL,
+ "ReadEventLog failed");
+
+ /* Now read the actual record */
+
+ r.in.number_of_bytes = *r.out.real_size;
+ r.out.data = talloc_array(tctx, uint8_t, r.in.number_of_bytes);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_ReadEventLogW_r(b, tctx, &r),
+ "ReadEventLogW failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ReadEventLog failed");
+
+ /* Decode a user-marshalled record */
+ size = IVAL(r.out.data, pos);
+
+ while (size > 0) {
+ DATA_BLOB blob = data_blob_const(
+ r.out.data + pos, size);
+ dump_data(0, blob.data, blob.length);
+
+ ndr_err = ndr_pull_struct_blob_all(&blob, tctx, &rec,
+ (ndr_pull_flags_fn_t)ndr_pull_EVENTLOGRECORD);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ torture_assert_ntstatus_ok(tctx, status,
+ "ReadEventLog failed parsing event log record");
+ }
+
+ NDR_PRINT_DEBUG(EVENTLOGRECORD, &rec);
+
+ pos += size;
+
+ if (pos + 4 > *r.out.sent_size) {
+ break;
+ }
+
+ size = IVAL(r.out.data, pos);
+ }
+
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "ReadEventLog failed parsing event log record");
+
+ r.in.offset++;
+ }
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+static bool test_ReportEventLog(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct eventlog_ReportEventW r;
+ struct eventlog_CloseEventLog cr;
+ struct policy_handle handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint32_t record_number = 0;
+ time_t time_written = 0;
+ struct lsa_String servername, *strings;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ init_lsa_String(&servername, NULL);
+
+ strings = talloc_array(tctx, struct lsa_String, 1);
+ init_lsa_String(&strings[0], "Currently tortured by samba 4");
+
+ ZERO_STRUCT(r);
+
+ r.in.handle = &handle;
+ r.in.timestamp = time(NULL);
+ r.in.event_type = EVENTLOG_INFORMATION_TYPE;
+ r.in.event_category = 0;
+ r.in.event_id = 0;
+ r.in.num_of_strings = 1;
+ r.in.data_size = 0;
+ r.in.servername = &servername;
+ r.in.user_sid = NULL;
+ r.in.strings = &strings;
+ r.in.data = NULL;
+ r.in.flags = 0;
+ r.in.record_number = r.out.record_number = &record_number;
+ r.in.time_written = r.out.time_written = &time_written;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_ReportEventW_r(b, tctx, &r),
+ "ReportEventW failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ReportEventW failed");
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+static bool test_FlushEventLog(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct eventlog_FlushEventLog r;
+ struct eventlog_CloseEventLog cr;
+ struct policy_handle handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ r.in.handle = &handle;
+
+ /* Huh? Does this RPC always return access denied? */
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_FlushEventLog_r(b, tctx, &r),
+ "FlushEventLog failed");
+
+ torture_assert_ntstatus_equal(tctx,
+ r.out.result,
+ NT_STATUS_ACCESS_DENIED,
+ "FlushEventLog failed");
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+static bool test_ClearEventLog(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct eventlog_ClearEventLogW r;
+ struct eventlog_CloseEventLog cr;
+ struct policy_handle handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ r.in.handle = &handle;
+ r.in.backupfile = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_ClearEventLogW_r(b, tctx, &r),
+ "ClearEventLog failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "ClearEventLog failed");
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+static bool test_GetLogInformation(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct eventlog_GetLogInformation r;
+ struct eventlog_CloseEventLog cr;
+ struct policy_handle handle;
+ uint32_t bytes_needed = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ r.in.handle = &handle;
+ r.in.level = 1;
+ r.in.buf_size = 0;
+ r.out.buffer = NULL;
+ r.out.bytes_needed = &bytes_needed;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_GetLogInformation_r(b, tctx, &r),
+ "GetLogInformation failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_LEVEL,
+ "GetLogInformation failed");
+
+ r.in.level = 0;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_GetLogInformation_r(b, tctx, &r),
+ "GetLogInformation failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_BUFFER_TOO_SMALL,
+ "GetLogInformation failed");
+
+ r.in.buf_size = bytes_needed;
+ r.out.buffer = talloc_array(tctx, uint8_t, bytes_needed);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_GetLogInformation_r(b, tctx, &r),
+ "GetLogInformation failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetLogInformation failed");
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+
+static bool test_OpenEventLog(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct policy_handle handle;
+ struct eventlog_CloseEventLog cr;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+static bool test_BackupLog(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct policy_handle handle, backup_handle;
+ struct eventlog_BackupEventLogW r;
+ struct eventlog_OpenBackupEventLogW br;
+ struct eventlog_CloseEventLog cr;
+ const char *tmp;
+ struct lsa_String backup_filename;
+ struct eventlog_OpenUnknown0 unknown0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping BackupLog test against samba");
+ }
+
+ if (!get_policy_handle(tctx, b, &handle))
+ return false;
+
+ tmp = talloc_asprintf(tctx, "C:\\%s", TEST_BACKUP_NAME);
+ init_lsa_String(&backup_filename, tmp);
+
+ r.in.handle = &handle;
+ r.in.backup_filename = &backup_filename;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_BackupEventLogW_r(b, tctx, &r),
+ "BackupEventLogW failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result,
+ NT_STATUS_OBJECT_PATH_SYNTAX_BAD, "BackupEventLogW failed");
+
+ tmp = talloc_asprintf(tctx, "\\??\\C:\\%s", TEST_BACKUP_NAME);
+ init_lsa_String(&backup_filename, tmp);
+
+ r.in.handle = &handle;
+ r.in.backup_filename = &backup_filename;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_BackupEventLogW_r(b, tctx, &r),
+ "BackupEventLogW failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "BackupEventLogW failed");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_BackupEventLogW_r(b, tctx, &r),
+ "BackupEventLogW failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result,
+ NT_STATUS_OBJECT_NAME_COLLISION, "BackupEventLogW failed");
+
+ cr.in.handle = cr.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "BackupLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "BackupLog failed");
+
+ unknown0.unknown0 = 0x005c;
+ unknown0.unknown1 = 0x0001;
+
+ br.in.unknown0 = &unknown0;
+ br.in.backup_logname = &backup_filename;
+ br.in.major_version = 1;
+ br.in.minor_version = 1;
+ br.out.handle = &backup_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_eventlog_OpenBackupEventLogW_r(b, tctx, &br),
+ "OpenBackupEventLogW failed");
+
+ torture_assert_ntstatus_ok(tctx, br.out.result, "OpenBackupEventLogW failed");
+
+ cr.in.handle = cr.out.handle = &backup_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_eventlog_CloseEventLog_r(b, tctx, &cr),
+ "CloseEventLog failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result,
+ "CloseEventLog failed");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_eventlog(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+ struct torture_test *test;
+
+ suite = torture_suite_create(mem_ctx, "eventlog");
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "eventlog",
+ &ndr_table_eventlog);
+
+ torture_rpc_tcase_add_test(tcase, "OpenEventLog", test_OpenEventLog);
+ test = torture_rpc_tcase_add_test(tcase, "ClearEventLog",
+ test_ClearEventLog);
+ test->dangerous = true;
+ torture_rpc_tcase_add_test(tcase, "GetNumRecords", test_GetNumRecords);
+ torture_rpc_tcase_add_test(tcase, "ReadEventLog", test_ReadEventLog);
+ torture_rpc_tcase_add_test(tcase, "ReportEventLog", test_ReportEventLog);
+ torture_rpc_tcase_add_test(tcase, "FlushEventLog", test_FlushEventLog);
+ torture_rpc_tcase_add_test(tcase, "GetLogIntormation", test_GetLogInformation);
+ torture_rpc_tcase_add_test(tcase, "BackupLog", test_BackupLog);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/forest_trust.c b/source4/torture/rpc/forest_trust.c
new file mode 100644
index 0000000..e7b641e
--- /dev/null
+++ b/source4/torture/rpc/forest_trust.c
@@ -0,0 +1,914 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for forest trust
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "libcli/security/security.h"
+#include "libcli/auth/credentials.h"
+#include "libcli/auth/libcli_auth.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#undef strcasecmp
+
+#define TEST_DOM "torturedom"
+#define TEST_DOM_DNS "torturedom.samba.example.com"
+#define TEST_DOM_SID "S-1-5-21-97398-379795-10000"
+#define TEST_MACHINE_NAME "lsatestmach"
+
+
+static bool test_get_policy_handle(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ uint32_t access_mask,
+ struct policy_handle **handle )
+{
+ struct policy_handle *h;
+ struct lsa_OpenPolicy2 pr;
+ struct lsa_ObjectAttribute attr;
+ NTSTATUS status;
+
+ h = talloc(tctx, struct policy_handle);
+ torture_assert(tctx, h != NULL, "talloc(tctx, struct policy_handle)");
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = NULL;
+
+ pr.in.system_name = "\\";
+ pr.in.attr = &attr;
+ pr.in.access_mask = access_mask;
+ pr.out.handle = h;
+
+ status = dcerpc_lsa_OpenPolicy2_r(p->binding_handle, tctx, &pr);
+ torture_assert_ntstatus_ok(tctx, status, "OpenPolicy2 failed");
+ torture_assert_ntstatus_ok(tctx, pr.out.result, "OpenPolicy2 failed");
+
+ *handle = h;
+ return true;
+}
+
+static bool test_create_trust_and_set_info(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *trust_name,
+ const char *trust_name_dns,
+ struct dom_sid *domsid,
+ struct lsa_TrustDomainInfoAuthInfoInternal *authinfo)
+{
+ struct policy_handle *handle;
+ struct lsa_lsaRSetForestTrustInformation fti;
+ struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
+ struct lsa_Close cr;
+ struct policy_handle closed_handle;
+ struct lsa_CreateTrustedDomainEx2 r;
+ struct lsa_TrustDomainInfoInfoEx trustinfo;
+ struct policy_handle trustdom_handle;
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info = NULL;
+
+ if (!test_get_policy_handle(tctx, p,
+ (LSA_POLICY_VIEW_LOCAL_INFORMATION |
+ LSA_POLICY_TRUST_ADMIN |
+ LSA_POLICY_CREATE_SECRET), &handle)) {
+ return false;
+ }
+
+ torture_comment(tctx, "\nTesting CreateTrustedDomainEx2\n");
+
+ trustinfo.sid = domsid;
+ trustinfo.netbios_name.string = trust_name;
+ trustinfo.domain_name.string = trust_name_dns;
+
+ trustinfo.trust_direction = LSA_TRUST_DIRECTION_INBOUND |
+ LSA_TRUST_DIRECTION_OUTBOUND;
+
+ trustinfo.trust_type = LSA_TRUST_TYPE_UPLEVEL;
+
+ /*
+ * MS-LSAD: Section 3.1.4.7.10 makes it clear that Win2k3
+ * functional level and above return
+ * NT_STATUS_INVALID_DOMAIN_STATE if
+ * TRUST_ATTRIBUTE_FOREST_TRANSITIVE or
+ * TRUST_ATTRIBUTE_CROSS_ORGANIZATION is set here.
+ *
+ * But we really want to test forest trusts here.
+ */
+ trustinfo.trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
+
+ r.in.policy_handle = handle;
+ r.in.info = &trustinfo;
+ r.in.auth_info_internal = authinfo;
+ /* LSA_TRUSTED_QUERY_DOMAIN_NAME is needed for for following
+ * QueryTrustedDomainInfo call, although it seems that Windows does not
+ * expect this */
+ r.in.access_mask = LSA_TRUSTED_SET_POSIX | LSA_TRUSTED_SET_AUTH | LSA_TRUSTED_QUERY_DOMAIN_NAME;
+ r.out.trustdom_handle = &trustdom_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx2_r(p->binding_handle, tctx, &r),
+ "CreateTrustedDomainEx2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "CreateTrustedDomainEx2 failed");
+
+ q.in.trustdom_handle = &trustdom_handle;
+ q.in.level = LSA_TRUSTED_DOMAIN_INFO_INFO_EX;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_QueryTrustedDomainInfo_r(p->binding_handle, tctx, &q),
+ "QueryTrustedDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, q.out.result, "QueryTrustedDomainInfo level 1");
+ torture_assert(tctx, q.out.info != NULL, "QueryTrustedDomainInfo level 1 failed to return an info pointer");
+ torture_assert_str_equal(tctx, info->info_ex.netbios_name.string,
+ trustinfo.netbios_name.string,
+ "QueryTrustedDomainInfo returned inconsistent short name");
+ torture_assert_int_equal(tctx, info->info_ex.trust_type, trustinfo.trust_type,
+ "QueryTrustedDomainInfo returned incorrect trust type");
+ torture_assert_int_equal(tctx, info->info_ex.trust_attributes, trustinfo.trust_attributes,
+ "QueryTrustedDomainInfo of returned incorrect trust attributes");
+ torture_assert_int_equal(tctx, info->info_ex.trust_direction, trustinfo.trust_direction,
+ "QueryTrustedDomainInfo of returned incorrect trust direction");
+
+ fti.in.handle = handle;
+ fti.in.trusted_domain_name = talloc_zero(tctx, struct lsa_StringLarge);
+ fti.in.trusted_domain_name->string = trust_name_dns;
+ fti.in.highest_record_type = 2;
+ fti.in.forest_trust_info = talloc_zero(tctx, struct lsa_ForestTrustInformation);
+ fti.in.forest_trust_info->count = 2;
+ fti.in.forest_trust_info->entries = talloc_array(tctx, struct lsa_ForestTrustRecord *, 2);
+ fti.in.forest_trust_info->entries[0] = talloc_zero(tctx, struct lsa_ForestTrustRecord);
+ fti.in.forest_trust_info->entries[0]->flags = 0;
+ fti.in.forest_trust_info->entries[0]->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME;
+ fti.in.forest_trust_info->entries[0]->time = 0;
+ fti.in.forest_trust_info->entries[0]->forest_trust_data.top_level_name.string = trust_name_dns;
+ fti.in.forest_trust_info->entries[1] = talloc_zero(tctx, struct lsa_ForestTrustRecord);
+ fti.in.forest_trust_info->entries[1]->flags = 0;
+ fti.in.forest_trust_info->entries[1]->type = LSA_FOREST_TRUST_DOMAIN_INFO;
+ fti.in.forest_trust_info->entries[1]->time = 0;
+ fti.in.forest_trust_info->entries[1]->forest_trust_data.domain_info.domain_sid = domsid;
+ fti.in.forest_trust_info->entries[1]->forest_trust_data.domain_info.dns_domain_name.string = trust_name_dns;
+ fti.in.forest_trust_info->entries[1]->forest_trust_data.domain_info.netbios_domain_name.string = trust_name;
+ fti.in.check_only = 0;
+ fti.out.collision_info = &collision_info;
+
+ torture_comment(tctx, "\nTesting SetForestTrustInformation\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_lsaRSetForestTrustInformation_r(p->binding_handle, tctx, &fti),
+ "lsaRSetForestTrustInformation failed");
+ torture_assert_ntstatus_ok(tctx, fti.out.result, "lsaRSetForestTrustInformation failed");
+
+ cr.in.handle = handle;
+ cr.out.handle = &closed_handle;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_Close_r(p->binding_handle, tctx, &cr),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result, "Close failed");
+
+ return true;
+}
+
+struct get_set_info {
+ enum lsa_TrustDomInfoEnum info_level;
+ NTSTATUS get_result;
+ NTSTATUS set_result;
+};
+
+static bool get_and_set_info(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *name)
+{
+ struct policy_handle *handle;
+ NTSTATUS status;
+ struct lsa_QueryTrustedDomainInfoByName qr;
+ struct lsa_SetTrustedDomainInfoByName sr;
+ union lsa_TrustedDomainInfo *info;
+ struct lsa_Close cr;
+ struct policy_handle closed_handle;
+ size_t c;
+
+ struct get_set_info il[] = {
+ {LSA_TRUSTED_DOMAIN_INFO_NAME, NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER},
+ /* {LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ {LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET, NT_STATUS_OK, NT_STATUS_OK},
+ /* {LSA_TRUSTED_DOMAIN_INFO_PASSWORD, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ /* {LSA_TRUSTED_DOMAIN_INFO_BASIC, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ {LSA_TRUSTED_DOMAIN_INFO_INFO_EX, NT_STATUS_OK, NT_STATUS_OK},
+ /* {LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ {LSA_TRUSTED_DOMAIN_INFO_FULL_INFO, NT_STATUS_OK, NT_STATUS_OK},
+ /* {LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO_INTERNAL, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ /* {LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ /* {LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL, NT_STATUS_INVALID_PARAMETER, NT_STATUS_INVALID_INFO_CLASS}, */
+ {LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL, NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER},
+ {LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES, NT_STATUS_OK, NT_STATUS_OK},
+ { .info_level = -1, },
+ };
+
+ torture_comment(tctx, "\nGetting/Setting dom info\n");
+
+ if(!test_get_policy_handle(tctx, p, LSA_POLICY_VIEW_LOCAL_INFORMATION,
+ &handle)) {
+ return false;
+ }
+
+ qr.in.handle = handle;
+ qr.in.trusted_domain = talloc_zero(tctx, struct lsa_String);
+ qr.in.trusted_domain->string = name;
+ qr.out.info = &info;
+
+ sr.in.handle = handle;
+ sr.in.trusted_domain = talloc_zero(tctx, struct lsa_String);
+ sr.in.trusted_domain->string = name;
+ sr.in.info = info;
+
+ for (c = 0; il[c].info_level != -1; c++) {
+ torture_comment(tctx, "\nGetting/Setting dom info [%d]\n",il[c].info_level);
+
+ qr.in.level = il[c].info_level;
+ status = dcerpc_lsa_QueryTrustedDomainInfoByName_r(p->binding_handle,
+ tctx, &qr);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+ "QueryTrustedDomainInfoByName failed");
+ if (!NT_STATUS_EQUAL(qr.out.result, il[c].get_result)) {
+ torture_comment(tctx, "QueryTrustedDomainInfoByName did not return "
+ "%s but %s\n",
+ nt_errstr(il[c].get_result),
+ nt_errstr(qr.out.result));
+
+ /* We may be testing a server without support for this level */
+ if (qr.in.level == LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES && NT_STATUS_EQUAL(qr.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ return true;
+ }
+ return false;
+ }
+
+ sr.in.level = il[c].info_level;
+ sr.in.info = info;
+ status = dcerpc_lsa_SetTrustedDomainInfoByName_r(p->binding_handle,
+ tctx, &sr);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+ "SetTrustedDomainInfoByName failed");
+ if (!NT_STATUS_EQUAL(sr.out.result, il[c].set_result)) {
+ torture_comment(tctx, "SetTrustedDomainInfoByName did not return "
+ "%s but %s\n",
+ nt_errstr(il[c].set_result),
+ nt_errstr(sr.out.result));
+ return false;
+ }
+ }
+
+ cr.in.handle = handle;
+ cr.out.handle = &closed_handle;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_Close_r(p->binding_handle, tctx, &cr),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result, "Close failed");
+
+ return true;
+}
+
+static bool check_name(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *name)
+{
+ struct policy_handle *handle;
+ NTSTATUS status;
+ struct lsa_QueryTrustedDomainInfoByName qr;
+ union lsa_TrustedDomainInfo *info;
+ struct lsa_Close cr;
+ struct policy_handle closed_handle;
+
+ torture_comment(tctx, "\nGetting LSA_TRUSTED_DOMAIN_INFO_FULL_INFO\n");
+
+ if(!test_get_policy_handle(tctx, p, LSA_POLICY_VIEW_LOCAL_INFORMATION,
+ &handle)) {
+ return false;
+ }
+
+ qr.in.handle = handle;
+ qr.in.trusted_domain = talloc_zero(tctx, struct lsa_String);
+ qr.in.trusted_domain->string = name;
+ qr.in.level = LSA_TRUSTED_DOMAIN_INFO_FULL_INFO;
+ qr.out.info = &info;
+ status = dcerpc_lsa_QueryTrustedDomainInfoByName_r(p->binding_handle,
+ tctx, &qr);
+ torture_assert_ntstatus_ok(tctx, status,
+ "QueryInfoPolicy2 failed");
+ torture_assert_ntstatus_equal(tctx, qr.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "QueryInfoPolicy2 did not return "
+ "NT_STATUS_OBJECT_NAME_NOT_FOUND");
+
+ cr.in.handle = handle;
+ cr.out.handle = &closed_handle;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_Close_r(p->binding_handle, tctx, &cr),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result, "Close failed");
+
+ return true;
+}
+
+static bool get_lsa_policy_info_dns(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ union lsa_PolicyInformation **info)
+{
+ struct policy_handle *handle;
+ NTSTATUS status;
+ struct lsa_QueryInfoPolicy2 qr;
+ struct lsa_Close cr;
+ struct policy_handle closed_handle;
+
+ torture_comment(tctx, "\nGetting LSA_POLICY_INFO_DNS\n");
+
+ if (!test_get_policy_handle(tctx, p, LSA_POLICY_VIEW_LOCAL_INFORMATION,
+ &handle)) {
+ return false;
+ }
+
+ qr.in.handle = handle;
+ qr.in.level = LSA_POLICY_INFO_DNS;
+ qr.out.info = info;
+ status = dcerpc_lsa_QueryInfoPolicy2_r(p->binding_handle, tctx, &qr);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+ "QueryInfoPolicy2 failed");
+ if (!NT_STATUS_IS_OK(qr.out.result)) {
+ torture_comment(tctx, "QueryInfoPolicy2 failed - %s\n",
+ nt_errstr(qr.out.result));
+ return false;
+ }
+
+ cr.in.handle = handle;
+ cr.out.handle = &closed_handle;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_Close_r(p->binding_handle, tctx, &cr),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result, "Close failed");
+
+ return true;
+}
+
+static bool delete_trusted_domain_by_sid(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct dom_sid *domsid)
+{
+ struct policy_handle *handle;
+ struct lsa_Close cr;
+ struct policy_handle closed_handle;
+ struct lsa_DeleteTrustedDomain dr;
+
+ torture_comment(tctx, "\nDeleting trusted domain.\n");
+
+ /* Against a windows server it was sufficient to have
+ * LSA_POLICY_VIEW_LOCAL_INFORMATION although the documentations says
+ * otherwise. */
+ if (!test_get_policy_handle(tctx, p, LSA_POLICY_TRUST_ADMIN,
+ &handle)) {
+ return false;
+ }
+
+ dr.in.handle = handle;
+ dr.in.dom_sid = domsid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_DeleteTrustedDomain_r(p->binding_handle, tctx, &dr),
+ "DeleteTrustedDomain failed");
+ torture_assert_ntstatus_ok(tctx, dr.out.result, "DeleteTrustedDomain failed");
+
+ cr.in.handle = handle;
+ cr.out.handle = &closed_handle;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_Close_r(p->binding_handle, tctx, &cr),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, cr.out.result, "Close failed");
+
+ return true;
+}
+
+/*
+static const uint8_t my_blob[] = {
+0xa3,0x0b,0x32,0x45,0x8b,0x84,0x3b,0x01,0x68,0xe8,0x2b,0xbb,0x00,0x13,0x69,0x1f,
+0x10,0x35,0x72,0xa9,0x4f,0x77,0xb7,0xeb,0x59,0x08,0x07,0xc3,0xe8,0x17,0x00,0xc5,
+0xf2,0xa9,0x6d,0xb7,0x69,0x45,0x63,0x20,0xcb,0x44,0x44,0x22,0x02,0xe3,0x28,0x84,
+0x9b,0xd5,0x43,0x6f,0x8d,0x36,0x9b,0x9b,0x3b,0x31,0x86,0x84,0x8b,0xf2,0x36,0xd4,
+0xe8,0xc4,0xee,0x90,0x0c,0xcb,0x3e,0x11,0x2f,0x86,0xfe,0x87,0x6d,0xce,0xae,0x0c,
+0x83,0xfb,0x21,0x22,0x6d,0x7f,0x5e,0x08,0x71,0x1a,0x35,0xf4,0x5a,0x76,0x9b,0xf7,
+0x54,0x62,0xa5,0x4c,0xcd,0xf6,0xa5,0xb0,0x0b,0xc7,0x79,0xe1,0x6f,0x85,0x16,0x6f,
+0x82,0xdd,0x15,0x11,0x4c,0x9d,0x26,0x01,0x74,0x7e,0xbb,0xec,0x88,0x1d,0x71,0x9e,
+0x5f,0xb2,0x9c,0xab,0x66,0x20,0x08,0x3d,0xae,0x07,0x2d,0xbb,0xa6,0xfb,0xec,0xcc,
+0x51,0x58,0x48,0x47,0x38,0x3b,0x47,0x66,0xe8,0x17,0xfa,0x54,0x5c,0x95,0x73,0x29,
+0xdf,0x7e,0x4a,0xb4,0x45,0x30,0xf7,0xbf,0xc0,0x56,0x6d,0x80,0xf6,0x11,0x56,0x93,
+0xeb,0x97,0xd5,0x10,0xd6,0xd6,0xf7,0x23,0xc3,0xc0,0x93,0xa7,0x5c,0xa9,0xc0,0x81,
+0x55,0x3d,0xec,0x03,0x31,0x7e,0x9d,0xf9,0xd0,0x9e,0xb5,0xc7,0xef,0xa8,0x54,0xf6,
+0x9c,0xdc,0x0d,0xd4,0xd7,0xee,0x8d,0x5f,0xbd,0x89,0x48,0x3b,0x63,0xff,0xe8,0xca,
+0x10,0x64,0x61,0xdf,0xfd,0x50,0xff,0x51,0xa0,0x2c,0xd7,0x8a,0xf1,0x13,0x02,0x02,
+0x71,0xe9,0xff,0x0d,0x03,0x48,0xf8,0x08,0x8d,0xd5,0xe6,0x31,0x9f,0xf0,0x26,0x07,
+0x91,0x6d,0xd3,0x01,0x91,0x92,0xc7,0x28,0x18,0x58,0xd8,0xf6,0x1b,0x97,0x8d,0xd0,
+0xd2,0xa1,0x7c,0xae,0xc1,0xca,0xfe,0x20,0x91,0x1c,0x4d,0x15,0x89,0x29,0x37,0xd5,
+0xf5,0xca,0x40,0x2b,0x03,0x8f,0x7b,0xc2,0x10,0xb4,0xd3,0xe8,0x14,0xb0,0x9b,0x5d,
+0x85,0x30,0xe5,0x13,0x24,0xf7,0x78,0xec,0xbe,0x0b,0x9a,0x3f,0xb5,0x76,0xd9,0x0d,
+0x49,0x64,0xa4,0xa7,0x33,0x88,0xdd,0xe9,0xe2,0x5f,0x04,0x51,0xdd,0x89,0xe2,0x68,
+0x5b,0x5f,0x64,0x35,0xe3,0x23,0x4a,0x0e,0x09,0x15,0xcc,0x97,0x47,0xf4,0xc2,0x4f,
+0x06,0xc3,0x96,0xa9,0x2f,0xb3,0xde,0x29,0x10,0xc7,0xf5,0x16,0xc5,0x3c,0x84,0xd2,
+0x9b,0x6b,0xaa,0x54,0x59,0x8d,0x94,0xde,0xd1,0x75,0xb6,0x08,0x0d,0x7d,0xf1,0x18,
+0xc8,0xf5,0xdf,0xaa,0xcd,0xec,0xab,0xb6,0xd1,0xcb,0xdb,0xe7,0x75,0x5d,0xbe,0x76,
+0xea,0x1d,0x01,0xc8,0x0b,0x2d,0x32,0xe9,0xa8,0x65,0xbb,0x4a,0xcb,0x72,0xbc,0xda,
+0x04,0x7f,0x82,0xfb,0x04,0xeb,0xd8,0xe1,0xb9,0xb1,0x1e,0xdc,0xb3,0x60,0xf3,0x55,
+0x1e,0xcf,0x90,0x6a,0x15,0x74,0x4d,0xff,0xb4,0xc7,0xc9,0xc2,0x4f,0x67,0x9e,0xeb,
+0x00,0x61,0x02,0xe3,0x9e,0x59,0x88,0x20,0xf1,0x0c,0xbe,0xe0,0x26,0x69,0x63,0x67,
+0x72,0x3c,0x06,0x00,0x9e,0x4f,0xc7,0xa6,0x4d,0x6c,0xbe,0x68,0x8e,0xf4,0x32,0x36,
+0x2e,0x5f,0xa6,0xcf,0xa7,0x19,0x40,0x2b,0xbd,0xa2,0x22,0x73,0xc4,0xb6,0xe3,0x86,
+0x64,0xeb,0xb1,0xc7,0x45,0x7d,0xd6,0xd9,0x36,0xf1,0x04,0xd4,0x61,0xdc,0x41,0xb7,
+0x01,0x00,0x00,0x00,0x0c,0x00,0x00,0x00, 0x30,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,
+0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x30,0x00,0x01,0x00,0x00,0x00,
+0x0c,0x00,0x00,0x00, 0x30,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
+0x14,0x00,0x00,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,
+0x37,0x00,0x38,0x00,0x39,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00
+};
+*/
+static bool get_trust_domain_passwords_auth_blob(TALLOC_CTX *mem_ctx,
+ const char *password,
+ DATA_BLOB *auth_blob)
+{
+ struct trustDomainPasswords auth_struct;
+ struct AuthenticationInformation *auth_info_array;
+ enum ndr_err_code ndr_err;
+ size_t converted_size;
+
+ generate_random_buffer(auth_struct.confounder,
+ sizeof(auth_struct.confounder));
+
+ auth_info_array = talloc_array(mem_ctx,
+ struct AuthenticationInformation, 1);
+ if (auth_info_array == NULL) {
+ return false;
+ }
+
+ auth_info_array[0].AuthType = TRUST_AUTH_TYPE_CLEAR;
+ if (!convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, password,
+ strlen(password),
+ &auth_info_array[0].AuthInfo.clear.password,
+ &converted_size)) {
+ return false;
+ }
+
+ auth_info_array[0].AuthInfo.clear.size = converted_size;
+
+ auth_struct.outgoing.count = 1;
+ auth_struct.outgoing.current.count = 1;
+ auth_struct.outgoing.current.array = auth_info_array;
+ auth_struct.outgoing.previous.count = 0;
+ auth_struct.outgoing.previous.array = NULL;
+
+ auth_struct.incoming.count = 1;
+ auth_struct.incoming.current.count = 1;
+ auth_struct.incoming.current.array = auth_info_array;
+ auth_struct.incoming.previous.count = 0;
+ auth_struct.incoming.previous.array = NULL;
+
+ ndr_err = ndr_push_struct_blob(auth_blob, mem_ctx, &auth_struct,
+ (ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_validate_trust(struct torture_context *tctx,
+ const char *binding,
+ const char *trusting_dom_name,
+ const char *trusting_dom_dns_name,
+ const char *trusted_dom_name,
+ const char *trusted_dom_dns_name,
+ const char *trust_password)
+{
+ struct netr_ServerGetTrustInfo r;
+
+ struct netr_Authenticator a;
+ struct netr_Authenticator return_authenticator;
+ struct samr_Password new_owf_password;
+ struct samr_Password old_owf_password;
+ struct netr_TrustInfo *trust_info;
+
+ struct netlogon_creds_CredentialState *creds;
+
+ NTSTATUS status;
+ struct cli_credentials *credentials;
+ struct dcerpc_binding *b;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p = NULL;
+
+ struct netr_GetForestTrustInformation fr;
+ struct lsa_ForestTrustInformation *forest_trust_info;
+ struct lsa_ForestTrustRecord *tln = NULL;
+ struct lsa_ForestTrustRecord *di = NULL;
+ int i;
+ struct samr_Password *new_nt_hash;
+ struct samr_Password *old_nt_hash;
+ char *dummy;
+ uint32_t trust_attributes = LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE;
+
+ status = dcerpc_parse_binding(tctx, binding, &b);
+ torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
+
+ credentials = cli_credentials_init(tctx);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_init()");
+
+ dummy = talloc_asprintf(tctx, "%s$", trusted_dom_name);
+ cli_credentials_set_username(credentials, dummy,
+ CRED_SPECIFIED);
+ cli_credentials_set_domain(credentials, trusting_dom_name,
+ CRED_SPECIFIED);
+ cli_credentials_set_realm(credentials, trusting_dom_dns_name,
+ CRED_SPECIFIED);
+ cli_credentials_set_password(credentials, trust_password, CRED_SPECIFIED);
+ cli_credentials_set_old_password(credentials, trust_password, CRED_SPECIFIED);
+ cli_credentials_set_workstation(credentials,
+ trusted_dom_name, CRED_SPECIFIED);
+ cli_credentials_set_secure_channel_type(credentials, SEC_CHAN_DOMAIN);
+
+ status = dcerpc_pipe_connect_b(tctx, &p1, b,
+ &ndr_table_netlogon, credentials,
+ tctx->ev, tctx->lp_ctx);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx, "Failed to connect to remote server: %s with %s - %s\n",
+ binding,
+ cli_credentials_get_unparsed_name(credentials, tctx),
+ nt_errstr(status));
+ return false;
+ }
+
+ if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ credentials, &creds)) {
+ torture_comment(tctx, "test_SetupCredentials3 failed.\n");
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ torture_comment(tctx, "test_SetupCredentialsPipe failed.\n");
+ return false;
+ }
+
+ netlogon_creds_client_authenticator(creds, &a);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", trusted_dom_name);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(credentials);
+ r.in.computer_name = trusted_dom_name;
+ r.in.credential = &a;
+
+ r.out.return_authenticator = &return_authenticator;
+ r.out.new_owf_password = &new_owf_password;
+ r.out.old_owf_password = &old_owf_password;
+ r.out.trust_info = &trust_info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_ServerGetTrustInfo_r(p->binding_handle, tctx, &r),
+ "ServerGetTrustInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "ServerGetTrustInfo failed");
+
+ torture_assert(tctx, trust_info != NULL, "ServerGetTrustInfo got no trust_info");
+ torture_assert_int_equal(tctx, trust_info->count, 1,
+ "Unexpected number of results");
+ torture_assert_int_equal(tctx, trust_info->data[0], trust_attributes,
+ "Unexpected trust_attributes");
+
+ new_nt_hash = cli_credentials_get_nt_hash(credentials, tctx);
+ torture_assert(tctx, new_nt_hash != NULL, "cli_credentials_get_nt_hash()");
+
+ old_nt_hash = cli_credentials_get_old_nt_hash(credentials, tctx);
+ torture_assert(tctx, old_nt_hash != NULL, "cli_credentials_get_old_nt_hash()");
+
+ netlogon_creds_des_decrypt(creds, &new_owf_password);
+ netlogon_creds_des_decrypt(creds, &old_owf_password);
+
+ dump_data(1, new_owf_password.hash, 16);
+ dump_data(1, new_nt_hash->hash, 16);
+ dump_data(1, old_owf_password.hash, 16);
+ dump_data(1, old_nt_hash->hash, 16);
+
+ torture_assert_mem_equal(tctx, new_owf_password.hash, new_nt_hash->hash, 16,
+ "received unexpected new owf password\n");
+
+ torture_assert_mem_equal(tctx, old_owf_password.hash, old_nt_hash->hash, 16,
+ "received unexpected old owf password\n");
+
+ netlogon_creds_client_authenticator(creds, &a);
+
+ fr.in.server_name = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ fr.in.computer_name = trusted_dom_name;
+ fr.in.credential = &a;
+ fr.in.flags = 0;
+ fr.out.return_authenticator = &return_authenticator;
+ fr.out.forest_trust_info = &forest_trust_info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_GetForestTrustInformation_r(p->binding_handle, tctx, &fr),
+ "netr_GetForestTrustInformation failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "netr_GetForestTrustInformation failed");
+
+ for(i = 0; i < forest_trust_info->count; i++) {
+ struct lsa_ForestTrustRecord *e = forest_trust_info->entries[i];
+
+ switch (e->type) {
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME:
+ if (strcmp(e->forest_trust_data.top_level_name.string, trusting_dom_dns_name) != 0) {
+ break;
+ }
+
+ torture_assert(tctx, tln == NULL, "TOP_LEVEL_NAME found twice");
+
+ tln = e;
+ break;
+
+ case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
+ break;
+
+ case LSA_FOREST_TRUST_DOMAIN_INFO:
+ if (strcmp(e->forest_trust_data.domain_info.dns_domain_name.string, trusting_dom_dns_name) != 0) {
+ break;
+ }
+
+ torture_assert(tctx, di == NULL, "DOMAIN_INFO found twice");
+
+ di = e;
+ break;
+ default:
+ torture_assert_int_equal(tctx, e->type, LSA_FOREST_TRUST_TOP_LEVEL_NAME,
+ "Unexpected LSA_FOREST_TRUST_* type");
+ }
+ }
+
+ torture_assert(tctx, tln != NULL, "TOP_LEVEL_NAME entry missing");
+ torture_assert(tctx, di != NULL, "DOMAIN_INFO entry missing");
+
+ torture_assert_str_equal(tctx, di->forest_trust_data.domain_info.netbios_domain_name.string,
+ trusting_dom_name,
+ "netbios_domain_name mismatch");
+
+ return true;
+}
+
+static bool test_setup_trust(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *netbios_name,
+ const char *dns_name,
+ struct dom_sid *sid,
+ DATA_BLOB *auth_blob)
+
+{
+ DATA_BLOB session_key;
+ struct lsa_TrustDomainInfoAuthInfoInternal authinfo;
+ NTSTATUS status;
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t _session_key;
+
+ if (!check_name(p, tctx, netbios_name)) {
+ return false;
+ }
+ if (!check_name(p, tctx, dns_name)) {
+ return false;
+ }
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed - %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ authinfo.auth_blob.data = talloc_memdup(tctx, auth_blob->data,
+ auth_blob->length);
+ if (authinfo.auth_blob.data == NULL) {
+ return false;
+ }
+ authinfo.auth_blob.size = auth_blob->length;
+
+ _session_key = (gnutls_datum_t) {
+ .data = session_key.data,
+ .size = session_key.length,
+ };
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &_session_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd,
+ authinfo.auth_blob.data,
+ authinfo.auth_blob.size);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ if (!test_create_trust_and_set_info(p, tctx, netbios_name,
+ dns_name, sid, &authinfo)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool testcase_ForestTrusts(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ const char *dom2_binding_string;
+ const char * dom2_cred_string;
+ NTSTATUS status;
+ struct dom_sid *domsid;
+ DATA_BLOB auth_blob;
+ struct dcerpc_binding *dom2_binding;
+ struct dcerpc_pipe *dom2_p;
+ struct cli_credentials *dom2_credentials;
+ union lsa_PolicyInformation *dom1_info_dns = NULL;
+ union lsa_PolicyInformation *dom2_info_dns = NULL;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ char *test_password;
+
+ torture_comment(tctx, "Testing Forest Trusts\n");
+
+ test_password = generate_random_password(tctx, 32, 64);
+ torture_assert(tctx, test_password != NULL, "test password must be generated");
+
+ if (!get_trust_domain_passwords_auth_blob(tctx, test_password, &auth_blob)) {
+ torture_comment(tctx,
+ "get_trust_domain_passwords_auth_blob failed\n");
+ return false;
+ }
+
+#if 0
+ /* Use the following if get_trust_domain_passwords_auth_blob() cannot
+ * generate a usable blob due to errors in the IDL */
+ auth_blob.data = talloc_memdup(tctx, my_blob, sizeof(my_blob));
+ auth_blob.length = sizeof(my_blob);
+
+ test_password = "1234567890"
+#endif
+
+ domsid = dom_sid_parse_talloc(tctx, TEST_DOM_SID);
+ if (domsid == NULL) {
+ return false;
+ }
+
+ if (!test_setup_trust(tctx, p, TEST_DOM, TEST_DOM_DNS, domsid,
+ &auth_blob)) {
+ return false;
+ }
+
+ if (!get_lsa_policy_info_dns(p, tctx, &dom1_info_dns)) {
+ return false;
+ }
+
+ if (!get_and_set_info(p, tctx, TEST_DOM)) {
+ return false;
+ }
+
+ if (!test_validate_trust(tctx, binding,
+ dom1_info_dns->dns.name.string,
+ dom1_info_dns->dns.dns_domain.string,
+ TEST_DOM, TEST_DOM_DNS, test_password)) {
+ return false;
+ }
+
+ if (!delete_trusted_domain_by_sid(p, tctx, domsid)) {
+ return false;
+ }
+
+ dom2_binding_string = torture_setting_string(tctx,
+ "Forest_Trust_Dom2_Binding",
+ NULL);
+ if (dom2_binding_string == NULL) {
+ torture_skip(tctx, "torture:Forest_Trust_Dom2_Binding not specified\n");
+ }
+
+ status = dcerpc_parse_binding(tctx, dom2_binding_string, &dom2_binding);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_parse_binding()");
+
+ dom2_cred_string = torture_setting_string(tctx,
+ "Forest_Trust_Dom2_Creds",
+ NULL);
+ torture_assert(tctx, dom2_cred_string != NULL, "torture:Forest_Trust_Dom2_Creds missing");
+
+ dom2_credentials = cli_credentials_init(tctx);
+ torture_assert(tctx, dom2_credentials != NULL, "cli_credentials_init()");
+
+ cli_credentials_parse_string(dom2_credentials, dom2_cred_string,
+ CRED_SPECIFIED);
+ cli_credentials_set_workstation(dom2_credentials,
+ TEST_MACHINE_NAME, CRED_SPECIFIED);
+
+ status = dcerpc_pipe_connect_b(tctx, &dom2_p, dom2_binding,
+ &ndr_table_lsarpc, dom2_credentials,
+ tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx,
+ "Failed to connect to remote server: %s\n",
+ dcerpc_binding_string(tctx, dom2_binding)));
+
+ if (!get_lsa_policy_info_dns(dom2_p, tctx, &dom2_info_dns)) {
+ return false;
+ }
+
+ if (strcasecmp(dom1_info_dns->dns.name.string,
+ dom2_info_dns->dns.name.string) == 0 ||
+ strcasecmp(dom1_info_dns->dns.dns_domain.string,
+ dom2_info_dns->dns.dns_domain.string) == 0)
+ {
+ torture_assert(tctx, false, talloc_asprintf(tctx,
+ "Trusting (%s;%s) and trusted domain (%s;%s) have the "
+ "same name",
+ dom1_info_dns->dns.name.string,
+ dom1_info_dns->dns.dns_domain.string,
+ dom2_info_dns->dns.name.string,
+ dom2_info_dns->dns.dns_domain.string));
+ }
+
+ if (!test_setup_trust(tctx, p, dom2_info_dns->dns.name.string,
+ dom2_info_dns->dns.dns_domain.string,
+ dom2_info_dns->dns.sid, &auth_blob)) {
+ return false;
+ }
+ if (!test_setup_trust(tctx, dom2_p, dom1_info_dns->dns.name.string,
+ dom1_info_dns->dns.dns_domain.string,
+ dom1_info_dns->dns.sid, &auth_blob)) {
+ return false;
+ }
+
+ if (!test_validate_trust(tctx, binding,
+ dom1_info_dns->dns.name.string,
+ dom1_info_dns->dns.dns_domain.string,
+ dom2_info_dns->dns.name.string,
+ dom2_info_dns->dns.dns_domain.string, test_password)) {
+ return false;
+ }
+
+ if (!test_validate_trust(tctx, dom2_binding_string,
+ dom2_info_dns->dns.name.string,
+ dom2_info_dns->dns.dns_domain.string,
+ dom1_info_dns->dns.name.string,
+ dom1_info_dns->dns.dns_domain.string, test_password)) {
+ return false;
+ }
+
+ if (!delete_trusted_domain_by_sid(p, tctx, dom2_info_dns->dns.sid)) {
+ return false;
+ }
+
+ if (!delete_trusted_domain_by_sid(dom2_p, tctx, dom1_info_dns->dns.sid)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* By default this test creates a trust object in the destination server to a
+ * dummy domain. If a second server from a different domain is specified on the
+ * command line a trust is created between those two domains.
+ *
+ * Example:
+ * smbtorture ncacn_np:srv1.dom1.test[print] RPC-LSA-FOREST-TRUST \
+ * -U 'dom1\testadm1%12345678' \
+ * --option=torture:Forest_Trust_Dom2_Binding=ncacn_np:srv2.dom2.test[print] \
+ * --option=torture:Forest_Trust_Dom2_Creds='dom2\testadm2%12345678'
+ */
+
+struct torture_suite *torture_rpc_lsa_forest_trust(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+
+ suite = torture_suite_create(mem_ctx, "lsa.forest.trust");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "lsa-forest-trust",
+ &ndr_table_lsarpc);
+ torture_rpc_tcase_add_test(tcase, "ForestTrust", testcase_ForestTrusts);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/frsapi.c b/source4/torture/rpc/frsapi.c
new file mode 100644
index 0000000..710826a
--- /dev/null
+++ b/source4/torture/rpc/frsapi.c
@@ -0,0 +1,276 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for rpc frsapi operations
+
+ Copyright (C) Guenther Deschner 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_frsapi_c.h"
+#include "param/param.h"
+
+static bool test_GetDsPollingIntervalW(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t *CurrentInterval,
+ uint32_t *DsPollingLongInterval,
+ uint32_t *DsPollingShortInterval)
+{
+ struct frsapi_GetDsPollingIntervalW r;
+
+ ZERO_STRUCT(r);
+
+ r.out.CurrentInterval = CurrentInterval;
+ r.out.DsPollingLongInterval = DsPollingLongInterval;
+ r.out.DsPollingShortInterval = DsPollingShortInterval;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_frsapi_GetDsPollingIntervalW_r(b, tctx, &r),
+ "GetDsPollingIntervalW failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "GetDsPollingIntervalW failed");
+
+ return true;
+}
+
+static bool test_SetDsPollingIntervalW(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t CurrentInterval,
+ uint32_t DsPollingLongInterval,
+ uint32_t DsPollingShortInterval)
+{
+ struct frsapi_SetDsPollingIntervalW r;
+
+ ZERO_STRUCT(r);
+
+ r.in.CurrentInterval = CurrentInterval;
+ r.in.DsPollingLongInterval = DsPollingLongInterval;
+ r.in.DsPollingShortInterval = DsPollingShortInterval;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_frsapi_SetDsPollingIntervalW_r(b, tctx, &r),
+ "SetDsPollingIntervalW failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SetDsPollingIntervalW failed");
+
+ return true;
+}
+
+static bool test_DsPollingIntervalW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t i1, i2, i3;
+ uint32_t k1, k2, k3;
+
+ if (!test_GetDsPollingIntervalW(tctx, b, &i1, &i2, &i3)) {
+ return false;
+ }
+
+ if (!test_SetDsPollingIntervalW(tctx, b, i1, i2, i3)) {
+ return false;
+ }
+
+ k1 = i1;
+ k2 = k3 = 0;
+
+ if (!test_SetDsPollingIntervalW(tctx, b, k1, k2, k3)) {
+ return false;
+ }
+
+ if (!test_GetDsPollingIntervalW(tctx, b, &k1, &k2, &k3)) {
+ return false;
+ }
+
+ if ((i1 != k1) || (i2 != k2) || (i3 != k3)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_IsPathReplicated_err(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *path,
+ uint32_t type,
+ WERROR werr)
+{
+ struct frsapi_IsPathReplicated r;
+ struct GUID guid;
+ uint32_t replicated, primary, root;
+
+ ZERO_STRUCT(r);
+
+ r.in.path = path;
+ r.in.replica_set_type = type;
+ r.out.replicated = &replicated;
+ r.out.primary = &primary;
+ r.out.root = &root;
+ r.out.replica_set_guid = &guid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_frsapi_IsPathReplicated_r(b, tctx, &r),
+ "IsPathReplicated failed");
+
+ torture_assert_werr_equal(tctx, r.out.result, werr,
+ "GetDsPollingIntervalW failed");
+
+ return true;
+}
+
+static bool _test_IsPathReplicated(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *path,
+ uint32_t type)
+{
+ return test_IsPathReplicated_err(tctx, b, path, type, WERR_OK);
+}
+
+static bool test_IsPathReplicated(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const uint32_t lvls[] = {
+ FRSAPI_REPLICA_SET_TYPE_0,
+ FRSAPI_REPLICA_SET_TYPE_DOMAIN,
+ FRSAPI_REPLICA_SET_TYPE_DFS };
+ int i;
+ bool ret = true;
+
+ if (!test_IsPathReplicated_err(tctx, b, NULL, 0,
+ WERR_FRS_ERR_INVALID_SERVICE_PARAMETER)) {
+ ret = false;
+ }
+
+ for (i=0; i<ARRAY_SIZE(lvls); i++) {
+ if (!_test_IsPathReplicated(tctx, b, dcerpc_server_name(p),
+ lvls[i])) {
+ ret = false;
+ }
+ }
+
+ for (i=0; i<ARRAY_SIZE(lvls); i++) {
+ const char *path = talloc_asprintf(tctx, "\\\\%s\\SYSVOL",
+ dcerpc_server_name(p));
+ if (!_test_IsPathReplicated(tctx, b, path, lvls[i])) {
+ ret = false;
+ }
+ }
+
+ for (i=0; i<ARRAY_SIZE(lvls); i++) {
+ if (!_test_IsPathReplicated(tctx, b,
+ "C:\\windows\\sysvol\\domain",
+ lvls[i])) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_ForceReplication(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct frsapi_ForceReplication r;
+
+ ZERO_STRUCT(r);
+
+ r.in.replica_set_guid = NULL;
+ r.in.connection_guid = NULL;
+ r.in.replica_set_name = lpcfg_dnsdomain(tctx->lp_ctx);
+ r.in.partner_dns_name = dcerpc_server_name(p);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_frsapi_ForceReplication_r(b, tctx, &r),
+ "ForceReplication failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "ForceReplication failed");
+
+ return true;
+}
+
+static bool test_InfoW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ int i;
+
+ for (i=0; i<10; i++) {
+
+ struct frsapi_InfoW r;
+ struct frsapi_Info *info;
+ int d;
+ DATA_BLOB blob;
+
+ ZERO_STRUCT(r);
+
+ info = talloc_zero(tctx, struct frsapi_Info);
+
+ r.in.length = 0x1000;
+ r.in.info = r.out.info = info;
+
+ info->length = r.in.length;
+ info->length2 = r.in.length;
+ info->level = i;
+ info->offset = 0x2c;
+ info->blob_len = 0x2c;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_frsapi_InfoW_r(b, tctx, &r),
+ "InfoW failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "InfoW failed");
+
+ /* display the formatted blob text */
+ blob = r.out.info->blob;
+ for (d = 0; d < blob.length; d++) {
+ if (blob.data[d]) {
+ printf("%c", blob.data[d]);
+ }
+ }
+ printf("\n");
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_frsapi(TALLOC_CTX *mem_ctx)
+{
+ struct torture_rpc_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "frsapi");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "frsapi",
+ &ndr_table_frsapi);
+
+ torture_rpc_tcase_add_test(tcase, "DsPollingIntervalW",
+ test_DsPollingIntervalW);
+
+ torture_rpc_tcase_add_test(tcase, "IsPathReplicated",
+ test_IsPathReplicated);
+
+ torture_rpc_tcase_add_test(tcase, "ForceReplication",
+ test_ForceReplication);
+
+ torture_rpc_tcase_add_test(tcase, "InfoW",
+ test_InfoW);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/fsrvp.c b/source4/torture/rpc/fsrvp.c
new file mode 100644
index 0000000..1b38947
--- /dev/null
+++ b/source4/torture/rpc/fsrvp.c
@@ -0,0 +1,973 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for File Server Remote VSS Protocol operations
+
+ Copyright (C) David Disseldorp 2012-2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Windows Server "8" Beta is very picky in how it accepts FSRVP requests, the
+ * client must be a member of the same AD domain, ndr64 and signing must be
+ * negotiated for the DCE/RPC bind. E.g.
+ *
+ * smbtorture ncacn_np:LUTZE[/pipe/FssagentRpc,smb2,ndr64,sign] \
+ * -U 'DOM\user%pw' rpc.fsrvp
+ *
+ * This test suite requires a snapshotable share named FSHARE (see #def below).
+ */
+#include "includes.h"
+#include "lib/param/param.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/util/hresult.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/security_descriptor.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "librpc/gen_ndr/ndr_fsrvp_c.h"
+#include "lib/cmdline/cmdline.h"
+
+#define FSHARE "fsrvp_share"
+#define FNAME "testfss.dat"
+
+static bool test_fsrvp_is_path_supported(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fss_IsPathSupported r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+
+ ZERO_STRUCT(r);
+ r.in.ShareName = talloc_asprintf(tctx,"\\\\%s\\%s\\",
+ dcerpc_server_name(p),
+ FSHARE);
+ status = dcerpc_fss_IsPathSupported_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "IsPathSupported failed");
+
+ torture_assert(tctx, *r.out.SupportedByThisProvider,
+ "path not supported");
+
+ torture_comment(tctx, "path %s is supported by fsrvp server %s\n",
+ r.in.ShareName, *r.out.OwnerMachineName);
+
+ return true;
+}
+
+static bool test_fsrvp_get_version(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fss_GetSupportedVersion r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+
+ ZERO_STRUCT(r);
+ status = dcerpc_fss_GetSupportedVersion_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "GetSupportedVersion failed");
+
+ torture_comment(tctx, "got MinVersion %u\n", *r.out.MinVersion);
+ torture_comment(tctx, "got MaxVersion %u\n", *r.out.MaxVersion);
+
+ return true;
+}
+
+static bool test_fsrvp_set_ctx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fss_SetContext r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+
+ ZERO_STRUCT(r);
+ r.in.Context = FSRVP_CTX_BACKUP;
+ status = dcerpc_fss_SetContext_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
+
+ return true;
+}
+
+enum test_fsrvp_inject {
+ TEST_FSRVP_TOUT_NONE = 0,
+ TEST_FSRVP_TOUT_SET_CTX,
+ TEST_FSRVP_TOUT_START_SET,
+ TEST_FSRVP_TOUT_ADD_TO_SET,
+ TEST_FSRVP_TOUT_PREPARE,
+ TEST_FSRVP_TOUT_COMMIT,
+
+ TEST_FSRVP_STOP_B4_EXPOSE,
+};
+
+static bool test_fsrvp_sc_create(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *share,
+ enum test_fsrvp_inject inject,
+ struct fssagent_share_mapping_1 **sc_map)
+{
+ struct fss_IsPathSupported r_pathsupport_get;
+ struct fss_GetSupportedVersion r_version_get;
+ struct fss_SetContext r_context_set;
+ struct fss_StartShadowCopySet r_scset_start;
+ struct fss_AddToShadowCopySet r_scset_add1;
+ struct fss_AddToShadowCopySet r_scset_add2;
+ struct fss_PrepareShadowCopySet r_scset_prep;
+ struct fss_CommitShadowCopySet r_scset_commit;
+ struct fss_ExposeShadowCopySet r_scset_expose;
+ struct fss_GetShareMapping r_sharemap_get;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ time_t start_time;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ struct fssagent_share_mapping_1 *map = NULL;
+ int sleep_time;
+
+ /*
+ * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
+ * 60 second dcerpc request timeout against Windows Server "8" Beta.
+ */
+ dcerpc_binding_handle_set_timeout(b, 240);
+
+ ZERO_STRUCT(r_pathsupport_get);
+ r_pathsupport_get.in.ShareName = share;
+ status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
+ torture_assert_ntstatus_ok(tctx, status,
+ "IsPathSupported failed");
+ torture_assert_int_equal(tctx, r_pathsupport_get.out.result, 0,
+ "failed IsPathSupported response");
+ torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider,
+ "path not supported");
+
+ ZERO_STRUCT(r_version_get);
+ status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
+ torture_assert_ntstatus_ok(tctx, status,
+ "GetSupportedVersion failed");
+ torture_assert_int_equal(tctx, r_version_get.out.result, 0,
+ "failed GetSupportedVersion response");
+
+ ZERO_STRUCT(r_context_set);
+ r_context_set.in.Context = FSRVP_CTX_BACKUP;
+ status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
+ torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
+ torture_assert_int_equal(tctx, r_context_set.out.result, 0,
+ "failed SetContext response");
+
+ if (inject == TEST_FSRVP_TOUT_SET_CTX) {
+ sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
+ "sequence timeout", 180);
+ torture_comment(tctx, "sleeping for %d\n", sleep_time);
+ smb_msleep((sleep_time * 1000) + 500);
+ }
+
+ ZERO_STRUCT(r_scset_start);
+ r_scset_start.in.ClientShadowCopySetId = GUID_random();
+ status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
+ torture_assert_ntstatus_ok(tctx, status,
+ "StartShadowCopySet failed");
+ if (inject == TEST_FSRVP_TOUT_SET_CTX) {
+ /* expect error due to message sequence timeout after set_ctx */
+ torture_assert_int_equal(tctx, r_scset_start.out.result,
+ FSRVP_E_BAD_STATE,
+ "StartShadowCopySet timeout response");
+ goto done;
+ }
+ torture_assert_int_equal(tctx, r_scset_start.out.result, 0,
+ "failed StartShadowCopySet response");
+ torture_comment(tctx, "%s: shadow-copy set created\n",
+ GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId));
+
+ if (inject == TEST_FSRVP_TOUT_START_SET) {
+ sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
+ "sequence timeout", 180);
+ torture_comment(tctx, "sleeping for %d\n", sleep_time);
+ smb_msleep((sleep_time * 1000) + 500);
+ }
+
+ ZERO_STRUCT(r_scset_add1);
+ r_scset_add1.in.ClientShadowCopyId = GUID_random();
+ r_scset_add1.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ r_scset_add1.in.ShareName = share;
+ status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add1);
+ torture_assert_ntstatus_ok(tctx, status,
+ "AddToShadowCopySet failed");
+ if (inject == TEST_FSRVP_TOUT_START_SET) {
+ torture_assert_int_equal(tctx, r_scset_add1.out.result,
+ HRES_ERROR_V(HRES_E_INVALIDARG),
+ "AddToShadowCopySet timeout response");
+ goto done;
+ }
+ torture_assert_int_equal(tctx, r_scset_add1.out.result, 0,
+ "failed AddToShadowCopySet response");
+ torture_comment(tctx, "%s(%s): %s added to shadow-copy set\n",
+ GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
+ GUID_string(tmp_ctx, r_scset_add1.out.pShadowCopyId),
+ r_scset_add1.in.ShareName);
+
+ /* attempts to add the same share twice should fail */
+ ZERO_STRUCT(r_scset_add2);
+ r_scset_add2.in.ClientShadowCopyId = GUID_random();
+ r_scset_add2.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ r_scset_add2.in.ShareName = share;
+ status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "AddToShadowCopySet failed");
+ torture_assert_int_equal(tctx, r_scset_add2.out.result,
+ FSRVP_E_OBJECT_ALREADY_EXISTS,
+ "failed AddToShadowCopySet response");
+
+ if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) {
+ sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
+ "sequence timeout", 1800);
+ torture_comment(tctx, "sleeping for %d\n", sleep_time);
+ smb_msleep((sleep_time * 1000) + 500);
+ }
+
+ start_time = time_mono(NULL);
+ ZERO_STRUCT(r_scset_prep);
+ r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+// r_scset_prep.in.TimeOutInMilliseconds = (1800 * 1000); /* win8 */
+ r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000);
+ status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep);
+ torture_assert_ntstatus_ok(tctx, status,
+ "PrepareShadowCopySet failed");
+ if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) {
+ torture_assert_int_equal(tctx, r_scset_prep.out.result,
+ HRES_ERROR_V(HRES_E_INVALIDARG),
+ "PrepareShadowCopySet tout response");
+ goto done;
+ }
+ torture_assert_int_equal(tctx, r_scset_prep.out.result, 0,
+ "failed PrepareShadowCopySet response");
+ torture_comment(tctx, "%s: prepare completed in %llu secs\n",
+ GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
+ (unsigned long long)(time_mono(NULL) - start_time));
+
+ if (inject == TEST_FSRVP_TOUT_PREPARE) {
+ sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
+ "sequence timeout", 1800);
+ torture_comment(tctx, "sleeping for %d\n", sleep_time);
+ smb_msleep((sleep_time * 1000) + 500);
+ }
+
+ start_time = time_mono(NULL);
+ ZERO_STRUCT(r_scset_commit);
+ r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */
+ status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit);
+ torture_assert_ntstatus_ok(tctx, status,
+ "CommitShadowCopySet failed");
+ if (inject == TEST_FSRVP_TOUT_PREPARE) {
+ torture_assert_int_equal(tctx, r_scset_commit.out.result,
+ HRES_ERROR_V(HRES_E_INVALIDARG),
+ "CommitShadowCopySet tout response");
+ goto done;
+ }
+ torture_assert_int_equal(tctx, r_scset_commit.out.result, 0,
+ "failed CommitShadowCopySet response");
+ torture_comment(tctx, "%s: commit completed in %llu secs\n",
+ GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
+ (unsigned long long)(time_mono(NULL) - start_time));
+
+ if (inject == TEST_FSRVP_TOUT_COMMIT) {
+ sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
+ "sequence timeout", 180);
+ torture_comment(tctx, "sleeping for %d\n", sleep_time);
+ smb_msleep((sleep_time * 1000) + 500);
+ } else if (inject == TEST_FSRVP_STOP_B4_EXPOSE) {
+ /* return partial snapshot information */
+ map = talloc_zero(tctx, struct fssagent_share_mapping_1);
+ map->ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ map->ShadowCopyId = *r_scset_add1.out.pShadowCopyId;
+ goto done;
+ }
+
+ start_time = time_mono(NULL);
+ ZERO_STRUCT(r_scset_expose);
+ r_scset_expose.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
+ status = dcerpc_fss_ExposeShadowCopySet_r(b, tmp_ctx, &r_scset_expose);
+ torture_assert_ntstatus_ok(tctx, status,
+ "ExposeShadowCopySet failed");
+ if (inject == TEST_FSRVP_TOUT_COMMIT) {
+ torture_assert_int_equal(tctx, r_scset_expose.out.result,
+ HRES_ERROR_V(HRES_E_INVALIDARG),
+ "ExposeShadowCopySet tout response");
+ goto done;
+ }
+ torture_assert_int_equal(tctx, r_scset_expose.out.result, 0,
+ "failed ExposeShadowCopySet response");
+ torture_comment(tctx, "%s: expose completed in %llu secs\n",
+ GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
+ (unsigned long long)(time_mono(NULL) - start_time));
+
+ ZERO_STRUCT(r_sharemap_get);
+ r_sharemap_get.in.ShadowCopyId = *r_scset_add1.out.pShadowCopyId;
+ r_sharemap_get.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ r_sharemap_get.in.ShareName = r_scset_add1.in.ShareName;
+ r_sharemap_get.in.Level = 1;
+ status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get);
+ torture_assert_ntstatus_ok(tctx, status, "GetShareMapping failed");
+ torture_assert_int_equal(tctx, r_sharemap_get.out.result, 0,
+ "failed GetShareMapping response");
+ torture_comment(tctx, "%s(%s): %s is a snapshot of %s at %s\n",
+ GUID_string(tmp_ctx, &r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopySetId),
+ GUID_string(tmp_ctx, &r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyId),
+ r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyShareName,
+ r_sharemap_get.out.ShareMapping->ShareMapping1->ShareNameUNC,
+ nt_time_string(tmp_ctx, r_sharemap_get.out.ShareMapping->ShareMapping1->tstamp));
+
+ map = talloc_zero(tctx, struct fssagent_share_mapping_1);
+ map->ShadowCopySetId = r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopySetId;
+ map->ShadowCopyId = r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyId;
+ map->ShadowCopyShareName
+ = talloc_strdup(tctx, r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyShareName);
+ map->ShareNameUNC
+ = talloc_strdup(tctx, r_sharemap_get.out.ShareMapping->ShareMapping1->ShareNameUNC);
+ map->tstamp = r_sharemap_get.out.ShareMapping->ShareMapping1->tstamp;
+
+ torture_assert(tctx, !GUID_compare(&r_sharemap_get.in.ShadowCopySetId,
+ &map->ShadowCopySetId),
+ "sc_set GUID mismatch in GetShareMapping");
+ torture_assert(tctx, !GUID_compare(&r_sharemap_get.in.ShadowCopyId,
+ &map->ShadowCopyId),
+ "sc GUID mismatch in GetShareMapping");
+
+done:
+ talloc_free(tmp_ctx);
+ *sc_map = map;
+
+ return true;
+}
+
+static bool test_fsrvp_sc_delete(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct fssagent_share_mapping_1 *sc_map)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct fss_DeleteShareMapping r_sharemap_del;
+ NTSTATUS status;
+
+ ZERO_STRUCT(r_sharemap_del);
+ r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
+ r_sharemap_del.in.ShadowCopyId = sc_map->ShadowCopyId;
+ r_sharemap_del.in.ShareName = sc_map->ShareNameUNC;
+ status = dcerpc_fss_DeleteShareMapping_r(b, tctx, &r_sharemap_del);
+ torture_assert_ntstatus_ok(tctx, status, "DeleteShareMapping failed");
+ torture_assert_int_equal(tctx, r_sharemap_del.out.result, 0,
+ "failed DeleteShareMapping response");
+
+ return true;
+}
+
+static bool test_fsrvp_sc_create_simple(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fssagent_share_mapping_1 *sc_map;
+ /* no trailing backslash - should work. See note in cmd_fss.c */
+ char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s",
+ dcerpc_server_name(p), FSHARE);
+
+ torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
+ "sc create");
+
+ torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
+
+ return true;
+}
+
+static bool test_fsrvp_sc_set_abort(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s\\",
+ dcerpc_server_name(p), FSHARE);
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct fss_IsPathSupported r_pathsupport_get;
+ struct fss_GetSupportedVersion r_version_get;
+ struct fss_SetContext r_context_set;
+ struct fss_StartShadowCopySet r_scset_start;
+ struct fss_AbortShadowCopySet r_scset_abort;
+ struct fss_AddToShadowCopySet r_scset_add;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+
+ ZERO_STRUCT(r_pathsupport_get);
+ r_pathsupport_get.in.ShareName = share_unc;
+ status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
+ torture_assert_ntstatus_ok(tctx, status,
+ "IsPathSupported failed");
+ torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider,
+ "path not supported");
+
+ ZERO_STRUCT(r_version_get);
+ status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
+ torture_assert_ntstatus_ok(tctx, status,
+ "GetSupportedVersion failed");
+
+ ZERO_STRUCT(r_context_set);
+ r_context_set.in.Context = FSRVP_CTX_BACKUP;
+ status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
+ torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
+
+ ZERO_STRUCT(r_scset_start);
+ r_scset_start.in.ClientShadowCopySetId = GUID_random();
+ status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
+ torture_assert_ntstatus_ok(tctx, status,
+ "StartShadowCopySet failed");
+
+ ZERO_STRUCT(r_scset_abort);
+ r_scset_abort.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ status = dcerpc_fss_AbortShadowCopySet_r(b, tmp_ctx, &r_scset_abort);
+ torture_assert_ntstatus_ok(tctx, status,
+ "AbortShadowCopySet failed");
+
+ ZERO_STRUCT(r_scset_add);
+ r_scset_add.in.ClientShadowCopyId = GUID_random();
+ r_scset_add.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
+ r_scset_add.in.ShareName = share_unc;
+ status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add);
+ torture_assert_ntstatus_ok(tctx, status, "AddToShadowCopySet failed "
+ "following abort");
+ /*
+ * XXX Windows 8 server beta returns FSRVP_E_BAD_STATE here rather than
+ * FSRVP_E_BAD_ID / HRES_E_INVALIDARG.
+ */
+ torture_assert(tctx, (r_scset_add.out.result != 0),
+ "incorrect AddToShadowCopySet response following abort");
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_fsrvp_bad_id(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fssagent_share_mapping_1 *sc_map;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct fss_DeleteShareMapping r_sharemap_del;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
+ dcerpc_server_name(p), FSHARE);
+
+ torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
+ "sc create");
+
+ ZERO_STRUCT(r_sharemap_del);
+ r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
+ r_sharemap_del.in.ShadowCopySetId.time_low++; /* bogus */
+ r_sharemap_del.in.ShadowCopyId = sc_map->ShadowCopyId;
+ r_sharemap_del.in.ShareName = sc_map->ShareNameUNC;
+ status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
+ torture_assert_ntstatus_ok(tctx, status,
+ "DeleteShareMapping failed");
+ torture_assert_int_equal(tctx, r_sharemap_del.out.result,
+ FSRVP_E_OBJECT_NOT_FOUND,
+ "incorrect DeleteShareMapping response");
+
+ r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
+ r_sharemap_del.in.ShadowCopyId.time_mid++; /* bogus */
+ status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
+ torture_assert_ntstatus_ok(tctx, status,
+ "DeleteShareMapping failed");
+ torture_assert_int_equal(tctx, r_sharemap_del.out.result,
+ HRES_ERROR_V(HRES_E_INVALIDARG),
+ "incorrect DeleteShareMapping response");
+
+ torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
+
+ talloc_free(sc_map);
+ talloc_free(tmp_ctx);
+
+ return true;
+}
+
+static bool test_fsrvp_sc_share_io(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fssagent_share_mapping_1 *sc_map;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s",
+ dcerpc_server_name(p), FSHARE);
+ struct smb2_tree *tree_base;
+ struct smb2_tree *tree_snap;
+ struct smbcli_options options;
+ struct smb2_handle base_fh;
+ struct smb2_read r;
+ struct smb2_create io;
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ status = smb2_connect(tmp_ctx,
+ dcerpc_server_name(p),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ FSHARE,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree_base,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to connect to SMB2 share");
+
+ smb2_util_unlink(tree_base, FNAME);
+ status = torture_smb2_testfile(tree_base, FNAME, &base_fh);
+ torture_assert_ntstatus_ok(tctx, status, "base write open");
+
+ status = smb2_util_write(tree_base, base_fh, "pre-snap", 0,
+ sizeof("pre-snap"));
+ torture_assert_ntstatus_ok(tctx, status, "src write");
+
+
+ torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
+ "sc create");
+
+ status = smb2_util_write(tree_base, base_fh, "post-snap", 0,
+ sizeof("post-snap"));
+ torture_assert_ntstatus_ok(tctx, status, "base write");
+
+ /* connect to snapshot share and verify pre-snapshot data */
+ status = smb2_connect(tmp_ctx,
+ dcerpc_server_name(p),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ sc_map->ShadowCopyShareName,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree_snap,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to connect to SMB2 shadow-copy share");
+ /* Windows server 8 allows RW open to succeed here for a ro snapshot */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_RIGHTS_FILE_READ;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = FNAME;
+ status = smb2_create(tree_snap, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "snap read open");
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = io.out.file.handle;
+ r.in.length = sizeof("pre-snap");
+ status = smb2_read(tree_snap, tmp_ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "read");
+ torture_assert_u64_equal(tctx, r.out.data.length, r.in.length,
+ "read data len mismatch");
+ torture_assert_str_equal(tctx, (char *)r.out.data.data, "pre-snap",
+ "bad snapshot data");
+
+ torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
+
+ talloc_free(sc_map);
+ talloc_free(tmp_ctx);
+
+ return true;
+}
+
+static bool test_fsrvp_enum_snaps(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ int *_count)
+{
+ struct smb2_ioctl io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.level = RAW_IOCTL_SMB2;
+ io.in.file.handle = fh;
+ io.in.function = FSCTL_SRV_ENUM_SNAPS;
+ io.in.max_output_response = 16;
+ io.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "enum ioctl");
+
+ *_count = IVAL(io.out.out.data, 0);
+
+ /* with max_output_response=16, no labels should be sent */
+ torture_assert_int_equal(tctx, IVAL(io.out.out.data, 4), 0,
+ "enum snaps labels");
+
+ /* TODO with 0 snaps, needed_data_count should be 0? */
+ if (*_count != 0) {
+ torture_assert(tctx, IVAL(io.out.out.data, 8) != 0,
+ "enum snaps needed non-zero");
+ }
+
+ return true;
+}
+
+static bool test_fsrvp_enum_created(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct fssagent_share_mapping_1 *sc_map;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
+ dcerpc_server_name(p), FSHARE);
+ struct smb2_tree *tree_base;
+ struct smbcli_options options;
+ struct smb2_handle base_fh;
+ int count;
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ status = smb2_connect(tmp_ctx,
+ dcerpc_server_name(p),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ FSHARE,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree_base,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to connect to SMB2 share");
+
+ smb2_util_unlink(tree_base, FNAME);
+ status = torture_smb2_testfile(tree_base, FNAME, &base_fh);
+ torture_assert_ntstatus_ok(tctx, status, "base write open");
+
+ status = smb2_util_write(tree_base, base_fh, "pre-snap", 0,
+ sizeof("pre-snap"));
+ torture_assert_ntstatus_ok(tctx, status, "src write");
+
+ torture_assert(tctx,
+ test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
+ &count),
+ "count");
+ torture_assert_int_equal(tctx, count, 0, "num snaps");
+
+ torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
+ "sc create");
+ talloc_free(sc_map);
+
+ torture_assert(tctx,
+ test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
+ &count),
+ "count");
+ /*
+ * Snapshots created via FSRVP on Windows Server 2012 are not added to
+ * the previous versions list, so it will fail here...
+ */
+ torture_assert_int_equal(tctx, count, 1, "num snaps");
+
+ smb_msleep(1100); /* @GMT tokens have a 1 second resolution */
+ torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
+ "sc create");
+ talloc_free(sc_map);
+
+ torture_assert(tctx,
+ test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
+ &count),
+ "count");
+ torture_assert_int_equal(tctx, count, 2, "num snaps");
+
+ smb2_util_close(tree_base, base_fh);
+ ZERO_STRUCT(base_fh);
+
+ smb2_util_unlink(tree_base, FNAME);
+
+ talloc_free(tmp_ctx);
+
+ return true;
+}
+
+static bool test_fsrvp_seq_timeout(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ int i;
+ struct fssagent_share_mapping_1 *sc_map;
+ char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s",
+ dcerpc_server_name(p), FSHARE);
+
+ for (i = TEST_FSRVP_TOUT_NONE; i <= TEST_FSRVP_TOUT_COMMIT; i++) {
+ torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc,
+ i, &sc_map),
+ "sc create");
+
+ /* only need to delete if create process didn't timeout */
+ if (i == TEST_FSRVP_TOUT_NONE) {
+ torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map),
+ "sc del");
+ }
+ }
+
+ return true;
+}
+
+static bool test_fsrvp_share_sd(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *srvsvc_p;
+ struct srvsvc_NetShareGetInfo q;
+ struct srvsvc_NetShareSetInfo s;
+ struct srvsvc_NetShareInfo502 *info502;
+ struct fssagent_share_mapping_1 *sc_map;
+ struct fss_ExposeShadowCopySet r_scset_expose;
+ struct fss_GetShareMapping r_sharemap_get;
+ struct security_descriptor *sd_old;
+ struct security_descriptor *sd_base;
+ struct security_descriptor *sd_snap;
+ struct security_ace *ace;
+ int i;
+ int aces_found;
+ char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s",
+ dcerpc_server_name(p), FSHARE);
+ ZERO_STRUCT(q);
+ q.in.server_unc = dcerpc_server_name(p);
+ q.in.share_name = FSHARE;
+ q.in.level = 502;
+
+ status = torture_rpc_connection(tctx, &srvsvc_p, &ndr_table_srvsvc);
+ torture_assert_ntstatus_ok(tctx, status, "srvsvc rpc conn failed");
+
+ /* ensure srvsvc out pointers are allocated during unmarshalling */
+ srvsvc_p->conn->flags |= DCERPC_NDR_REF_ALLOC;
+
+ /* obtain the existing DACL for the base share */
+ status = dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p->binding_handle,
+ tctx, &q);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
+ torture_assert_werr_ok(tctx, q.out.result, "NetShareGetInfo failed");
+
+ info502 = q.out.info->info502;
+
+ /* back up the existing share SD, so it can be restored on completion */
+ sd_old = info502->sd_buf.sd;
+ sd_base = security_descriptor_copy(tctx, info502->sd_buf.sd);
+ torture_assert(tctx, sd_base != NULL, "sd dup");
+ torture_assert(tctx, sd_base->dacl != NULL, "no existing share DACL");
+
+ /* the Builtin_X_Operators placeholder ACEs need to be unique */
+ for (i = 0; i < sd_base->dacl->num_aces; i++) {
+ ace = &sd_base->dacl->aces[i];
+ if (dom_sid_equal(&ace->trustee,
+ &global_sid_Builtin_Backup_Operators)
+ || dom_sid_equal(&ace->trustee,
+ &global_sid_Builtin_Print_Operators)) {
+ torture_skip(tctx, "placeholder ACE already exists\n");
+ }
+ }
+
+ /* add Backup_Operators placeholder ACE and set base share DACL */
+ ace = talloc_zero(tctx, struct security_ace);
+ ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace->access_mask = SEC_STD_SYNCHRONIZE;
+ ace->trustee = global_sid_Builtin_Backup_Operators;
+
+ status = security_descriptor_dacl_add(sd_base, ace);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to add placeholder ACE to DACL");
+
+ info502->sd_buf.sd = sd_base;
+ info502->sd_buf.sd_size = ndr_size_security_descriptor(sd_base, 0);
+
+ ZERO_STRUCT(s);
+ s.in.server_unc = dcerpc_server_name(p);
+ s.in.share_name = FSHARE;
+ s.in.level = 502;
+ s.in.info = q.out.info;
+
+ status = dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p->binding_handle,
+ tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareSetInfo failed");
+ torture_assert_werr_ok(tctx, s.out.result, "NetShareSetInfo failed");
+
+ /* create a snapshot, but don't expose yet */
+ torture_assert(tctx,
+ test_fsrvp_sc_create(tctx, p, share_unc,
+ TEST_FSRVP_STOP_B4_EXPOSE, &sc_map),
+ "sc create");
+
+ /*
+ * Add another unique placeholder ACE.
+ * By changing the share DACL between snapshot creation and exposure we
+ * can determine at which point the server clones the base share DACL.
+ */
+ ace = talloc_zero(tctx, struct security_ace);
+ ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace->access_mask = SEC_STD_SYNCHRONIZE;
+ ace->trustee = global_sid_Builtin_Print_Operators;
+
+ status = security_descriptor_dacl_add(sd_base, ace);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to add placeholder ACE to DACL");
+
+ info502->sd_buf.sd = sd_base;
+ info502->sd_buf.sd_size = ndr_size_security_descriptor(sd_base, 0);
+
+ ZERO_STRUCT(s);
+ s.in.server_unc = dcerpc_server_name(p);
+ s.in.share_name = FSHARE;
+ s.in.level = 502;
+ s.in.info = q.out.info;
+
+ status = dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p->binding_handle,
+ tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareSetInfo failed");
+ torture_assert_werr_ok(tctx, s.out.result, "NetShareSetInfo failed");
+
+ /* expose the snapshot share and get the new share details */
+ ZERO_STRUCT(r_scset_expose);
+ r_scset_expose.in.ShadowCopySetId = sc_map->ShadowCopySetId;
+ r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
+ status = dcerpc_fss_ExposeShadowCopySet_r(p->binding_handle, tctx,
+ &r_scset_expose);
+ torture_assert_ntstatus_ok(tctx, status,
+ "ExposeShadowCopySet failed");
+ torture_assert_int_equal(tctx, r_scset_expose.out.result, 0,
+ "failed ExposeShadowCopySet response");
+
+ ZERO_STRUCT(r_sharemap_get);
+ r_sharemap_get.in.ShadowCopyId = sc_map->ShadowCopyId;
+ r_sharemap_get.in.ShadowCopySetId = sc_map->ShadowCopySetId;
+ r_sharemap_get.in.ShareName = share_unc;
+ r_sharemap_get.in.Level = 1;
+ status = dcerpc_fss_GetShareMapping_r(p->binding_handle, tctx,
+ &r_sharemap_get);
+ torture_assert_ntstatus_ok(tctx, status, "GetShareMapping failed");
+ torture_assert_int_equal(tctx, r_sharemap_get.out.result, 0,
+ "failed GetShareMapping response");
+ talloc_free(sc_map);
+ sc_map = r_sharemap_get.out.ShareMapping->ShareMapping1;
+
+ /* restore the original base share ACL */
+ info502->sd_buf.sd = sd_old;
+ info502->sd_buf.sd_size = ndr_size_security_descriptor(sd_old, 0);
+ status = dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p->binding_handle,
+ tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareSetInfo failed");
+ torture_assert_werr_ok(tctx, s.out.result, "NetShareSetInfo failed");
+
+ /* check for placeholder ACEs in the snapshot share DACL */
+ ZERO_STRUCT(q);
+ q.in.server_unc = dcerpc_server_name(p);
+ q.in.share_name = sc_map->ShadowCopyShareName;
+ q.in.level = 502;
+ status = dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p->binding_handle,
+ tctx, &q);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
+ torture_assert_werr_ok(tctx, q.out.result, "NetShareGetInfo failed");
+ info502 = q.out.info->info502;
+
+ sd_snap = info502->sd_buf.sd;
+ torture_assert(tctx, sd_snap != NULL, "sd");
+ torture_assert(tctx, sd_snap->dacl != NULL, "no snap share DACL");
+
+ aces_found = 0;
+ for (i = 0; i < sd_snap->dacl->num_aces; i++) {
+ ace = &sd_snap->dacl->aces[i];
+ if (dom_sid_equal(&ace->trustee,
+ &global_sid_Builtin_Backup_Operators)) {
+ torture_comment(tctx,
+ "found share ACE added before snapshot\n");
+ aces_found++;
+ } else if (dom_sid_equal(&ace->trustee,
+ &global_sid_Builtin_Print_Operators)) {
+ torture_comment(tctx,
+ "found share ACE added after snapshot\n");
+ aces_found++;
+ }
+ }
+ /*
+ * Expect snapshot share to match the base share DACL at the time of
+ * exposure, not at the time of snapshot creation. This is in line with
+ * Windows Server 2012 behaviour.
+ */
+ torture_assert_int_equal(tctx, aces_found, 2,
+ "placeholder ACE missing from snap share DACL");
+
+ torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
+
+ return true;
+}
+
+static bool fsrvp_rpc_setup(struct torture_context *tctx, void **data)
+{
+ NTSTATUS status;
+ struct torture_rpc_tcase *tcase = talloc_get_type(
+ tctx->active_tcase, struct torture_rpc_tcase);
+ struct torture_rpc_tcase_data *tcase_data;
+
+ *data = tcase_data = talloc_zero(tctx, struct torture_rpc_tcase_data);
+ tcase_data->credentials = samba_cmdline_get_creds();
+
+ status = torture_rpc_connection(tctx,
+ &(tcase_data->pipe),
+ tcase->table);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ /* XXX required, otherwise ndr out ptrs are not allocated */
+ tcase_data->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
+
+ return true;
+}
+
+/*
+ testing of FSRVP (FSS agent)
+*/
+struct torture_suite *torture_rpc_fsrvp(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "fsrvp");
+
+ struct torture_rpc_tcase *tcase
+ = torture_suite_add_rpc_iface_tcase(suite, "fsrvp",
+ &ndr_table_FileServerVssAgent);
+ /* override torture_rpc_setup() to set DCERPC_NDR_REF_ALLOC */
+ tcase->tcase.setup = fsrvp_rpc_setup;
+
+ torture_rpc_tcase_add_test(tcase, "share_sd",
+ test_fsrvp_share_sd);
+ torture_rpc_tcase_add_test(tcase, "enum_created",
+ test_fsrvp_enum_created);
+ torture_rpc_tcase_add_test(tcase, "sc_share_io",
+ test_fsrvp_sc_share_io);
+ torture_rpc_tcase_add_test(tcase, "bad_id",
+ test_fsrvp_bad_id);
+ torture_rpc_tcase_add_test(tcase, "sc_set_abort",
+ test_fsrvp_sc_set_abort);
+ torture_rpc_tcase_add_test(tcase, "create_simple",
+ test_fsrvp_sc_create_simple);
+ torture_rpc_tcase_add_test(tcase, "set_ctx",
+ test_fsrvp_set_ctx);
+ torture_rpc_tcase_add_test(tcase, "get_version",
+ test_fsrvp_get_version);
+ torture_rpc_tcase_add_test(tcase, "is_path_supported",
+ test_fsrvp_is_path_supported);
+ torture_rpc_tcase_add_test(tcase, "seq_timeout",
+ test_fsrvp_seq_timeout);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/handles.c b/source4/torture/rpc/handles.c
new file mode 100644
index 0000000..7c108e5
--- /dev/null
+++ b/source4/torture/rpc/handles.c
@@ -0,0 +1,622 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for behaviour of rpc policy handles
+
+ Copyright (C) Andrew Tridgell 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+/*
+ this tests the use of policy handles between connections
+*/
+
+static bool test_handles_lsa(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2;
+ struct dcerpc_binding_handle *b1, *b2;
+ struct policy_handle handle;
+ struct policy_handle handle2;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy r;
+ struct lsa_Close c;
+ uint16_t system_name = '\\';
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+
+ torture_comment(torture, "RPC-HANDLE-LSARPC\n");
+
+ status = torture_rpc_connection(torture, &p1, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe1");
+ b1 = p1->binding_handle;
+
+ status = torture_rpc_connection(torture, &p2, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe1");
+ b2 = p2->binding_handle;
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = &system_name;
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_OpenPolicy_r(b1, mem_ctx, &r),
+ "OpenPolicy failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(torture, "lsa_OpenPolicy not supported - skipping\n");
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ c.in.handle = &handle;
+ c.out.handle = &handle2;
+
+ status = dcerpc_lsa_Close_r(b2, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p2");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_Close_r(b1, mem_ctx, &c),
+ "Close failed");
+ torture_assert_ntstatus_ok(torture, c.out.result, "closing policy handle on p1");
+
+ status = dcerpc_lsa_Close_r(b1, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p1 again");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+static bool test_handles_lsa_shared(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2, *p3, *p4, *p5;
+ struct dcerpc_binding_handle *b1, *b2, *b3, *b4;
+ struct policy_handle handle;
+ struct policy_handle handle2;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy r;
+ struct lsa_Close c;
+ struct lsa_QuerySecurity qsec;
+ struct sec_desc_buf *sdbuf = NULL;
+ uint16_t system_name = '\\';
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ enum dcerpc_transport_t transport;
+ uint32_t assoc_group_id;
+
+ torture_comment(torture, "RPC-HANDLE-LSARPC-SHARED\n");
+
+ torture_comment(torture, "connect lsa pipe1\n");
+ status = torture_rpc_connection(torture, &p1, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe1");
+ b1 = p1->binding_handle;
+
+ transport = p1->conn->transport.transport;
+ assoc_group_id = dcerpc_binding_get_assoc_group_id(p1->binding);
+
+ torture_comment(torture, "use assoc_group_id[0x%08X] for new connections\n", assoc_group_id);
+
+ torture_comment(torture, "connect lsa pipe2\n");
+ status = torture_rpc_connection_transport(torture, &p2, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe2");
+ b2 = p2->binding_handle;
+
+ torture_comment(torture, "got assoc_group_id[0x%08X] for p2\n",
+ dcerpc_binding_get_assoc_group_id(p2->binding));
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = &system_name;
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ torture_comment(torture, "open lsa policy handle\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_OpenPolicy_r(b1, mem_ctx, &r),
+ "OpenPolicy failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(torture, "lsa_OpenPolicy not supported - skipping\n");
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ /*
+ * connect p3 after the policy handle is opened
+ */
+ torture_comment(torture, "connect lsa pipe3 after the policy handle is opened\n");
+ status = torture_rpc_connection_transport(torture, &p3, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe3");
+ b3 = p3->binding_handle;
+
+ qsec.in.handle = &handle;
+ qsec.in.sec_info = 0;
+ qsec.out.sdbuf = &sdbuf;
+ c.in.handle = &handle;
+ c.out.handle = &handle2;
+
+ /*
+ * use policy handle on all 3 connections
+ */
+ torture_comment(torture, "use the policy handle on p1,p2,p3\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b1, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "use policy handle on p1");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b2, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "use policy handle on p2");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b3, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "use policy handle on p3");
+
+ /*
+ * close policy handle on connection 2 and the others get a fault
+ */
+ torture_comment(torture, "close the policy handle on p2 others get a fault\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_Close_r(b2, mem_ctx, &c),
+ "Close failed");
+ torture_assert_ntstatus_equal(torture, c.out.result, NT_STATUS_OK,
+ "closing policy handle on p2");
+
+ status = dcerpc_lsa_Close_r(b1, mem_ctx, &c);
+
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p1 again");
+
+ status = dcerpc_lsa_Close_r(b3, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p3");
+
+ status = dcerpc_lsa_Close_r(b2, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p2 again");
+
+ /*
+ * open a new policy handle on p3
+ */
+ torture_comment(torture, "open a new policy handle on p3\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_OpenPolicy_r(b3, mem_ctx, &r),
+ "OpenPolicy failed");
+ torture_assert_ntstatus_equal(torture, r.out.result, NT_STATUS_OK,
+ "open policy handle on p3");
+
+ /*
+ * use policy handle on all 3 connections
+ */
+ torture_comment(torture, "use the policy handle on p1,p2,p3\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b1, mem_ctx, &qsec),
+ "Query Security failed");
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "use policy handle on p1");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b2, mem_ctx, &qsec),
+ "Query Security failed");
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "use policy handle on p2");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b3, mem_ctx, &qsec),
+ "Query Security failed");
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "use policy handle on p3");
+
+ /*
+ * close policy handle on connection 2 and the others get a fault
+ */
+ torture_comment(torture, "close the policy handle on p2 others get a fault\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_Close_r(b2, mem_ctx, &c),
+ "Close failed");
+ torture_assert_ntstatus_equal(torture, c.out.result, NT_STATUS_OK,
+ "closing policy handle on p2");
+
+ status = dcerpc_lsa_Close_r(b1, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p1 again");
+
+ status = dcerpc_lsa_Close_r(b3, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p3");
+
+ status = dcerpc_lsa_Close_r(b2, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p2 again");
+
+ /*
+ * open a new policy handle
+ */
+ torture_comment(torture, "open a new policy handle on p1 and use it\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_OpenPolicy_r(b1, mem_ctx, &r),
+ "OpenPolicy failed");
+ torture_assert_ntstatus_equal(torture, r.out.result, NT_STATUS_OK,
+ "open 2nd policy handle on p1");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b1, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "QuerySecurity handle on p1");
+
+ /* close first connection */
+ torture_comment(torture, "disconnect p1\n");
+ talloc_free(p1);
+ smb_msleep(5);
+
+ /*
+ * and it's still available on p2,p3
+ */
+ torture_comment(torture, "use policy handle on p2,p3\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b2, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "QuerySecurity handle on p2 after p1 was disconnected");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b3, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "QuerySecurity handle on p3 after p1 was disconnected");
+
+ /*
+ * now open p4
+ * and use the handle on it
+ */
+ torture_comment(torture, "connect lsa pipe4 and use policy handle\n");
+ status = torture_rpc_connection_transport(torture, &p4, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe4");
+ b4 = p4->binding_handle;
+
+ torture_assert_ntstatus_ok(torture, dcerpc_lsa_QuerySecurity_r(b4, mem_ctx, &qsec),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_equal(torture, qsec.out.result, NT_STATUS_OK,
+ "using policy handle on p4");
+
+ /*
+ * now close p2,p3,p4
+ * without closing the policy handle
+ */
+ torture_comment(torture, "disconnect p2,p3,p4\n");
+ talloc_free(p2);
+ talloc_free(p3);
+ talloc_free(p4);
+ smb_msleep(10);
+
+ /*
+ * now open p5
+ */
+ torture_comment(torture, "connect lsa pipe5 - should fail\n");
+ status = torture_rpc_connection_transport(torture, &p5, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening lsa pipe5");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+
+static bool test_handles_samr(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2;
+ struct dcerpc_binding_handle *b1, *b2;
+ struct policy_handle handle;
+ struct policy_handle handle2;
+ struct samr_Connect r;
+ struct samr_Close c;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+
+ torture_comment(torture, "RPC-HANDLE-SAMR\n");
+
+ status = torture_rpc_connection(torture, &p1, &ndr_table_samr);
+ torture_assert_ntstatus_ok(torture, status, "opening samr pipe1");
+ b1 = p1->binding_handle;
+
+ status = torture_rpc_connection(torture, &p2, &ndr_table_samr);
+ torture_assert_ntstatus_ok(torture, status, "opening samr pipe2");
+ b2 = p2->binding_handle;
+
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.connect_handle = &handle;
+
+ torture_assert_ntstatus_ok(torture, dcerpc_samr_Connect_r(b1, mem_ctx, &r),
+ "Connect failed");
+ torture_assert_ntstatus_ok(torture, r.out.result, "opening policy handle on p1");
+
+ c.in.handle = &handle;
+ c.out.handle = &handle2;
+
+ status = dcerpc_samr_Close_r(b2, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p2");
+
+ torture_assert_ntstatus_ok(torture, dcerpc_samr_Close_r(b1, mem_ctx, &c),
+ "Close failed");
+ torture_assert_ntstatus_ok(torture, c.out.result, "closing policy handle on p1");
+
+ status = dcerpc_samr_Close_r(b1, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p1 again");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+static bool test_handles_mixed_shared(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2, *p3, *p4, *p5, *p6;
+ struct dcerpc_binding_handle *b1, *b2;
+ struct policy_handle handle;
+ struct policy_handle handle2;
+ struct samr_Connect r;
+ struct lsa_Close lc;
+ struct samr_Close sc;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ enum dcerpc_transport_t transport;
+ uint32_t assoc_group_id;
+
+ torture_comment(torture, "RPC-HANDLE-MIXED-SHARED\n");
+
+ torture_comment(torture, "connect samr pipe1\n");
+ status = torture_rpc_connection(torture, &p1, &ndr_table_samr);
+ torture_assert_ntstatus_ok(torture, status, "opening samr pipe1");
+ b1 = p1->binding_handle;
+
+ transport = p1->conn->transport.transport;
+ assoc_group_id = dcerpc_binding_get_assoc_group_id(p1->binding);
+
+ torture_comment(torture, "use assoc_group_id[0x%08X] for new connections\n", assoc_group_id);
+
+ torture_comment(torture, "connect lsa pipe2\n");
+ status = torture_rpc_connection_transport(torture, &p2, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe2");
+ b2 = p2->binding_handle;
+
+ torture_comment(torture, "got assoc_group_id[0x%08X] for p2\n",
+ dcerpc_binding_get_assoc_group_id(p2->binding));
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.connect_handle = &handle;
+
+ torture_comment(torture, "samr_Connect to open a policy handle on samr p1\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_samr_Connect_r(b1, mem_ctx, &r),
+ "Connect failed");
+ torture_assert_ntstatus_ok(torture, r.out.result, "opening policy handle on p1");
+
+ lc.in.handle = &handle;
+ lc.out.handle = &handle2;
+ sc.in.handle = &handle;
+ sc.out.handle = &handle2;
+
+ torture_comment(torture, "use policy handle on lsa p2 - should fail\n");
+ status = dcerpc_lsa_Close_r(b2, mem_ctx, &lc);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing handle on lsa p2");
+
+ torture_comment(torture, "closing policy handle on samr p1\n");
+ torture_assert_ntstatus_ok(torture, dcerpc_samr_Close_r(b1, mem_ctx, &sc),
+ "Close failed");
+ torture_assert_ntstatus_ok(torture, sc.out.result, "closing policy handle on p1");
+
+ talloc_free(p1);
+ talloc_free(p2);
+ smb_msleep(10);
+
+ torture_comment(torture, "connect samr pipe3 - should fail\n");
+ status = torture_rpc_connection_transport(torture, &p3, &ndr_table_samr,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening samr pipe3");
+
+ torture_comment(torture, "connect lsa pipe4 - should fail\n");
+ status = torture_rpc_connection_transport(torture, &p4, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening lsa pipe4");
+
+ /*
+ * We use ~assoc_group_id instead of p1->assoc_group_id, because
+ * this way we are less likely to use an id which is already in use.
+ */
+ assoc_group_id = ~assoc_group_id;
+ torture_comment(torture, "connect samr pipe5 with assoc_group_id[0x%08X]- should fail\n", ++assoc_group_id);
+ status = torture_rpc_connection_transport(torture, &p5, &ndr_table_samr,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening samr pipe5");
+
+ torture_comment(torture, "connect lsa pipe6 with assoc_group_id[0x%08X]- should fail\n", ++assoc_group_id);
+ status = torture_rpc_connection_transport(torture, &p6, &ndr_table_lsarpc,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening lsa pipe6");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+static bool test_handles_random_assoc(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2, *p3;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+ enum dcerpc_transport_t transport;
+ uint32_t assoc_group_id;
+
+ torture_comment(torture, "RPC-HANDLE-RANDOM-ASSOC\n");
+
+ torture_comment(torture, "connect samr pipe1\n");
+ status = torture_rpc_connection(torture, &p1, &ndr_table_samr);
+ torture_assert_ntstatus_ok(torture, status, "opening samr pipe1");
+
+ torture_comment(torture, "pipe1 uses assoc_group_id[0x%08X]\n",
+ dcerpc_binding_get_assoc_group_id(p1->binding));
+
+ transport = p1->conn->transport.transport;
+ /*
+ * We use ~p1->assoc_group_id instead of p1->assoc_group_id, because
+ * this way we are less likely to use an id which is already in use.
+ *
+ * And make sure it doesn't wrap.
+ */
+ assoc_group_id = dcerpc_binding_get_assoc_group_id(p1->binding);
+ assoc_group_id = ~MIN(assoc_group_id, UINT32_MAX - 3);
+
+ torture_comment(torture, "connect samr pipe2 with assoc_group_id[0x%08X]- should fail\n", ++assoc_group_id);
+ status = torture_rpc_connection_transport(torture, &p2, &ndr_table_samr,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening samr pipe2");
+
+ torture_comment(torture, "connect samr pipe3 with assoc_group_id[0x%08X]- should fail\n", ++assoc_group_id);
+ status = torture_rpc_connection_transport(torture, &p3, &ndr_table_samr,
+ transport,
+ assoc_group_id,
+ 0);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_UNSUCCESSFUL,
+ "opening samr pipe3");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+
+static bool test_handles_drsuapi(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2;
+ struct dcerpc_binding_handle *b1, *b2;
+ struct policy_handle handle;
+ struct policy_handle handle2;
+ struct GUID bind_guid;
+ struct drsuapi_DsBind r;
+ struct drsuapi_DsUnbind c;
+ TALLOC_CTX *mem_ctx = talloc_new(torture);
+
+ torture_comment(torture, "RPC-HANDLE-DRSUAPI\n");
+
+ status = torture_rpc_connection(torture, &p1, &ndr_table_drsuapi);
+ torture_assert_ntstatus_ok(torture, status, "opening drsuapi pipe1");
+ b1 = p1->binding_handle;
+
+ status = torture_rpc_connection(torture, &p2, &ndr_table_drsuapi);
+ torture_assert_ntstatus_ok(torture, status, "opening drsuapi pipe1");
+ b2 = p2->binding_handle;
+
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
+
+ r.in.bind_guid = &bind_guid;
+ r.in.bind_info = NULL;
+ r.out.bind_handle = &handle;
+
+ status = dcerpc_drsuapi_DsBind_r(b1, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "drsuapi_DsBind not supported - skipping\n");
+ talloc_free(mem_ctx);
+ return true;
+ }
+
+ c.in.bind_handle = &handle;
+ c.out.bind_handle = &handle2;
+
+ status = dcerpc_drsuapi_DsUnbind_r(b2, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p2");
+
+ status = dcerpc_drsuapi_DsUnbind_r(b1, mem_ctx, &c);
+ torture_assert_ntstatus_ok(torture, status, "closing policy handle on p1");
+
+ status = dcerpc_drsuapi_DsUnbind_r(b1, mem_ctx, &c);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "closing policy handle on p1 again");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_handles(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(mem_ctx, "handles");
+ torture_suite_add_simple_test(suite, "lsarpc", test_handles_lsa);
+ torture_suite_add_simple_test(suite, "lsarpc-shared", test_handles_lsa_shared);
+ torture_suite_add_simple_test(suite, "samr", test_handles_samr);
+ torture_suite_add_simple_test(suite, "mixed-shared", test_handles_mixed_shared);
+ torture_suite_add_simple_test(suite, "random-assoc", test_handles_random_assoc);
+ torture_suite_add_simple_test(suite, "drsuapi", test_handles_drsuapi);
+ return suite;
+}
diff --git a/source4/torture/rpc/initshutdown.c b/source4/torture/rpc/initshutdown.c
new file mode 100644
index 0000000..28eaacd
--- /dev/null
+++ b/source4/torture/rpc/initshutdown.c
@@ -0,0 +1,116 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for initshutdown operations
+
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Jelmer Vernooij 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_initshutdown_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+static void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
+{
+ name->string = s;
+}
+
+
+static bool test_Abort(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct initshutdown_Abort r;
+ NTSTATUS status;
+ uint16_t server = 0x0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server = &server;
+
+ status = dcerpc_initshutdown_Abort_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "initshutdown_Abort failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "initshutdown_Abort failed");
+
+ return true;
+}
+
+static bool test_Init(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct initshutdown_Init r;
+ NTSTATUS status;
+ uint16_t hostname = 0x0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.hostname = &hostname;
+ r.in.message = talloc(tctx, struct lsa_StringLarge);
+ init_lsa_StringLarge(r.in.message, "spottyfood");
+ r.in.force_apps = 1;
+ r.in.timeout = 30;
+ r.in.do_reboot = 1;
+
+ status = dcerpc_initshutdown_Init_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "initshutdown_Init failed");
+ torture_assert_werr_ok(tctx, r.out.result, "initshutdown_Init failed");
+
+ return test_Abort(tctx, p);
+}
+
+static bool test_InitEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct initshutdown_InitEx r;
+ NTSTATUS status;
+ uint16_t hostname = 0x0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.hostname = &hostname;
+ r.in.message = talloc(tctx, struct lsa_StringLarge);
+ init_lsa_StringLarge(r.in.message, "spottyfood");
+ r.in.force_apps = 1;
+ r.in.timeout = 30;
+ r.in.do_reboot = 1;
+ r.in.reason = 0;
+
+ status = dcerpc_initshutdown_InitEx_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "initshutdown_InitEx failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "initshutdown_InitEx failed");
+
+ return test_Abort(tctx, p);
+}
+
+
+struct torture_suite *torture_rpc_initshutdown(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "initshutdown");
+ struct torture_rpc_tcase *tcase;
+ struct torture_test *test;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "initshutdown",
+ &ndr_table_initshutdown);
+
+ test = torture_rpc_tcase_add_test(tcase, "Init", test_Init);
+ test->dangerous = true;
+ test = torture_rpc_tcase_add_test(tcase, "InitEx", test_InitEx);
+ test->dangerous = true;
+
+ return suite;
+}
diff --git a/source4/torture/rpc/iremotewinspool.c b/source4/torture/rpc/iremotewinspool.c
new file mode 100644
index 0000000..3a7ee64
--- /dev/null
+++ b/source4/torture/rpc/iremotewinspool.c
@@ -0,0 +1,1090 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for iremotewinspool rpc operations
+
+ Copyright (C) Guenther Deschner 2013,2023
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_winspool.h"
+#include "librpc/gen_ndr/ndr_winspool_c.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/registry/util_reg.h"
+#include "torture/rpc/iremotewinspool_common.h"
+
+static bool torture_rpc_iremotewinspool_setup_common(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ const char *printer_name;
+ struct spoolss_UserLevel1 client_info;
+ struct dcerpc_binding *binding;
+
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &t->object_uuid),
+ "failed to parse GUID");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "failed to retrieve torture binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_object(binding, t->object_uuid),
+ "failed to set object_uuid");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection_with_binding(tctx, binding, &t->iremotewinspool_pipe, &ndr_table_iremotewinspool),
+ "Error connecting to server");
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(t->iremotewinspool_pipe));
+
+ client_info = test_get_client_info(tctx, WIN_7, 6, 1, "testclient_machine", "testclient_user");
+
+ torture_assert(tctx,
+ test_AsyncOpenPrinter_byprinter(tctx, t,
+ t->iremotewinspool_pipe, printer_name,
+ client_info, &t->server_handle),
+ "failed to open printserver");
+ torture_assert(tctx,
+ test_get_environment(tctx,
+ t->iremotewinspool_pipe->binding_handle,
+ &t->server_handle, &t->environment),
+ "failed to get environment");
+
+ return true;
+}
+
+static bool torture_rpc_iremotewinspool_setup(struct torture_context *tctx,
+ void **data)
+{
+ struct test_iremotewinspool_context *t;
+
+ *data = t = talloc_zero(tctx, struct test_iremotewinspool_context);
+
+ return torture_rpc_iremotewinspool_setup_common(tctx, t);
+}
+
+static bool torture_rpc_iremotewinspool_teardown_common(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+
+ test_AsyncClosePrinter_byhandle(tctx, t, t->iremotewinspool_pipe, &t->server_handle);
+
+ return true;
+}
+
+static bool torture_rpc_iremotewinspool_teardown(struct torture_context *tctx,
+ void *data)
+{
+ struct test_iremotewinspool_context *t = talloc_get_type(data, struct test_iremotewinspool_context);
+ bool ret;
+
+ ret = torture_rpc_iremotewinspool_teardown_common(tctx, t);
+ talloc_free(t);
+
+ return ret;
+}
+
+static bool test_AsyncClosePrinter(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ const char *printer_name;
+ struct spoolss_UserLevel1 client_info;
+ struct policy_handle handle;
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ client_info = test_get_client_info(tctx, WIN_7, 6, 1, "testclient_machine", "testclient_user");
+
+ torture_assert(tctx,
+ test_AsyncOpenPrinter_byprinter(tctx, ctx, p, printer_name, client_info, &handle),
+ "failed to test AsyncOpenPrinter");
+
+ torture_assert(tctx,
+ test_AsyncClosePrinter_byhandle(tctx, ctx, p, &handle),
+ "failed to test AsyncClosePrinter");
+
+ return true;
+}
+
+static bool test_AsyncOpenPrinter(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ const char *printer_name;
+ struct spoolss_UserLevel1 client_info;
+ struct policy_handle handle;
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ client_info = test_get_client_info(tctx, WIN_7, 6, 1, "testclient_machine", "testclient_user");
+
+ torture_assert(tctx,
+ test_AsyncOpenPrinter_byprinter(tctx, ctx, p, printer_name, client_info, &handle),
+ "failed to test AsyncOpenPrinter");
+
+ test_AsyncClosePrinter_byhandle(tctx, ctx, p, &handle);
+
+ return true;
+}
+
+/*
+ * Validate the result of AsyncOpenPrinter calls based on client info
+ * build number. Windows Server 2016 rejects an advertised build
+ * number less than 6000(Windows Vista and Windows Server 2008, or older)
+ */
+static bool test_AsyncOpenPrinterValidateBuildNumber(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ const char *printer_name;
+ struct spoolss_UserLevel1 client_info;
+ struct policy_handle handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct spoolss_UserLevelCtr client_info_ctr = {
+ .level = 1,
+ };
+ uint32_t access_mask = SERVER_ALL_ACCESS;
+ struct winspool_AsyncOpenPrinter r;
+ NTSTATUS status;
+ bool ok = false;
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_assert_not_null(tctx, printer_name, "Cannot allocate memory");
+
+ /* fail with Windows 2000 build number */
+ client_info = test_get_client_info(tctx, WIN_2000, 3, SPOOLSS_MINOR_VERSION_0,
+ "testclient_machine", "testclient_user");
+
+ ZERO_STRUCT(devmode_ctr);
+
+ client_info_ctr.user_info.level1 = &client_info;
+
+ r.in.pPrinterName = printer_name;
+ r.in.pDatatype = NULL;
+ r.in.pDevModeContainer = &devmode_ctr;
+ r.in.AccessRequired = access_mask;
+ r.in.pClientInfo = &client_info_ctr;
+ r.out.pHandle = &handle;
+
+ status = dcerpc_winspool_AsyncOpenPrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "AsyncOpenPrinter failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED,
+ "AsyncOpenPrinter should have failed");
+
+ /* succeed with Windows 7 build number */
+ client_info = test_get_client_info(tctx, WIN_7, 6, 1,
+ "testclient_machine", "testclient_user");
+ client_info_ctr.user_info.level1 = &client_info;
+ r.in.pClientInfo = &client_info_ctr;
+
+ status = dcerpc_winspool_AsyncOpenPrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "AsyncOpenPrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AsyncOpenPrinter failed");
+
+ ok = test_AsyncClosePrinter_byhandle(tctx, ctx, p, &handle);
+ torture_assert(tctx, ok, "failed to AsyncClosePrinter handle");
+
+ return true;
+
+}
+
+static struct spoolss_NotifyOption *setup_printserver_NotifyOption(struct torture_context *tctx)
+{
+ struct spoolss_NotifyOption *o;
+
+ o = talloc_zero(tctx, struct spoolss_NotifyOption);
+ if (o == NULL) {
+ return NULL;
+ }
+
+ o->version = 2;
+ o->flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
+
+ o->count = 2;
+ o->types = talloc_zero_array(o, struct spoolss_NotifyOptionType, o->count);
+ if (o->types == NULL) {
+ talloc_free(o);
+ return NULL;
+ }
+
+ o->types[0].type = PRINTER_NOTIFY_TYPE;
+ o->types[0].count = 1;
+ o->types[0].fields = talloc_array(o->types, union spoolss_Field, o->types[0].count);
+ if (o->types[0].fields == NULL) {
+ talloc_free(o);
+ return NULL;
+ }
+ o->types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
+
+ o->types[1].type = JOB_NOTIFY_TYPE;
+ o->types[1].count = 1;
+ o->types[1].fields = talloc_array(o->types, union spoolss_Field, o->types[1].count);
+ if (o->types[1].fields == NULL) {
+ talloc_free(o);
+ return NULL;
+ }
+ o->types[1].fields[0].field = JOB_NOTIFY_FIELD_MACHINE_NAME;
+
+ return o;
+}
+
+static bool test_SyncUnRegisterForRemoteNotifications_args(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *notify_handle)
+{
+ struct winspool_SyncUnRegisterForRemoteNotifications r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.phRpcHandle = notify_handle;
+ r.out.phRpcHandle = notify_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_SyncUnRegisterForRemoteNotifications_r(b, tctx, &r),
+ "SyncUnRegisterForRemoteNotifications failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "SyncUnRegisterForRemoteNotifications failed");
+
+ return true;
+}
+
+static bool test_SyncRegisterForRemoteNotifications_args(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *server_handle,
+ struct policy_handle *notify_handle);
+
+static bool test_SyncUnRegisterForRemoteNotifications(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+ struct policy_handle notify_handle;
+
+ torture_assert(tctx,
+ test_SyncRegisterForRemoteNotifications_args(tctx,
+ ctx->iremotewinspool_pipe,
+ &ctx->server_handle,
+ &notify_handle),
+ "failed to test SyncRegisterForRemoteNotifications");
+
+ torture_assert(tctx,
+ test_SyncUnRegisterForRemoteNotifications_args(tctx,
+ ctx->iremotewinspool_pipe,
+ &notify_handle),
+ "failed to test UnSyncRegisterForRemoteNotifications");
+
+ return true;
+}
+
+static bool test_SyncRegisterForRemoteNotifications_args(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *server_handle,
+ struct policy_handle *notify_handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct winspool_SyncRegisterForRemoteNotifications r;
+ struct winspool_PrintPropertiesCollection NotifyFilter;
+ struct winspool_PrintNamedProperty *c;
+ struct spoolss_NotifyOption *options;
+
+ ZERO_STRUCT(NotifyFilter);
+
+ options = setup_printserver_NotifyOption(tctx);
+ torture_assert(tctx, options, "out of memory");
+
+ c = talloc_zero_array(tctx, struct winspool_PrintNamedProperty, 4);
+ torture_assert(tctx, c, "out of memory");
+
+ c[0].propertyName = "RemoteNotifyFilter Flags";
+ c[0].propertyValue.PropertyType = winspool_PropertyTypeInt32;
+ c[0].propertyValue.value.propertyInt32 = 0xff;
+
+ c[1].propertyName = "RemoteNotifyFilter Options";
+ c[1].propertyValue.PropertyType = winspool_PropertyTypeInt32;
+ c[1].propertyValue.value.propertyInt32 = 0;
+
+ c[2].propertyName = "RemoteNotifyFilter Color";
+ c[2].propertyValue.PropertyType = winspool_PropertyTypeInt32;
+ c[2].propertyValue.value.propertyInt32 = 0;
+
+ c[3].propertyName = "RemoteNotifyFilter NotifyOptions";
+ c[3].propertyValue.PropertyType = winspool_PropertyTypeNotificationOptions;
+ c[3].propertyValue.value.propertyOptionsContainer.pOptions = options;
+
+ NotifyFilter.numberOfProperties = 4;
+ NotifyFilter.propertiesCollection = c;
+
+ r.in.hPrinter = *server_handle;
+ r.in.pNotifyFilter = &NotifyFilter;
+ r.out.phRpcHandle = notify_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_SyncRegisterForRemoteNotifications_r(b, tctx, &r),
+ "SyncRegisterForRemoteNotifications failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "SyncRegisterForRemoteNotifications failed");
+
+ return true;
+}
+
+static bool test_SyncRegisterForRemoteNotifications(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+ struct policy_handle notify_handle;
+
+ torture_assert(tctx,
+ test_SyncRegisterForRemoteNotifications_args(tctx,
+ ctx->iremotewinspool_pipe,
+ &ctx->server_handle,
+ &notify_handle),
+ "failed to test SyncRegisterForRemoteNotifications");
+
+ test_SyncUnRegisterForRemoteNotifications_args(tctx, ctx->iremotewinspool_pipe, &notify_handle);
+
+ return true;
+}
+
+static bool test_AsyncUploadPrinterDriverPackage(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct winspool_AsyncUploadPrinterDriverPackage r;
+ uint32_t pcchDestInfPath = 0;
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.pszInfPath = "";
+ r.in.pszEnvironment = "";
+ r.in.dwFlags = 0;
+ r.in.pszDestInfPath = NULL;
+ r.in.pcchDestInfPath = &pcchDestInfPath;
+ r.out.pszDestInfPath = NULL;
+ r.out.pcchDestInfPath = &pcchDestInfPath;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
+ "AsyncUploadPrinterDriverPackage failed");
+ torture_assert_hresult_equal(tctx, r.out.result, HRES_E_INVALIDARG,
+ "AsyncUploadPrinterDriverPackage failed");
+
+ pcchDestInfPath = 260;
+ r.in.pszDestInfPath = talloc_zero(tctx, const char);
+ r.out.pszDestInfPath = talloc_zero(tctx, const char);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
+ "AsyncUploadPrinterDriverPackage failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
+ "AsyncUploadPrinterDriverPackage failed");
+
+ r.in.pszEnvironment = SPOOLSS_ARCHITECTURE_x64;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
+ "AsyncUploadPrinterDriverPackage failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_FILE_NOT_FOUND,
+ "AsyncUploadPrinterDriverPackage failed");
+
+ r.in.pszInfPath = "\\\\mthelena\\print$\\x64\\{BD443844-ED00-4D96-8CAE-95E49492312A}\\prnbrcl1.inf";
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r),
+ "AsyncUploadPrinterDriverPackage failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_FILE_NOT_FOUND,
+ "AsyncUploadPrinterDriverPackage failed");
+
+ return true;
+}
+
+static bool test_AsyncEnumPrinters(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct winspool_AsyncEnumPrinters r;
+ uint32_t levels[] = { 1, 2, /*3,*/ 4, 5 };
+ int i;
+
+ uint32_t needed;
+ uint32_t returned;
+
+ for (i = 0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.Flags = PRINTER_ENUM_LOCAL;
+ r.in.pName = NULL;
+ r.in.Level = levels[i];
+ r.in.cbBuf = 0;
+ r.in.pPrinterEnum = NULL;
+ r.out.pcbNeeded = &needed;
+ r.out.pcReturned = &returned;
+ r.out.pPrinterEnum = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncEnumPrinters_r(b, tctx, &r),
+ "AsyncEnumPrinters failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "AsyncEnumPrinters failed");
+
+ r.in.cbBuf = needed;
+ r.in.pPrinterEnum = talloc_zero_array(tctx, uint8_t, r.in.cbBuf);
+ r.out.pPrinterEnum = r.in.pPrinterEnum;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncEnumPrinters_r(b, tctx, &r),
+ "AsyncEnumPrinters failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AsyncEnumPrinters failed");
+ }
+
+ return true;
+}
+
+static bool test_AsyncGetPrinterData(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ DATA_BLOB blob;
+ const char *s;
+ bool ok;
+
+ uint32_t pType;
+ uint32_t pcbNeeded;
+ uint8_t *pData;
+
+ torture_assert(tctx,
+ test_AsyncGetPrinterData_args(tctx, b, &ctx->server_handle,
+ "MajorVersion",
+ &pType, &pData, &pcbNeeded),
+ "failed to check for MajorVersion");
+
+ torture_assert_int_equal(tctx, pcbNeeded, 4, "pcbNeeded");
+ torture_assert_int_equal(tctx, pType, REG_DWORD, "pType");
+ torture_assert_int_equal(tctx, IVAL(pData, 0), 3, "pData");
+
+ torture_assert(tctx,
+ test_AsyncGetPrinterData_args(tctx, b, &ctx->server_handle,
+ "Architecture",
+ &pType, &pData, &pcbNeeded),
+ "failed to check for Architecture");
+
+ blob = data_blob_const(pData, pcbNeeded);
+
+ torture_assert_int_equal(tctx, pType, REG_SZ, "pType");
+ torture_assert(tctx, pull_reg_sz(tctx, &blob, &s), "");
+ ok = strequal(s, SPOOLSS_ARCHITECTURE_x64) || strequal(s, SPOOLSS_ARCHITECTURE_NT_X86);
+ torture_assert(tctx, ok, "unexpected architecture returned");
+
+ return true;
+}
+
+static bool test_AsyncCorePrinterDriverInstalled(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct winspool_AsyncCorePrinterDriverInstalled r;
+ int32_t pbDriverInstalled;
+ struct GUID guid;
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.pszEnvironment = "";
+ r.in.CoreDriverGUID = GUID_zero();
+ r.in.ftDriverDate = 0;
+ r.in.dwlDriverVersion = 0;
+ r.out.pbDriverInstalled = &pbDriverInstalled;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
+ "AsyncCorePrinterDriverInstalled failed");
+
+ r.in.pszEnvironment = SPOOLSS_ARCHITECTURE_x64;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
+ "unexpected driver installed");
+
+ r.in.CoreDriverGUID = GUID_random();
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
+ "unexpected driver installed");
+
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV, &guid), "");
+
+ r.in.CoreDriverGUID = guid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, true,
+ "xps core driver not installed?");
+
+ r.in.dwlDriverVersion = 0xffffffff;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, true,
+ "xps core driver not installed?");
+
+ r.in.dwlDriverVersion = 1234;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, true,
+ "xps core driver not installed?");
+
+ r.in.ftDriverDate = unix_timespec_to_nt_time(timespec_current());
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
+ "driver too old ?");
+
+ r.in.dwlDriverVersion = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncCorePrinterDriverInstalled_r(b, tctx, &r),
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "AsyncCorePrinterDriverInstalled failed");
+ torture_assert_int_equal(tctx, *r.out.pbDriverInstalled, false,
+ "unexpected driver installed");
+
+ return true;
+}
+
+static bool test_get_core_printer_drivers_arch_guid(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *architecture,
+ const char *guid_str,
+ const char **package_id)
+{
+ struct winspool_AsyncGetCorePrinterDrivers r;
+ DATA_BLOB blob;
+ const char **s;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ s = talloc_zero_array(tctx, const char *, 2);
+ s[0] = guid_str;
+
+ torture_assert(tctx,
+ push_reg_multi_sz(tctx, &blob, s),
+ "push_reg_multi_sz failed");
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.pszEnvironment = architecture;
+ r.in.cchCoreDrivers = blob.length/2;
+ r.in.pszzCoreDriverDependencies = (uint16_t *)blob.data;
+ r.in.cCorePrinterDrivers = 1;
+ r.out.pCorePrinterDrivers = talloc_zero_array(tctx, struct spoolss_CorePrinterDriver, r.in.cCorePrinterDrivers);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncGetCorePrinterDrivers_r(b, tctx, &r),
+ "winspool_AsyncCorePrinterDrivers failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "winspool_AsyncCorePrinterDrivers failed");
+
+ if (package_id) {
+ *package_id = r.out.pCorePrinterDrivers[0].szPackageID;
+ }
+
+ return true;
+}
+
+static bool test_AsyncDeletePrintDriverPackage(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct winspool_AsyncDeletePrinterDriverPackage r;
+
+ const char *architectures[] = {
+/* SPOOLSS_ARCHITECTURE_NT_X86, */
+ SPOOLSS_ARCHITECTURE_x64
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(architectures); i++) {
+
+ const char *package_id;
+
+ torture_assert(tctx,
+ test_get_core_printer_drivers_arch_guid(tctx, p,
+ architectures[i],
+ SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV,
+ &package_id),
+ "failed to get core printer driver");
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.pszEnvironment = "";
+ r.in.pszInfPath = "";
+
+ torture_comment(tctx, "Testing AsyncDeletePrinterDriverPackage(%s, %s, %s)\n",
+ r.in.pszServer, architectures[i], package_id);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r),
+ "AsyncDeletePrinterDriverPackage failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_NOT_FOUND,
+ "AsyncDeletePrinterDriverPackage failed");
+
+ r.in.pszInfPath = package_id;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r),
+ "AsyncDeletePrinterDriverPackage failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
+ "AsyncDeletePrinterDriverPackage failed");
+
+ r.in.pszEnvironment = architectures[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r),
+ "AsyncDeletePrinterDriverPackage failed");
+ torture_assert_hresult_equal(tctx, r.out.result, HRES_E_ACCESSDENIED,
+ "AsyncDeletePrinterDriverPackage failed");
+ }
+
+ return true;
+}
+
+static bool test_AsyncGetPrinterDriverDirectory(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct winspool_AsyncGetPrinterDriverDirectory r;
+ uint32_t pcbNeeded;
+ DATA_BLOB blob;
+ const char *s;
+
+ r.in.pName = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.pEnvironment = ctx->environment;
+ r.in.Level = 1;
+ r.in.cbBuf = 0x200;
+ r.in.pDriverDirectory = talloc_zero_array(tctx, uint8_t, r.in.cbBuf);
+ r.out.pcbNeeded = &pcbNeeded;
+ r.out.pDriverDirectory = r.in.pDriverDirectory;
+
+ torture_comment(tctx, "Testing AsyncGetPrinterDriverDirectory(%s, %s)\n",
+ r.in.pName, r.in.pEnvironment);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winspool_AsyncGetPrinterDriverDirectory_r(b, tctx, &r),
+ "AsyncGetPrinterDriverDirectory failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AsyncGetPrinterDriverDirectory failed");
+
+ blob = data_blob_const(r.out.pDriverDirectory, pcbNeeded);
+
+ torture_assert(tctx,
+ pull_reg_sz(tctx, &blob, &s),
+ "failed to pull reg_sz");
+
+ torture_comment(tctx, "got: %s\n", s);
+
+ return true;
+}
+
+/*
+ * Test if one can close a printserver handle that has been acquired via
+ * winspool_AsyncOpenPrinter with a spoolss_ClosePrinter operation.
+ */
+
+static bool test_OpenPrinter(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ const char *printer_name;
+ struct policy_handle handle;
+ struct dcerpc_pipe *s;
+ struct dcerpc_binding *binding;
+ struct spoolss_UserLevel1 client_info;
+ struct spoolss_ClosePrinter r;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "failed to get binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_transport(binding, NCACN_NP),
+ "failed to set ncacn_np transport");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_object(binding, GUID_zero()),
+ "failed to set object uuid to zero");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection_with_binding(tctx, binding, &s, &ndr_table_spoolss),
+ "failed to connect to spoolss");
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ client_info = test_get_client_info(tctx, WIN_7, 6, 1, "testclient_machine", "testclient_user");
+
+ torture_assert(tctx,
+ test_AsyncOpenPrinter_byprinter(tctx, ctx, p, printer_name, client_info, &handle),
+ "failed to open printserver via winspool");
+
+
+ r.in.handle = &handle;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_spoolss_ClosePrinter_r(s->binding_handle, tctx, &r),
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "ClosePrinter failed");
+
+ talloc_free(s);
+
+ return true;
+}
+
+static bool test_object_one_uuid(struct torture_context *tctx,
+ const struct GUID *object_uuid,
+ NTSTATUS expected_status,
+ uint32_t expected_fault_code)
+{
+ const char *printer_name;
+ struct spoolss_UserLevel1 client_info;
+ struct dcerpc_binding *binding;
+ struct dcerpc_pipe *p;
+ struct policy_handle server_handle;
+
+ torture_comment(tctx, "Testing with object_uuid: %s\n",
+ GUID_string(tctx, object_uuid));
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "failed to retrieve torture binding");
+
+ if (object_uuid) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_object(binding, *object_uuid),
+ "failed to set object_uuid");
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection_with_binding(tctx, binding, &p,
+ &ndr_table_iremotewinspool),
+ "Error connecting to server");
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_assert(tctx, printer_name, "out of memory");
+
+ client_info = test_get_client_info(tctx,
+ WIN_7, 6, 1, "testclient_machine", "testclient_user");
+
+ torture_assert(tctx,
+ test_AsyncOpenPrinter_byprinter_expect(tctx, NULL,
+ p,
+ printer_name,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ client_info,
+ expected_status,
+ WERR_OK,
+ expected_fault_code,
+ &server_handle),
+ "failed to open printserver");
+ if (NT_STATUS_IS_OK(expected_status)) {
+ test_AsyncClosePrinter_byhandle(tctx, NULL, p, &server_handle);
+ }
+
+ talloc_free(p);
+
+ return true;
+}
+
+static bool test_object_uuid(struct torture_context *tctx,
+ void *private_data)
+{
+ struct GUID object_uuid;
+
+ torture_assert(tctx,
+ test_object_one_uuid(tctx, NULL,
+ NT_STATUS_RPC_NOT_RPC_ERROR,
+ DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ "failed to test NULL object uuid");
+
+ object_uuid = GUID_zero();
+ torture_assert(tctx,
+ test_object_one_uuid(tctx, &object_uuid,
+ NT_STATUS_RPC_NOT_RPC_ERROR,
+ DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ "failed to test zeroed object uuid");
+
+ object_uuid = GUID_random();
+ torture_assert(tctx,
+ test_object_one_uuid(tctx, &object_uuid,
+ NT_STATUS_RPC_NOT_RPC_ERROR,
+ DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ "failed to test random object uuid");
+
+ GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &object_uuid);
+ torture_assert(tctx,
+ test_object_one_uuid(tctx, &object_uuid,
+ NT_STATUS_OK,
+ 0),
+ "failed to test IREMOTEWINSPOOL_OBJECT_GUID");
+
+ torture_assert(tctx,
+ test_object_one_uuid(tctx, &ndr_table_spoolss.syntax_id.uuid,
+ NT_STATUS_RPC_NOT_RPC_ERROR,
+ DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ "failed to test spoolss interface uuid");
+
+ torture_assert(tctx,
+ test_object_one_uuid(tctx, &ndr_table_iremotewinspool.syntax_id.uuid,
+ NT_STATUS_RPC_NOT_RPC_ERROR,
+ DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ "failed to test iremotewinspool interface uuid");
+
+ return true;
+}
+
+static bool test_setup_binding_handle(struct torture_context *tctx,
+ struct GUID object_uuid,
+ enum dcerpc_transport_t transport,
+ const struct ndr_interface_table *table,
+ struct dcerpc_pipe **p)
+{
+ struct dcerpc_binding *binding;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "failed to retrieve torture binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_object(binding, object_uuid),
+ "failed to set object_uuid");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_transport(binding, transport),
+ "failed to set transport");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection_with_binding(tctx, binding, p, table),
+ "Error connecting to server");
+
+ return true;
+}
+
+static enum ndr_err_code ndr_push_inout_blob(DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ ndr_flags_type flags,
+ const void *p,
+ ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK_FREE(fn(ndr, flags, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
+}
+
+static bool test_compare_spoolss(struct torture_context *tctx,
+ void *private_data)
+{
+ DATA_BLOB reply_iremotewinspool, reply_spoolss, request_spoolss;
+ struct dcerpc_pipe *iremotewinspool_pipe, *spoolss_pipe;
+ struct GUID object_uuid;
+ uint32_t out_flags;
+ NTSTATUS status;
+ struct spoolss_EnumPrinters r;
+ DATA_BLOB blob;
+
+ /* setup two dcerpc pipes */
+
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &object_uuid),
+ "failed to parse GUID");
+
+ torture_assert(tctx,
+ test_setup_binding_handle(tctx, object_uuid, NCACN_IP_TCP,
+ &ndr_table_iremotewinspool, &iremotewinspool_pipe),
+ "failed to setup binding handle");
+
+ torture_assert(tctx,
+ test_setup_binding_handle(tctx, GUID_zero(), NCACN_NP,
+ &ndr_table_spoolss, &spoolss_pipe),
+ "failed to setup binding handle");
+
+
+ /* create a spoolss enumprinters request */
+
+ ZERO_STRUCT(r);
+
+ blob = data_blob_talloc_zero(tctx, 0x1000);
+
+ r.in.flags = PRINTER_ENUM_LOCAL;
+ r.in.server = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(spoolss_pipe));
+ r.in.level = 1;
+ r.in.buffer = &blob;
+ r.in.offered = blob.length;
+
+ torture_assert_ndr_success(tctx,
+ ndr_push_inout_blob(&request_spoolss, tctx, NDR_IN | NDR_SET_VALUES, &r,
+ (ndr_push_flags_fn_t)ndr_push_spoolss_EnumPrinters),
+ "failed to push EnumPrinters request");
+
+ /* send same request to both endpoints */
+
+ status = dcerpc_binding_handle_raw_call(iremotewinspool_pipe->binding_handle,
+ NULL,
+ NDR_WINSPOOL_ASYNCENUMPRINTERS,
+ 0, /* in_flags */
+ request_spoolss.data,
+ request_spoolss.length,
+ tctx,
+ &reply_iremotewinspool.data,
+ &reply_iremotewinspool.length,
+ &out_flags);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_binding_handle_raw_call failed");
+
+ status = dcerpc_binding_handle_raw_call(spoolss_pipe->binding_handle,
+ NULL,
+ NDR_SPOOLSS_ENUMPRINTERS,
+ 0, /* in_flags */
+ request_spoolss.data,
+ request_spoolss.length,
+ tctx,
+ &reply_spoolss.data,
+ &reply_spoolss.length,
+ &out_flags);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_binding_handle_raw_call failed");
+
+ torture_assert_data_blob_equal(tctx,
+ reply_iremotewinspool,
+ reply_spoolss,
+ "unexpected difference in replies from spoolss and iremotewinspool servers");
+
+ talloc_free(iremotewinspool_pipe);
+ talloc_free(spoolss_pipe);
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_iremotewinspool(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "iremotewinspool");
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "printserver");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_iremotewinspool_setup,
+ torture_rpc_iremotewinspool_teardown);
+
+ torture_tcase_add_simple_test(tcase, "AsyncOpenPrinter", test_AsyncOpenPrinter);
+ torture_tcase_add_simple_test(tcase, "SyncRegisterForRemoteNotifications", test_SyncRegisterForRemoteNotifications);
+ torture_tcase_add_simple_test(tcase, "SyncUnRegisterForRemoteNotifications", test_SyncUnRegisterForRemoteNotifications);
+ torture_tcase_add_simple_test(tcase, "AsyncClosePrinter", test_AsyncClosePrinter);
+ torture_tcase_add_simple_test(tcase, "AsyncUploadPrinterDriverPackage", test_AsyncUploadPrinterDriverPackage);
+ torture_tcase_add_simple_test(tcase, "AsyncEnumPrinters", test_AsyncEnumPrinters);
+ torture_tcase_add_simple_test(tcase, "AsyncGetPrinterData", test_AsyncGetPrinterData);
+ torture_tcase_add_simple_test(tcase, "AsyncCorePrinterDriverInstalled", test_AsyncCorePrinterDriverInstalled);
+ torture_tcase_add_simple_test(tcase, "AsyncDeletePrintDriverPackage", test_AsyncDeletePrintDriverPackage);
+ torture_tcase_add_simple_test(tcase, "AsyncGetPrinterDriverDirectory", test_AsyncGetPrinterDriverDirectory);
+ torture_tcase_add_simple_test(tcase, "AsyncOpenPrinterValidateBuildNumber", test_AsyncOpenPrinterValidateBuildNumber);
+
+ tcase = torture_suite_add_tcase(suite, "handles");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_iremotewinspool_setup,
+ torture_rpc_iremotewinspool_teardown);
+
+ torture_tcase_add_simple_test(tcase, "OpenPrinter", test_OpenPrinter);
+
+ tcase = torture_suite_add_tcase(suite, "protocol");
+ torture_tcase_add_simple_test(tcase, "object_uuid", test_object_uuid);
+ torture_tcase_add_simple_test(tcase, "compare_spoolss", test_compare_spoolss);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/iremotewinspool_common.c b/source4/torture/rpc/iremotewinspool_common.c
new file mode 100644
index 0000000..d4dd19a
--- /dev/null
+++ b/source4/torture/rpc/iremotewinspool_common.c
@@ -0,0 +1,269 @@
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_winspool.h"
+#include "librpc/gen_ndr/ndr_winspool_c.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/registry/util_reg.h"
+#include "torture/rpc/iremotewinspool_common.h"
+#include "lib/printer_driver/printer_driver.h"
+
+void init_winreg_String(struct winreg_String *name, const char *s)
+{
+ name->name = s;
+ if (s != NULL) {
+ name->name_len = 2 * (strlen_m(s) + 1);
+ name->name_size = name->name_len;
+ } else {
+ name->name_len = 0;
+ name->name_size = 0;
+ }
+}
+
+struct spoolss_UserLevel1 test_get_client_info(struct torture_context *tctx,
+ enum client_os_version os,
+ enum spoolss_MajorVersion major_number,
+ enum spoolss_MinorVersion minor_number,
+ const char *machine,
+ const char *user)
+{
+ struct spoolss_UserLevel1 level1;
+
+ level1.size = 28;
+ level1.client = talloc_asprintf(tctx, "\\\\%s", machine);
+ level1.user = user;
+ level1.processor = PROCESSOR_ARCHITECTURE_AMD64;
+ level1.major = major_number;
+ level1.minor = minor_number;
+
+ if (os == WIN_SERVER_2016 || os == WIN_10) {
+ level1.build = 10586;
+ } else if (os == WIN_SERVER_2012 || os == WIN_8) {
+ level1.build = 9200;
+ } else if (os == WIN_SERVER_2008R2 || os == WIN_7) {
+ level1.build = 7007;
+ } else if (os == WIN_SERVER_2008 || os == WIN_VISTA) {
+ level1.build = 6000;
+ } else if (os == WIN_2000) {
+ level1.build = 1382;
+ }
+
+ return level1;
+}
+
+bool test_AsyncOpenPrinter_byprinter_expect(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx,
+ struct dcerpc_pipe *p,
+ const char *printer_name,
+ uint32_t access_mask,
+ struct spoolss_UserLevel1 cinfo,
+ NTSTATUS expected_status,
+ WERROR expected_result,
+ uint32_t expected_fault_code,
+ struct policy_handle *handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct spoolss_UserLevelCtr client_info_ctr;
+ struct winspool_AsyncOpenPrinter r;
+ NTSTATUS status;
+ bool ok = true;
+
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(devmode_ctr);
+
+ client_info_ctr.level = 1;
+ client_info_ctr.user_info.level1 = &cinfo;
+
+ r.in.pPrinterName = printer_name;
+ r.in.pDatatype = NULL;
+ r.in.pDevModeContainer = &devmode_ctr;
+ r.in.AccessRequired = access_mask;
+ r.in.pClientInfo = &client_info_ctr;
+ r.out.pHandle = handle;
+
+ status = dcerpc_winspool_AsyncOpenPrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_equal(tctx, status, expected_status, "AsyncOpenPrinter failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "AsyncOpenPrinter failed");
+ torture_assert_u32_equal(tctx, p->last_fault_code, expected_fault_code,
+ "unexpected DCERPC fault code");
+
+ return ok;
+}
+
+bool test_AsyncOpenPrinter_byprinter(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx,
+ struct dcerpc_pipe *p,
+ const char *printer_name,
+ struct spoolss_UserLevel1 cinfo,
+ struct policy_handle *handle)
+{
+ return test_AsyncOpenPrinter_byprinter_expect(tctx,
+ ctx,
+ p,
+ printer_name,
+ SERVER_ALL_ACCESS,
+ cinfo,
+ NT_STATUS_OK,
+ WERR_OK,
+ 0,
+ handle);
+}
+
+bool test_get_environment(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char **architecture)
+{
+ DATA_BLOB blob;
+ enum winreg_Type type;
+ uint8_t *data;
+ uint32_t needed;
+ bool ok;
+
+ ok = test_AsyncGetPrinterData_args(tctx, b, handle, "Architecture", &type, &data, &needed);
+ torture_assert(tctx, ok, "failed to get Architecture");
+
+ torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");
+
+ blob = data_blob_const(data, needed);
+
+ torture_assert(tctx,
+ pull_reg_sz(tctx, &blob, architecture),
+ "failed to pull environment");
+
+ return true;
+}
+
+bool test_AsyncClosePrinter_byhandle(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct winspool_AsyncClosePrinter r;
+ NTSTATUS status;
+ bool ok = true;
+
+ r.in.phPrinter = handle;
+ r.out.phPrinter = handle;
+
+ status = dcerpc_winspool_AsyncClosePrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncClosePrinter failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AsyncClosePrinter failed");
+
+done:
+
+ return ok;
+}
+
+static bool test_AsyncGetPrinterData_checktype(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type *expected_type,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p)
+{
+ struct winspool_AsyncGetPrinterData r;
+ enum winreg_Type type;
+ uint32_t needed;
+ NTSTATUS status;
+ bool ok = true;
+
+ r.in.hPrinter = *handle;
+ r.in.pValueName = value_name;
+ r.in.nSize = 0;
+ r.out.pType = &type;
+ r.out.pData = talloc_zero_array(tctx, uint8_t, r.in.nSize);
+ r.out.pcbNeeded = &needed;
+
+ torture_comment(tctx, "Testing AsyncGetPrinterData(%s)\n",
+ r.in.pValueName);
+
+ status = dcerpc_winspool_AsyncGetPrinterData_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncGetPrinterData failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ if (expected_type) {
+ torture_assert_int_equal(tctx, type, *expected_type, "unexpected type");
+ }
+ r.in.nSize = needed;
+ r.out.pData = talloc_zero_array(tctx, uint8_t, r.in.nSize);
+
+ status = dcerpc_winspool_AsyncGetPrinterData_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncGetPrinterData failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AsyncGetPrinterData failed");
+
+ if (type_p) {
+ *type_p = type;
+ }
+
+ if (data_p) {
+ *data_p = r.out.pData;
+ }
+
+ if (needed_p) {
+ *needed_p = needed;
+ }
+
+done:
+
+ return ok;
+}
+
+bool test_AsyncGetPrinterData_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p)
+{
+ return test_AsyncGetPrinterData_checktype(tctx, b, handle,
+ value_name,
+ NULL,
+ type_p, data_p, needed_p);
+}
+
+/* Parse a driver inf file */
+bool parse_inf_driver(struct torture_context *tctx,
+ const char *driver_name,
+ const char *abs_inf_path,
+ const char *driver_arch,
+ const char *core_driver_inf,
+ struct spoolss_AddDriverInfo8 **_parsed_dinfo)
+{
+ struct spoolss_AddDriverInfo8 *drv_info;
+ const char *source_disk_name = NULL;
+ NTSTATUS status;
+ bool ok = true;
+
+ drv_info = talloc_zero(tctx, struct spoolss_AddDriverInfo8);
+ torture_assert_not_null_goto(tctx, drv_info, ok, done, "Cannot allocate memory");
+
+ status = driver_inf_parse(tctx,
+ core_driver_inf,
+ abs_inf_path,
+ driver_arch,
+ driver_name,
+ drv_info,
+ &source_disk_name);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_DRIVER_INTERNAL_ERROR)) {
+ torture_comment(tctx, "--- Verify the correct torture option:driver_name is provided\n");
+ }
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Failed to parse driver inf\n");
+
+ *_parsed_dinfo = drv_info;
+done:
+ return ok;
+}
diff --git a/source4/torture/rpc/iremotewinspool_common.h b/source4/torture/rpc/iremotewinspool_common.h
new file mode 100644
index 0000000..5887416
--- /dev/null
+++ b/source4/torture/rpc/iremotewinspool_common.h
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ iremotewinspool rpc test operations
+
+ Copyright (C) 2018 Justin Stephenson
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "torture/rpc/torture_rpc.h"
+
+#define REG_DRIVER_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print"
+
+struct test_driver_info {
+ struct smbcli_state *cli;
+ struct spoolss_AddDriverInfo8 *info;
+ const char *local_driver_path;
+ size_t driver_path_len;
+ char *server_name;
+ char *share_name;
+ char *print_upload_guid_dir;
+ const char *inf_file;
+ const char *uploaded_inf_path;
+ const char *driver_name;
+ const char *driver_arch;
+ const char *core_driver_inf;
+};
+
+struct test_iremotewinspool_context {
+ struct GUID object_uuid;
+ struct dcerpc_pipe *iremotewinspool_pipe;
+ struct policy_handle server_handle;
+ struct test_driver_info *dinfo;
+ const char *environment;
+};
+
+enum client_os_version
+{
+ WIN_2000,
+ WIN_VISTA,
+ WIN_SERVER_2008,
+ WIN_7,
+ WIN_SERVER_2008R2,
+ WIN_8,
+ WIN_SERVER_2012,
+ WIN_10,
+ WIN_SERVER_2016
+};
+
+void init_winreg_String(struct winreg_String *name, const char *s);
+
+struct spoolss_UserLevel1 test_get_client_info(struct torture_context *tctx,
+ enum client_os_version os,
+ enum spoolss_MajorVersion major_number,
+ enum spoolss_MinorVersion minor_number,
+ const char *machine,
+ const char *user);
+
+bool test_AsyncOpenPrinter_byprinter(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx,
+ struct dcerpc_pipe *p,
+ const char *printer_name,
+ struct spoolss_UserLevel1 cinfo,
+ struct policy_handle *handle);
+bool test_AsyncOpenPrinter_byprinter_expect(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx,
+ struct dcerpc_pipe *p,
+ const char *printer_name,
+ uint32_t access_mask,
+ struct spoolss_UserLevel1 cinfo,
+ NTSTATUS exected_status,
+ WERROR exected_result,
+ uint32_t expected_fault_code,
+ struct policy_handle *handle);
+bool test_get_environment(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char **architecture);
+
+bool test_AsyncClosePrinter_byhandle(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle);
+
+bool test_AsyncGetPrinterData_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p);
+
+bool parse_inf_driver(struct torture_context *tctx,
+ const char *driver_name,
+ const char *abs_inf_path,
+ const char *driver_arch,
+ const char *core_driver_inf,
+ struct spoolss_AddDriverInfo8 **_parsed_dinfo);
diff --git a/source4/torture/rpc/iremotewinspool_driver.c b/source4/torture/rpc/iremotewinspool_driver.c
new file mode 100644
index 0000000..4e558ef
--- /dev/null
+++ b/source4/torture/rpc/iremotewinspool_driver.c
@@ -0,0 +1,840 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for iremotewinspool driver rpc operations
+
+ Copyright (C) Justin Stephenson 2018
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <dirent.h>
+#include <talloc.h>
+#include <libgen.h>
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_winspool.h"
+#include "librpc/gen_ndr/ndr_winspool_c.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "librpc/gen_ndr/ndr_winreg_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/registry/util_reg.h"
+#include "torture/rpc/iremotewinspool_common.h"
+#include "libcli/libcli.h"
+#include "param/param.h"
+#include "lib/registry/registry.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "lib/cmdline/cmdline.h"
+#include "system/filesys.h"
+#include "lib/util/tftw.h"
+
+/* Connect to print driver share //server_name/share */
+static bool smb_connect_print_share(struct torture_context *tctx,
+ const char *server_name,
+ const char *share_name,
+ struct smbcli_state **cli)
+{
+ NTSTATUS status;
+ bool ok = true;
+
+ struct smbcli_options smb_options;
+ struct smbcli_session_options smb_session_options;
+
+ torture_comment(tctx, "Connecting to printer driver share '//%s/%s'\n",
+ server_name, share_name);
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &smb_options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &smb_session_options);
+
+ /* On Windows, SMB1 must be enabled! */
+ status = smbcli_full_connection(tctx, cli, server_name,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share_name, NULL,
+ lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev,
+ &smb_options,
+ &smb_session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Failed to connect to print$ share");
+
+done:
+
+ return ok;
+}
+
+/* Copy file to destination where dst_fpath is a smb share path,
+ * files are either created or overwritten */
+static bool smb_copy_files(TALLOC_CTX *tctx,
+ const char *fpath,
+ const char *dst_fpath,
+ struct test_driver_info *dinfo)
+{
+ FILE *fp;
+ int smbfp = 0;
+ char *buffer = NULL;
+ int maxwrite = 64512;
+ size_t nread;
+ ssize_t nwrote;
+ bool ok = true;
+ size_t total_read;
+
+ fp = fopen(fpath, "r");
+ torture_assert_goto(tctx, fp, ok, done, "Failed to open local file\n");
+
+ smbfp = smbcli_open(dinfo->cli->tree, dst_fpath, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+ torture_assert_int_not_equal_goto(tctx, smbfp, -1, ok, done, "Failed to open dst file\n");
+
+ buffer = talloc_array(tctx, char, maxwrite);
+ torture_assert_not_null_goto(tctx, buffer, ok, done, "Failed to allocate buffer\n");
+
+ total_read = 0;
+
+ while (!feof(fp)) {
+ nread = fread(buffer, 1, maxwrite, fp);
+ if (ferror(fp)) {
+ torture_warning(tctx, "Error reading file [%s]\n", fpath);
+ continue;
+ }
+
+ nwrote = smbcli_write(dinfo->cli->tree, smbfp, 0, buffer, total_read, nread);
+ if (nwrote != nread) {
+ torture_warning(tctx, "Not all data in stream written!\n");
+ }
+
+ total_read += nread;
+ }
+
+ fclose(fp);
+ smbcli_close(dinfo->cli->tree, smbfp);
+done:
+
+ TALLOC_FREE(buffer);
+ return ok;
+}
+
+/* Callback function provided to tftw() to
+ * copy driver files to smb share */
+static int copy_driver_files(TALLOC_CTX *tctx,
+ const char *fpath,
+ const struct stat *sb,
+ enum tftw_flags_e flag,
+ void *userdata)
+{
+ char *dst_fpath = NULL;
+ struct test_driver_info *dinfo = userdata;
+ char *path = NULL;
+ NTSTATUS status;
+ bool ok = true;
+
+ path = talloc_strdup(tctx, fpath + dinfo->driver_path_len);
+ torture_assert_not_null_goto(tctx, path, ok, done, "Cannot allocate memory");
+
+ string_replace(path, '/', '\\');
+
+ dst_fpath = talloc_asprintf(tctx, "%s%s", dinfo->print_upload_guid_dir, path);
+ torture_assert_not_null_goto(tctx, dst_fpath, ok, done, "Cannot allocate memory");
+
+ switch (flag) {
+ case TFTW_FLAG_FILE:
+ ok = smb_copy_files(tctx, fpath, dst_fpath, dinfo);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to copy files over smb");
+ break;
+ case TFTW_FLAG_DIR:
+ status = smbcli_mkdir(dinfo->cli->tree, dst_fpath);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Failed to create directories");
+ break;
+ case TFTW_FLAG_SLINK:
+ case TFTW_FLAG_DNR:
+ case TFTW_FLAG_NSTAT:
+ case TFTW_FLAG_SPEC:
+ case TFTW_FLAG_DP:
+ case TFTW_FLAG_SLN:
+ torture_warning(tctx, "WARN: Unhandled typeflag [%s]\n", fpath);
+ break;
+ }
+
+done:
+ TALLOC_FREE(path);
+ TALLOC_FREE(dst_fpath);
+
+ if (ok == true) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static bool test_get_driver_torture_options(struct torture_context *tctx,
+ const char **_local_driver_path,
+ const char **_inf_file,
+ const char **_driver_name,
+ const char **_driver_arch,
+ const char **_core_driver_inf)
+{
+ const char *local_driver_path = NULL;
+ const char *inf_file = NULL;
+ const char *driver_name = NULL;
+ const char *driver_arch = NULL;
+ const char *core_driver_inf = NULL;
+ const char *arches_list[] = {
+ SPOOLSS_ARCHITECTURE_x64,
+ SPOOLSS_ARCHITECTURE_NT_X86,
+ SPOOLSS_ARCHITECTURE_IA_64,
+ SPOOLSS_ARCHITECTURE_ARM,
+ SPOOLSS_ARCHITECTURE_4_0,
+ NULL,
+ };
+ const char **p;
+ bool valid = false;
+ bool ok = true;
+
+ local_driver_path = torture_setting_string(tctx, "driver_path", NULL);
+ if (local_driver_path == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:driver_path="
+ "/full/path/to/local/driver/dir\n");
+ }
+
+ inf_file = torture_setting_string(tctx, "inf_file", NULL);
+ if (inf_file == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:inf_file="
+ "filename.inf\n");
+ }
+
+ driver_name = torture_setting_string(tctx, "driver_name", NULL);
+ if (driver_name == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:driver_name="
+ "driver name\n");
+ }
+
+ driver_arch = torture_setting_string(tctx, "driver_arch", NULL);
+ if (driver_arch == NULL) {
+ torture_fail(tctx,
+ "option --option=torture:driver_arch="
+ "driver arch\n");
+ }
+
+ core_driver_inf = torture_setting_string(tctx, "core_driver_inf", NULL);
+
+ for (p = arches_list; *p != NULL; p++) {
+ if (strequal(*p, driver_arch) == 0) {
+ valid = true;
+ break;
+ }
+ }
+ torture_assert_goto(tctx, valid, ok, done, "Invalid driver arch provided");
+
+ *_local_driver_path = local_driver_path;
+ *_inf_file = inf_file;
+ *_driver_name = driver_name;
+ *_driver_arch = driver_arch;
+ *_core_driver_inf = core_driver_inf;
+done:
+ return ok;
+}
+
+
+static bool test_get_misc_driver_info(struct torture_context *tctx,
+ struct test_driver_info *dinfo,
+ const char **_abs_inf_path,
+ size_t *_driver_path_len)
+{
+ const char *abs_inf_path;
+ size_t driver_path_len;
+ bool ok = true;
+
+ driver_path_len = strlen(dinfo->local_driver_path);
+ torture_assert_int_not_equal_goto(tctx, driver_path_len, 0, ok, done, "driver path length is 0");
+
+ abs_inf_path = talloc_asprintf(tctx, "%s/%s", dinfo->local_driver_path, dinfo->inf_file);
+ torture_assert_not_null_goto(tctx, abs_inf_path, ok, done, "Cannot allocate memory");
+
+ *_abs_inf_path = abs_inf_path;
+ *_driver_path_len = driver_path_len;
+done:
+
+ return ok;
+}
+
+/* Uninstall the previously installed print driver */
+static bool test_uninstall_printer_driver(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx)
+{
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct winspool_AsyncDeletePrinterDriverEx r;
+ bool ok = true;
+ NTSTATUS status;
+
+ r.in.pName = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ r.in.pDriverName = talloc_strdup(tctx, ctx->dinfo->driver_name);
+ torture_assert_not_null_goto(tctx, r.in.pDriverName, ok, done, "Cannot allocate memory");
+
+ r.in.pEnvironment = SPOOLSS_ARCHITECTURE_x64;
+
+ r.in.dwDeleteFlag = 0;
+ r.in.dwVersionNum = 0;
+
+ status = dcerpc_winspool_AsyncDeletePrinterDriverEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncDeletePrinterDriverEx failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "AsyncDeletePrinterDriverEx failed");
+done:
+
+ return ok;
+}
+
+/* Remove the leftover print driver package files from the driver store */
+static bool test_remove_driver_package(struct torture_context *tctx,
+ struct test_iremotewinspool_context *ctx)
+{
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct winspool_AsyncDeletePrinterDriverPackage r;
+ bool ok = true;
+ NTSTATUS status;
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_assert_not_null_goto(tctx, r.in.pszServer, ok, done, "Cannot allocate memory");
+
+ r.in.pszInfPath = ctx->dinfo->uploaded_inf_path;
+
+ r.in.pszEnvironment = SPOOLSS_ARCHITECTURE_x64;
+
+ status = dcerpc_winspool_AsyncDeletePrinterDriverPackage_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncDeletePrinterPackage failed");
+
+ torture_assert_hresult_ok(tctx, r.out.result, "AsyncDeletePrinterDriverPackage failed");
+done:
+
+ return ok;
+}
+
+static bool test_winreg_iremotewinspool_openhklm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *winreg_bh,
+ struct policy_handle *_hklm_handle)
+{
+ struct winreg_OpenHKLM r;
+ NTSTATUS status;
+ bool ok = true;
+
+ r.in.system_name = NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = _hklm_handle;
+
+ status = dcerpc_winreg_OpenHKLM_r(winreg_bh, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Failed to Open HKLM");
+
+ torture_assert_werr_ok(tctx, r.out.result, "Failed to Open HKLM");
+done:
+
+ return ok;
+}
+
+static bool test_winreg_iremotewinspool_openkey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *winreg_bh,
+ struct policy_handle *hklm_handle,
+ const char *keyname,
+ struct policy_handle *_key_handle)
+{
+ struct winreg_OpenKey r;
+ NTSTATUS status;
+ bool ok = true;
+
+ r.in.parent_handle = hklm_handle;
+ init_winreg_String(&r.in.keyname, keyname);
+ r.in.options = REG_OPTION_NON_VOLATILE;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = _key_handle;
+
+ status = dcerpc_winreg_OpenKey_r(winreg_bh, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "OpenKey failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
+done:
+
+ return ok;
+}
+
+static bool test_winreg_iremotewinspool_queryvalue(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *key_handle,
+ const char *value_name,
+ const char **_valuestr)
+{
+ struct winreg_QueryValue r;
+ enum winreg_Type type = REG_NONE;
+ struct winreg_String valuename;
+ DATA_BLOB blob;
+ const char *str;
+ uint32_t data_size = 0;
+ uint32_t data_length = 0;
+ uint8_t *data = NULL;
+ NTSTATUS status;
+ bool ok = true;
+
+ init_winreg_String(&valuename, value_name);
+
+ data = talloc_zero_array(tctx, uint8_t, 0);
+
+ r.in.handle = key_handle;
+ r.in.value_name = &valuename;
+ r.in.type = &type;
+ r.in.data_size = &data_size;
+ r.in.data_length = &data_length;
+ r.in.data = data;
+
+ r.out.type = &type;
+ r.out.data = data;
+ r.out.data_size = &data_size;
+ r.out.data_length = &data_length;
+
+ status = dcerpc_winreg_QueryValue_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "winreg_QueryValue failure");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ *r.in.data_size = *r.out.data_size;
+ data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
+ r.in.data = data;
+ r.out.data = data;
+ status = dcerpc_winreg_QueryValue_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "QueryValue failed");
+ }
+ torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
+
+ torture_assert_int_equal_goto(tctx, *r.out.type, REG_SZ, ok, done, "unexpected type");
+ blob = data_blob(r.out.data, *r.out.data_size);
+ str = reg_val_data_string(tctx, REG_SZ, blob);
+
+ *_valuestr = str;
+done:
+
+ return ok;
+}
+
+/* Validate the installed driver subkey exists, and the InfPath
+ * value matches the pszDestInfPath from test_UploadPrinterDriverPackage */
+static bool test_winreg_validate_driver(struct torture_context *tctx,
+ struct dcerpc_pipe *winreg_pipe,
+ struct test_driver_info *dinfo)
+{
+ struct policy_handle hklm_handle;
+ struct policy_handle key_handle;
+ char *driver_key = NULL;
+ const char *val_name = NULL;
+ const char *val_str = NULL;
+ bool ok = true;
+
+ struct dcerpc_binding_handle *winreg_bh;
+ struct spoolss_AddDriverInfo8 *parsed_dinfo;
+
+ winreg_bh = winreg_pipe->binding_handle;
+ parsed_dinfo = dinfo->info;
+
+ /* OpenHKLM */
+ ok = test_winreg_iremotewinspool_openhklm(tctx, winreg_bh, &hklm_handle);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to perform winreg OpenHKLM");
+
+ /* Open registry subkey for the installed print driver */
+ driver_key = talloc_asprintf(tctx, "%s\\Environments\\%s\\Drivers\\Version-%d\\%s",
+ REG_DRIVER_CONTROL_KEY,
+ parsed_dinfo->architecture,
+ parsed_dinfo->version,
+ parsed_dinfo->driver_name);
+ torture_assert_not_null_goto(tctx, driver_key, ok, done, "Cannot allocate driver_key string");
+ ok = test_winreg_iremotewinspool_openkey(tctx, winreg_bh, &hklm_handle,
+ driver_key,
+ &key_handle);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to perform winreg OpenKey");
+
+ /* Read infpath value and validate this matches what was uploaded */
+ val_name = "InfPath";
+ ok = test_winreg_iremotewinspool_queryvalue(tctx, winreg_bh, &key_handle, val_name,
+ &val_str);
+ torture_assert_goto(tctx, ok, ok, done, "QueryValue failed");
+
+ torture_assert_casestr_equal(tctx, val_str,
+ dinfo->uploaded_inf_path,
+ "InfPath does not match uploaded inf");
+done:
+
+ return ok;
+}
+
+static bool test_init_iremotewinspool_conn(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ struct dcerpc_binding *binding = {0};
+ bool ok = true;
+ NTSTATUS status;
+
+ status = GUID_from_string(IREMOTEWINSPOOL_OBJECT_GUID, &t->object_uuid);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "failed to parse GUID");
+
+ status = torture_rpc_binding(tctx, &binding);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "failed to retrieve torture binding");
+
+ status = dcerpc_binding_set_object(binding, t->object_uuid);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "failed to set object_uuid");
+
+ status = torture_rpc_connection_with_binding(tctx, binding, &t->iremotewinspool_pipe,
+ &ndr_table_iremotewinspool);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Error connecting to server");
+
+done:
+
+ return ok;
+
+}
+
+static bool test_init_iremotewinspool_openprinter(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ struct spoolss_UserLevel1 client_info = {0};
+ char *printer_name = NULL;
+ bool ok = true;
+
+ printer_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(t->iremotewinspool_pipe));
+ torture_assert_not_null_goto(tctx, printer_name, ok, done, "Cannot allocate memory");
+
+ client_info = test_get_client_info(tctx, WIN_7, 3, SPOOLSS_MINOR_VERSION_0,
+ "testclient_machine", "testclient_user");
+
+ ok = test_AsyncOpenPrinter_byprinter(tctx, t, t->iremotewinspool_pipe, printer_name,
+ client_info, &t->server_handle);
+ torture_assert_goto(tctx, ok, ok, done, "failed to open printserver");
+
+ ok = test_get_environment(tctx, t->iremotewinspool_pipe->binding_handle,
+ &t->server_handle, &t->environment);
+ torture_assert_goto(tctx, ok, ok, done, "failed to get environment");
+
+done:
+ TALLOC_FREE(printer_name);
+
+ return ok;
+}
+
+static bool test_init_driver_info(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ bool ok = true;
+ const char *abs_inf_path;
+ struct test_driver_info *drv_info = {0};
+
+ drv_info = talloc_zero(tctx, struct test_driver_info);
+ torture_assert_not_null_goto(tctx, drv_info, ok, done, "Cannot allocate memory");
+
+ t->dinfo = drv_info;
+
+ ok = test_get_driver_torture_options(tctx,
+ &drv_info->local_driver_path,
+ &drv_info->inf_file,
+ &drv_info->driver_name,
+ &drv_info->driver_arch,
+ &drv_info->core_driver_inf);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to get driver torture options");
+
+ ok = test_get_misc_driver_info(tctx, drv_info,
+ &abs_inf_path,
+ &drv_info->driver_path_len);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to get misc driver info");
+
+ ok = parse_inf_driver(tctx, drv_info->driver_name, abs_inf_path, drv_info->driver_arch,
+ drv_info->core_driver_inf, &drv_info->info);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to parse inf driver");
+
+ /* Ensure that we are trying to install the correct device class:
+ * https://docs.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors
+ */
+ if (!(drv_info->info->printer_driver_attributes & PRINTER_DRIVER_CLASS)) {
+ ok = false;
+ torture_fail_goto(tctx, done, "Inf file Class value must be Printer");
+ }
+done:
+ return ok;
+
+}
+
+static bool test_init_server_and_share_info(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ struct GUID guid;
+ bool ok = true;
+
+ t->dinfo->server_name = talloc_asprintf(tctx, "%s", dcerpc_server_name(t->iremotewinspool_pipe));
+ torture_assert_not_null_goto(tctx, t->dinfo->server_name, ok, done, "Cannot allocate memory");
+
+ t->dinfo->share_name = talloc_strdup(tctx, "print$");
+ torture_assert_not_null_goto(tctx, t->dinfo->share_name, ok, done, "Cannot allocate memory");
+
+ guid = GUID_random();
+ t->dinfo->print_upload_guid_dir = GUID_string2(tctx, &guid);
+done:
+ return ok;
+}
+
+
+static bool torture_rpc_iremotewinspool_drv_setup_common(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ bool ok = true;
+ int ret = 0;
+
+ ok = test_init_driver_info(tctx, t);
+ torture_assert_goto(tctx, ok, ok, done, "failed to init driver info");
+
+ ok = test_init_iremotewinspool_conn(tctx, t);
+ torture_assert_goto(tctx, ok, ok, done, "failed to init iremotewinspool conn");
+
+ ok = test_init_iremotewinspool_openprinter(tctx, t);
+ torture_assert_goto(tctx, ok, ok, done, "failed to init iremotewinspool openprinter");
+
+ ok = test_init_server_and_share_info(tctx, t);
+ torture_assert_goto(tctx, ok, ok, done, "failed to init server and share info");
+
+ ret = smb_connect_print_share(tctx, t->dinfo->server_name, t->dinfo->share_name, &t->dinfo->cli);
+ torture_assert_goto(tctx, ret, ok, done, "Failed to connect to print share");
+
+done:
+
+ return ok;
+}
+
+static bool torture_rpc_iremotewinspool_drv_setup(struct torture_context *tctx,
+ void **data)
+{
+ struct test_iremotewinspool_context *t;
+
+ *data = t = talloc_zero(tctx, struct test_iremotewinspool_context);
+
+ return torture_rpc_iremotewinspool_drv_setup_common(tctx, t);
+}
+
+static bool torture_rpc_iremotewinspool_drv_teardown_common(struct torture_context *tctx,
+ struct test_iremotewinspool_context *t)
+{
+ smbcli_deltree(t->dinfo->cli->tree, t->dinfo->print_upload_guid_dir);
+ smb_raw_exit(t->dinfo->cli->session);
+
+ test_uninstall_printer_driver(tctx, t);
+ test_remove_driver_package(tctx, t);
+
+ test_AsyncClosePrinter_byhandle(tctx, t, t->iremotewinspool_pipe, &t->server_handle);
+
+ return true;
+}
+
+static bool torture_rpc_iremotewinspool_drv_teardown(struct torture_context *tctx,
+ void *data)
+{
+ struct test_iremotewinspool_context *t = talloc_get_type(data, struct test_iremotewinspool_context);
+ bool ret;
+
+ ret = torture_rpc_iremotewinspool_drv_teardown_common(tctx, t);
+ talloc_free(t);
+
+ return ret;
+}
+
+/* Creates {GUID} directory inside //server/print$ then copies driver files
+ * and directories from torture option driver_path to this directory over smb */
+static bool test_CopyDriverFiles(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ bool ret = false;
+ bool ok = true;
+ NTSTATUS status;
+
+ status = smbcli_mkdir(ctx->dinfo->cli->tree, ctx->dinfo->print_upload_guid_dir);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Failed to create upload directory");
+
+ /* Walk the provided torture option driver_path file tree, creating the directory hierarchy and
+ * copying all files to print$/{GUID}/ share */
+ ret = tftw(tctx, ctx->dinfo->local_driver_path, copy_driver_files, TFTW_MAX_DEPTH, ctx->dinfo);
+ torture_assert_int_equal_goto(tctx, ret, 0, ok, done, "Failed to copy driver files to print$/{GUID}/ dir");
+
+done:
+
+ return ok;
+}
+
+/*
+ * Upload print driver package files and inf file, preparing the print server
+ * for driver installation
+ */
+static bool test_UploadPrinterDriverPackage(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct spoolss_AddDriverInfo8 *parsed_dinfo;
+ struct winspool_AsyncUploadPrinterDriverPackage r;
+ uint32_t pcchDestInfPath = 0;
+ NTSTATUS status;
+ bool ok = true;
+
+ parsed_dinfo = ctx->dinfo->info;
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_assert_not_null_goto(tctx, r.in.pszServer, ok, done, "Cannot allocate memory");
+
+ r.in.pszInfPath = talloc_asprintf(tctx, "\\\\%s\\%s\\%s\\%s", ctx->dinfo->server_name,
+ ctx->dinfo->share_name,
+ ctx->dinfo->print_upload_guid_dir,
+ ctx->dinfo->inf_file);
+ torture_assert_not_null_goto(tctx, r.in.pszInfPath, ok, done, "Cannot allocate memory");
+
+ r.in.pszEnvironment = parsed_dinfo->architecture;
+ /* Upload driver package files even if the driver package is already present
+ * on the print server */
+ r.in.dwFlags = UPDP_UPLOAD_ALWAYS;
+ pcchDestInfPath = 260;
+ r.in.pszDestInfPath = NULL;
+ r.in.pcchDestInfPath = &pcchDestInfPath;
+ r.out.pszDestInfPath = NULL;
+ r.out.pcchDestInfPath = &pcchDestInfPath;
+
+ r.in.pszDestInfPath = talloc_zero(tctx, const char);
+ torture_assert_not_null_goto(tctx, r.in.pszDestInfPath, ok, done, "Cannot allocate memory");
+ r.out.pszDestInfPath = talloc_zero(tctx, const char);
+ torture_assert_not_null_goto(tctx, r.out.pszDestInfPath, ok, done, "Cannot allocate memory");
+
+ status = dcerpc_winspool_AsyncUploadPrinterDriverPackage_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncUploadPrinterDriverPackage failed");
+
+ torture_assert_hresult_ok(tctx, r.out.result, "AsyncUploadPrinterDriverPackage failed");
+
+ ctx->dinfo->uploaded_inf_path = talloc_strdup(tctx, r.out.pszDestInfPath);
+ torture_assert_not_null_goto(tctx, ctx->dinfo->uploaded_inf_path, ok, done, "Cannot allocate memory");
+
+done:
+
+ return ok;
+}
+
+/* Install the driver that was successfully uploaded to the printer driver
+ * store, note that Windows validates the pszDriverName as mentioned below */
+static bool test_InstallPrinterDriverFromPackage(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *p = ctx->iremotewinspool_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ char *abs_inf_path = NULL;
+ struct spoolss_AddDriverInfo8 *parsed_dinfo;
+ struct winspool_AsyncInstallPrinterDriverFromPackage r;
+ bool ok = true;
+ NTSTATUS status;
+
+ parsed_dinfo = ctx->dinfo->info;
+
+ r.in.pszServer = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_assert_not_null_goto(tctx, r.in.pszServer, ok, done, "Cannot allocate memory");
+
+ /* output string(pszDestInfPath) from test_UploadPrinterDriverPackage() */
+ r.in.pszInfPath = talloc_strdup(tctx, ctx->dinfo->uploaded_inf_path);
+ torture_assert_not_null_goto(tctx, r.in.pszInfPath, ok, done, "Cannot allocate memory");
+
+ abs_inf_path = talloc_asprintf(tctx, "%s/%s", ctx->dinfo->local_driver_path, ctx->dinfo->inf_file);
+ torture_assert_not_null_goto(tctx, abs_inf_path, ok, done, "Cannot allocate memory");
+
+ r.in.pszEnvironment = parsed_dinfo->architecture;
+ torture_assert_not_null_goto(tctx, r.in.pszEnvironment, ok, done, "Cannot allocate memory");
+
+ /* Windows validates the print driver name by checking the pszDriverName input against the inf file:
+ * 1) "DriverName" value
+ * 2) "CompatName" value
+ * 3) left-hand-side value under the [Model] section
+ * otherwise ERROR_UNKNOWN_PRINTER_DRIVER is returned */
+ r.in.pszDriverName = parsed_dinfo->driver_name;
+ torture_assert_not_null_goto(tctx, r.in.pszDriverName, ok, done, "Cannot allocate memory");
+
+ /* All files should be installed, even if doing so would overwrite some newer
+ * versions */
+ r.in.dwFlags = IPDFP_COPY_ALL_FILES;
+
+ status = dcerpc_winspool_AsyncInstallPrinterDriverFromPackage_r(b, tctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "AsyncInstallPrinterDriverFromPackage failed");
+
+ torture_assert_hresult_ok(tctx, r.out.result, "AsyncInstallPrinterDriverFromPackage failed");
+done:
+ TALLOC_FREE(abs_inf_path);
+
+ return ok;
+}
+
+/* Check the registry to validate the print driver installed successfully */
+static bool test_ValidatePrinterDriverInstalled(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_iremotewinspool_context *ctx =
+ talloc_get_type_abort(private_data, struct test_iremotewinspool_context);
+
+ struct dcerpc_pipe *winreg_pipe = NULL;
+ NTSTATUS status;
+ bool ok = true;
+
+ /* winreg is not available over ncacn_ip_tcp */
+ status = torture_rpc_connection_transport(tctx, &winreg_pipe, &ndr_table_winreg, NCACN_NP, 0, 0);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_NOT_AVAILABLE)) {
+ /* retry */
+ status = torture_rpc_connection_transport(tctx, &winreg_pipe, &ndr_table_winreg, NCACN_NP, 0, 0);
+ }
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "Failed to connect to winreg");
+
+ ok = test_winreg_validate_driver(tctx, winreg_pipe, ctx->dinfo);
+ torture_assert_goto(tctx, ok, ok, done, "Failed to validate driver with winreg");
+
+done:
+ TALLOC_FREE(winreg_pipe);
+
+ return ok;
+}
+
+struct torture_suite *torture_rpc_iremotewinspool_drv(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "iremotewinspool_driver");
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "drivers");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_iremotewinspool_drv_setup,
+ torture_rpc_iremotewinspool_drv_teardown);
+
+ torture_tcase_add_simple_test(tcase, "CopyDriverFiles", test_CopyDriverFiles);
+ torture_tcase_add_simple_test(tcase, "UploadPrinterDriverPackage", test_UploadPrinterDriverPackage);
+ torture_tcase_add_simple_test(tcase, "InstallPrinterDriverFromPackage", test_InstallPrinterDriverFromPackage);
+ torture_tcase_add_simple_test(tcase, "ValidatePrinterDriverInstalled", test_ValidatePrinterDriverInstalled);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/join.c b/source4/torture/rpc/join.c
new file mode 100644
index 0000000..6e0afca
--- /dev/null
+++ b/source4/torture/rpc/join.c
@@ -0,0 +1,86 @@
+#include "includes.h"
+#include "libcli/libcli.h"
+
+#include "torture/rpc/torture_rpc.h"
+
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+
+#define TORTURE_NETBIOS_NAME "smbtorturejoin"
+
+
+bool torture_rpc_join(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct test_join *tj;
+ struct cli_credentials *machine_account;
+ struct smbcli_state *cli;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ /* Join domain as a member server. */
+ tj = torture_join_domain(torture,
+ TORTURE_NETBIOS_NAME,
+ ACB_WSTRUST,
+ &machine_account);
+
+ if (!tj) {
+ DEBUG(0, ("%s failed to join domain as workstation\n",
+ TORTURE_NETBIOS_NAME));
+ return false;
+ }
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(tj, &cli, host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ machine_account,
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("%s failed to connect to IPC$ with workstation credentials\n",
+ TORTURE_NETBIOS_NAME));
+ return false;
+ }
+ smbcli_tdis(cli);
+
+ /* Leave domain. */
+ torture_leave_domain(torture, tj);
+
+ /* Join domain as a domain controller. */
+ tj = torture_join_domain(torture, TORTURE_NETBIOS_NAME,
+ ACB_SVRTRUST,
+ &machine_account);
+ if (!tj) {
+ DEBUG(0, ("%s failed to join domain as domain controller\n",
+ TORTURE_NETBIOS_NAME));
+ return false;
+ }
+
+ status = smbcli_full_connection(tj, &cli, host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ machine_account,
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("%s failed to connect to IPC$ with workstation credentials\n",
+ TORTURE_NETBIOS_NAME));
+ return false;
+ }
+
+ smbcli_tdis(cli);
+
+ /* Leave domain. */
+ torture_leave_domain(torture, tj);
+
+ return true;
+}
+
diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c
new file mode 100644
index 0000000..c2190e5
--- /dev/null
+++ b/source4/torture/rpc/lsa.c
@@ -0,0 +1,5645 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for lsa rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "libcli/cldap/cldap.h"
+#include "../lib/tsocket/tsocket.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "lib/events/events.h"
+#include "libcli/security/security.h"
+#include "libcli/auth/libcli_auth.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "source4/auth/kerberos/kerberos.h"
+#include "source4/auth/kerberos/kerberos_util.h"
+#include "lib/util/util_net.h"
+#include "libcli/resolve/resolve.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#define TEST_MACHINENAME "lsatestmach"
+#define TRUSTPW "12345678"
+
+static void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+}
+
+static bool test_OpenPolicy(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct lsa_ObjectAttribute attr;
+ struct policy_handle handle;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy r;
+ uint16_t system_name = '\\';
+
+ torture_comment(tctx, "\nTesting OpenPolicy\n");
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = &system_name;
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenPolicy_r(b, tctx, &r),
+ "OpenPolicy failed");
+
+ torture_assert_ntstatus_ok(tctx,
+ r.out.result,
+ "OpenPolicy failed");
+
+ return true;
+}
+
+static bool test_OpenPolicy_fail(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct lsa_ObjectAttribute attr;
+ struct policy_handle handle;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy r;
+ uint16_t system_name = '\\';
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting OpenPolicy_fail\n");
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = &system_name;
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ status = dcerpc_lsa_OpenPolicy_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx,
+ "OpenPolicy correctly returned with "
+ "status: %s\n",
+ nt_errstr(status));
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_ACCESS_DENIED,
+ "OpenPolicy return value should "
+ "be ACCESS_DENIED");
+ return true;
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+ torture_comment(tctx,
+ "OpenPolicy correctly returned with "
+ "result: %s\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ r.out.result,
+ NT_STATUS_OK,
+ "OpenPolicy return value should be "
+ "ACCESS_DENIED");
+
+ return false;
+}
+
+
+bool test_lsa_OpenPolicy2_ex(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle **handle,
+ NTSTATUS expected_status,
+ NTSTATUS expected_status2)
+{
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 r;
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting OpenPolicy2\n");
+
+ *handle = talloc(tctx, struct policy_handle);
+ torture_assert(tctx, *handle != NULL, "talloc(tctx, struct policy_handle)");
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = "\\";
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = *handle;
+
+ status = dcerpc_lsa_OpenPolicy2_r(b, tctx, &r);
+
+ /* Allow two possible failure status codes */
+ if (!NT_STATUS_EQUAL(status, expected_status2)) {
+ torture_assert_ntstatus_equal(tctx, status,
+ expected_status,
+ "OpenPolicy2 failed");
+ }
+ if (!NT_STATUS_IS_OK(expected_status) ||
+ !NT_STATUS_IS_OK(expected_status2)) {
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ r.out.result,
+ "OpenPolicy2 failed");
+
+ return true;
+}
+
+
+bool test_lsa_OpenPolicy2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle **handle)
+{
+ return test_lsa_OpenPolicy2_ex(b, tctx, handle,
+ NT_STATUS_OK, NT_STATUS_OK);
+}
+
+static bool test_OpenPolicy2_fail(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct lsa_ObjectAttribute attr;
+ struct policy_handle handle;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 r;
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting OpenPolicy2_fail\n");
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = "\\";
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ status = dcerpc_lsa_OpenPolicy2_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx,
+ "OpenPolicy2 correctly returned with "
+ "status: %s\n",
+ nt_errstr(status));
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_ACCESS_DENIED,
+ "OpenPolicy2 return value should "
+ "be ACCESS_DENIED");
+ return true;
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+ torture_comment(tctx,
+ "OpenPolicy2 correctly returned with "
+ "result: %s\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+
+ torture_fail(tctx,
+ "OpenPolicy2 return value should be "
+ "ACCESS_DENIED or RPC_PROTSEQ_NOT_SUPPORTED");
+
+ return false;
+}
+
+bool test_lsa_OpenPolicy3_ex(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle **handle,
+ NTSTATUS expected_status,
+ NTSTATUS expected_status2)
+{
+ struct lsa_QosInfo qos = {
+ .impersonation_level = 2,
+ .context_mode = 1,
+ };
+ struct lsa_ObjectAttribute attr = {
+ .len = 0,
+ .sec_qos = &qos,
+ };
+ struct lsa_revision_info1 in_rinfo1 = {
+ .revision = 1,
+ .supported_features = 0,
+ };
+ union lsa_revision_info in_rinfo = {
+ .info1 = in_rinfo1,
+ };
+ struct lsa_revision_info1 out_rinfo1 = {
+ .revision = 0,
+ };
+ union lsa_revision_info out_rinfo = {
+ .info1 = out_rinfo1,
+ };
+ uint32_t out_version = 0;
+ struct lsa_OpenPolicy3 r = {
+ .in.system_name = "\\",
+ .in.attr = &attr,
+ .in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.in_version = 1,
+ .in.in_revision_info = &in_rinfo,
+ .out.out_version = &out_version,
+ .out.out_revision_info = &out_rinfo,
+ };
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting OpenPolicy3\n");
+
+ *handle = talloc(tctx, struct policy_handle);
+ torture_assert(tctx,
+ *handle != NULL,
+ "talloc(tctx, struct policy_handle)");
+ r.out.handle = *handle;
+
+ status = dcerpc_lsa_OpenPolicy3_r(b, tctx, &r);
+
+ /* Allow two possible failure status codes */
+ if (!NT_STATUS_EQUAL(status, expected_status2)) {
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ expected_status,
+ "OpenPolicy3 failed");
+ }
+ if (!NT_STATUS_IS_OK(expected_status) ||
+ !NT_STATUS_IS_OK(expected_status2)) {
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "OpenPolicy3 failed");
+ torture_assert_int_equal(tctx, out_version, 1, "Invalid out_version");
+ torture_assert_int_equal(tctx,
+ out_rinfo1.revision,
+ 1,
+ "Invalid revision");
+#if 0 /* TODO: Enable as soon as it is supported */
+ torture_assert_int_equal(tctx,
+ out_rinfo1.supported_features,
+ LSA_FEATURE_TDO_AUTH_INFO_AES_CIPHER,
+ "Invalid supported feature set");
+#endif
+
+ return true;
+}
+
+bool test_lsa_OpenPolicy3(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle **handle)
+{
+ return test_lsa_OpenPolicy3_ex(b,
+ tctx,
+ handle,
+ NT_STATUS_OK,
+ NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE);
+}
+
+static bool test_OpenPolicy3_fail(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct policy_handle handle = {
+ .handle_type = 0,
+ };
+ struct lsa_QosInfo qos = {
+ .impersonation_level = 2,
+ .context_mode = 1,
+ };
+ struct lsa_ObjectAttribute attr = {
+ .len = 0,
+ .sec_qos = &qos,
+ };
+ struct lsa_revision_info1 in_rinfo1 = {
+ .revision = 0,
+ .supported_features = 0,
+ };
+ union lsa_revision_info in_rinfo = {
+ .info1 = in_rinfo1,
+ };
+ struct lsa_revision_info1 out_rinfo1 = {
+ .revision = 0,
+ };
+ union lsa_revision_info out_rinfo = {
+ .info1 = out_rinfo1,
+ };
+ uint32_t out_version = 0;
+ struct lsa_OpenPolicy3 r = {
+ .in.system_name = "\\",
+ .in.attr = &attr,
+ .in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.in_version = 1,
+ .in.in_revision_info = &in_rinfo,
+ .out.out_version = &out_version,
+ .out.out_revision_info = &out_rinfo,
+ .out.handle = &handle,
+ };
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting OpenPolicy3_fail\n");
+
+ status = dcerpc_lsa_OpenPolicy3_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status,
+ NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ torture_comment(tctx,
+ "OpenPolicy3 correctly returned with "
+ "status: %s\n",
+ nt_errstr(status));
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_ACCESS_DENIED,
+ "OpenPolicy3 return value should "
+ "be ACCESS_DENIED or CONNECTION_DISCONNECTED");
+ return true;
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(r.out.result,
+ NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+ torture_comment(tctx,
+ "OpenPolicy3 correctly returned with "
+ "result: %s\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+
+ torture_fail(tctx,
+ "OpenPolicy3 return value should be "
+ "ACCESS_DENIED or RPC_PROTSEQ_NOT_SUPPORTED");
+
+ return false;
+}
+
+static bool test_LookupNames(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_TransNameArray *tnames)
+{
+ struct lsa_LookupNames r;
+ struct lsa_TransSidArray sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String *names;
+ uint32_t count = 0;
+ int i;
+ uint32_t *input_idx;
+
+ torture_comment(tctx, "\nTesting LookupNames with %d names\n", tnames->count);
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+
+ r.in.num_names = 0;
+
+ input_idx = talloc_array(tctx, uint32_t, tnames->count);
+ names = talloc_array(tctx, struct lsa_String, tnames->count);
+
+ for (i=0;i<tnames->count;i++) {
+ if (tnames->names[i].sid_type != SID_NAME_UNKNOWN) {
+ init_lsa_String(&names[r.in.num_names], tnames->names[i].name.string);
+ input_idx[r.in.num_names] = i;
+ r.in.num_names++;
+ }
+ }
+
+ r.in.handle = handle;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames_r(b, tctx, &r),
+ "LookupNames failed");
+ if (NT_STATUS_EQUAL(r.out.result, STATUS_SOME_UNMAPPED) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_NONE_MAPPED)) {
+ for (i=0;i< r.in.num_names;i++) {
+ if (i < count && sids.sids[i].sid_type == SID_NAME_UNKNOWN) {
+ torture_comment(tctx, "LookupName of %s was unmapped\n",
+ tnames->names[i].name.string);
+ } else if (i >=count) {
+ torture_comment(tctx, "LookupName of %s failed to return a result\n",
+ tnames->names[i].name.string);
+ }
+ }
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LookupNames failed");
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LookupNames failed");
+ }
+
+ for (i=0;i< r.in.num_names;i++) {
+ torture_assert(tctx, (i < count),
+ talloc_asprintf(tctx,
+ "LookupName of %s failed to return a result\n",
+ tnames->names[input_idx[i]].name.string));
+
+ torture_assert_int_equal(tctx,
+ sids.sids[i].sid_type,
+ tnames->names[input_idx[i]].sid_type,
+ talloc_asprintf(tctx,
+ "LookupName of %s got unexpected name type: %s\n",
+ tnames->names[input_idx[i]].name.string,
+ sid_type_lookup(sids.sids[i].sid_type)));
+ if (sids.sids[i].sid_type != SID_NAME_DOMAIN) {
+ continue;
+ }
+ torture_assert_int_equal(tctx,
+ sids.sids[i].rid,
+ UINT32_MAX,
+ talloc_asprintf(tctx,
+ "LookupName of %s got unexpected rid: %d\n",
+ tnames->names[input_idx[i]].name.string,
+ sids.sids[i].rid));
+ }
+
+ return true;
+}
+
+static bool test_LookupNames_bogus(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level)
+{
+ struct lsa_LookupNames r;
+ struct lsa_TransSidArray sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String names[1];
+ uint32_t count = 0;
+
+ torture_comment(tctx, "\nTesting LookupNames with bogus name\n");
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ init_lsa_String(&names[0], "NT AUTHORITY\\BOGUS");
+
+ r.in.handle = handle;
+ r.in.num_names = 1;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames_r(b, tctx, &r),
+ "LookupNames bogus failed");
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_NONE_MAPPED)) {
+ torture_comment(tctx, "LookupNames failed - %s\n",
+ nt_errstr(r.out.result));
+ return false;
+ }
+
+ torture_comment(tctx, "\n");
+
+ return true;
+}
+
+static bool test_LookupNames_NULL(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level)
+{
+ struct lsa_LookupNames r;
+ struct lsa_TransSidArray sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String names[1];
+ uint32_t count = 0;
+
+ torture_comment(tctx, "\nTesting LookupNames with NULL name\n");
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ names[0].string = NULL;
+
+ r.in.handle = handle;
+ r.in.num_names = 1;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ /* nt4 returns NT_STATUS_NONE_MAPPED with sid_type
+ * SID_NAME_UNKNOWN, rid 0, and sid_index -1;
+ *
+ * w2k3/w2k8 return NT_STATUS_OK with sid_type
+ * SID_NAME_DOMAIN, rid -1 and sid_index 0 and BUILTIN domain
+ */
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames_r(b, tctx, &r),
+ "LookupNames with NULL name failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LookupNames with NULL name failed");
+
+ torture_comment(tctx, "\n");
+
+ return true;
+}
+
+static bool test_LookupNames_wellknown(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level)
+{
+ struct lsa_TranslatedName name;
+ struct lsa_TransNameArray tnames;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing LookupNames with well known names\n");
+
+ tnames.names = &name;
+ tnames.count = 1;
+ name.name.string = "NT AUTHORITY\\SYSTEM";
+ name.sid_type = SID_NAME_WKN_GRP;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+ name.name.string = "NT AUTHORITY\\ANONYMOUS LOGON";
+ name.sid_type = SID_NAME_WKN_GRP;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+ name.name.string = "NT AUTHORITY\\Authenticated Users";
+ name.sid_type = SID_NAME_WKN_GRP;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+#if 0
+ name.name.string = "NT AUTHORITY";
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+ name.name.string = "NT AUTHORITY\\";
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+#endif
+
+ name.name.string = "BUILTIN\\";
+ name.sid_type = SID_NAME_DOMAIN;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+ name.name.string = "BUILTIN\\Administrators";
+ name.sid_type = SID_NAME_ALIAS;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+ name.name.string = "SYSTEM";
+ name.sid_type = SID_NAME_WKN_GRP;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+
+ name.name.string = "Everyone";
+ name.sid_type = SID_NAME_WKN_GRP;
+ ret &= test_LookupNames(b, tctx, handle, level, &tnames);
+ return ret;
+}
+
+static bool test_LookupNames2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_TransNameArray2 *tnames,
+ bool check_result)
+{
+ struct lsa_LookupNames2 r;
+ struct lsa_TransSidArray2 sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String *names;
+ uint32_t *input_idx;
+ uint32_t count = 0;
+ int i;
+
+ torture_comment(tctx, "\nTesting LookupNames2 with %d names\n", tnames->count);
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ r.in.num_names = 0;
+
+ input_idx = talloc_array(tctx, uint32_t, tnames->count);
+ names = talloc_array(tctx, struct lsa_String, tnames->count);
+
+ for (i=0;i<tnames->count;i++) {
+ if (tnames->names[i].sid_type != SID_NAME_UNKNOWN) {
+ init_lsa_String(&names[r.in.num_names], tnames->names[i].name.string);
+ input_idx[r.in.num_names] = i;
+ r.in.num_names++;
+ }
+ }
+
+ r.in.handle = handle;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames2_r(b, tctx, &r),
+ "LookupNames2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LookupNames2 failed");
+
+ if (check_result) {
+ torture_assert_int_equal(tctx, count, sids.count,
+ "unexpected number of results returned");
+ if (sids.count > 0) {
+ torture_assert(tctx, sids.sids, "invalid sid buffer");
+ }
+ }
+
+ torture_comment(tctx, "\n");
+
+ return true;
+}
+
+
+static bool test_LookupNames3(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_TransNameArray2 *tnames,
+ bool check_result)
+{
+ struct lsa_LookupNames3 r;
+ struct lsa_TransSidArray3 sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String *names;
+ uint32_t count = 0;
+ int i;
+ uint32_t *input_idx;
+
+ torture_comment(tctx, "\nTesting LookupNames3 with %d names\n", tnames->count);
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ r.in.num_names = 0;
+
+ input_idx = talloc_array(tctx, uint32_t, tnames->count);
+ names = talloc_array(tctx, struct lsa_String, tnames->count);
+ for (i=0;i<tnames->count;i++) {
+ if (tnames->names[i].sid_type != SID_NAME_UNKNOWN) {
+ init_lsa_String(&names[r.in.num_names], tnames->names[i].name.string);
+ input_idx[r.in.num_names] = i;
+ r.in.num_names++;
+ }
+ }
+
+ r.in.handle = handle;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames3_r(b, tctx, &r),
+ "LookupNames3 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LookupNames3 failed");
+
+ if (check_result) {
+ torture_assert_int_equal(tctx, count, sids.count,
+ "unexpected number of results returned");
+ if (sids.count > 0) {
+ torture_assert(tctx, sids.sids, "invalid sid buffer");
+ }
+ }
+
+ torture_comment(tctx, "\n");
+
+ return true;
+}
+
+static bool test_LookupNames4(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_TransNameArray2 *tnames,
+ bool check_result)
+{
+ struct lsa_LookupNames4 r;
+ struct lsa_TransSidArray3 sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String *names;
+ uint32_t count = 0;
+ int i;
+ uint32_t *input_idx;
+
+ torture_comment(tctx, "\nTesting LookupNames4 with %d names\n", tnames->count);
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ r.in.num_names = 0;
+
+ input_idx = talloc_array(tctx, uint32_t, tnames->count);
+ names = talloc_array(tctx, struct lsa_String, tnames->count);
+ for (i=0;i<tnames->count;i++) {
+ if (tnames->names[i].sid_type != SID_NAME_UNKNOWN) {
+ init_lsa_String(&names[r.in.num_names], tnames->names[i].name.string);
+ input_idx[r.in.num_names] = i;
+ r.in.num_names++;
+ }
+ }
+
+ r.in.num_names = tnames->count;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupNames4_r(b, tctx, &r),
+ "LookupNames4 failed");
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NONE_MAPPED)) {
+ torture_comment(tctx,
+ "LookupNames4 failed: %s - not considered as an error",
+ nt_errstr(r.out.result));
+
+ return true;
+ }
+ }
+ torture_assert_ntstatus_ok(tctx,
+ r.out.result,
+ "LookupNames4 failed");
+
+ if (check_result) {
+ torture_assert_int_equal(tctx, count, sids.count,
+ "unexpected number of results returned");
+ if (sids.count > 0) {
+ torture_assert(tctx, sids.sids, "invalid sid buffer");
+ }
+ }
+
+ torture_comment(tctx, "\n");
+
+ return true;
+}
+
+static bool test_LookupNames4_fail(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ enum lsa_LookupNamesLevel level)
+{
+ struct lsa_LookupNames4 r;
+ struct lsa_TransSidArray3 sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String *names = NULL;
+ uint32_t count = 0;
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting LookupNames4_fail");
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ r.in.num_names = 0;
+
+ r.in.num_names = count;
+ r.in.names = names;
+ r.in.sids = &sids;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.count = &count;
+ r.out.sids = &sids;
+ r.out.domains = &domains;
+
+ status = dcerpc_lsa_LookupNames4_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ torture_comment(tctx,
+ "LookupNames4 correctly returned with "
+ "status: %s\n",
+ nt_errstr(status));
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_ACCESS_DENIED,
+ "LookupNames4 return value should "
+ "be ACCESS_DENIED");
+ return true;
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+ torture_comment(tctx,
+ "LookupSids3 correctly returned with "
+ "result: %s\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+ }
+
+ torture_fail(tctx,
+ "LookupNames4 return value should be "
+ "ACCESS_DENIED or RPC_PROTSEQ_NOT_SUPPORTED");
+
+ return false;
+}
+
+
+static bool test_LookupSids(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_SidArray *sids)
+{
+ struct lsa_LookupSids r;
+ struct lsa_TransNameArray names;
+ struct lsa_RefDomainList *domains = NULL;
+ uint32_t count = sids->num_sids;
+
+ torture_comment(tctx, "\nTesting LookupSids\n");
+
+ names.count = 0;
+ names.names = NULL;
+
+ r.in.handle = handle;
+ r.in.sids = sids;
+ r.in.names = &names;
+ r.in.level = level;
+ r.in.count = &count;
+ r.out.count = &count;
+ r.out.names = &names;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupSids_r(b, tctx, &r),
+ "LookupSids failed");
+ if (!NT_STATUS_EQUAL(r.out.result, STATUS_SOME_UNMAPPED)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LookupSids failed");
+ }
+
+ torture_comment(tctx, "\n");
+
+ if (!test_LookupNames(b, tctx, handle, level, &names)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_LookupSids2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_SidArray *sids)
+{
+ struct lsa_LookupSids2 r;
+ struct lsa_TransNameArray2 names;
+ struct lsa_RefDomainList *domains = NULL;
+ uint32_t count = sids->num_sids;
+
+ torture_comment(tctx, "\nTesting LookupSids2\n");
+
+ names.count = 0;
+ names.names = NULL;
+
+ r.in.handle = handle;
+ r.in.sids = sids;
+ r.in.names = &names;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.count = &count;
+ r.out.names = &names;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupSids2_r(b, tctx, &r),
+ "LookupSids2 failed");
+ if (!NT_STATUS_IS_OK(r.out.result) &&
+ !NT_STATUS_EQUAL(r.out.result, STATUS_SOME_UNMAPPED)) {
+ torture_comment(tctx, "LookupSids2 failed - %s\n",
+ nt_errstr(r.out.result));
+ return false;
+ }
+
+ torture_comment(tctx, "\n");
+
+ if (!test_LookupNames2(b, tctx, handle, level, &names, false)) {
+ return false;
+ }
+
+ if (!test_LookupNames3(b, tctx, handle, level, &names, false)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_LookupSids3(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_SidArray *sids)
+{
+ struct lsa_LookupSids3 r;
+ struct lsa_TransNameArray2 names;
+ struct lsa_RefDomainList *domains = NULL;
+ uint32_t count = sids->num_sids;
+
+ torture_comment(tctx, "\nTesting LookupSids3\n");
+
+ names.count = 0;
+ names.names = NULL;
+
+ r.in.sids = sids;
+ r.in.names = &names;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.domains = &domains;
+ r.out.count = &count;
+ r.out.names = &names;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupSids3_r(b, tctx, &r),
+ "LookupSids3 failed");
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NONE_MAPPED)) {
+ torture_comment(tctx,
+ "LookupSids3 failed: %s - not considered as an error",
+ nt_errstr(r.out.result));
+
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ r.out.result,
+ "LookupSids3 failed");
+
+ return false;
+ }
+
+ torture_comment(tctx, "\n");
+
+ if (!test_LookupNames4(b, tctx, level, &names, true)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_LookupSids3_fail(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ enum lsa_LookupNamesLevel level,
+ struct lsa_SidArray *sids)
+{
+ struct lsa_LookupSids3 r;
+ struct lsa_TransNameArray2 names;
+ struct lsa_RefDomainList *domains = NULL;
+ uint32_t count = sids->num_sids;
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting LookupSids3\n");
+
+ names.count = 0;
+ names.names = NULL;
+
+ r.in.sids = sids;
+ r.in.names = &names;
+ r.in.level = level;
+ r.in.count = &count;
+ r.in.lookup_options = 0;
+ r.in.client_revision = 0;
+ r.out.domains = &domains;
+ r.out.count = &count;
+ r.out.names = &names;
+
+ status = dcerpc_lsa_LookupSids3_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ torture_comment(tctx,
+ "LookupSids3 correctly returned with "
+ "status: %s\n",
+ nt_errstr(status));
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_ACCESS_DENIED,
+ "LookupSids3 return value should "
+ "be ACCESS_DENIED");
+ return true;
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+ torture_comment(tctx,
+ "LookupNames4 correctly returned with "
+ "result: %s\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+
+ torture_fail(tctx,
+ "LookupSids3 return value should be "
+ "ACCESS_DENIED or RPC_PROTSEQ_NOT_SUPPORTED");
+
+ return false;
+}
+
+bool test_many_LookupSids(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level)
+{
+ uint32_t count;
+ struct lsa_SidArray sids;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_transport_t transport = dcerpc_binding_get_transport(p->binding);
+
+ torture_comment(tctx, "\nTesting LookupSids with lots of SIDs\n");
+
+ sids.num_sids = 100;
+
+ sids.sids = talloc_array(tctx, struct lsa_SidPtr, sids.num_sids);
+
+ for (i=0; i<sids.num_sids; i++) {
+ const char *sidstr = "S-1-5-32-545";
+ sids.sids[i].sid = dom_sid_parse_talloc(tctx, sidstr);
+ }
+
+ count = sids.num_sids;
+
+ if (handle) {
+ struct lsa_LookupSids r;
+ struct lsa_TransNameArray names;
+ struct lsa_RefDomainList *domains = NULL;
+ names.count = 0;
+ names.names = NULL;
+
+ r.in.handle = handle;
+ r.in.sids = &sids;
+ r.in.names = &names;
+ r.in.level = level;
+ r.in.count = &names.count;
+ r.out.count = &count;
+ r.out.names = &names;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupSids_r(b, tctx, &r),
+ "LookupSids failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "LookupSids failed - %s\n",
+ nt_errstr(r.out.result));
+ return false;
+ }
+
+ torture_comment(tctx, "\n");
+
+ if (!test_LookupNames(b, tctx, handle, level, &names)) {
+ return false;
+ }
+ }
+
+ if (transport == NCACN_NP) {
+ if (!test_LookupSids3_fail(b, tctx, level, &sids)) {
+ return false;
+ }
+ if (!test_LookupNames4_fail(b, tctx, level)) {
+ return false;
+ }
+ } else if (transport == NCACN_IP_TCP) {
+ struct lsa_TransNameArray2 names;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ names.count = 0;
+ names.names = NULL;
+
+ dcerpc_binding_handle_auth_info(p->binding_handle,
+ &auth_type, &auth_level);
+
+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL &&
+ auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
+ if (!test_LookupSids3(b, tctx, level, &sids)) {
+ return false;
+ }
+ if (!test_LookupNames4(b, tctx, level, &names, true)) {
+ return false;
+ }
+ } else {
+ /*
+ * If we don't have a secure channel these tests must
+ * fail with ACCESS_DENIED.
+ */
+ if (!test_LookupSids3_fail(b, tctx, level, &sids)) {
+ return false;
+ }
+ if (!test_LookupNames4_fail(b, tctx, level)) {
+ return false;
+ }
+ }
+ }
+
+ torture_comment(tctx, "\n");
+
+
+
+ return true;
+}
+
+static void lookupsids_cb(struct tevent_req *subreq)
+{
+ int *replies = (int *)tevent_req_callback_data_void(subreq);
+ NTSTATUS status;
+
+ status = dcerpc_lsa_LookupSids_r_recv(subreq, subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("lookupsids returned %s\n", nt_errstr(status));
+ *replies = -1;
+ }
+
+ if (*replies >= 0) {
+ *replies += 1;
+ }
+}
+
+static bool test_LookupSids_async(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ enum lsa_LookupNamesLevel level)
+{
+ struct lsa_SidArray sids;
+ struct lsa_SidPtr sidptr;
+ uint32_t *count;
+ struct lsa_TransNameArray *names;
+ struct lsa_LookupSids *r;
+ struct lsa_RefDomainList *domains = NULL;
+ struct tevent_req **req;
+ int i, replies;
+ bool ret = true;
+ const int num_async_requests = 50;
+
+ count = talloc_array(tctx, uint32_t, num_async_requests);
+ names = talloc_array(tctx, struct lsa_TransNameArray, num_async_requests);
+ r = talloc_array(tctx, struct lsa_LookupSids, num_async_requests);
+
+ torture_comment(tctx, "\nTesting %d async lookupsids request\n", num_async_requests);
+
+ req = talloc_array(tctx, struct tevent_req *, num_async_requests);
+
+ sids.num_sids = 1;
+ sids.sids = &sidptr;
+ sidptr.sid = dom_sid_parse_talloc(tctx, "S-1-5-32-545");
+
+ replies = 0;
+
+ for (i=0; i<num_async_requests; i++) {
+ count[i] = 0;
+ names[i].count = 0;
+ names[i].names = NULL;
+
+ r[i].in.handle = handle;
+ r[i].in.sids = &sids;
+ r[i].in.names = &names[i];
+ r[i].in.level = level;
+ r[i].in.count = &names[i].count;
+ r[i].out.count = &count[i];
+ r[i].out.names = &names[i];
+ r[i].out.domains = &domains;
+
+ req[i] = dcerpc_lsa_LookupSids_r_send(tctx, tctx->ev, b, &r[i]);
+ if (req[i] == NULL) {
+ ret = false;
+ break;
+ }
+
+ tevent_req_set_callback(req[i], lookupsids_cb, &replies);
+ }
+
+ while (replies >= 0 && replies < num_async_requests) {
+ tevent_loop_once(tctx->ev);
+ }
+
+ talloc_free(req);
+
+ if (replies < 0) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_LookupPrivValue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_String *name)
+{
+ struct lsa_LookupPrivValue r;
+ struct lsa_LUID luid;
+
+ r.in.handle = handle;
+ r.in.name = name;
+ r.out.luid = &luid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupPrivValue_r(b, tctx, &r),
+ "LookupPrivValue failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LookupPrivValue failed");
+
+ return true;
+}
+
+static bool test_LookupPrivName(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_LUID *luid)
+{
+ struct lsa_LookupPrivName r;
+ struct lsa_StringLarge *name = NULL;
+
+ r.in.handle = handle;
+ r.in.luid = luid;
+ r.out.name = &name;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupPrivName_r(b, tctx, &r),
+ "LookupPrivName failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LookupPrivName failed");
+
+ return true;
+}
+
+static bool test_RemovePrivilegesFromAccount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct policy_handle *acct_handle,
+ struct lsa_LUID *luid)
+{
+ struct lsa_RemovePrivilegesFromAccount r;
+ struct lsa_PrivilegeSet privs;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting RemovePrivilegesFromAccount\n");
+
+ r.in.handle = acct_handle;
+ r.in.remove_all = 0;
+ r.in.privs = &privs;
+
+ privs.count = 1;
+ privs.unknown = 0;
+ privs.set = talloc_array(tctx, struct lsa_LUIDAttribute, 1);
+ privs.set[0].luid = *luid;
+ privs.set[0].attribute = 0;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_RemovePrivilegesFromAccount_r(b, tctx, &r),
+ "RemovePrivilegesFromAccount failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+
+ struct lsa_LookupPrivName r_name;
+ struct lsa_StringLarge *name = NULL;
+
+ r_name.in.handle = handle;
+ r_name.in.luid = luid;
+ r_name.out.name = &name;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupPrivName_r(b, tctx, &r_name),
+ "LookupPrivName failed");
+ if (!NT_STATUS_IS_OK(r_name.out.result)) {
+ torture_comment(tctx, "\nLookupPrivName failed - %s\n",
+ nt_errstr(r_name.out.result));
+ return false;
+ }
+ /* Windows 2008 does not allow this to be removed */
+ if (strcmp("SeAuditPrivilege", name->string) == 0) {
+ return ret;
+ }
+
+ torture_comment(tctx, "RemovePrivilegesFromAccount failed to remove %s - %s\n",
+ name->string,
+ nt_errstr(r.out.result));
+ return false;
+ }
+
+ return ret;
+}
+
+static bool test_AddPrivilegesToAccount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *acct_handle,
+ struct lsa_LUID *luid)
+{
+ struct lsa_AddPrivilegesToAccount r;
+ struct lsa_PrivilegeSet privs;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting AddPrivilegesToAccount\n");
+
+ r.in.handle = acct_handle;
+ r.in.privs = &privs;
+
+ privs.count = 1;
+ privs.unknown = 0;
+ privs.set = talloc_array(tctx, struct lsa_LUIDAttribute, 1);
+ privs.set[0].luid = *luid;
+ privs.set[0].attribute = 0;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_AddPrivilegesToAccount_r(b, tctx, &r),
+ "AddPrivilegesToAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "AddPrivilegesToAccount failed");
+ return ret;
+}
+
+static bool test_EnumPrivsAccount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct policy_handle *acct_handle)
+{
+ struct lsa_EnumPrivsAccount r;
+ struct lsa_PrivilegeSet *privs = NULL;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting EnumPrivsAccount\n");
+
+ r.in.handle = acct_handle;
+ r.out.privs = &privs;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumPrivsAccount_r(b, tctx, &r),
+ "EnumPrivsAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "EnumPrivsAccount failed");
+
+ if (privs && privs->count > 0) {
+ int i;
+ for (i=0;i<privs->count;i++) {
+ test_LookupPrivName(b, tctx, handle,
+ &privs->set[i].luid);
+ }
+
+ ret &= test_RemovePrivilegesFromAccount(b, tctx, handle, acct_handle,
+ &privs->set[0].luid);
+ ret &= test_AddPrivilegesToAccount(b, tctx, acct_handle,
+ &privs->set[0].luid);
+ }
+
+ return ret;
+}
+
+static bool test_GetSystemAccessAccount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct policy_handle *acct_handle)
+{
+ uint32_t access_mask;
+ struct lsa_GetSystemAccessAccount r;
+
+ torture_comment(tctx, "\nTesting GetSystemAccessAccount\n");
+
+ r.in.handle = acct_handle;
+ r.out.access_mask = &access_mask;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetSystemAccessAccount_r(b, tctx, &r),
+ "GetSystemAccessAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "GetSystemAccessAccount failed");
+
+ if (r.out.access_mask != NULL) {
+ torture_comment(tctx, "Rights:");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_INTERACTIVE)
+ torture_comment(tctx, " LSA_POLICY_MODE_INTERACTIVE");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_NETWORK)
+ torture_comment(tctx, " LSA_POLICY_MODE_NETWORK");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_BATCH)
+ torture_comment(tctx, " LSA_POLICY_MODE_BATCH");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_SERVICE)
+ torture_comment(tctx, " LSA_POLICY_MODE_SERVICE");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_PROXY)
+ torture_comment(tctx, " LSA_POLICY_MODE_PROXY");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_DENY_INTERACTIVE)
+ torture_comment(tctx, " LSA_POLICY_MODE_DENY_INTERACTIVE");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_DENY_NETWORK)
+ torture_comment(tctx, " LSA_POLICY_MODE_DENY_NETWORK");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_DENY_BATCH)
+ torture_comment(tctx, " LSA_POLICY_MODE_DENY_BATCH");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_DENY_SERVICE)
+ torture_comment(tctx, " LSA_POLICY_MODE_DENY_SERVICE");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_REMOTE_INTERACTIVE)
+ torture_comment(tctx, " LSA_POLICY_MODE_REMOTE_INTERACTIVE");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_DENY_REMOTE_INTERACTIVE)
+ torture_comment(tctx, " LSA_POLICY_MODE_DENY_REMOTE_INTERACTIVE");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_ALL)
+ torture_comment(tctx, " LSA_POLICY_MODE_ALL");
+ if (*(r.out.access_mask) & LSA_POLICY_MODE_ALL_NT4)
+ torture_comment(tctx, " LSA_POLICY_MODE_ALL_NT4");
+ torture_comment(tctx, "\n");
+ }
+
+ return true;
+}
+
+static bool test_Delete(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_Delete r;
+
+ torture_comment(tctx, "\nTesting Delete\n");
+
+ r.in.handle = handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_Delete_r(b, tctx, &r),
+ "Delete failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_SUPPORTED,
+ "Delete should have failed NT_STATUS_NOT_SUPPORTED");
+
+ return true;
+}
+
+static bool test_DeleteObject(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_DeleteObject r;
+
+ torture_comment(tctx, "\nTesting DeleteObject\n");
+
+ r.in.handle = handle;
+ r.out.handle = handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_DeleteObject_r(b, tctx, &r),
+ "DeleteObject failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "DeleteObject failed");
+
+ return true;
+}
+
+
+static bool test_CreateAccount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_CreateAccount r;
+ struct dom_sid2 *newsid;
+ struct policy_handle acct_handle;
+
+ newsid = dom_sid_parse_talloc(tctx, "S-1-5-12349876-4321-2854");
+
+ torture_comment(tctx, "\nTesting CreateAccount\n");
+
+ r.in.handle = handle;
+ r.in.sid = newsid;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.acct_handle = &acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateAccount_r(b, tctx, &r),
+ "CreateAccount failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ struct lsa_OpenAccount r_o;
+ r_o.in.handle = handle;
+ r_o.in.sid = newsid;
+ r_o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r_o.out.acct_handle = &acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenAccount_r(b, tctx, &r_o),
+ "OpenAccount failed");
+ torture_assert_ntstatus_ok(tctx, r_o.out.result,
+ "OpenAccount failed");
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "CreateAccount failed");
+ }
+
+ if (!test_Delete(b, tctx, &acct_handle)) {
+ return false;
+ }
+
+ if (!test_DeleteObject(b, tctx, &acct_handle)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_DeleteTrustedDomain(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_StringLarge name)
+{
+ struct lsa_OpenTrustedDomainByName r;
+ struct policy_handle trustdom_handle;
+
+ r.in.handle = handle;
+ r.in.name.string = name.string;
+ r.in.access_mask = SEC_STD_DELETE;
+ r.out.trustdom_handle = &trustdom_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenTrustedDomainByName_r(b, tctx, &r),
+ "OpenTrustedDomainByName failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "OpenTrustedDomainByName failed");
+
+ if (!test_Delete(b, tctx, &trustdom_handle)) {
+ return false;
+ }
+
+ if (!test_DeleteObject(b, tctx, &trustdom_handle)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_DeleteTrustedDomainBySid(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct dom_sid *sid)
+{
+ struct lsa_DeleteTrustedDomain r;
+
+ r.in.handle = handle;
+ r.in.dom_sid = sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_DeleteTrustedDomain_r(b, tctx, &r),
+ "DeleteTrustedDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "DeleteTrustedDomain failed");
+
+ return true;
+}
+
+
+static bool test_CreateSecret(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_CreateSecret r;
+ struct lsa_OpenSecret r2;
+ struct lsa_SetSecret r3;
+ struct lsa_QuerySecret r4;
+ struct lsa_SetSecret r5;
+ struct lsa_QuerySecret r6;
+ struct lsa_SetSecret r7;
+ struct lsa_QuerySecret r8;
+ struct policy_handle sec_handle, sec_handle2, sec_handle3;
+ struct lsa_DeleteObject d_o;
+ struct lsa_DATA_BUF buf1;
+ struct lsa_DATA_BUF_PTR bufp1;
+ struct lsa_DATA_BUF_PTR bufp2;
+ DATA_BLOB enc_key;
+ bool ret = true;
+ DATA_BLOB session_key;
+ NTTIME old_mtime, new_mtime;
+ DATA_BLOB blob1;
+ const char *secret1 = "abcdef12345699qwerty";
+ char *secret2;
+ const char *secret3 = "ABCDEF12345699QWERTY";
+ char *secret4;
+ const char *secret5 = "NEW-SAMBA4-SECRET";
+ char *secret6;
+ char *secname[2];
+ int i;
+ const int LOCAL = 0;
+ const int GLOBAL = 1;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ secname[LOCAL] = talloc_asprintf(tctx, "torturesecret-%u", (unsigned int)random());
+ secname[GLOBAL] = talloc_asprintf(tctx, "G$torturesecret-%u", (unsigned int)random());
+
+ for (i=0; i< 2; i++) {
+ torture_comment(tctx, "\nTesting CreateSecret of %s\n", secname[i]);
+
+ init_lsa_String(&r.in.name, secname[i]);
+
+ r.in.handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.sec_handle = &sec_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateSecret_r(b, tctx, &r),
+ "CreateSecret failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "CreateSecret failed");
+
+ r.in.handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.sec_handle = &sec_handle3;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateSecret_r(b, tctx, &r),
+ "CreateSecret failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_COLLISION,
+ "CreateSecret should have failed OBJECT_NAME_COLLISION");
+
+ r2.in.handle = handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.name = r.in.name;
+ r2.out.sec_handle = &sec_handle2;
+
+ torture_comment(tctx, "Testing OpenSecret\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(b, tctx, &r2),
+ "OpenSecret failed");
+ torture_assert_ntstatus_ok(tctx, r2.out.result,
+ "OpenSecret failed");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_fetch_session_key(p, &session_key),
+ "dcerpc_fetch_session_key failed");
+
+ enc_key = sess_encrypt_string(secret1, &session_key);
+
+ r3.in.sec_handle = &sec_handle;
+ r3.in.new_val = &buf1;
+ r3.in.old_val = NULL;
+ r3.in.new_val->data = enc_key.data;
+ r3.in.new_val->length = enc_key.length;
+ r3.in.new_val->size = enc_key.length;
+
+ torture_comment(tctx, "Testing SetSecret\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_SetSecret_r(b, tctx, &r3),
+ "SetSecret failed");
+ torture_assert_ntstatus_ok(tctx, r3.out.result,
+ "SetSecret failed");
+
+ r3.in.sec_handle = &sec_handle;
+ r3.in.new_val = &buf1;
+ r3.in.old_val = NULL;
+ r3.in.new_val->data = enc_key.data;
+ r3.in.new_val->length = enc_key.length;
+ r3.in.new_val->size = enc_key.length;
+
+ /* break the encrypted data */
+ enc_key.data[0]++;
+
+ torture_comment(tctx, "Testing SetSecret with broken key\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_SetSecret_r(b, tctx, &r3),
+ "SetSecret failed");
+ torture_assert_ntstatus_equal(tctx, r3.out.result, NT_STATUS_UNKNOWN_REVISION,
+ "SetSecret should have failed UNKNOWN_REVISION");
+
+ data_blob_free(&enc_key);
+
+ ZERO_STRUCT(new_mtime);
+ ZERO_STRUCT(old_mtime);
+
+ /* fetch the secret back again */
+ r4.in.sec_handle = &sec_handle;
+ r4.in.new_val = &bufp1;
+ r4.in.new_mtime = &new_mtime;
+ r4.in.old_val = NULL;
+ r4.in.old_mtime = NULL;
+
+ bufp1.buf = NULL;
+
+ torture_comment(tctx, "Testing QuerySecret\n");
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(b, tctx, &r4),
+ "QuerySecret failed");
+ if (!NT_STATUS_IS_OK(r4.out.result)) {
+ torture_comment(tctx, "QuerySecret failed - %s\n", nt_errstr(r4.out.result));
+ ret = false;
+ } else {
+ if (r4.out.new_val == NULL || r4.out.new_val->buf == NULL) {
+ torture_comment(tctx, "No secret buffer returned\n");
+ ret = false;
+ } else {
+ blob1.data = r4.out.new_val->buf->data;
+ blob1.length = r4.out.new_val->buf->size;
+
+ secret2 = sess_decrypt_string(tctx,
+ &blob1, &session_key);
+
+ if (strcmp(secret1, secret2) != 0) {
+ torture_comment(tctx, "Returned secret (r4) '%s' doesn't match '%s'\n",
+ secret2, secret1);
+ ret = false;
+ }
+ }
+ }
+
+ enc_key = sess_encrypt_string(secret3, &session_key);
+
+ r5.in.sec_handle = &sec_handle;
+ r5.in.new_val = &buf1;
+ r5.in.old_val = NULL;
+ r5.in.new_val->data = enc_key.data;
+ r5.in.new_val->length = enc_key.length;
+ r5.in.new_val->size = enc_key.length;
+
+
+ smb_msleep(200);
+ torture_comment(tctx, "Testing SetSecret (existing value should move to old)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_SetSecret_r(b, tctx, &r5),
+ "SetSecret failed");
+ if (!NT_STATUS_IS_OK(r5.out.result)) {
+ torture_comment(tctx, "SetSecret failed - %s\n", nt_errstr(r5.out.result));
+ ret = false;
+ }
+
+ data_blob_free(&enc_key);
+
+ ZERO_STRUCT(new_mtime);
+ ZERO_STRUCT(old_mtime);
+
+ /* fetch the secret back again */
+ r6.in.sec_handle = &sec_handle;
+ r6.in.new_val = &bufp1;
+ r6.in.new_mtime = &new_mtime;
+ r6.in.old_val = &bufp2;
+ r6.in.old_mtime = &old_mtime;
+
+ bufp1.buf = NULL;
+ bufp2.buf = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(b, tctx, &r6),
+ "QuerySecret failed");
+ if (!NT_STATUS_IS_OK(r6.out.result)) {
+ torture_comment(tctx, "QuerySecret failed - %s\n", nt_errstr(r6.out.result));
+ ret = false;
+ secret4 = NULL;
+ } else {
+
+ if (r6.out.new_val->buf == NULL || r6.out.old_val->buf == NULL
+ || r6.out.new_mtime == NULL || r6.out.old_mtime == NULL) {
+ torture_comment(tctx, "Both secret buffers and both times not returned\n");
+ ret = false;
+ secret4 = NULL;
+ } else {
+ blob1.data = r6.out.new_val->buf->data;
+ blob1.length = r6.out.new_val->buf->size;
+
+ secret4 = sess_decrypt_string(tctx,
+ &blob1, &session_key);
+
+ if (strcmp(secret3, secret4) != 0) {
+ torture_comment(tctx, "Returned NEW secret %s doesn't match %s\n", secret4, secret3);
+ ret = false;
+ }
+
+ blob1.data = r6.out.old_val->buf->data;
+ blob1.length = r6.out.old_val->buf->length;
+
+ secret2 = sess_decrypt_string(tctx,
+ &blob1, &session_key);
+
+ if (strcmp(secret1, secret2) != 0) {
+ torture_comment(tctx, "Returned OLD secret %s doesn't match %s\n", secret2, secret1);
+ ret = false;
+ }
+
+ if (*r6.out.new_mtime == *r6.out.old_mtime) {
+ torture_comment(tctx, "Returned secret (r6-%d) %s must not have same mtime for both secrets: %s != %s\n",
+ i,
+ secname[i],
+ nt_time_string(tctx, *r6.out.old_mtime),
+ nt_time_string(tctx, *r6.out.new_mtime));
+ ret = false;
+ }
+ }
+ }
+
+ enc_key = sess_encrypt_string(secret5, &session_key);
+
+ r7.in.sec_handle = &sec_handle;
+ r7.in.old_val = &buf1;
+ r7.in.old_val->data = enc_key.data;
+ r7.in.old_val->length = enc_key.length;
+ r7.in.old_val->size = enc_key.length;
+ r7.in.new_val = NULL;
+
+ torture_comment(tctx, "Testing SetSecret of old Secret only\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_SetSecret_r(b, tctx, &r7),
+ "SetSecret failed");
+ if (!NT_STATUS_IS_OK(r7.out.result)) {
+ torture_comment(tctx, "SetSecret failed - %s\n", nt_errstr(r7.out.result));
+ ret = false;
+ }
+
+ data_blob_free(&enc_key);
+
+ /* fetch the secret back again */
+ r8.in.sec_handle = &sec_handle;
+ r8.in.new_val = &bufp1;
+ r8.in.new_mtime = &new_mtime;
+ r8.in.old_val = &bufp2;
+ r8.in.old_mtime = &old_mtime;
+
+ bufp1.buf = NULL;
+ bufp2.buf = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(b, tctx, &r8),
+ "QuerySecret failed");
+ if (!NT_STATUS_IS_OK(r8.out.result)) {
+ torture_comment(tctx, "QuerySecret failed - %s\n", nt_errstr(r8.out.result));
+ ret = false;
+ } else {
+ if (!r8.out.new_val || !r8.out.old_val) {
+ torture_comment(tctx, "in/out pointers not returned, despite being set on in for QuerySecret\n");
+ ret = false;
+ } else if (r8.out.new_val->buf != NULL) {
+ torture_comment(tctx, "NEW secret buffer must not be returned after OLD set\n");
+ ret = false;
+ } else if (r8.out.old_val->buf == NULL) {
+ torture_comment(tctx, "OLD secret buffer was not returned after OLD set\n");
+ ret = false;
+ } else if (r8.out.new_mtime == NULL || r8.out.old_mtime == NULL) {
+ torture_comment(tctx, "Both times not returned after OLD set\n");
+ ret = false;
+ } else {
+ blob1.data = r8.out.old_val->buf->data;
+ blob1.length = r8.out.old_val->buf->size;
+
+ secret6 = sess_decrypt_string(tctx,
+ &blob1, &session_key);
+
+ if (strcmp(secret5, secret6) != 0) {
+ torture_comment(tctx, "Returned OLD secret %s doesn't match %s\n", secret5, secret6);
+ ret = false;
+ }
+
+ if (*r8.out.new_mtime != *r8.out.old_mtime) {
+ torture_comment(tctx, "Returned secret (r8) %s did not had same mtime for both secrets: %s != %s\n",
+ secname[i],
+ nt_time_string(tctx, *r8.out.old_mtime),
+ nt_time_string(tctx, *r8.out.new_mtime));
+ ret = false;
+ }
+ }
+ }
+
+ if (!test_Delete(b, tctx, &sec_handle)) {
+ ret = false;
+ }
+
+ if (!test_DeleteObject(b, tctx, &sec_handle)) {
+ return false;
+ }
+
+ d_o.in.handle = &sec_handle2;
+ d_o.out.handle = &sec_handle2;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_DeleteObject_r(b, tctx, &d_o),
+ "DeleteObject failed");
+ torture_assert_ntstatus_equal(tctx, d_o.out.result, NT_STATUS_INVALID_HANDLE,
+ "OpenSecret expected INVALID_HANDLE");
+
+ torture_comment(tctx, "Testing OpenSecret of just-deleted secret\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(b, tctx, &r2),
+ "OpenSecret failed");
+ torture_assert_ntstatus_equal(tctx, r2.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "OpenSecret expected OBJECT_NAME_NOT_FOUND");
+ }
+ return ret;
+}
+
+
+static bool test_EnumAccountRights(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *acct_handle,
+ struct dom_sid *sid)
+{
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet rights;
+
+ torture_comment(tctx, "\nTesting EnumAccountRights\n");
+
+ r.in.handle = acct_handle;
+ r.in.sid = sid;
+ r.out.rights = &rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(b, tctx, &r),
+ "EnumAccountRights failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "EnumAccountRights of %s failed - %s\n",
+ dom_sid_string(tctx, sid), nt_errstr(r.out.result));
+ }
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "EnumAccountRights failed");
+
+ return true;
+}
+
+
+static bool test_QuerySecurity(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct policy_handle *acct_handle)
+{
+ struct lsa_QuerySecurity r;
+ struct sec_desc_buf *sdbuf = NULL;
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "\nskipping QuerySecurity test against Samba4\n");
+ return true;
+ }
+
+ torture_comment(tctx, "\nTesting QuerySecurity\n");
+
+ r.in.handle = acct_handle;
+ r.in.sec_info = SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ r.out.sdbuf = &sdbuf;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecurity_r(b, tctx, &r),
+ "QuerySecurity failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "QuerySecurity failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_OpenAccount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct dom_sid *sid)
+{
+ struct lsa_OpenAccount r;
+ struct policy_handle acct_handle;
+
+ torture_comment(tctx, "\nTesting OpenAccount\n");
+
+ r.in.handle = handle;
+ r.in.sid = sid;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.acct_handle = &acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenAccount_r(b, tctx, &r),
+ "OpenAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "OpenAccount failed");
+
+ if (!test_EnumPrivsAccount(b, tctx, handle, &acct_handle)) {
+ return false;
+ }
+
+ if (!test_GetSystemAccessAccount(b, tctx, handle, &acct_handle)) {
+ return false;
+ }
+
+ if (!test_QuerySecurity(b, tctx, handle, &acct_handle)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_EnumAccounts(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_EnumAccounts r;
+ struct lsa_SidArray sids1, sids2;
+ uint32_t resume_handle = 0;
+ int i;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting EnumAccounts\n");
+
+ r.in.handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.num_entries = 100;
+ r.out.resume_handle = &resume_handle;
+ r.out.sids = &sids1;
+
+ resume_handle = 0;
+ while (true) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(b, tctx, &r),
+ "EnumAccounts failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES)) {
+ break;
+ }
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "EnumAccounts failed");
+
+ if (!test_LookupSids(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &sids1)) {
+ return false;
+ }
+
+ if (!test_LookupSids2(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &sids1)) {
+ return false;
+ }
+
+ /* Can't test lookupSids3 here, as clearly we must not
+ * be on schannel, or we would not be able to do the
+ * rest */
+
+ torture_comment(tctx, "Testing all accounts\n");
+ for (i=0;i<sids1.num_sids;i++) {
+ ret &= test_OpenAccount(b, tctx, handle, sids1.sids[i].sid);
+ ret &= test_EnumAccountRights(b, tctx, handle, sids1.sids[i].sid);
+ }
+ torture_comment(tctx, "\n");
+ }
+
+ if (sids1.num_sids < 3) {
+ return ret;
+ }
+
+ torture_comment(tctx, "Trying EnumAccounts partial listing (asking for 1 at 2)\n");
+ resume_handle = 2;
+ r.in.num_entries = 1;
+ r.out.sids = &sids2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(b, tctx, &r),
+ "EnumAccounts failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "EnumAccounts failed");
+
+ if (sids2.num_sids != 1) {
+ torture_comment(tctx, "Returned wrong number of entries (%d)\n", sids2.num_sids);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_LookupPrivDisplayName(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_String *priv_name)
+{
+ struct lsa_LookupPrivDisplayName r;
+ /* produce a reasonable range of language output without screwing up
+ terminals */
+ uint16_t language_id = (random() % 4) + 0x409;
+ uint16_t returned_language_id = 0;
+ struct lsa_StringLarge *disp_name = NULL;
+
+ torture_comment(tctx, "\nTesting LookupPrivDisplayName(%s)\n", priv_name->string);
+
+ r.in.handle = handle;
+ r.in.name = priv_name;
+ r.in.language_id = language_id;
+ r.in.language_id_sys = 0;
+ r.out.returned_language_id = &returned_language_id;
+ r.out.disp_name = &disp_name;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupPrivDisplayName_r(b, tctx, &r),
+ "LookupPrivDisplayName failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "LookupPrivDisplayName failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+ torture_comment(tctx, "%s -> \"%s\" (language 0x%x/0x%x)\n",
+ priv_name->string, disp_name->string,
+ r.in.language_id, *r.out.returned_language_id);
+
+ return true;
+}
+
+static bool test_EnumAccountsWithUserRight(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_String *priv_name)
+{
+ struct lsa_EnumAccountsWithUserRight r;
+ struct lsa_SidArray sids;
+
+ ZERO_STRUCT(sids);
+
+ torture_comment(tctx, "\nTesting EnumAccountsWithUserRight(%s)\n", priv_name->string);
+
+ r.in.handle = handle;
+ r.in.name = priv_name;
+ r.out.sids = &sids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountsWithUserRight_r(b, tctx, &r),
+ "EnumAccountsWithUserRight failed");
+
+ /* NT_STATUS_NO_MORE_ENTRIES means no one has this privilege */
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES)) {
+ return true;
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "EnumAccountsWithUserRight failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_EnumPrivs(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_EnumPrivs r;
+ struct lsa_PrivArray privs1;
+ uint32_t resume_handle = 0;
+ int i;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting EnumPrivs\n");
+
+ r.in.handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.max_count = 100;
+ r.out.resume_handle = &resume_handle;
+ r.out.privs = &privs1;
+
+ resume_handle = 0;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumPrivs_r(b, tctx, &r),
+ "EnumPrivs failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "EnumPrivs failed");
+
+ for (i = 0; i< privs1.count; i++) {
+ test_LookupPrivDisplayName(b, tctx, handle, (struct lsa_String *)&privs1.privs[i].name);
+ test_LookupPrivValue(b, tctx, handle, (struct lsa_String *)&privs1.privs[i].name);
+ if (!test_EnumAccountsWithUserRight(b, tctx, handle, (struct lsa_String *)&privs1.privs[i].name)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryForestTrustInformation(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *trusted_domain_name)
+{
+ bool ret = true;
+ struct lsa_lsaRQueryForestTrustInformation r;
+ struct lsa_String string;
+ struct lsa_ForestTrustInformation info, *info_ptr;
+
+ torture_comment(tctx, "\nTesting lsaRQueryForestTrustInformation\n");
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping QueryForestTrustInformation against Samba4\n");
+ return true;
+ }
+
+ ZERO_STRUCT(string);
+
+ if (trusted_domain_name) {
+ init_lsa_String(&string, trusted_domain_name);
+ }
+
+ info_ptr = &info;
+
+ r.in.handle = handle;
+ r.in.trusted_domain_name = &string;
+ r.in.highest_record_type = LSA_FOREST_TRUST_TOP_LEVEL_NAME;
+ r.out.forest_trust_info = &info_ptr;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_lsaRQueryForestTrustInformation_r(b, tctx, &r),
+ "lsaRQueryForestTrustInformation failed");
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "lsaRQueryForestTrustInformation of %s failed - %s\n", trusted_domain_name, nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_query_each_TrustDomEx(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_DomainListEx *domains)
+{
+ int i;
+ bool ret = true;
+
+ for (i=0; i< domains->count; i++) {
+
+ if (domains->domains[i].trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
+ ret &= test_QueryForestTrustInformation(b, tctx, handle,
+ domains->domains[i].domain_name.string);
+ }
+ }
+
+ return ret;
+}
+
+static bool test_query_each_TrustDom(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct lsa_DomainList *domains)
+{
+ int i,j;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting OpenTrustedDomain, OpenTrustedDomainByName and QueryInfoTrustedDomain\n");
+ for (i=0; i< domains->count; i++) {
+ struct lsa_OpenTrustedDomain trust;
+ struct lsa_OpenTrustedDomainByName trust_by_name;
+ struct policy_handle trustdom_handle;
+ struct policy_handle handle2;
+ struct lsa_Close c;
+ struct lsa_CloseTrustedDomainEx c_trust;
+ int levels [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
+ int ok[] = {1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1};
+
+ if (domains->domains[i].sid) {
+ trust.in.handle = handle;
+ trust.in.sid = domains->domains[i].sid;
+ trust.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ trust.out.trustdom_handle = &trustdom_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenTrustedDomain_r(b, tctx, &trust),
+ "OpenTrustedDomain failed");
+
+ if (NT_STATUS_EQUAL(trust.out.result, NT_STATUS_NO_SUCH_DOMAIN)) {
+ torture_comment(tctx, "DOMAIN(%s, %s) not a direct trust?\n",
+ domains->domains[i].name.string,
+ dom_sid_string(tctx, domains->domains[i].sid));
+ continue;
+ }
+ if (!NT_STATUS_IS_OK(trust.out.result)) {
+ torture_comment(tctx, "OpenTrustedDomain failed - %s\n", nt_errstr(trust.out.result));
+ return false;
+ }
+
+ c.in.handle = &trustdom_handle;
+ c.out.handle = &handle2;
+
+ c_trust.in.handle = &trustdom_handle;
+ c_trust.out.handle = &handle2;
+
+ for (j=0; j < ARRAY_SIZE(levels); j++) {
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info = NULL;
+ q.in.trustdom_handle = &trustdom_handle;
+ q.in.level = levels[j];
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfo_r(b, tctx, &q),
+ "QueryTrustedDomainInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result) && ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level %d failed - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ } else if (NT_STATUS_IS_OK(q.out.result) && !ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level %d unexpectedly succeeded - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ }
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CloseTrustedDomainEx_r(b, tctx, &c_trust),
+ "CloseTrustedDomainEx failed");
+ if (!NT_STATUS_EQUAL(c_trust.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
+ torture_comment(tctx, "Expected CloseTrustedDomainEx to return NT_STATUS_NOT_IMPLEMENTED, instead - %s\n", nt_errstr(c_trust.out.result));
+ return false;
+ }
+
+ c.in.handle = &trustdom_handle;
+ c.out.handle = &handle2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_Close_r(b, tctx, &c),
+ "Close failed");
+ if (!NT_STATUS_IS_OK(c.out.result)) {
+ torture_comment(tctx, "Close of trusted domain failed - %s\n", nt_errstr(c.out.result));
+ return false;
+ }
+
+ for (j=0; j < ARRAY_SIZE(levels); j++) {
+ struct lsa_QueryTrustedDomainInfoBySid q;
+ union lsa_TrustedDomainInfo *info = NULL;
+
+ if (!domains->domains[i].sid) {
+ continue;
+ }
+
+ q.in.handle = handle;
+ q.in.dom_sid = domains->domains[i].sid;
+ q.in.level = levels[j];
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfoBySid_r(b, tctx, &q),
+ "lsa_QueryTrustedDomainInfoBySid failed");
+ if (!NT_STATUS_IS_OK(q.out.result) && ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfoBySid level %d failed - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ } else if (NT_STATUS_IS_OK(q.out.result) && !ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfoBySid level %d unexpectedly succeeded - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ }
+ }
+ }
+
+ trust_by_name.in.handle = handle;
+ trust_by_name.in.name.string = domains->domains[i].name.string;
+ trust_by_name.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ trust_by_name.out.trustdom_handle = &trustdom_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenTrustedDomainByName_r(b, tctx, &trust_by_name),
+ "OpenTrustedDomainByName failed");
+
+ if (NT_STATUS_EQUAL(trust_by_name.out.result, NT_STATUS_NO_SUCH_DOMAIN)) {
+ torture_comment(tctx, "DOMAIN(%s, %s) not a direct trust?\n",
+ domains->domains[i].name.string,
+ dom_sid_string(tctx, domains->domains[i].sid));
+ continue;
+ }
+ if (!NT_STATUS_IS_OK(trust_by_name.out.result)) {
+ torture_comment(tctx, "OpenTrustedDomainByName failed - %s\n", nt_errstr(trust_by_name.out.result));
+ return false;
+ }
+
+ for (j=0; j < ARRAY_SIZE(levels); j++) {
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info = NULL;
+ q.in.trustdom_handle = &trustdom_handle;
+ q.in.level = levels[j];
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfo_r(b, tctx, &q),
+ "QueryTrustedDomainInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result) && ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level %d failed - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ } else if (NT_STATUS_IS_OK(q.out.result) && !ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level %d unexpectedly succeeded - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ }
+ }
+
+ c.in.handle = &trustdom_handle;
+ c.out.handle = &handle2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_Close_r(b, tctx, &c),
+ "Close failed");
+ if (!NT_STATUS_IS_OK(c.out.result)) {
+ torture_comment(tctx, "Close of trusted domain failed - %s\n", nt_errstr(c.out.result));
+ return false;
+ }
+
+ for (j=0; j < ARRAY_SIZE(levels); j++) {
+ struct lsa_QueryTrustedDomainInfoByName q;
+ union lsa_TrustedDomainInfo *info = NULL;
+ struct lsa_String name;
+
+ name.string = domains->domains[i].name.string;
+
+ q.in.handle = handle;
+ q.in.trusted_domain = &name;
+ q.in.level = levels[j];
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfoByName_r(b, tctx, &q),
+ "QueryTrustedDomainInfoByName failed");
+ if (!NT_STATUS_IS_OK(q.out.result) && ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfoByName level %d failed - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ } else if (NT_STATUS_IS_OK(q.out.result) && !ok[j]) {
+ torture_comment(tctx, "QueryTrustedDomainInfoByName level %d unexpectedly succeeded - %s\n",
+ levels[j], nt_errstr(q.out.result));
+ ret = false;
+ }
+ }
+ }
+ return ret;
+}
+
+static bool test_EnumTrustDom(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_EnumTrustDom r;
+ uint32_t in_resume_handle = 0;
+ uint32_t out_resume_handle;
+ struct lsa_DomainList domains;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting EnumTrustDom\n");
+
+ r.in.handle = handle;
+ r.in.resume_handle = &in_resume_handle;
+ r.in.max_size = 0;
+ r.out.domains = &domains;
+ r.out.resume_handle = &out_resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumTrustDom_r(b, tctx, &r),
+ "lsa_EnumTrustDom failed");
+
+ /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
+ * always be larger than the previous input resume handle, in
+ * particular when hitting the last query it is vital to set the
+ * resume handle correctly to avoid infinite client loops, as
+ * seen e.g. with Windows XP SP3 when resume handle is 0 and
+ * status is NT_STATUS_OK - gd */
+
+ if (NT_STATUS_IS_OK(r.out.result) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES) ||
+ NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES))
+ {
+ if (out_resume_handle <= in_resume_handle) {
+ torture_comment(tctx, "EnumTrustDom failed - should have returned output resume_handle (0x%08x) larger than input resume handle (0x%08x)\n",
+ out_resume_handle, in_resume_handle);
+ return false;
+ }
+ }
+
+ if (NT_STATUS_IS_OK(r.out.result)) {
+ if (domains.count == 0) {
+ torture_comment(tctx, "EnumTrustDom failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n");
+ return false;
+ }
+ } else if (!(NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) || NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES))) {
+ torture_comment(tctx, "EnumTrustDom of zero size failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ /* Start from the bottom again */
+ in_resume_handle = 0;
+
+ do {
+ r.in.handle = handle;
+ r.in.resume_handle = &in_resume_handle;
+ r.in.max_size = LSA_ENUM_TRUST_DOMAIN_MULTIPLIER * 3;
+ r.out.domains = &domains;
+ r.out.resume_handle = &out_resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumTrustDom_r(b, tctx, &r),
+ "EnumTrustDom failed");
+
+ /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
+ * always be larger than the previous input resume handle, in
+ * particular when hitting the last query it is vital to set the
+ * resume handle correctly to avoid infinite client loops, as
+ * seen e.g. with Windows XP SP3 when resume handle is 0 and
+ * status is NT_STATUS_OK - gd */
+
+ if (NT_STATUS_IS_OK(r.out.result) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES) ||
+ NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES))
+ {
+ if (out_resume_handle <= in_resume_handle) {
+ torture_comment(tctx, "EnumTrustDom failed - should have returned output resume_handle (0x%08x) larger than input resume handle (0x%08x)\n",
+ out_resume_handle, in_resume_handle);
+ return false;
+ }
+ }
+
+ /* NO_MORE_ENTRIES is allowed */
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES)) {
+ if (domains.count == 0) {
+ return true;
+ }
+ torture_comment(tctx, "EnumTrustDom failed - should have returned 0 trusted domains with 'NT_STATUS_NO_MORE_ENTRIES'\n");
+ return false;
+ } else if (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES)) {
+ /* Windows 2003 gets this off by one on the first run */
+ if (r.out.domains->count < 3 || r.out.domains->count > 4) {
+ torture_comment(tctx, "EnumTrustDom didn't fill the buffer we "
+ "asked it to (got %d, expected %d / %d == %d entries)\n",
+ r.out.domains->count, LSA_ENUM_TRUST_DOMAIN_MULTIPLIER * 3,
+ LSA_ENUM_TRUST_DOMAIN_MULTIPLIER, r.in.max_size);
+ ret = false;
+ }
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "EnumTrustDom failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (domains.count == 0) {
+ torture_comment(tctx, "EnumTrustDom failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n");
+ return false;
+ }
+
+ ret &= test_query_each_TrustDom(b, tctx, handle, &domains);
+
+ in_resume_handle = out_resume_handle;
+
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+
+ return ret;
+}
+
+static bool test_EnumTrustDomEx(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_EnumTrustedDomainsEx r_ex;
+ uint32_t in_resume_handle = 0;
+ uint32_t out_resume_handle;
+ struct lsa_DomainListEx domains_ex;
+ bool ret = true;
+
+ torture_comment(tctx, "\nTesting EnumTrustedDomainsEx\n");
+
+ r_ex.in.handle = handle;
+ r_ex.in.resume_handle = &in_resume_handle;
+ r_ex.in.max_size = 0;
+ r_ex.out.domains = &domains_ex;
+ r_ex.out.resume_handle = &out_resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumTrustedDomainsEx_r(b, tctx, &r_ex),
+ "EnumTrustedDomainsEx failed");
+
+ /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST
+ * always be larger than the previous input resume handle, in
+ * particular when hitting the last query it is vital to set the
+ * resume handle correctly to avoid infinite client loops, as
+ * seen e.g. with Windows XP SP3 when resume handle is 0 and
+ * status is NT_STATUS_OK - gd */
+
+ if (NT_STATUS_IS_OK(r_ex.out.result) ||
+ NT_STATUS_EQUAL(r_ex.out.result, NT_STATUS_NO_MORE_ENTRIES) ||
+ NT_STATUS_EQUAL(r_ex.out.result, STATUS_MORE_ENTRIES))
+ {
+ if (out_resume_handle <= in_resume_handle) {
+ torture_comment(tctx, "EnumTrustDomEx failed - should have returned output resume_handle (0x%08x) larger than input resume handle (0x%08x)\n",
+ out_resume_handle, in_resume_handle);
+ return false;
+ }
+ }
+
+ if (NT_STATUS_IS_OK(r_ex.out.result)) {
+ if (domains_ex.count == 0) {
+ torture_comment(tctx, "EnumTrustDom failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n");
+ return false;
+ }
+ } else if (!(NT_STATUS_EQUAL(r_ex.out.result, STATUS_MORE_ENTRIES) ||
+ NT_STATUS_EQUAL(r_ex.out.result, NT_STATUS_NO_MORE_ENTRIES))) {
+ torture_comment(tctx, "EnumTrustDom of zero size failed - %s\n",
+ nt_errstr(r_ex.out.result));
+ return false;
+ }
+
+ in_resume_handle = 0;
+ do {
+ r_ex.in.handle = handle;
+ r_ex.in.resume_handle = &in_resume_handle;
+ r_ex.in.max_size = LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER * 3;
+ r_ex.out.domains = &domains_ex;
+ r_ex.out.resume_handle = &out_resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumTrustedDomainsEx_r(b, tctx, &r_ex),
+ "EnumTrustedDomainsEx failed");
+
+ in_resume_handle = out_resume_handle;
+
+ /* NO_MORE_ENTRIES is allowed */
+ if (NT_STATUS_EQUAL(r_ex.out.result, NT_STATUS_NO_MORE_ENTRIES)) {
+ if (domains_ex.count == 0) {
+ return true;
+ }
+ torture_comment(tctx, "EnumTrustDomainsEx failed - should have returned 0 trusted domains with 'NT_STATUS_NO_MORE_ENTRIES'\n");
+ return false;
+ } else if (NT_STATUS_EQUAL(r_ex.out.result, STATUS_MORE_ENTRIES)) {
+ /* Windows 2003 gets this off by one on the first run */
+ if (r_ex.out.domains->count < 3 || r_ex.out.domains->count > 4) {
+ torture_comment(tctx, "EnumTrustDom didn't fill the buffer we "
+ "asked it to (got %d, expected %d / %d == %d entries)\n",
+ r_ex.out.domains->count,
+ r_ex.in.max_size,
+ LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER,
+ r_ex.in.max_size / LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER);
+ }
+ } else if (!NT_STATUS_IS_OK(r_ex.out.result)) {
+ torture_comment(tctx, "EnumTrustedDomainEx failed - %s\n", nt_errstr(r_ex.out.result));
+ return false;
+ }
+
+ if (domains_ex.count == 0) {
+ torture_comment(tctx, "EnumTrustDomainEx failed - should have returned 'NT_STATUS_NO_MORE_ENTRIES' for 0 trusted domains\n");
+ return false;
+ }
+
+ ret &= test_query_each_TrustDomEx(b, tctx, handle, &domains_ex);
+
+ } while (NT_STATUS_EQUAL(r_ex.out.result, STATUS_MORE_ENTRIES));
+
+ return ret;
+}
+
+
+static bool test_CreateTrustedDomain(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_trusts)
+{
+ bool ret = true;
+ struct lsa_CreateTrustedDomain r;
+ struct lsa_DomainInfo trustinfo;
+ struct dom_sid **domsid;
+ struct policy_handle *trustdom_handle;
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info = NULL;
+ int i;
+
+ torture_comment(tctx, "\nTesting CreateTrustedDomain for %d domains\n", num_trusts);
+
+ if (!test_EnumTrustDom(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_EnumTrustDomEx(b, tctx, handle)) {
+ ret = false;
+ }
+
+ domsid = talloc_array(tctx, struct dom_sid *, num_trusts);
+ trustdom_handle = talloc_array(tctx, struct policy_handle, num_trusts);
+
+ for (i=0; i< num_trusts; i++) {
+ char *trust_name = talloc_asprintf(tctx, "TORTURE1%02d", i);
+ char *trust_sid = talloc_asprintf(tctx, "S-1-5-21-97398-379795-1%02d", i);
+
+ domsid[i] = dom_sid_parse_talloc(tctx, trust_sid);
+
+ trustinfo.sid = domsid[i];
+ init_lsa_String((struct lsa_String *)&trustinfo.name, trust_name);
+
+ r.in.policy_handle = handle;
+ r.in.info = &trustinfo;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.trustdom_handle = &trustdom_handle[i];
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateTrustedDomain_r(b, tctx, &r),
+ "CreateTrustedDomain failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ test_DeleteTrustedDomain(b, tctx, handle, trustinfo.name);
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateTrustedDomain_r(b, tctx, &r),
+ "CreateTrustedDomain failed");
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "CreateTrustedDomain failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ } else {
+
+ q.in.trustdom_handle = &trustdom_handle[i];
+ q.in.level = LSA_TRUSTED_DOMAIN_INFO_INFO_EX;
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfo_r(b, tctx, &q),
+ "QueryTrustedDomainInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level %d failed - %s\n", q.in.level, nt_errstr(q.out.result));
+ ret = false;
+ } else if (!q.out.info) {
+ ret = false;
+ } else {
+ if (strcmp(info->info_ex.domain_name.string, trustinfo.name.string) != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo returned inconsistent long name: %s != %s\n",
+ info->info_ex.domain_name.string, trustinfo.name.string);
+ ret = false;
+ }
+ if (strcmp(info->info_ex.netbios_name.string, trustinfo.name.string) != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo returned inconsistent short name: %s != %s\n",
+ info->info_ex.netbios_name.string, trustinfo.name.string);
+ ret = false;
+ }
+ if (info->info_ex.trust_type != LSA_TRUST_TYPE_DOWNLEVEL) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust type %d != %d\n",
+ trust_name, info->info_ex.trust_type, LSA_TRUST_TYPE_DOWNLEVEL);
+ ret = false;
+ }
+ if (info->info_ex.trust_attributes != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust attributes %d != %d\n",
+ trust_name, info->info_ex.trust_attributes, 0);
+ ret = false;
+ }
+ if (info->info_ex.trust_direction != LSA_TRUST_DIRECTION_OUTBOUND) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust direction %d != %d\n",
+ trust_name, info->info_ex.trust_direction, LSA_TRUST_DIRECTION_OUTBOUND);
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* now that we have some domains to look over, we can test the enum calls */
+ if (!test_EnumTrustDom(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_EnumTrustDomEx(b, tctx, handle)) {
+ ret = false;
+ }
+
+ for (i=0; i<num_trusts; i++) {
+ if (!test_DeleteTrustedDomainBySid(b, tctx, handle, domsid[i])) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool gen_authinfo_internal(TALLOC_CTX *mem_ctx,
+ const char *incoming_old, const char *incoming_new,
+ const char *outgoing_old, const char *outgoing_new,
+ DATA_BLOB session_key,
+ struct lsa_TrustDomainInfoAuthInfoInternal **_authinfo_internal)
+{
+ struct lsa_TrustDomainInfoAuthInfoInternal *authinfo_internal;
+ struct trustDomainPasswords auth_struct;
+ struct AuthenticationInformation in_info;
+ struct AuthenticationInformation io_info;
+ struct AuthenticationInformation on_info;
+ struct AuthenticationInformation oo_info;
+ size_t converted_size;
+ DATA_BLOB auth_blob;
+ enum ndr_err_code ndr_err;
+ bool ok;
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t _session_key;
+
+ authinfo_internal = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoAuthInfoInternal);
+ if (authinfo_internal == NULL) {
+ return false;
+ }
+
+ in_info.AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16,
+ incoming_new,
+ strlen(incoming_new),
+ &in_info.AuthInfo.clear.password,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ in_info.AuthInfo.clear.size = converted_size;
+
+ io_info.AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16,
+ incoming_old,
+ strlen(incoming_old),
+ &io_info.AuthInfo.clear.password,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ io_info.AuthInfo.clear.size = converted_size;
+
+ on_info.AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16,
+ outgoing_new,
+ strlen(outgoing_new),
+ &on_info.AuthInfo.clear.password,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ on_info.AuthInfo.clear.size = converted_size;
+
+ oo_info.AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16,
+ outgoing_old,
+ strlen(outgoing_old),
+ &oo_info.AuthInfo.clear.password,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ oo_info.AuthInfo.clear.size = converted_size;
+
+ generate_random_buffer(auth_struct.confounder, sizeof(auth_struct.confounder));
+ auth_struct.outgoing.count = 1;
+ auth_struct.outgoing.current.count = 1;
+ auth_struct.outgoing.current.array = &on_info;
+ auth_struct.outgoing.previous.count = 1;
+ auth_struct.outgoing.previous.array = &oo_info;
+
+ auth_struct.incoming.count = 1;
+ auth_struct.incoming.current.count = 1;
+ auth_struct.incoming.current.array = &in_info;
+ auth_struct.incoming.previous.count = 1;
+ auth_struct.incoming.previous.array = &io_info;
+
+ ndr_err = ndr_push_struct_blob(&auth_blob, mem_ctx, &auth_struct,
+ (ndr_push_flags_fn_t)ndr_push_trustDomainPasswords);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ _session_key = (gnutls_datum_t) {
+ .data = session_key.data,
+ .size = session_key.length,
+ };
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &_session_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd,
+ auth_blob.data,
+ auth_blob.length);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ authinfo_internal->auth_blob.size = auth_blob.length;
+ authinfo_internal->auth_blob.data = auth_blob.data;
+
+ *_authinfo_internal = authinfo_internal;
+
+ return true;
+}
+
+static bool gen_authinfo(TALLOC_CTX *mem_ctx,
+ const char *incoming_old, const char *incoming_new,
+ const char *outgoing_old, const char *outgoing_new,
+ struct lsa_TrustDomainInfoAuthInfo **_authinfo)
+{
+ struct lsa_TrustDomainInfoAuthInfo *authinfo;
+ struct lsa_TrustDomainInfoBuffer *in_buffer;
+ struct lsa_TrustDomainInfoBuffer *io_buffer;
+ struct lsa_TrustDomainInfoBuffer *on_buffer;
+ struct lsa_TrustDomainInfoBuffer *oo_buffer;
+ size_t converted_size;
+ bool ok;
+
+ authinfo = talloc_zero(mem_ctx, struct lsa_TrustDomainInfoAuthInfo);
+ if (authinfo == NULL) {
+ return false;
+ }
+
+ in_buffer = talloc_zero(authinfo, struct lsa_TrustDomainInfoBuffer);
+ if (in_buffer == NULL) {
+ return false;
+ }
+ in_buffer->AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(in_buffer, CH_UNIX, CH_UTF16,
+ incoming_new,
+ strlen(incoming_new),
+ &in_buffer->data.data,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ in_buffer->data.size = converted_size;
+
+ io_buffer = talloc_zero(authinfo, struct lsa_TrustDomainInfoBuffer);
+ if (io_buffer == NULL) {
+ return false;
+ }
+ io_buffer->AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(io_buffer, CH_UNIX, CH_UTF16,
+ incoming_old,
+ strlen(incoming_old),
+ &io_buffer->data.data,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ io_buffer->data.size = converted_size;
+
+ on_buffer = talloc_zero(authinfo, struct lsa_TrustDomainInfoBuffer);
+ if (on_buffer == NULL) {
+ return false;
+ }
+ on_buffer->AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(on_buffer, CH_UNIX, CH_UTF16,
+ outgoing_new,
+ strlen(outgoing_new),
+ &on_buffer->data.data,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ on_buffer->data.size = converted_size;
+
+ oo_buffer = talloc_zero(authinfo, struct lsa_TrustDomainInfoBuffer);
+ if (oo_buffer == NULL) {
+ return false;
+ }
+ oo_buffer->AuthType = TRUST_AUTH_TYPE_CLEAR;
+ ok = convert_string_talloc(oo_buffer, CH_UNIX, CH_UTF16,
+ outgoing_old,
+ strlen(outgoing_old),
+ &oo_buffer->data.data,
+ &converted_size);
+ if (!ok) {
+ return false;
+ }
+ oo_buffer->data.size = converted_size;
+
+ authinfo->incoming_count = 1;
+ authinfo->incoming_current_auth_info = in_buffer;
+ authinfo->incoming_previous_auth_info = io_buffer;
+ authinfo->outgoing_count = 1;
+ authinfo->outgoing_current_auth_info = on_buffer;
+ authinfo->outgoing_previous_auth_info = oo_buffer;
+
+ *_authinfo = authinfo;
+
+ return true;
+}
+
+static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ const char *server_name,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ const struct samr_Password *new_password = NULL;
+ const struct samr_Password *old_password = NULL;
+ uint32_t rid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ new_password = cli_credentials_get_nt_hash(machine_credentials, tctx);
+ old_password = cli_credentials_get_old_nt_hash(machine_credentials, tctx);
+
+ r.in.server_name = server_name;
+ r.in.computer_name = cli_credentials_get_workstation(machine_credentials);
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ a.in.server_name = server_name;
+ a.in.account_name = cli_credentials_get_username(machine_credentials);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = cli_credentials_get_workstation(machine_credentials);
+ a.in.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ new_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ if (!NT_STATUS_IS_OK(a.out.result)) {
+ if (!NT_STATUS_EQUAL(a.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_assert_ntstatus_ok(tctx, a.out.result,
+ "ServerAuthenticate3 failed");
+ }
+ return false;
+ }
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ if (old_password != NULL) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ old_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ if (!NT_STATUS_IS_OK(a.out.result)) {
+ if (!NT_STATUS_EQUAL(a.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_assert_ntstatus_ok(tctx, a.out.result,
+ "ServerAuthenticate3 (old) failed");
+ }
+ return false;
+ }
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential (old) chaining failed");
+ }
+
+ /* Prove that requesting a challenge again won't break it */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ *creds_out = creds;
+ return true;
+}
+
+#ifdef SAMBA4_USES_HEIMDAL
+
+/*
+ * This function is set in torture_krb5_init_context as krb5
+ * send_and_recv function. This allows us to override what server the
+ * test is aimed at, and to inspect the packets just before they are
+ * sent to the network, and before they are processed on the recv
+ * side.
+ *
+ * The torture_krb5_pre_send_test() and torture_krb5_post_recv_test()
+ * functions are implement the actual tests.
+ *
+ * When this asserts, the caller will get a spurious 'cannot contact
+ * any KDC' message.
+ *
+ */
+struct check_pw_with_krb5_ctx {
+ struct addrinfo *server;
+ const char *server_nb_domain;
+ const char *server_dns_domain;
+ struct {
+ unsigned io;
+ unsigned fail;
+ unsigned errors;
+ unsigned error_io;
+ unsigned ok;
+ } counts;
+ krb5_error error;
+ struct smb_krb5_context *smb_krb5_context;
+ krb5_get_init_creds_opt *krb_options;
+ krb5_creds my_creds;
+ krb5_get_creds_opt opt_canon;
+ krb5_get_creds_opt opt_nocanon;
+ krb5_principal upn_realm;
+ krb5_principal upn_dns;
+ krb5_principal upn_netbios;
+ krb5_ccache krbtgt_ccache;
+ krb5_principal krbtgt_trust_realm;
+ krb5_creds *krbtgt_trust_realm_creds;
+ krb5_principal krbtgt_trust_dns;
+ krb5_creds *krbtgt_trust_dns_creds;
+ krb5_principal krbtgt_trust_netbios;
+ krb5_creds *krbtgt_trust_netbios_creds;
+ krb5_principal cifs_trust_dns;
+ krb5_creds *cifs_trust_dns_creds;
+ krb5_principal cifs_trust_netbios;
+ krb5_creds *cifs_trust_netbios_creds;
+ krb5_principal drs_trust_dns;
+ krb5_creds *drs_trust_dns_creds;
+ krb5_principal drs_trust_netbios;
+ krb5_creds *drs_trust_netbios_creds;
+ krb5_principal four_trust_dns;
+ krb5_creds *four_trust_dns_creds;
+ krb5_creds krbtgt_referral_creds;
+ Ticket krbtgt_referral_ticket;
+ krb5_keyblock krbtgt_referral_keyblock;
+ EncTicketPart krbtgt_referral_enc_part;
+};
+
+static krb5_error_code check_pw_with_krb5_send_to_realm(
+ struct smb_krb5_context *smb_krb5_context,
+ void *data, /* struct check_pw_with_krb5_ctx */
+ krb5_const_realm realm,
+ time_t timeout,
+ const krb5_data *send_buf,
+ krb5_data *recv_buf)
+{
+ struct check_pw_with_krb5_ctx *ctx =
+ talloc_get_type_abort(data, struct check_pw_with_krb5_ctx);
+ krb5_error_code k5ret;
+ size_t used;
+ int ret;
+
+ SMB_ASSERT(smb_krb5_context == ctx->smb_krb5_context);
+
+ if (!strequal_m(realm, ctx->server_nb_domain) &&
+ !strequal_m(realm, ctx->server_dns_domain))
+ {
+ return KRB5_KDC_UNREACH;
+ }
+
+ krb5_free_error_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->error);
+ ctx->counts.io++;
+
+ k5ret = smb_krb5_send_and_recv_func_forced_tcp(ctx->smb_krb5_context,
+ ctx->server,
+ timeout, send_buf, recv_buf);
+ if (k5ret != 0) {
+ ctx->counts.fail++;
+ return k5ret;
+ }
+
+ ret = decode_KRB_ERROR(recv_buf->data, recv_buf->length,
+ &ctx->error, &used);
+ if (ret == 0) {
+ ctx->counts.errors++;
+ ctx->counts.error_io = ctx->counts.io;
+ } else {
+ ctx->counts.ok++;
+ }
+
+ return k5ret;
+}
+
+static int check_pw_with_krb5_ctx_destructor(struct check_pw_with_krb5_ctx *ctx)
+{
+ if (ctx->server != NULL) {
+ freeaddrinfo(ctx->server);
+ ctx->server = NULL;
+ }
+
+ if (ctx->krb_options != NULL) {
+ krb5_get_init_creds_opt_free(ctx->smb_krb5_context->krb5_context,
+ ctx->krb_options);
+ ctx->krb_options = NULL;
+ }
+
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->my_creds);
+
+ if (ctx->opt_canon != NULL) {
+ krb5_get_creds_opt_free(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon);
+ ctx->opt_canon = NULL;
+ }
+
+ if (ctx->opt_nocanon != NULL) {
+ krb5_get_creds_opt_free(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_nocanon);
+ ctx->opt_nocanon = NULL;
+ }
+
+ if (ctx->krbtgt_ccache != NULL) {
+ krb5_cc_close(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache);
+ ctx->krbtgt_ccache = NULL;
+ }
+
+ if (ctx->upn_realm != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->upn_realm);
+ ctx->upn_realm = NULL;
+ }
+
+ if (ctx->upn_dns != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->upn_dns);
+ ctx->upn_dns = NULL;
+ }
+
+ if (ctx->upn_netbios != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->upn_netbios);
+ ctx->upn_netbios = NULL;
+ }
+
+ if (ctx->krbtgt_trust_realm != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_realm);
+ ctx->krbtgt_trust_realm = NULL;
+ }
+
+ if (ctx->krbtgt_trust_realm_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_realm_creds);
+ ctx->krbtgt_trust_realm_creds = NULL;
+ }
+
+ if (ctx->krbtgt_trust_dns != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_dns);
+ ctx->krbtgt_trust_dns = NULL;
+ }
+
+ if (ctx->krbtgt_trust_dns_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_dns_creds);
+ ctx->krbtgt_trust_dns_creds = NULL;
+ }
+
+ if (ctx->krbtgt_trust_netbios != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_netbios);
+ ctx->krbtgt_trust_netbios = NULL;
+ }
+
+ if (ctx->krbtgt_trust_netbios_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_netbios_creds);
+ ctx->krbtgt_trust_netbios_creds = NULL;
+ }
+
+ if (ctx->cifs_trust_dns != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->cifs_trust_dns);
+ ctx->cifs_trust_dns = NULL;
+ }
+
+ if (ctx->cifs_trust_dns_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->cifs_trust_dns_creds);
+ ctx->cifs_trust_dns_creds = NULL;
+ }
+
+ if (ctx->cifs_trust_netbios != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->cifs_trust_netbios);
+ ctx->cifs_trust_netbios = NULL;
+ }
+
+ if (ctx->cifs_trust_netbios_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->cifs_trust_netbios_creds);
+ ctx->cifs_trust_netbios_creds = NULL;
+ }
+
+ if (ctx->drs_trust_dns != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->drs_trust_dns);
+ ctx->drs_trust_dns = NULL;
+ }
+
+ if (ctx->drs_trust_dns_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->drs_trust_dns_creds);
+ ctx->drs_trust_dns_creds = NULL;
+ }
+
+ if (ctx->drs_trust_netbios != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->drs_trust_netbios);
+ ctx->drs_trust_netbios = NULL;
+ }
+
+ if (ctx->drs_trust_netbios_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->drs_trust_netbios_creds);
+ ctx->drs_trust_netbios_creds = NULL;
+ }
+
+ if (ctx->four_trust_dns != NULL) {
+ krb5_free_principal(ctx->smb_krb5_context->krb5_context,
+ ctx->four_trust_dns);
+ ctx->four_trust_dns = NULL;
+ }
+
+ if (ctx->four_trust_dns_creds != NULL) {
+ krb5_free_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->four_trust_dns_creds);
+ ctx->four_trust_dns_creds = NULL;
+ }
+
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+
+ free_Ticket(&ctx->krbtgt_referral_ticket);
+
+ krb5_free_keyblock_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_keyblock);
+
+ free_EncTicketPart(&ctx->krbtgt_referral_enc_part);
+
+ krb5_free_error_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->error);
+
+ talloc_unlink(ctx, ctx->smb_krb5_context);
+ ctx->smb_krb5_context = NULL;
+ return 0;
+}
+
+static bool check_pw_with_krb5(struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ const struct lsa_TrustDomainInfoInfoEx *trusted)
+{
+ const char *trusted_dns_name = trusted->domain_name.string;
+ const char *trusted_netbios_name = trusted->netbios_name.string;
+ char *trusted_realm_name = NULL;
+ krb5_principal principal = NULL;
+ enum credentials_obtained obtained;
+ const char *error_string = NULL;
+ const char *workstation = cli_credentials_get_workstation(credentials);
+ const char *password = cli_credentials_get_password(credentials);
+#ifndef USING_EMBEDDED_HEIMDAL
+ const struct samr_Password *nthash = NULL;
+ const struct samr_Password *old_nthash = NULL;
+#endif
+ const char *old_password = cli_credentials_get_old_password(credentials);
+#ifndef USING_EMBEDDED_HEIMDAL
+ int kvno = cli_credentials_get_kvno(credentials);
+ int expected_kvno = 0;
+ krb5uint32 t_kvno = 0;
+#endif
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ krb5_error_code k5ret;
+ krb5_boolean k5ok;
+ int type;
+ bool ok;
+ struct check_pw_with_krb5_ctx *ctx = NULL;
+ char *assertion_message = NULL;
+ const char *realm = NULL;
+ char *upn_realm_string = NULL;
+ char *upn_dns_string = NULL;
+ char *upn_netbios_string = NULL;
+ char *krbtgt_cc_name = NULL;
+ char *krbtgt_trust_realm_string = NULL;
+ char *krbtgt_trust_dns_string = NULL;
+ char *krbtgt_trust_netbios_string = NULL;
+ char *cifs_trust_dns_string = NULL;
+ char *cifs_trust_netbios_string = NULL;
+ char *drs_trust_dns_string = NULL;
+ char *drs_trust_netbios_string = NULL;
+ char *four_trust_dns_string = NULL;
+
+ ctx = talloc_zero(tctx, struct check_pw_with_krb5_ctx);
+ torture_assert(tctx, ctx != NULL, "Failed to allocate");
+
+ realm = cli_credentials_get_realm(credentials);
+ trusted_realm_name = strupper_talloc(tctx, trusted_dns_name);
+
+#ifndef USING_EMBEDDED_HEIMDAL
+ nthash = cli_credentials_get_nt_hash(credentials, ctx);
+ old_nthash = cli_credentials_get_old_nt_hash(credentials, ctx);
+#endif
+
+ k5ret = smb_krb5_init_context(ctx, tctx->lp_ctx, &ctx->smb_krb5_context);
+ torture_assert_int_equal(tctx, k5ret, 0, "smb_krb5_init_context failed");
+
+ ctx->server_nb_domain = cli_credentials_get_domain(credentials);
+ ctx->server_dns_domain = cli_credentials_get_realm(credentials);
+
+ ok = interpret_string_addr_internal(&ctx->server, host, 0);
+ torture_assert(tctx, ok, "Failed to parse target server");
+ talloc_set_destructor(ctx, check_pw_with_krb5_ctx_destructor);
+
+ set_sockaddr_port(ctx->server->ai_addr, 88);
+
+ k5ret = smb_krb5_set_send_to_kdc_func(ctx->smb_krb5_context,
+ check_pw_with_krb5_send_to_realm,
+ NULL, /* send_to_kdc */
+ ctx);
+ torture_assert_int_equal(tctx, k5ret, 0, "krb5_set_send_to_kdc_func failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_alloc(ctx->smb_krb5_context->krb5_context,
+ &ctx->krb_options),
+ 0, "krb5_get_init_creds_opt_alloc failed");
+ torture_assert_int_equal(tctx,
+ krb5_get_init_creds_opt_set_pac_request(
+ ctx->smb_krb5_context->krb5_context,
+ ctx->krb_options, true),
+ 0, "krb5_get_init_creds_opt_set_pac_request failed");
+
+ upn_realm_string = talloc_asprintf(ctx, "user@%s",
+ trusted_realm_name);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->upn_realm,
+ realm, upn_realm_string, NULL),
+ 0, "smb_krb5_make_principal failed");
+ smb_krb5_principal_set_type(ctx->smb_krb5_context->krb5_context,
+ ctx->upn_realm, KRB5_NT_ENTERPRISE_PRINCIPAL);
+
+ upn_dns_string = talloc_asprintf(ctx, "user@%s",
+ trusted_dns_name);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->upn_dns,
+ realm, upn_dns_string, NULL),
+ 0, "smb_krb5_make_principal failed");
+ smb_krb5_principal_set_type(ctx->smb_krb5_context->krb5_context,
+ ctx->upn_dns, KRB5_NT_ENTERPRISE_PRINCIPAL);
+
+ upn_netbios_string = talloc_asprintf(ctx, "user@%s",
+ trusted_netbios_name);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->upn_netbios,
+ realm, upn_netbios_string, NULL),
+ 0, "smb_krb5_make_principal failed");
+ smb_krb5_principal_set_type(ctx->smb_krb5_context->krb5_context,
+ ctx->upn_netbios, KRB5_NT_ENTERPRISE_PRINCIPAL);
+
+ k5ret = principal_from_credentials(ctx, credentials, ctx->smb_krb5_context,
+ &principal, &obtained, &error_string);
+ torture_assert_int_equal(tctx, k5ret, 0, error_string);
+
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_init_creds_password(ctx->smb_krb5_context->krb5_context,
+ &ctx->my_creds, ctx->upn_realm,
+ "_none_", NULL, NULL, 0,
+ NULL, ctx->krb_options);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_init_creds_password(%s, canon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u/%u,ok=%u]",
+ upn_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.error_io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.error_io, 1, assertion_message);
+ torture_assert_int_equal(tctx, KRB5_ERROR_CODE(&ctx->error), 68, assertion_message);
+ torture_assert(tctx, ctx->error.crealm != NULL, assertion_message);
+ torture_assert_str_equal(tctx, *ctx->error.crealm, trusted_realm_name, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert(tctx, ctx->error.cname != NULL, assertion_message);
+ torture_assert_int_equal(tctx, ctx->error.cname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL, assertion_message);
+ torture_assert_int_equal(tctx, ctx->error.cname->name_string.len, 1, assertion_message);
+ torture_assert_str_equal(tctx, ctx->error.cname->name_string.val[0], upn_realm_string, assertion_message);
+#else
+ torture_assert(tctx, ctx->error.cname == NULL, assertion_message);
+#endif
+ torture_assert_str_equal(tctx, ctx->error.realm, realm, assertion_message);
+
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_init_creds_password(ctx->smb_krb5_context->krb5_context,
+ &ctx->my_creds, ctx->upn_dns,
+ "_none_", NULL, NULL, 0,
+ NULL, ctx->krb_options);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_init_creds_password(%s, canon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u/%u,ok=%u]",
+ upn_dns_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.error_io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.error_io, 1, assertion_message);
+ torture_assert_int_equal(tctx, KRB5_ERROR_CODE(&ctx->error), 68, assertion_message);
+ torture_assert(tctx, ctx->error.crealm != NULL, assertion_message);
+ torture_assert_str_equal(tctx, *ctx->error.crealm, trusted_realm_name, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert(tctx, ctx->error.cname != NULL, assertion_message);
+ torture_assert_int_equal(tctx, ctx->error.cname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL, assertion_message);
+ torture_assert_int_equal(tctx, ctx->error.cname->name_string.len, 1, assertion_message);
+ torture_assert_str_equal(tctx, ctx->error.cname->name_string.val[0], upn_dns_string, assertion_message);
+#else
+ torture_assert(tctx, ctx->error.cname == NULL, assertion_message);
+#endif
+ torture_assert_str_equal(tctx, ctx->error.realm, realm, assertion_message);
+
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_init_creds_password(ctx->smb_krb5_context->krb5_context,
+ &ctx->my_creds, ctx->upn_netbios,
+ "_none_", NULL, NULL, 0,
+ NULL, ctx->krb_options);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_init_creds_password(%s, canon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u/%u,ok=%u]",
+ upn_netbios_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.error_io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.error_io, 1, assertion_message);
+ torture_assert_int_equal(tctx, KRB5_ERROR_CODE(&ctx->error), 68, assertion_message);
+ torture_assert(tctx, ctx->error.crealm != NULL, assertion_message);
+ torture_assert_str_equal(tctx, *ctx->error.crealm, trusted_realm_name, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert(tctx, ctx->error.cname != NULL, assertion_message);
+ torture_assert_int_equal(tctx, ctx->error.cname->name_type, KRB5_NT_ENTERPRISE_PRINCIPAL, assertion_message);
+ torture_assert_int_equal(tctx, ctx->error.cname->name_string.len, 1, assertion_message);
+ torture_assert_str_equal(tctx, ctx->error.cname->name_string.val[0], upn_netbios_string, assertion_message);
+#else
+ torture_assert(tctx, ctx->error.cname == NULL, assertion_message);
+#endif
+ torture_assert_str_equal(tctx, ctx->error.realm, realm, assertion_message);
+
+ torture_comment(tctx, "(%s:%s) password[%s] old_password[%s]\n",
+ __location__, __FUNCTION__,
+ password, old_password);
+ if (old_password != NULL) {
+ k5ret = krb5_get_init_creds_password(ctx->smb_krb5_context->krb5_context,
+ &ctx->my_creds, principal,
+ old_password, NULL, NULL, 0,
+ NULL, ctx->krb_options);
+ torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_PREAUTH_FAILED,
+ "preauth should fail with old password");
+ }
+
+ k5ret = krb5_get_init_creds_password(ctx->smb_krb5_context->krb5_context,
+ &ctx->my_creds, principal,
+ password, NULL, NULL, 0,
+ NULL, ctx->krb_options);
+ if (k5ret == KRB5KDC_ERR_PREAUTH_FAILED) {
+ TALLOC_FREE(ctx);
+ return false;
+ }
+
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_init_creds_password for failed: %s",
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ torture_assert_int_equal(tctx,
+ krb5_get_creds_opt_alloc(ctx->smb_krb5_context->krb5_context,
+ &ctx->opt_canon),
+ 0, "krb5_get_creds_opt_alloc");
+
+ krb5_get_creds_opt_add_options(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ KRB5_GC_CANONICALIZE);
+
+ krb5_get_creds_opt_add_options(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ KRB5_GC_NO_STORE);
+
+ torture_assert_int_equal(tctx,
+ krb5_get_creds_opt_alloc(ctx->smb_krb5_context->krb5_context,
+ &ctx->opt_nocanon),
+ 0, "krb5_get_creds_opt_alloc");
+
+ krb5_get_creds_opt_add_options(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_nocanon,
+ KRB5_GC_NO_STORE);
+
+ krbtgt_cc_name = talloc_asprintf(ctx, "MEMORY:%p.krbtgt", ctx->smb_krb5_context);
+ torture_assert_int_equal(tctx,
+ krb5_cc_resolve(ctx->smb_krb5_context->krb5_context,
+ krbtgt_cc_name,
+ &ctx->krbtgt_ccache),
+ 0, "krb5_cc_resolve failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_cc_initialize(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ ctx->my_creds.client),
+ 0, "krb5_cc_initialize failed");
+
+ torture_assert_int_equal(tctx,
+ krb5_cc_store_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ &ctx->my_creds),
+ 0, "krb5_cc_store_cred failed");
+
+ krbtgt_trust_realm_string = talloc_asprintf(ctx, "krbtgt/%s@%s",
+ trusted_realm_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_trust_realm,
+ realm, "krbtgt",
+ trusted_realm_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ krbtgt_trust_dns_string = talloc_asprintf(ctx, "krbtgt/%s@%s",
+ trusted_dns_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_trust_dns,
+ realm, "krbtgt",
+ trusted_dns_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ krbtgt_trust_netbios_string = talloc_asprintf(ctx, "krbtgt/%s@%s",
+ trusted_netbios_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_trust_netbios,
+ realm, "krbtgt",
+ trusted_netbios_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ /* Confirm if we can do a TGS for krbtgt/trusted_realm */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_nocanon,
+ ctx->krbtgt_ccache,
+ ctx->krbtgt_trust_realm,
+ &ctx->krbtgt_trust_realm_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s, canon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_realm_creds->server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_realm_creds->server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Confirm if we have no referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+
+ /* Confirm if we can do a TGS for krbtgt/trusted_dns with CANON */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->krbtgt_trust_dns,
+ &ctx->krbtgt_trust_dns_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s, canon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ krbtgt_trust_dns_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+#endif
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+ k5ret = decode_Ticket(ctx->krbtgt_referral_creds.ticket.data,
+ ctx->krbtgt_referral_creds.ticket.length,
+ &ctx->krbtgt_referral_ticket, NULL);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ if (kvno > 0) {
+ expected_kvno = kvno - 1;
+ }
+ if (ctx->krbtgt_referral_ticket.enc_part.kvno != NULL) {
+ t_kvno = *ctx->krbtgt_referral_ticket.enc_part.kvno;
+ assertion_message = talloc_asprintf(ctx,
+ "krbtgt_referral_ticket(%s) kvno(%u) expected(%u) current(%u)",
+ krbtgt_trust_realm_string,
+ (unsigned)t_kvno, (unsigned)expected_kvno,(unsigned)kvno);
+ torture_comment(tctx, "%s\n", assertion_message);
+ torture_assert_int_not_equal(tctx, t_kvno, 0, assertion_message);
+ } else {
+ assertion_message = talloc_asprintf(ctx,
+ "krbtgt_referral_ticket(%s) kvno(NULL) expected(%u) current(%u)",
+ krbtgt_trust_realm_string,
+ (unsigned)expected_kvno,(unsigned)kvno);
+ torture_comment(tctx, "%s\n", assertion_message);
+ }
+ torture_assert_int_equal(tctx, t_kvno, expected_kvno, assertion_message);
+
+ if (old_nthash != NULL && expected_kvno != kvno) {
+ torture_comment(tctx, "old_nthash: %s\n", assertion_message);
+ k5ret = smb_krb5_keyblock_init_contents(ctx->smb_krb5_context->krb5_context,
+ ENCTYPE_ARCFOUR_HMAC,
+ old_nthash->hash,
+ sizeof(old_nthash->hash),
+ &ctx->krbtgt_referral_keyblock);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ } else {
+ torture_comment(tctx, "nthash: %s\n", assertion_message);
+ k5ret = smb_krb5_keyblock_init_contents(ctx->smb_krb5_context->krb5_context,
+ ENCTYPE_ARCFOUR_HMAC,
+ nthash->hash,
+ sizeof(nthash->hash),
+ &ctx->krbtgt_referral_keyblock);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+ }
+ k5ret = krb5_decrypt_ticket(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_ticket,
+ &ctx->krbtgt_referral_keyblock,
+ &ctx->krbtgt_referral_enc_part,
+ 0);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ /* Confirm if we can do a TGS for krbtgt/trusted_dns no CANON */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_nocanon,
+ ctx->krbtgt_ccache,
+ ctx->krbtgt_trust_dns,
+ &ctx->krbtgt_trust_dns_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s, nocanon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ krbtgt_trust_dns_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 2, assertion_message);
+#endif
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_dns_creds->server,
+#ifdef USING_EMBEDDED_HEIMDAL
+ ctx->krbtgt_trust_dns);
+#else
+ ctx->krbtgt_trust_realm);
+#endif
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_dns_creds->server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ /* Confirm if we can do a TGS for krbtgt/NETBIOS with CANON */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->krbtgt_trust_netbios,
+ &ctx->krbtgt_trust_netbios_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s, canon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ krbtgt_trust_netbios_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+#endif
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_netbios_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ /* Confirm if we can do a TGS for krbtgt/NETBIOS no CANON */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_nocanon,
+ ctx->krbtgt_ccache,
+ ctx->krbtgt_trust_netbios,
+ &ctx->krbtgt_trust_netbios_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s, nocanon) for failed: "
+ "(%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ krbtgt_trust_netbios_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 2, assertion_message);
+#endif
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_netbios_creds->server,
+#ifdef USING_EMBEDDED_HEIMDAL
+ ctx->krbtgt_trust_netbios);
+#else
+ ctx->krbtgt_trust_realm);
+#endif
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_trust_netbios_creds->server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ cifs_trust_dns_string = talloc_asprintf(ctx, "cifs/%s@%s",
+ trusted_dns_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->cifs_trust_dns,
+ realm, "cifs",
+ trusted_dns_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ /* Confirm if we get krbtgt/trusted_realm back when asking for cifs/trusted_realm */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->cifs_trust_dns,
+ &ctx->cifs_trust_dns_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s) for failed: (%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ cifs_trust_dns_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 2, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+#endif
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ cifs_trust_netbios_string = talloc_asprintf(ctx, "cifs/%s@%s",
+ trusted_netbios_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->cifs_trust_netbios,
+ realm, "cifs",
+ trusted_netbios_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ /* Confirm if we get krbtgt/trusted_realm back when asking for cifs/trusted_realm */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->cifs_trust_netbios,
+ &ctx->cifs_trust_netbios_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s) for failed: (%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ cifs_trust_netbios_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 2, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+#endif
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ drs_trust_dns_string = talloc_asprintf(ctx,
+ "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s@%s",
+ workstation, trusted_dns_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->drs_trust_dns,
+ realm, "E3514235-4B06-11D1-AB04-00C04FC2DCD2",
+ workstation, trusted_dns_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ /* Confirm if we get krbtgt/trusted_realm back when asking for a 3 part principal */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->drs_trust_dns,
+ &ctx->drs_trust_dns_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s) for failed: (%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ drs_trust_dns_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 2, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+#endif
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ drs_trust_netbios_string = talloc_asprintf(ctx,
+ "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s@%s",
+ workstation, trusted_netbios_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->drs_trust_netbios,
+ realm, "E3514235-4B06-11D1-AB04-00C04FC2DCD2",
+ workstation, trusted_netbios_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ /* Confirm if we get krbtgt/trusted_realm back when asking for a 3 part principal */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->drs_trust_netbios,
+ &ctx->drs_trust_netbios_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s) for failed: (%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ drs_trust_netbios_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5_KDC_UNREACH, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 2, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.ok, 1, assertion_message);
+#endif
+
+ /* Confirm if we have the referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+#else
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+
+ k5ok = krb5_principal_compare(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server,
+ ctx->krbtgt_trust_realm);
+ torture_assert(tctx, k5ok, assertion_message);
+ type = smb_krb5_principal_get_type(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_referral_creds.server);
+ torture_assert_int_equal(tctx, type, KRB5_NT_SRV_INST, assertion_message);
+
+ /* Delete the referral ticket from the cache */
+ k5ret = krb5_cc_remove_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_remove_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, 0, assertion_message);
+#endif
+
+ four_trust_dns_string = talloc_asprintf(ctx, "four/tree/two/%s@%s",
+ trusted_dns_name, realm);
+ torture_assert_int_equal(tctx,
+ smb_krb5_make_principal(ctx->smb_krb5_context->krb5_context,
+ &ctx->four_trust_dns,
+ realm, "four", "tree", "two",
+ trusted_dns_name, NULL),
+ 0, "smb_krb5_make_principal failed");
+
+ /* Confirm if we get an error back for a 4 part principal */
+ ZERO_STRUCT(ctx->counts);
+ k5ret = krb5_get_creds(ctx->smb_krb5_context->krb5_context,
+ ctx->opt_canon,
+ ctx->krbtgt_ccache,
+ ctx->four_trust_dns,
+ &ctx->four_trust_dns_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_get_creds(%s) for failed: (%d) %s; t[d=0x%x,t=0x%x,a=0x%x] [io=%u,error=%u,ok=%u]",
+ four_trust_dns_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx),
+ trusted->trust_direction,
+ trusted->trust_type,
+ trusted->trust_attributes,
+ ctx->counts.io, ctx->counts.errors, ctx->counts.ok);
+ torture_assert_int_equal(tctx, k5ret, KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, assertion_message);
+#ifdef USING_EMBEDDED_HEIMDAL
+ torture_assert_int_equal(tctx, ctx->counts.io, 2, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.error_io, 2, assertion_message);
+#else
+ torture_assert_int_equal(tctx, ctx->counts.io, 1, assertion_message);
+ torture_assert_int_equal(tctx, ctx->counts.error_io, 1, assertion_message);
+#endif
+ torture_assert_int_equal(tctx, KRB5_ERROR_CODE(&ctx->error), 7, assertion_message);
+
+ /* Confirm if we have no referral ticket in the cache */
+ krb5_free_cred_contents(ctx->smb_krb5_context->krb5_context,
+ &ctx->krbtgt_referral_creds);
+ k5ret = krb5_cc_retrieve_cred(ctx->smb_krb5_context->krb5_context,
+ ctx->krbtgt_ccache,
+ 0,
+ ctx->krbtgt_trust_realm_creds,
+ &ctx->krbtgt_referral_creds);
+ assertion_message = talloc_asprintf(ctx,
+ "krb5_cc_retrieve_cred(%s) for failed: (%d) %s",
+ krbtgt_trust_realm_string,
+ k5ret,
+ smb_get_krb5_error_message(ctx->smb_krb5_context->krb5_context,
+ k5ret, ctx));
+ torture_assert_int_equal(tctx, k5ret, KRB5_CC_END, assertion_message);
+
+ TALLOC_FREE(ctx);
+ return true;
+}
+#endif
+
+static bool check_dom_trust_pw(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *our_netbios_name,
+ const char *our_dns_name,
+ enum netr_SchannelType secure_channel_type,
+ const struct lsa_TrustDomainInfoInfoEx *trusted,
+ const char *previous_password,
+ const char *current_password,
+ uint32_t current_version,
+ const char *next_password,
+ uint32_t next_version,
+ bool expected_result)
+{
+ struct cli_credentials *incoming_creds;
+ char *server_name = NULL;
+ char *account = NULL;
+ char *principal = NULL;
+ char *workstation = NULL;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *ip;
+ struct nbt_name nbt_name;
+ struct dcerpc_binding *b2;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword samr_crypt_password;
+ struct netr_CryptPassword netr_crypt_password;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+ struct netr_ServerPasswordSet2 s;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
+ NTSTATUS status;
+ bool ok;
+ int rc;
+ const char *trusted_netbios_name = trusted->netbios_name.string;
+ const char *trusted_dns_name = trusted->domain_name.string;
+ struct tsocket_address *dest_addr;
+ struct cldap_socket *cldap;
+ struct cldap_netlogon cldap1;
+
+ incoming_creds = cli_credentials_init(tctx);
+ torture_assert(tctx, incoming_creds, "cli_credentials_init");
+
+ cli_credentials_set_domain(incoming_creds, our_netbios_name, CRED_SPECIFIED);
+ cli_credentials_set_realm(incoming_creds, our_dns_name, CRED_SPECIFIED);
+
+ if (secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
+ account = talloc_asprintf(tctx, "%s.", trusted_dns_name);
+ torture_assert(tctx, account, __location__);
+
+ principal = talloc_asprintf(tctx, "%s$@%s",
+ trusted_netbios_name,
+ cli_credentials_get_realm(incoming_creds));
+ torture_assert(tctx, principal, __location__);
+
+ workstation = talloc_asprintf(tctx, "%sUP",
+ trusted_netbios_name);
+ torture_assert(tctx, workstation, __location__);
+ } else {
+ account = talloc_asprintf(tctx, "%s$", trusted_netbios_name);
+ torture_assert(tctx, account, __location__);
+
+ workstation = talloc_asprintf(tctx, "%sDOWN",
+ trusted_netbios_name);
+ torture_assert(tctx, workstation, __location__);
+ }
+
+ cli_credentials_set_username(incoming_creds, account, CRED_SPECIFIED);
+ if (principal != NULL) {
+ cli_credentials_set_principal(incoming_creds, principal,
+ CRED_SPECIFIED);
+ }
+ cli_credentials_set_kvno(incoming_creds, current_version);
+ cli_credentials_set_password(incoming_creds, current_password, CRED_SPECIFIED);
+ cli_credentials_set_old_password(incoming_creds, previous_password, CRED_SPECIFIED);
+ cli_credentials_set_workstation(incoming_creds, workstation, CRED_SPECIFIED);
+ cli_credentials_set_secure_channel_type(incoming_creds, secure_channel_type);
+
+ make_nbt_name_server(&nbt_name, host);
+
+ status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0, &nbt_name, tctx, &ip, tctx->ev);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx,"Failed to resolve %s: %s",
+ nbt_name.name, nt_errstr(status)));
+
+ rc = tsocket_address_inet_from_strings(tctx, "ip",
+ ip,
+ lpcfg_cldap_port(tctx->lp_ctx),
+ &dest_addr);
+ torture_assert_int_equal(tctx, rc, 0,
+ talloc_asprintf(tctx,
+ "tsocket_address_inet_from_strings failed parsing %s:%d",
+ host, lpcfg_cldap_port(tctx->lp_ctx)));
+
+ /* cldap_socket_init should now know about the dest. address */
+ status = cldap_socket_init(tctx, NULL, dest_addr, &cldap);
+ torture_assert_ntstatus_ok(tctx, status, "cldap_socket_init");
+
+ ZERO_STRUCT(cldap1);
+ cldap1.in.dest_address = NULL;
+ cldap1.in.dest_port = 0;
+ cldap1.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
+ cldap1.in.user = account;
+ if (secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
+ cldap1.in.acct_control = ACB_AUTOLOCK;
+ } else {
+ cldap1.in.acct_control = ACB_DOMTRUST;
+ }
+ status = cldap_netlogon(cldap, tctx, &cldap1);
+ torture_assert_ntstatus_ok(tctx, status, "cldap_netlogon");
+ torture_assert_int_equal(tctx, cldap1.out.netlogon.ntver,
+ NETLOGON_NT_VERSION_5EX,
+ "ntver");
+ torture_assert_int_equal(tctx, cldap1.out.netlogon.data.nt5_ex.nt_version,
+ NETLOGON_NT_VERSION_1 | NETLOGON_NT_VERSION_5EX,
+ "nt_version");
+ torture_assert_int_equal(tctx, cldap1.out.netlogon.data.nt5_ex.command,
+ LOGON_SAM_LOGON_RESPONSE_EX,
+ "command");
+ torture_assert_str_equal(tctx, cldap1.out.netlogon.data.nt5_ex.user_name,
+ cldap1.in.user,
+ "user_name");
+ server_name = talloc_asprintf(tctx, "\\\\%s",
+ cldap1.out.netlogon.data.nt5_ex.pdc_dns_name);
+ torture_assert(tctx, server_name, __location__);
+
+ status = dcerpc_parse_binding(tctx, binding, &b2);
+ torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
+
+ status = dcerpc_pipe_connect_b(tctx, &p1, b2,
+ &ndr_table_netlogon,
+ cli_credentials_init_anon(tctx),
+ tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b");
+
+ ok = check_pw_with_ServerAuthenticate3(p1, tctx,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ server_name,
+ incoming_creds, &creds);
+ torture_assert_int_equal(tctx, ok, expected_result,
+ "check_pw_with_ServerAuthenticate3");
+ if (expected_result == true) {
+ ok = test_SetupCredentialsPipe(p1, tctx, incoming_creds, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p2);
+ torture_assert_int_equal(tctx, ok, true,
+ "test_SetupCredentialsPipe");
+ }
+ TALLOC_FREE(p1);
+
+ if (trusted->trust_type != LSA_TRUST_TYPE_DOWNLEVEL) {
+#ifdef SAMBA4_USES_HEIMDAL
+ ok = check_pw_with_krb5(tctx, incoming_creds, trusted);
+ torture_assert_int_equal(tctx, ok, expected_result,
+ "check_pw_with_krb5");
+#else
+ torture_comment(tctx, "skipping check_pw_with_krb5 for MIT Kerberos build");
+#endif
+ }
+
+ if (expected_result != true || next_password == NULL) {
+ TALLOC_FREE(p2);
+ return true;
+ }
+
+ /*
+ * netr_ServerPasswordSet2
+ */
+ ok = encode_pw_buffer(samr_crypt_password.data,
+ next_password, STR_UNICODE);
+ torture_assert(tctx, ok, "encode_pw_buffer");
+
+ if (next_version != 0) {
+ struct NL_PASSWORD_VERSION version;
+ uint32_t len = IVAL(samr_crypt_password.data, 512);
+ uint32_t ofs = 512 - len;
+ uint8_t *ptr;
+
+ ofs -= 12;
+
+ version.ReservedField = 0;
+ version.PasswordVersionNumber = next_version;
+ version.PasswordVersionPresent =
+ NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
+
+ ptr = samr_crypt_password.data + ofs;
+ SIVAL(ptr, 0, version.ReservedField);
+ SIVAL(ptr, 4, version.PasswordVersionNumber);
+ SIVAL(ptr, 8, version.PasswordVersionPresent);
+ }
+
+ netlogon_creds_client_authenticator(creds, &req_auth);
+ ZERO_STRUCT(rep_auth);
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds,
+ samr_crypt_password.data,
+ 516);
+ } else {
+ netlogon_creds_arcfour_crypt(creds,
+ samr_crypt_password.data,
+ 516);
+ }
+
+ memcpy(netr_crypt_password.data,
+ samr_crypt_password.data, 512);
+ netr_crypt_password.length = IVAL(samr_crypt_password.data, 512);
+
+
+ s.in.server_name = server_name;
+ s.in.account_name = cli_credentials_get_username(incoming_creds);
+ s.in.secure_channel_type = cli_credentials_get_secure_channel_type(incoming_creds);
+ s.in.computer_name = cli_credentials_get_workstation(incoming_creds);
+ s.in.credential = &req_auth;
+ s.in.new_password = &netr_crypt_password;
+ s.out.return_authenticator = &rep_auth;
+ status = dcerpc_netr_ServerPasswordSet2_r(p2->binding_handle, tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "failed to set password");
+
+ ok = netlogon_creds_client_check(creds, &rep_auth.cred);
+ torture_assert(tctx, ok, "netlogon_creds_client_check");
+
+ cli_credentials_set_kvno(incoming_creds, next_version);
+ cli_credentials_set_password(incoming_creds, next_password, CRED_SPECIFIED);
+ cli_credentials_set_old_password(incoming_creds, current_password, CRED_SPECIFIED);
+
+ TALLOC_FREE(p2);
+ status = dcerpc_pipe_connect_b(tctx, &p2, b2,
+ &ndr_table_netlogon,
+ cli_credentials_init_anon(tctx),
+ tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b");
+
+ ok = check_pw_with_ServerAuthenticate3(p2, tctx,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ server_name,
+ incoming_creds, &creds);
+ torture_assert(tctx, ok, "check_pw_with_ServerAuthenticate3 with changed password");
+
+ if (trusted->trust_type != LSA_TRUST_TYPE_DOWNLEVEL) {
+#if SAMBA4_USES_HEIMDAL
+ ok = check_pw_with_krb5(tctx, incoming_creds, trusted);
+ torture_assert(tctx, ok, "check_pw_with_krb5 with changed password");
+#else
+ torture_comment(tctx, "skipping check_pw_with_krb5 for MIT Kerberos build");
+#endif
+ }
+
+ TALLOC_FREE(p2);
+ return true;
+}
+
+static bool test_CreateTrustedDomainEx_common(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_trusts,
+ bool ex2_call)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct lsa_QueryInfoPolicy2 p2;
+ union lsa_PolicyInformation *our_info = NULL;
+ struct lsa_CreateTrustedDomainEx r;
+ struct lsa_CreateTrustedDomainEx2 r2;
+ struct lsa_TrustDomainInfoInfoEx trustinfo;
+ struct lsa_TrustDomainInfoAuthInfoInternal *authinfo_internal = NULL;
+ struct lsa_TrustDomainInfoAuthInfo *authinfo = NULL;
+ struct dom_sid **domsid;
+ struct policy_handle *trustdom_handle;
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info = NULL;
+ DATA_BLOB session_key;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *id;
+ const char *incoming_v00 = TRUSTPW "InV00";
+ const char *incoming_v0 = TRUSTPW "InV0";
+ const char *incoming_v1 = TRUSTPW "InV1";
+ const char *incoming_v2 = TRUSTPW "InV2";
+ const char *incoming_v40 = TRUSTPW "InV40";
+ const char *outgoing_v00 = TRUSTPW "OutV00";
+ const char *outgoing_v0 = TRUSTPW "OutV0";
+
+ if (ex2_call) {
+ torture_comment(tctx, "\nTesting CreateTrustedDomainEx2 for %d domains\n", num_trusts);
+ id = "3";
+ } else {
+ torture_comment(tctx, "\nTesting CreateTrustedDomainEx for %d domains\n", num_trusts);
+ id = "2";
+ }
+
+ domsid = talloc_array(tctx, struct dom_sid *, num_trusts);
+ trustdom_handle = talloc_array(tctx, struct policy_handle, num_trusts);
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ZERO_STRUCT(p2);
+ p2.in.handle = handle;
+ p2.in.level = LSA_POLICY_INFO_DNS;
+ p2.out.info = &our_info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_QueryInfoPolicy2_r(b, tctx, &p2),
+ "lsa_QueryInfoPolicy2 failed");
+ torture_assert_ntstatus_ok(tctx, p2.out.result,
+ "lsa_QueryInfoPolicy2 failed");
+ torture_assert(tctx, our_info != NULL, "lsa_QueryInfoPolicy2 our_info");
+
+ for (i=0; i< num_trusts; i++) {
+ char *trust_name = talloc_asprintf(tctx, "TORTURE%s%02d", id, i);
+ char *trust_name_dns = talloc_asprintf(tctx, "torturedom%s%02d.samba._none_.example.com", id, i);
+ char *trust_sid = talloc_asprintf(tctx, "S-1-5-21-97398-379795-%s%02d", id, i);
+ bool ok;
+
+ domsid[i] = dom_sid_parse_talloc(tctx, trust_sid);
+
+ trustinfo.sid = domsid[i];
+ trustinfo.netbios_name.string = trust_name;
+ trustinfo.domain_name.string = trust_name_dns;
+
+ /* Create inbound, some outbound, and some
+ * bi-directional trusts in a repeating pattern based
+ * on i */
+
+ /* 1 == inbound, 2 == outbound, 3 == both */
+ trustinfo.trust_direction = (i % 3) + 1;
+
+ /* Try different trust types too */
+
+ /* 1 == downlevel (NT4), 2 == uplevel (ADS), 3 == MIT (kerberos but not AD) */
+ trustinfo.trust_type = (((i / 3) + 1) % 3) + 1;
+
+ trustinfo.trust_attributes = LSA_TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION;
+
+ ok = gen_authinfo_internal(tctx, incoming_v00, incoming_v0,
+ outgoing_v00, outgoing_v0,
+ session_key, &authinfo_internal);
+ if (!ok) {
+ torture_comment(tctx, "gen_authinfo_internal failed");
+ ret = false;
+ }
+
+ ok = gen_authinfo(tctx, incoming_v00, incoming_v0,
+ outgoing_v00, outgoing_v0,
+ &authinfo);
+ if (!ok) {
+ torture_comment(tctx, "gen_authinfonfo failed");
+ ret = false;
+ }
+
+ if (ex2_call) {
+
+ r2.in.policy_handle = handle;
+ r2.in.info = &trustinfo;
+ r2.in.auth_info_internal = authinfo_internal;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.out.trustdom_handle = &trustdom_handle[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx2_r(b, tctx, &r2),
+ "CreateTrustedDomainEx2 failed");
+
+ status = r2.out.result;
+ } else {
+
+ r.in.policy_handle = handle;
+ r.in.info = &trustinfo;
+ r.in.auth_info = authinfo;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.trustdom_handle = &trustdom_handle[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx_r(b, tctx, &r),
+ "CreateTrustedDomainEx failed");
+
+ status = r.out.result;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ test_DeleteTrustedDomain(b, tctx, handle, trustinfo.netbios_name);
+ if (ex2_call) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx2_r(b, tctx, &r2),
+ "CreateTrustedDomainEx2 failed");
+ status = r2.out.result;
+ } else {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_CreateTrustedDomainEx_r(b, tctx, &r),
+ "CreateTrustedDomainEx2 failed");
+ status = r.out.result;
+ }
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "CreateTrustedDomainEx failed2 - %s\n", nt_errstr(status));
+ ret = false;
+ } else {
+ /* For outbound and MIT trusts there is no trust account */
+ if (trustinfo.trust_direction != 2 &&
+ trustinfo.trust_type != 3) {
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_comment(tctx, "skipping trusted domain auth tests against samba3\n");
+ } else if (ex2_call == false &&
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping CreateTrustedDomainEx trusted domain auth tests against samba4\n");
+
+ } else {
+ ok = check_dom_trust_pw(p, tctx,
+ our_info->dns.name.string,
+ our_info->dns.dns_domain.string,
+ SEC_CHAN_DOMAIN,
+ &trustinfo,
+ NULL,
+ "x" TRUSTPW "x", 0,
+ NULL, 0,
+ false);
+ if (!ok) {
+ torture_comment(tctx, "Password check passed unexpectedly\n");
+ ret = false;
+ }
+ ok = check_dom_trust_pw(p, tctx,
+ our_info->dns.name.string,
+ our_info->dns.dns_domain.string,
+ SEC_CHAN_DOMAIN,
+ &trustinfo,
+ incoming_v00,
+ incoming_v0, 0,
+ incoming_v1, 1,
+ true);
+ if (!ok) {
+ torture_comment(tctx, "Password check failed (SEC_CHAN_DOMAIN)\n");
+ ret = false;
+ }
+ ok = check_dom_trust_pw(p, tctx,
+ our_info->dns.name.string,
+ our_info->dns.dns_domain.string,
+ SEC_CHAN_DNS_DOMAIN,
+ &trustinfo,
+ incoming_v0,
+ incoming_v1, 1,
+ incoming_v2, 2,
+ true);
+ if (!ok) {
+ torture_comment(tctx, "Password check failed v2 (SEC_CHAN_DNS_DOMAIN)\n");
+ ret = false;
+ }
+ ok = check_dom_trust_pw(p, tctx,
+ our_info->dns.name.string,
+ our_info->dns.dns_domain.string,
+ SEC_CHAN_DNS_DOMAIN,
+ &trustinfo,
+ incoming_v1,
+ incoming_v2, 2,
+ incoming_v40, 40,
+ true);
+ if (!ok) {
+ torture_comment(tctx, "Password check failed v4 (SEC_CHAN_DNS_DOMAIN)\n");
+ ret = false;
+ }
+ }
+ }
+
+ q.in.trustdom_handle = &trustdom_handle[i];
+ q.in.level = LSA_TRUSTED_DOMAIN_INFO_INFO_EX;
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfo_r(b, tctx, &q),
+ "QueryTrustedDomainInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level 1 failed - %s\n", nt_errstr(q.out.result));
+ ret = false;
+ } else if (!q.out.info) {
+ torture_comment(tctx, "QueryTrustedDomainInfo level 1 failed to return an info pointer\n");
+ ret = false;
+ } else {
+ if (strcmp(info->info_ex.domain_name.string, trustinfo.domain_name.string) != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo returned inconsistent long name: %s != %s\n",
+ info->info_ex.domain_name.string, trustinfo.domain_name.string);
+ ret = false;
+ }
+ if (strcmp(info->info_ex.netbios_name.string, trustinfo.netbios_name.string) != 0) {
+ torture_comment(tctx, "QueryTrustedDomainInfo returned inconsistent short name: %s != %s\n",
+ info->info_ex.netbios_name.string, trustinfo.netbios_name.string);
+ ret = false;
+ }
+ if (info->info_ex.trust_type != trustinfo.trust_type) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust type %d != %d\n",
+ trust_name, info->info_ex.trust_type, trustinfo.trust_type);
+ ret = false;
+ }
+ if (info->info_ex.trust_attributes != LSA_TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust attributes %d != %d\n",
+ trust_name, info->info_ex.trust_attributes, LSA_TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION);
+ ret = false;
+ }
+ if (info->info_ex.trust_direction != trustinfo.trust_direction) {
+ torture_comment(tctx, "QueryTrustedDomainInfo of %s returned incorrect trust direction %d != %d\n",
+ trust_name, info->info_ex.trust_direction, trustinfo.trust_direction);
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* now that we have some domains to look over, we can test the enum calls */
+ if (!test_EnumTrustDom(b, tctx, handle)) {
+ torture_comment(tctx, "test_EnumTrustDom failed\n");
+ ret = false;
+ }
+
+ if (!test_EnumTrustDomEx(b, tctx, handle)) {
+ torture_comment(tctx, "test_EnumTrustDomEx failed\n");
+ ret = false;
+ }
+
+ for (i=0; i<num_trusts; i++) {
+ if (!test_DeleteTrustedDomainBySid(b, tctx, handle, domsid[i])) {
+ torture_comment(tctx, "test_DeleteTrustedDomainBySid failed\n");
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_CreateTrustedDomainEx2(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_trusts)
+{
+ return test_CreateTrustedDomainEx_common(p, tctx, handle, num_trusts, true);
+}
+
+static bool test_CreateTrustedDomainEx(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_trusts)
+{
+ return test_CreateTrustedDomainEx_common(p, tctx, handle, num_trusts, false);
+}
+
+static bool test_QueryDomainInfoPolicy(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_QueryDomainInformationPolicy r;
+ union lsa_DomainInformationPolicy *info = NULL;
+ int i;
+ bool ret = true;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping QueryDomainInformationPolicy test\n");
+ }
+
+ torture_comment(tctx, "\nTesting QueryDomainInformationPolicy\n");
+
+ for (i=2;i<4;i++) {
+ r.in.handle = handle;
+ r.in.level = i;
+ r.out.info = &info;
+
+ torture_comment(tctx, "\nTrying QueryDomainInformationPolicy level %d\n", i);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryDomainInformationPolicy_r(b, tctx, &r),
+ "QueryDomainInformationPolicy failed");
+
+ /* If the server does not support EFS, then this is the correct return */
+ if (i == LSA_DOMAIN_INFO_POLICY_EFS && NT_STATUS_EQUAL(r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ continue;
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "QueryDomainInformationPolicy failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+
+static bool test_QueryInfoPolicyCalls( bool version2,
+ struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_QueryInfoPolicy r;
+ union lsa_PolicyInformation *info = NULL;
+ int i;
+ bool ret = true;
+ const char *call = talloc_asprintf(tctx, "QueryInfoPolicy%s", version2 ? "2":"");
+
+ torture_comment(tctx, "\nTesting %s\n", call);
+
+ if (version2 && torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping QueryInfoPolicy2 tests\n");
+ }
+
+ for (i=1;i<=14;i++) {
+ r.in.handle = handle;
+ r.in.level = i;
+ r.out.info = &info;
+
+ torture_comment(tctx, "\nTrying %s level %d\n", call, i);
+
+ if (version2)
+ /* We can perform the cast, because both types are
+ structurally equal */
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryInfoPolicy2_r(b, tctx,
+ (struct lsa_QueryInfoPolicy2*) &r),
+ "QueryInfoPolicy2 failed");
+ else
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryInfoPolicy_r(b, tctx, &r),
+ "QueryInfoPolicy2 failed");
+
+ switch (i) {
+ case LSA_POLICY_INFO_MOD:
+ case LSA_POLICY_INFO_AUDIT_FULL_SET:
+ case LSA_POLICY_INFO_AUDIT_FULL_QUERY:
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_comment(tctx, "Server should have failed level %u: %s\n", i, nt_errstr(r.out.result));
+ ret = false;
+ }
+ break;
+ case LSA_POLICY_INFO_DOMAIN:
+ case LSA_POLICY_INFO_ACCOUNT_DOMAIN:
+ case LSA_POLICY_INFO_REPLICA:
+ case LSA_POLICY_INFO_QUOTA:
+ case LSA_POLICY_INFO_ROLE:
+ case LSA_POLICY_INFO_AUDIT_LOG:
+ case LSA_POLICY_INFO_AUDIT_EVENTS:
+ case LSA_POLICY_INFO_PD:
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "%s failed - %s\n", call, nt_errstr(r.out.result));
+ ret = false;
+ }
+ break;
+ case LSA_POLICY_INFO_L_ACCOUNT_DOMAIN:
+ case LSA_POLICY_INFO_DNS_INT:
+ case LSA_POLICY_INFO_DNS:
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ /* Other levels not implemented yet */
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
+ torture_comment(tctx, "%s failed - %s\n", call, nt_errstr(r.out.result));
+ ret = false;
+ }
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "%s failed - %s\n", call, nt_errstr(r.out.result));
+ ret = false;
+ }
+ break;
+ default:
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ /* Other levels not implemented yet */
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
+ torture_comment(tctx, "%s failed - %s\n", call, nt_errstr(r.out.result));
+ ret = false;
+ }
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "%s failed - %s\n", call, nt_errstr(r.out.result));
+ ret = false;
+ }
+ break;
+ }
+
+ if (NT_STATUS_IS_OK(r.out.result) && (i == LSA_POLICY_INFO_DNS
+ || i == LSA_POLICY_INFO_DNS_INT)) {
+ /* Let's look up some of these names */
+
+ struct lsa_TransNameArray tnames, dnames;
+ tnames.count = 14;
+ tnames.names = talloc_zero_array(tctx, struct lsa_TranslatedName, tnames.count);
+ tnames.names[0].name.string = info->dns.name.string;
+ tnames.names[0].sid_type = SID_NAME_DOMAIN;
+ tnames.names[1].name.string = info->dns.dns_domain.string;
+ tnames.names[1].sid_type = SID_NAME_DOMAIN;
+ tnames.names[2].name.string = talloc_asprintf(tctx, "%s\\", info->dns.name.string);
+ tnames.names[2].sid_type = SID_NAME_DOMAIN;
+ tnames.names[3].name.string = talloc_asprintf(tctx, "%s\\", info->dns.dns_domain.string);
+ tnames.names[3].sid_type = SID_NAME_DOMAIN;
+ tnames.names[4].name.string = talloc_asprintf(tctx, "%s\\guest", info->dns.name.string);
+ tnames.names[4].sid_type = SID_NAME_USER;
+ tnames.names[5].name.string = talloc_asprintf(tctx, "%s\\krbtgt", info->dns.name.string);
+ tnames.names[5].sid_type = SID_NAME_USER;
+ tnames.names[6].name.string = talloc_asprintf(tctx, "%s\\guest", info->dns.dns_domain.string);
+ tnames.names[6].sid_type = SID_NAME_USER;
+ tnames.names[7].name.string = talloc_asprintf(tctx, "%s\\krbtgt", info->dns.dns_domain.string);
+ tnames.names[7].sid_type = SID_NAME_USER;
+ tnames.names[8].name.string = talloc_asprintf(tctx, "krbtgt@%s", info->dns.name.string);
+ tnames.names[8].sid_type = SID_NAME_USER;
+ tnames.names[9].name.string = talloc_asprintf(tctx, "krbtgt@%s", info->dns.dns_domain.string);
+ tnames.names[9].sid_type = SID_NAME_USER;
+ tnames.names[10].name.string = talloc_asprintf(tctx, "%s\\"TEST_MACHINENAME "$", info->dns.name.string);
+ tnames.names[10].sid_type = SID_NAME_USER;
+ tnames.names[11].name.string = talloc_asprintf(tctx, "%s\\"TEST_MACHINENAME "$", info->dns.dns_domain.string);
+ tnames.names[11].sid_type = SID_NAME_USER;
+ tnames.names[12].name.string = talloc_asprintf(tctx, TEST_MACHINENAME "$@%s", info->dns.name.string);
+ tnames.names[12].sid_type = SID_NAME_USER;
+ tnames.names[13].name.string = talloc_asprintf(tctx, TEST_MACHINENAME "$@%s", info->dns.dns_domain.string);
+ tnames.names[13].sid_type = SID_NAME_USER;
+ ret &= test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames);
+
+ /* Try to use in-forest search for the test machine */
+ dnames.count = 1;
+ dnames.names = talloc_zero_array(tctx, struct lsa_TranslatedName, dnames.count);
+ dnames.names[0].name.string = talloc_asprintf(tctx, "%s\\"TEST_MACHINENAME "$", info->dns.name.string);
+ dnames.names[0].sid_type = SID_NAME_USER;
+ ret &= test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2, &dnames);
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryInfoPolicy(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ return test_QueryInfoPolicyCalls(false, b, tctx, handle);
+}
+
+static bool test_QueryInfoPolicy2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ return test_QueryInfoPolicyCalls(true, b, tctx, handle);
+}
+
+static bool test_GetUserName(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct lsa_GetUserName r;
+ struct lsa_String *authority_name_p = NULL;
+ struct lsa_String *account_name_p = NULL;
+
+ torture_comment(tctx, "\nTesting GetUserName\n");
+
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = NULL;
+ r.out.account_name = &account_name_p;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetUserName_r(b, tctx, &r),
+ "GetUserName failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "GetUserName result failed");
+ torture_assert_not_null(tctx, r.out.account_name, "r.out.account_name");
+ torture_assert_not_null(tctx, *r.out.account_name, "*r.out.account_name");
+ torture_assert(tctx, r.out.authority_name == NULL, "r.out.authority_name");
+
+ account_name_p = NULL;
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetUserName_r(b, tctx, &r),
+ "GetUserName failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "GetUserName result failed");
+ torture_assert_not_null(tctx, r.out.account_name, "r.out.account_name");
+ torture_assert_not_null(tctx, *r.out.account_name, "*r.out.account_name");
+ torture_assert_not_null(tctx, r.out.authority_name, "r.out.authority_name");
+ torture_assert_not_null(tctx, *r.out.authority_name, "*r.out.authority_name");
+
+ torture_comment(tctx,
+ "Account Name: %s, Authority Name: %s\n",
+ (*r.out.account_name)->string,
+ (*r.out.authority_name)->string);
+
+ return true;
+}
+
+static bool test_GetUserName_fail(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct lsa_GetUserName r;
+ struct lsa_String *account_name_p = NULL;
+ NTSTATUS status;
+
+ torture_comment(tctx, "\nTesting GetUserName_fail\n");
+
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = NULL;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx,
+ "GetUserName correctly returned with "
+ "status: %s\n",
+ nt_errstr(status));
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_ACCESS_DENIED,
+ "GetUserName return value should "
+ "be ACCESS_DENIED");
+ return true;
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(r.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
+ torture_comment(tctx,
+ "GetUserName correctly returned with "
+ "result: %s\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+ }
+
+ torture_assert_ntstatus_equal(tctx,
+ r.out.result,
+ NT_STATUS_OK,
+ "GetUserName return value should be "
+ "ACCESS_DENIED");
+
+ return false;
+}
+
+bool test_lsa_Close(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct lsa_Close r;
+ struct policy_handle handle2;
+
+ torture_comment(tctx, "\nTesting Close\n");
+
+ r.in.handle = handle;
+ r.out.handle = &handle2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_Close_r(b, tctx, &r),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Close failed");
+
+ torture_assert_ntstatus_equal(tctx, dcerpc_lsa_Close_r(b, tctx, &r),
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH, "Close should failed");
+
+ torture_comment(tctx, "\n");
+
+ return true;
+}
+
+bool torture_rpc_lsa(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct policy_handle *handle = NULL;
+ struct test_join *join = NULL;
+ struct cli_credentials *machine_creds;
+ struct dcerpc_binding_handle *b;
+ enum dcerpc_transport_t transport;
+
+ status = torture_rpc_connection(tctx, &p, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ b = p->binding_handle;
+ transport = dcerpc_binding_get_transport(p->binding);
+
+ /* Test lsaLookupSids3 and lsaLookupNames4 over tcpip */
+ if (transport == NCACN_IP_TCP) {
+ if (!test_OpenPolicy_fail(b, tctx)) {
+ ret = false;
+ }
+
+ if (!test_OpenPolicy2_fail(b, tctx)) {
+ ret = false;
+ }
+
+ if (!test_OpenPolicy3_fail(b, tctx)) {
+ ret = false;
+ }
+
+ if (!test_many_LookupSids(p, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+
+ return ret;
+ }
+
+ if (!test_OpenPolicy(b, tctx)) {
+ ret = false;
+ }
+
+ if (!test_lsa_OpenPolicy2(b, tctx, &handle)) {
+ ret = false;
+ }
+
+ if (!test_lsa_OpenPolicy3(b, tctx, &handle)) {
+ ret = false;
+ }
+
+ if (handle) {
+ join = torture_join_domain(tctx, TEST_MACHINENAME, ACB_WSTRUST, &machine_creds);
+ if (!join) {
+ ret = false;
+ }
+
+ if (!test_LookupSids_async(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+
+ if (!test_QueryDomainInfoPolicy(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_CreateSecret(p, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryInfoPolicy(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryInfoPolicy2(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_Delete(b, tctx, handle)) {
+ ret = false;
+ }
+
+ if (!test_many_LookupSids(p, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+
+ if (!test_lsa_Close(b, tctx, handle)) {
+ ret = false;
+ }
+
+ torture_leave_domain(tctx, join);
+
+ } else {
+ if (!test_many_LookupSids(p, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+ }
+
+ if (!test_GetUserName(b, tctx)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+bool torture_rpc_lsa_get_user(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+ enum dcerpc_transport_t transport;
+
+ status = torture_rpc_connection(tctx, &p, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ b = p->binding_handle;
+ transport = dcerpc_binding_get_transport(p->binding);
+
+ if (transport == NCACN_IP_TCP) {
+ if (!test_GetUserName_fail(b, tctx)) {
+ ret = false;
+ }
+ return ret;
+ }
+
+ if (!test_GetUserName(b, tctx)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool testcase_LookupNames(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ bool ret = true;
+ struct policy_handle *handle;
+ struct lsa_TransNameArray tnames;
+ struct lsa_TransNameArray2 tnames2;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_transport_t transport = dcerpc_binding_get_transport(p->binding);
+
+ if (transport != NCACN_NP && transport != NCALRPC) {
+ torture_comment(tctx, "testcase_LookupNames is only available "
+ "over NCACN_NP or NCALRPC");
+ return true;
+ }
+
+ if (!test_OpenPolicy(b, tctx)) {
+ ret = false;
+ }
+
+ if (!test_lsa_OpenPolicy2(b, tctx, &handle)) {
+ ret = false;
+ }
+
+ if (!handle) {
+ ret = false;
+ }
+
+ tnames.count = 1;
+ tnames.names = talloc_array(tctx, struct lsa_TranslatedName, tnames.count);
+ ZERO_STRUCT(tnames.names[0]);
+ tnames.names[0].name.string = "BUILTIN";
+ tnames.names[0].sid_type = SID_NAME_DOMAIN;
+
+ if (!test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames)) {
+ ret = false;
+ }
+
+ tnames2.count = 1;
+ tnames2.names = talloc_array(tctx, struct lsa_TranslatedName2, tnames2.count);
+ ZERO_STRUCT(tnames2.names[0]);
+ tnames2.names[0].name.string = "BUILTIN";
+ tnames2.names[0].sid_type = SID_NAME_DOMAIN;
+
+ if (!test_LookupNames2(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames2, true)) {
+ ret = false;
+ }
+
+ if (!test_LookupNames3(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames2, true)) {
+ ret = false;
+ }
+
+ if (!test_LookupNames_wellknown(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+
+ if (!test_LookupNames_NULL(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+
+ if (!test_LookupNames_bogus(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) {
+ ret = false;
+ }
+
+ if (!test_lsa_Close(b, tctx, handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_lsa_lookup_names(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+
+ suite = torture_suite_create(mem_ctx, "lsa.lookupnames");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "lsa",
+ &ndr_table_lsarpc);
+ torture_rpc_tcase_add_test(tcase, "LookupNames",
+ testcase_LookupNames);
+
+ return suite;
+}
+
+struct lsa_trustdom_state {
+ uint32_t num_trusts;
+};
+
+static bool testcase_TrustedDomains(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ bool ret = true;
+ struct policy_handle *handle;
+ struct lsa_trustdom_state *state =
+ talloc_get_type_abort(data, struct lsa_trustdom_state);
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_transport_t transport = dcerpc_binding_get_transport(p->binding);
+
+ if (transport != NCACN_NP && transport != NCALRPC) {
+ torture_comment(tctx, "testcase_TrustedDomains is only available "
+ "over NCACN_NP or NCALRPC");
+ return true;
+ }
+
+ torture_comment(tctx, "Testing %d domains\n", state->num_trusts);
+
+ if (!test_OpenPolicy(b, tctx)) {
+ ret = false;
+ }
+
+ if (!test_lsa_OpenPolicy2(b, tctx, &handle)) {
+ ret = false;
+ }
+
+ if (!handle) {
+ ret = false;
+ }
+
+ if (!test_CreateTrustedDomain(b, tctx, handle, state->num_trusts)) {
+ ret = false;
+ }
+
+ if (!test_CreateTrustedDomainEx(p, tctx, handle, state->num_trusts)) {
+ ret = false;
+ }
+
+ if (!test_CreateTrustedDomainEx2(p, tctx, handle, state->num_trusts)) {
+ ret = false;
+ }
+
+ if (!test_lsa_Close(b, tctx, handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_lsa_trusted_domains(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+ struct lsa_trustdom_state *state;
+
+ state = talloc(mem_ctx, struct lsa_trustdom_state);
+
+ state->num_trusts = 12;
+
+ suite = torture_suite_create(mem_ctx, "lsa.trusted.domains");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "lsa",
+ &ndr_table_lsarpc);
+ torture_rpc_tcase_add_test_ex(tcase, "TrustedDomains",
+ testcase_TrustedDomains,
+ state);
+
+ return suite;
+}
+
+static bool testcase_Privileges(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct policy_handle *handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_transport_t transport = dcerpc_binding_get_transport(p->binding);
+
+ if (transport != NCACN_NP && transport != NCALRPC) {
+ torture_skip(tctx, "testcase_Privileges is only available "
+ "over NCACN_NP or NCALRPC");
+ }
+
+ if (!test_OpenPolicy(b, tctx)) {
+ return false;
+ }
+
+ if (!test_lsa_OpenPolicy2(b, tctx, &handle)) {
+ return false;
+ }
+
+ if (!handle) {
+ return false;
+ }
+
+ if (!test_CreateAccount(b, tctx, handle)) {
+ return false;
+ }
+
+ if (!test_EnumAccounts(b, tctx, handle)) {
+ return false;
+ }
+
+ if (!test_EnumPrivs(b, tctx, handle)) {
+ return false;
+ }
+
+ if (!test_lsa_Close(b, tctx, handle)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+struct torture_suite *torture_rpc_lsa_privileges(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+
+ suite = torture_suite_create(mem_ctx, "lsa.privileges");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "lsa",
+ &ndr_table_lsarpc);
+ torture_rpc_tcase_add_test(tcase, "Privileges",
+ testcase_Privileges);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/lsa_lookup.c b/source4/torture/rpc/lsa_lookup.c
new file mode 100644
index 0000000..f641827
--- /dev/null
+++ b/source4/torture/rpc/lsa_lookup.c
@@ -0,0 +1,428 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for lsa rpc lookup operations
+
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "libcli/security/security.h"
+
+static bool open_policy(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle **handle)
+{
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 r;
+
+ *handle = talloc(tctx, struct policy_handle);
+ if (!*handle) {
+ return false;
+ }
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = "\\";
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = *handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenPolicy2_r(b, tctx, &r),
+ "OpenPolicy2 failed");
+
+ return NT_STATUS_IS_OK(r.out.result);
+}
+
+static bool get_domainsid(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct dom_sid **sid)
+{
+ struct lsa_QueryInfoPolicy r;
+ union lsa_PolicyInformation *info = NULL;
+
+ r.in.level = LSA_POLICY_INFO_DOMAIN;
+ r.in.handle = handle;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryInfoPolicy_r(b, tctx, &r),
+ "QueryInfoPolicy failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "QueryInfoPolicy failed");
+
+ *sid = info->domain.sid;
+ return true;
+}
+
+static NTSTATUS lookup_sids(struct torture_context *tctx,
+ uint16_t level,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct dom_sid **sids, uint32_t num_sids,
+ struct lsa_TransNameArray *names)
+{
+ struct lsa_LookupSids r;
+ struct lsa_SidArray sidarray;
+ struct lsa_RefDomainList *domains;
+ uint32_t count = 0;
+ uint32_t i;
+ NTSTATUS status;
+
+ names->count = 0;
+ names->names = NULL;
+
+ sidarray.num_sids = num_sids;
+ sidarray.sids = talloc_array(tctx, struct lsa_SidPtr, num_sids);
+
+ for (i=0; i<num_sids; i++) {
+ sidarray.sids[i].sid = sids[i];
+ }
+
+ r.in.handle = handle;
+ r.in.sids = &sidarray;
+ r.in.names = names;
+ r.in.level = level;
+ r.in.count = &count;
+ r.out.names = names;
+ r.out.count = &count;
+ r.out.domains = &domains;
+
+ status = dcerpc_lsa_LookupSids_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return r.out.result;
+}
+
+static bool test_lookupsids(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct dom_sid **sids, uint32_t num_sids,
+ int level, NTSTATUS expected_result,
+ enum lsa_SidType *types)
+{
+ struct lsa_TransNameArray names;
+ NTSTATUS status;
+ uint32_t i;
+ bool ret = true;
+
+ status = lookup_sids(tctx, level, b, handle, sids, num_sids,
+ &names);
+ if (!NT_STATUS_EQUAL(status, expected_result)) {
+ printf("For level %d expected %s, got %s\n",
+ level, nt_errstr(expected_result),
+ nt_errstr(status));
+ return false;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK) &&
+ !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
+ return true;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ if (names.names[i].sid_type != types[i]) {
+ printf("In level %d, for sid %s expected %s, "
+ "got %s\n", level,
+ dom_sid_string(tctx, sids[i]),
+ sid_type_lookup(types[i]),
+ sid_type_lookup(names.names[i].sid_type));
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+static bool get_downleveltrust(struct torture_context *tctx, struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct dom_sid **sid)
+{
+ struct lsa_EnumTrustDom r;
+ uint32_t resume_handle = 0;
+ struct lsa_DomainList domains;
+ int i;
+
+ r.in.handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.max_size = 1000;
+ r.out.domains = &domains;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumTrustDom_r(b, tctx, &r),
+ "EnumTrustDom failed");
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NO_MORE_ENTRIES))
+ torture_fail(tctx, "no trusts");
+
+ if (domains.count == 0) {
+ torture_fail(tctx, "no trusts");
+ }
+
+ for (i=0; i<domains.count; i++) {
+ struct lsa_QueryTrustedDomainInfoBySid q;
+ union lsa_TrustedDomainInfo *info = NULL;
+
+ if (domains.domains[i].sid == NULL)
+ continue;
+
+ q.in.handle = handle;
+ q.in.dom_sid = domains.domains[i].sid;
+ q.in.level = 6;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QueryTrustedDomainInfoBySid_r(b, tctx, &q),
+ "QueryTrustedDomainInfoBySid failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) continue;
+
+ if ((info->info_ex.trust_direction & 2) &&
+ (info->info_ex.trust_type == 1)) {
+ *sid = domains.domains[i].sid;
+ return true;
+ }
+ }
+
+ torture_fail(tctx, "I need a AD DC with an outgoing trust to NT4");
+}
+
+#define NUM_SIDS 8
+
+bool torture_rpc_lsa_lookup(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct policy_handle *handle;
+ struct dom_sid *dom_sid = NULL;
+ struct dom_sid *trusted_sid = NULL;
+ struct dom_sid *sids[NUM_SIDS];
+ struct dcerpc_binding_handle *b;
+ enum dcerpc_transport_t transport;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_lsarpc);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_fail(torture, "unable to connect to table");
+ }
+ b = p->binding_handle;
+ transport = dcerpc_binding_get_transport(p->binding);
+
+ if (transport != NCACN_NP && transport != NCALRPC) {
+ torture_comment(torture,
+ "torture_rpc_lsa_lookup is only available "
+ "over NCACN_NP or NCALRPC");
+ return true;
+ }
+
+ ret &= open_policy(torture, b, &handle);
+ if (!ret) return false;
+
+ ret &= get_domainsid(torture, b, handle, &dom_sid);
+ if (!ret) return false;
+
+ ret &= get_downleveltrust(torture, b, handle, &trusted_sid);
+ if (!ret) return false;
+
+ torture_comment(torture, "domain sid: %s\n",
+ dom_sid_string(torture, dom_sid));
+
+ sids[0] = dom_sid_parse_talloc(torture, "S-1-1-0");
+ sids[1] = dom_sid_parse_talloc(torture, "S-1-5-4");
+ sids[2] = dom_sid_parse_talloc(torture, "S-1-5-32");
+ sids[3] = dom_sid_parse_talloc(torture, "S-1-5-32-545");
+ sids[4] = dom_sid_dup(torture, dom_sid);
+ sids[5] = dom_sid_add_rid(torture, dom_sid, 512);
+ sids[6] = dom_sid_dup(torture, trusted_sid);
+ sids[7] = dom_sid_add_rid(torture, trusted_sid, 512);
+
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 0,
+ NT_STATUS_INVALID_PARAMETER, NULL);
+
+ {
+ enum lsa_SidType types[NUM_SIDS] =
+ { SID_NAME_WKN_GRP, SID_NAME_WKN_GRP, SID_NAME_DOMAIN,
+ SID_NAME_ALIAS, SID_NAME_DOMAIN, SID_NAME_DOM_GRP,
+ SID_NAME_DOMAIN, SID_NAME_DOM_GRP };
+
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 1,
+ NT_STATUS_OK, types);
+ }
+
+ {
+ enum lsa_SidType types[NUM_SIDS] =
+ { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_DOMAIN, SID_NAME_DOM_GRP,
+ SID_NAME_DOMAIN, SID_NAME_DOM_GRP };
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 2,
+ STATUS_SOME_UNMAPPED, types);
+ }
+
+ {
+ enum lsa_SidType types[NUM_SIDS] =
+ { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_DOMAIN, SID_NAME_DOM_GRP,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN };
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 3,
+ STATUS_SOME_UNMAPPED, types);
+ }
+
+ {
+ enum lsa_SidType types[NUM_SIDS] =
+ { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_DOMAIN, SID_NAME_DOM_GRP,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN };
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 4,
+ STATUS_SOME_UNMAPPED, types);
+ }
+
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 5,
+ NT_STATUS_NONE_MAPPED, NULL);
+
+ {
+ enum lsa_SidType types[NUM_SIDS] =
+ { SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN,
+ SID_NAME_DOMAIN, SID_NAME_DOM_GRP,
+ SID_NAME_UNKNOWN, SID_NAME_UNKNOWN };
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 6,
+ STATUS_SOME_UNMAPPED, types);
+ }
+
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 7,
+ NT_STATUS_INVALID_PARAMETER, NULL);
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 8,
+ NT_STATUS_INVALID_PARAMETER, NULL);
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 9,
+ NT_STATUS_INVALID_PARAMETER, NULL);
+ ret &= test_lookupsids(torture, b, handle, sids, NUM_SIDS, 10,
+ NT_STATUS_INVALID_PARAMETER, NULL);
+
+ return ret;
+}
+
+static bool test_LookupSidsReply(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct policy_handle *handle = NULL;
+
+ struct dom_sid **sids = NULL;
+ uint32_t num_sids = 1;
+
+ struct lsa_LookupSids r;
+ struct lsa_SidArray sidarray;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_TransNameArray names;
+ uint32_t count = 0;
+
+ uint32_t i;
+ const char *dom_sid = "S-1-5-21-1111111111-2222222222-3333333333";
+ const char *dom_admin_sid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ enum dcerpc_transport_t transport = dcerpc_binding_get_transport(p->binding);
+
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(sidarray);
+ ZERO_STRUCT(names);
+
+ if (transport != NCACN_NP && transport != NCALRPC) {
+ torture_comment(tctx,
+ "test_LookupSidsReply is only available "
+ "over NCACN_NP or NCALRPC");
+ return true;
+ }
+
+ if (!open_policy(tctx, b, &handle)) {
+ return false;
+ }
+
+ dom_admin_sid = talloc_asprintf(tctx, "%s-%d", dom_sid, 512);
+
+ sids = talloc_zero_array(tctx, struct dom_sid *, num_sids);
+
+ sids[0] = dom_sid_parse_talloc(tctx, dom_admin_sid);
+
+ names.count = 0;
+ names.names = NULL;
+
+ sidarray.num_sids = num_sids;
+ sidarray.sids = talloc_zero_array(tctx, struct lsa_SidPtr, num_sids);
+
+ for (i=0; i<num_sids; i++) {
+ sidarray.sids[i].sid = sids[i];
+ }
+
+ r.in.handle = handle;
+ r.in.sids = &sidarray;
+ r.in.names = &names;
+ r.in.level = LSA_LOOKUP_NAMES_ALL;
+ r.in.count = &count;
+ r.out.names = &names;
+ r.out.count = &count;
+ r.out.domains = &domains;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_LookupSids_r(b, tctx, &r),
+ "LookupSids failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NONE_MAPPED,
+ "unexpected error code");
+
+ torture_assert_int_equal(tctx, names.count, num_sids,
+ "unexpected names count");
+ torture_assert(tctx, names.names,
+ "unexpected names pointer");
+ torture_assert_str_equal(tctx, names.names[0].name.string, dom_admin_sid,
+ "unexpected names[0].string");
+
+#if 0
+ /* vista sp1 passes, w2k3 sp2 fails */
+ torture_assert_int_equal(tctx, domains->count, num_sids,
+ "unexpected domains count");
+ torture_assert(tctx, domains->domains,
+ "unexpected domains pointer");
+ torture_assert_str_equal(tctx, dom_sid_string(tctx, domains->domains[0].sid), dom_sid,
+ "unexpected domain sid");
+#endif
+
+ return true;
+}
+
+/* check for lookup sids results */
+struct torture_suite *torture_rpc_lsa_lookup_sids(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+
+ suite = torture_suite_create(mem_ctx, "lsa.lookupsids");
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "lsa",
+ &ndr_table_lsarpc);
+
+ torture_rpc_tcase_add_test(tcase, "LookupSidsReply", test_LookupSidsReply);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c
new file mode 100644
index 0000000..2096ed7
--- /dev/null
+++ b/source4/torture/rpc/mdssvc.c
@@ -0,0 +1,1056 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for the mdssvc RPC service
+
+ Copyright (C) Ralph Boehme 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_mdssvc_c.h"
+#include "param/param.h"
+#include "lib/cmdline/cmdline.h"
+#include "rpc_server/mdssvc/dalloc.h"
+#include "rpc_server/mdssvc/marshalling.h"
+
+struct torture_mdsscv_state {
+ struct dcerpc_pipe *p;
+ struct policy_handle ph;
+
+ /* Known fields used across multiple commands */
+ uint32_t dev;
+ uint32_t flags;
+
+ /* cmd specific or unknown fields */
+ struct {
+ const char share_path[1025];
+ uint32_t unkn2;
+ uint32_t unkn3;
+ } mdscmd_open;
+ struct {
+ uint32_t status;
+ uint32_t unkn7;
+ } mdscmd_unknown1;
+ struct {
+ uint32_t fragment;
+ uint32_t unkn9;
+ } mdscmd_cmd;
+ struct {
+ uint32_t status;
+ } mdscmd_close;
+};
+
+static bool torture_rpc_mdssvc_setup(struct torture_context *tctx,
+ void **data)
+{
+ struct torture_mdsscv_state *state = NULL;
+ NTSTATUS status;
+
+ state = talloc_zero(tctx, struct torture_mdsscv_state);
+ if (state == NULL) {
+ return false;
+ }
+ *data = state;
+
+ status = torture_rpc_connection(tctx, &state->p, &ndr_table_mdssvc);
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ return true;
+}
+
+static bool torture_rpc_mdssvc_teardown(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+
+ TALLOC_FREE(state->p);
+ TALLOC_FREE(state);
+ return true;
+}
+
+static bool torture_rpc_mdssvc_open(struct torture_context *tctx,
+ void **data)
+{
+ struct torture_mdsscv_state *state = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ const char *share_name = NULL;
+ const char *share_mount_path = NULL;
+ NTSTATUS status;
+ bool ok = true;
+
+ state = talloc_zero(tctx, struct torture_mdsscv_state);
+ if (state == NULL) {
+ return false;
+ }
+ *data = state;
+
+ status = torture_rpc_connection(tctx, &state->p, &ndr_table_mdssvc);
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+ b = state->p->binding_handle;
+
+ share_name = torture_setting_string(
+ tctx, "spotlight_share", "spotlight");
+ share_mount_path = torture_setting_string(
+ tctx, "share_mount_path", "/foo/bar");
+
+ state->dev = generate_random();
+ state->mdscmd_open.unkn2 = 23;
+ state->mdscmd_open.unkn3 = 0;
+
+ ZERO_STRUCT(state->ph);
+
+ status = dcerpc_mdssvc_open(b,
+ state,
+ &state->dev,
+ &state->mdscmd_open.unkn2,
+ &state->mdscmd_open.unkn3,
+ share_mount_path,
+ share_name,
+ state->mdscmd_open.share_path,
+ &state->ph);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_open failed\n");
+
+ status = dcerpc_mdssvc_unknown1(b,
+ state,
+ &state->ph,
+ 0,
+ state->dev,
+ state->mdscmd_open.unkn2,
+ 0,
+ geteuid(),
+ getegid(),
+ &state->mdscmd_unknown1.status,
+ &state->flags,
+ &state->mdscmd_unknown1.unkn7);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_unknown1 failed\n");
+
+done:
+ if (!ok) {
+ (void)dcerpc_mdssvc_close(b,
+ state,
+ &state->ph,
+ 0,
+ state->dev,
+ state->mdscmd_open.unkn2,
+ 0,
+ &state->ph,
+ &state->mdscmd_close.status);
+ ZERO_STRUCTP(state);
+ }
+ return ok;
+}
+
+static bool torture_rpc_mdssvc_close(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ NTSTATUS status;
+ bool ok = true;
+
+ torture_comment(tctx, "test_teardown_mdssvc_disconnect\n");
+
+ if (state->p == NULL) {
+ /* We have already been disconnected. */
+ goto done;
+ }
+
+ status = dcerpc_mdssvc_close(state->p->binding_handle,
+ state,
+ &state->ph,
+ 0,
+ state->dev,
+ state->mdscmd_open.unkn2,
+ 0,
+ &state->ph,
+ &state->mdscmd_close.status);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_close failed\n");
+
+ ZERO_STRUCTP(state);
+
+done:
+ return ok;
+}
+
+/*
+ * Test unknown share name
+ */
+static bool test_mdssvc_open_unknown_share(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle ph;
+ struct policy_handle nullh;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn3;
+ uint32_t device_id_out;
+ uint32_t unkn2_out;
+ uint32_t unkn3_out;
+ const char *share_mount_path = NULL;
+ const char *share_name = NULL;
+ const char share_path[1025] = "X";
+ NTSTATUS status;
+ bool ok = true;
+
+ share_name = torture_setting_string(
+ tctx, "unknown_share", "choukawoohoo");
+ share_mount_path = torture_setting_string(
+ tctx, "share_mount_path", "/foo/bar");
+
+ device_id_out = device_id = generate_random();
+ unkn2_out = unkn2 = generate_random();
+ unkn3_out = unkn3 = generate_random();
+
+ ZERO_STRUCT(ph);
+ ZERO_STRUCT(nullh);
+
+ status = dcerpc_mdssvc_open(b,
+ tctx,
+ &device_id_out,
+ &unkn2_out,
+ &unkn3_out,
+ share_mount_path,
+ share_name,
+ share_path,
+ &ph);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_open failed\n");
+
+ torture_assert_u32_equal_goto(tctx, device_id_out, device_id, ok, done,
+ "Bad device_id\n");
+
+ torture_assert_u32_equal_goto(tctx, unkn2_out, unkn2, ok, done,
+ "Bad unkn2\n");
+
+ torture_assert_u32_equal_goto(tctx, unkn3_out, unkn3, ok, done,
+ "Bad unkn3\n");
+
+ torture_assert_goto(tctx, share_path[0] == '\0', ok, done,
+ "Expected empty string as share path\n");
+
+ torture_assert_mem_equal_goto(tctx, &ph, &nullh,
+ sizeof(ph), ok, done,
+ "Expected all-zero policy handle\n");
+
+done:
+ return ok;
+}
+
+/*
+ * Test on a share where Spotlight is not enabled
+ */
+static bool test_mdssvc_open_spotlight_disabled(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle ph;
+ struct policy_handle nullh;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn3;
+ uint32_t device_id_out;
+ uint32_t unkn2_out;
+ uint32_t unkn3_out;
+ const char *share_mount_path = NULL;
+ const char *share_name = NULL;
+ const char share_path[1025] = "";
+ NTSTATUS status;
+ bool ok = true;
+
+ share_name = torture_setting_string(
+ tctx, "no_spotlight_share", "no_spotlight");
+ share_mount_path = torture_setting_string(
+ tctx, "share_mount_path", "/foo/bar");
+
+ device_id_out = device_id = generate_random();
+ unkn2_out = unkn2 = 23;
+ unkn3_out = unkn3 = 0;
+
+ ZERO_STRUCT(ph);
+ ZERO_STRUCT(nullh);
+
+ status = dcerpc_mdssvc_open(b,
+ tctx,
+ &device_id_out,
+ &unkn2_out,
+ &unkn3_out,
+ share_mount_path,
+ share_name,
+ share_path,
+ &ph);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_open failed\n");
+
+ torture_assert_u32_equal_goto(tctx, device_id, device_id_out, ok, done,
+ "Bad device_id\n");
+
+ torture_assert_u32_equal_goto(tctx, unkn2, unkn2_out,
+ ok, done, "Bad unkn2\n");
+
+ torture_assert_u32_equal_goto(tctx, unkn3, unkn3_out,
+ ok, done, "Bad unkn3\n");
+
+ torture_assert_goto(tctx, share_path[0] == '\0', ok, done,
+ "Expected empty string as share path\n");
+
+ torture_assert_mem_equal_goto(tctx, &ph, &nullh,
+ sizeof(ph), ok, done,
+ "Expected all-zero policy handle\n");
+
+done:
+ return ok;
+}
+
+static bool test_mdssvc_close(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle ph;
+ struct policy_handle close_ph;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn3;
+ const char *share_mount_path = NULL;
+ const char *share_name = NULL;
+ const char share_path[1025] = "";
+ uint32_t close_status;
+ DATA_BLOB ph_blob;
+ DATA_BLOB close_ph_blob;
+ NTSTATUS status;
+ bool ok = true;
+
+ share_name = torture_setting_string(
+ tctx, "spotlight_share", "spotlight");
+ share_mount_path = torture_setting_string(
+ tctx, "share_mount_path", "/foo/bar");
+
+ device_id = generate_random();
+ unkn2 = 23;
+ unkn3 = 0;
+
+ ZERO_STRUCT(ph);
+ ZERO_STRUCT(close_ph);
+
+ status = dcerpc_mdssvc_open(b,
+ tctx,
+ &device_id,
+ &unkn2,
+ &unkn3,
+ share_mount_path,
+ share_name,
+ share_path,
+ &ph);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_open failed\n");
+
+ status = dcerpc_mdssvc_close(b,
+ tctx,
+ &ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ &close_ph,
+ &close_status);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_open failed\n");
+
+ ph_blob = (DATA_BLOB) {
+ .data = (uint8_t *)&ph,
+ .length = sizeof(struct policy_handle)
+ };
+ close_ph_blob = (DATA_BLOB) {
+ .data = (uint8_t *)&close_ph,
+ .length = sizeof(struct policy_handle),
+ };
+
+ torture_assert_data_blob_equal(tctx, close_ph_blob, ph_blob,
+ "bad blob");
+
+ torture_comment(tctx, "Test close with a all-zero handle\n");
+
+ ZERO_STRUCT(ph);
+ status = dcerpc_mdssvc_close(b,
+ tctx,
+ &ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ &close_ph,
+ &close_status);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_close failed\n");
+
+ torture_assert_data_blob_equal(tctx, close_ph_blob, ph_blob,
+ "bad blob");
+
+done:
+ return ok;
+}
+
+static bool test_mdssvc_null_ph(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle nullh;
+ struct policy_handle ph;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn7;
+ uint32_t cmd_status;
+ uint32_t flags;
+ NTSTATUS status;
+ bool ok = true;
+
+ device_id = generate_random();
+ unkn2 = 23;
+ unkn7 = 0;
+ cmd_status = 0;
+
+ ZERO_STRUCT(nullh);
+ ZERO_STRUCT(ph);
+
+ status = dcerpc_mdssvc_unknown1(b,
+ tctx,
+ &ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ geteuid(),
+ getegid(),
+ &cmd_status,
+ &flags,
+ &unkn7);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "dcerpc_mdssvc_unknown1 failed\n");
+
+ torture_assert_mem_equal_goto(tctx, &ph, &nullh,
+ sizeof(ph), ok, done,
+ "Expected all-zero policy handle\n");
+
+done:
+ return ok;
+}
+
+static bool test_mdssvc_invalid_ph_unknown1(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle ph;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn7;
+ uint32_t cmd_status;
+ uint32_t flags;
+ NTSTATUS status;
+ bool ok = true;
+
+ device_id = generate_random();
+ unkn2 = 23;
+ unkn7 = 0;
+ cmd_status = 0;
+
+ ZERO_STRUCT(ph);
+ ph.uuid = GUID_random();
+
+ status = dcerpc_mdssvc_unknown1(b,
+ tctx,
+ &ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ geteuid(),
+ getegid(),
+ &cmd_status,
+ &flags,
+ &unkn7);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done,
+ "dcerpc_mdssvc_unknown1 failed\n");
+
+ /* Free and set to NULL the no-longer-usable pipe. */
+ b = NULL;
+ TALLOC_FREE(state->p);
+
+done:
+ return ok;
+}
+
+static bool test_mdssvc_invalid_ph_cmd(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle ph;
+ struct mdssvc_blob request_blob;
+ struct mdssvc_blob response_blob;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn9;
+ uint32_t fragment;
+ uint32_t flags;
+ NTSTATUS status;
+ bool ok = true;
+
+ device_id = generate_random();
+ unkn2 = 23;
+ unkn9 = 0;
+ fragment = 0;
+ flags = UINT32_C(0x6b000001);
+
+ ZERO_STRUCT(ph);
+ ph.uuid = GUID_random();
+
+ request_blob.spotlight_blob = talloc_array(state,
+ uint8_t,
+ 0);
+ torture_assert_not_null_goto(tctx, request_blob.spotlight_blob,
+ ok, done, "dalloc_zero failed\n");
+ request_blob.size = 0;
+ request_blob.length = 0;
+ request_blob.size = 0;
+
+ status = dcerpc_mdssvc_cmd(b,
+ state,
+ &ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ flags,
+ request_blob,
+ 0,
+ 64 * 1024,
+ 1,
+ 64 * 1024,
+ 0,
+ 0,
+ &fragment,
+ &response_blob,
+ &unkn9);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done,
+ "dcerpc_mdssvc_unknown1 failed\n");
+
+ /* Free and set to NULL the no-longer-usable pipe. */
+ b = NULL;
+ TALLOC_FREE(state->p);
+
+done:
+ return ok;
+}
+
+static uint8_t test_sl_unpack_loop_buf[] = {
+ 0x34, 0x33, 0x32, 0x31, 0x33, 0x30, 0x64, 0x6d,
+ 0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00,
+ 0x66, 0x65, 0x74, 0x63, 0x68, 0x41, 0x74, 0x74,
+ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x3a,
+ 0x66, 0x6f, 0x72, 0x4f, 0x49, 0x44, 0x41, 0x72,
+ 0x72, 0x61, 0x79, 0x3a, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x78, 0x74, 0x3a, 0x00, 0x00, 0x00, 0xea,
+ 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x00,
+ 0x0a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00,
+ 0x6b, 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x50,
+ 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x87, 0x08, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0xdd, 0x0a, 0x20, 0x00, 0x00, 0x6b,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00,
+ 0x0f, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static bool test_mdssvc_sl_unpack_loop(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct mdssvc_blob request_blob;
+ struct mdssvc_blob response_blob;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn9;
+ uint32_t fragment;
+ uint32_t flags;
+ NTSTATUS status;
+ bool ok = true;
+
+ device_id = UINT32_C(0x2f000045);
+ unkn2 = 23;
+ unkn9 = 0;
+ fragment = 0;
+ flags = UINT32_C(0x6b000001);
+
+ request_blob.spotlight_blob = test_sl_unpack_loop_buf;
+ request_blob.size = sizeof(test_sl_unpack_loop_buf);
+ request_blob.length = sizeof(test_sl_unpack_loop_buf);
+
+ status = dcerpc_mdssvc_cmd(b,
+ state,
+ &state->ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ flags,
+ request_blob,
+ 0,
+ 64 * 1024,
+ 1,
+ 64 * 1024,
+ 0,
+ 0,
+ &fragment,
+ &response_blob,
+ &unkn9);
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ok, done,
+ "dcerpc_mdssvc_unknown1 failed\n");
+
+done:
+ return ok;
+}
+
+static bool test_sl_dict_type_safety(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct mdssvc_blob request_blob;
+ struct mdssvc_blob response_blob;
+ uint64_t ctx1 = 0xdeadbeef;
+ uint64_t ctx2 = 0xcafebabe;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t unkn9;
+ uint32_t fragment;
+ uint32_t flags;
+ DALLOC_CTX *d = NULL;
+ sl_array_t *array1 = NULL, *array2 = NULL;
+ sl_dict_t *arg = NULL;
+ int result;
+ NTSTATUS status;
+ bool ok = true;
+
+ device_id = UINT32_C(0x2f000045);
+ unkn2 = 23;
+ unkn9 = 0;
+ fragment = 0;
+ flags = UINT32_C(0x6b000001);
+
+ d = dalloc_new(tctx);
+ torture_assert_not_null_goto(tctx, d,
+ ok, done, "dalloc_new failed\n");
+
+ array1 = dalloc_zero(d, sl_array_t);
+ torture_assert_not_null_goto(tctx, array1,
+ ok, done, "dalloc_zero failed\n");
+
+ array2 = dalloc_zero(d, sl_array_t);
+ torture_assert_not_null_goto(tctx, array2,
+ ok, done, "dalloc_new failed\n");
+
+ result = dalloc_stradd(array2, "openQueryWithParams:forContext:");
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ result = dalloc_add_copy(array2, &ctx1, uint64_t);
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ result = dalloc_add_copy(array2, &ctx2, uint64_t);
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ arg = dalloc_zero(array1, sl_dict_t);
+ torture_assert_not_null_goto(tctx, d,
+ ok, done, "dalloc_zero failed\n");
+
+ result = dalloc_stradd(arg, "kMDQueryString");
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ result = dalloc_stradd(arg, "*");
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ result = dalloc_stradd(arg, "kMDScopeArray");
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ result = dalloc_stradd(arg, "AAAABBBB");
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_stradd failed\n");
+
+ result = dalloc_add(array1, array2, sl_array_t);
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_add failed\n");
+
+ result = dalloc_add(array1, arg, sl_dict_t);
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_add failed\n");
+
+ result = dalloc_add(d, array1, sl_array_t);
+ torture_assert_goto(tctx, result == 0,
+ ok, done, "dalloc_add failed\n");
+
+ torture_comment(tctx, "%s", dalloc_dump(d, 0));
+
+ request_blob.spotlight_blob = talloc_array(tctx,
+ uint8_t,
+ 64 * 1024);
+ torture_assert_not_null_goto(tctx, request_blob.spotlight_blob,
+ ok, done, "dalloc_new failed\n");
+ request_blob.size = 64 * 1024;
+
+ status = sl_pack_alloc(tctx, d, &request_blob, 64 * 1024);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "sl_pack_alloc() failed\n");
+
+ status = dcerpc_mdssvc_cmd(b,
+ state,
+ &state->ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ flags,
+ request_blob,
+ 0,
+ 64 * 1024,
+ 1,
+ 64 * 1024,
+ 0,
+ 0,
+ &fragment,
+ &response_blob,
+ &unkn9);
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ok, done,
+ "dcerpc_mdssvc_cmd failed\n");
+
+done:
+ return ok;
+}
+
+static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ struct policy_handle ph;
+ uint32_t device_id;
+ uint32_t unkn2;
+ uint32_t close_status;
+ NTSTATUS status;
+ bool ok = true;
+
+ device_id = generate_random();
+ unkn2 = 23;
+ close_status = 0;
+
+ ZERO_STRUCT(ph);
+ ph.uuid = GUID_random();
+
+ status = dcerpc_mdssvc_close(b,
+ state,
+ &ph,
+ 0,
+ device_id,
+ unkn2,
+ 0,
+ &ph,
+ &close_status);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done,
+ "dcerpc_mdssvc_unknown1 failed\n");
+
+ /* Free and set to NULL the no-longer-usable pipe. */
+ b = NULL;
+ TALLOC_FREE(state->p);
+
+done:
+ return ok;
+}
+
+/*
+ * Test fetchAttributes with unknown CNID
+ */
+static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx,
+ void *data)
+{
+ struct torture_mdsscv_state *state = talloc_get_type_abort(
+ data, struct torture_mdsscv_state);
+ struct dcerpc_binding_handle *b = state->p->binding_handle;
+ uint32_t max_fragment_size = 64 * 1024;
+ struct mdssvc_blob request_blob;
+ struct mdssvc_blob response_blob;
+ DALLOC_CTX *d = NULL, *mds_reply = NULL;
+ uint64_t *uint64var = NULL;
+ sl_array_t *array = NULL;
+ sl_array_t *cmd_array = NULL;
+ sl_array_t *attr_array = NULL;
+ sl_cnids_t *cnids = NULL;
+ void *path = NULL;
+ const char *path_type = NULL;
+ uint64_t ino64;
+ NTSTATUS status;
+ int ret;
+ bool ok = true;
+
+ d = dalloc_new(state);
+ torture_assert_not_null_goto(tctx, d, ret, done, "dalloc_new failed\n");
+
+ array = dalloc_zero(d, sl_array_t);
+ torture_assert_not_null_goto(tctx, array, ret, done,
+ "dalloc_zero failed\n");
+
+ ret = dalloc_add(d, array, sl_array_t);
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
+
+ cmd_array = dalloc_zero(d, sl_array_t);
+ torture_assert_not_null_goto(tctx, cmd_array, ret, done,
+ "dalloc_zero failed\n");
+
+ ret = dalloc_add(array, cmd_array, sl_array_t);
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
+
+ ret = dalloc_stradd(cmd_array, "fetchAttributes:forOIDArray:context:");
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_stradd failed\n");
+
+ uint64var = talloc_zero_array(cmd_array, uint64_t, 2);
+ torture_assert_not_null_goto(tctx, uint64var, ret, done,
+ "talloc_zero_array failed\n");
+ talloc_set_name(uint64var, "uint64_t *");
+
+ uint64var[0] = 0x500a;
+ uint64var[1] = 0;
+
+ ret = dalloc_add(cmd_array, &uint64var[0], uint64_t *);
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
+
+ attr_array = dalloc_zero(d, sl_array_t);
+ torture_assert_not_null_goto(tctx, attr_array, ret, done,
+ "dalloc_zero failed\n");
+
+ ret = dalloc_add(array, attr_array, sl_array_t);
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
+
+ ret = dalloc_stradd(attr_array, "kMDItemPath");
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_stradd failed\n");
+
+ /* CNIDs */
+ cnids = talloc_zero(array, sl_cnids_t);
+ torture_assert_not_null_goto(tctx, cnids, ret, done,
+ "talloc_zero failed\n");
+
+ cnids->ca_cnids = dalloc_new(cnids);
+ torture_assert_not_null_goto(tctx, cnids->ca_cnids, ret, done,
+ "dalloc_new failed\n");
+
+ cnids->ca_unkn1 = 0xadd;
+ cnids->ca_context = 0x6b000020;
+
+ ino64 = UINT64_C(64382947389618974);
+ ret = dalloc_add_copy(cnids->ca_cnids, &ino64, uint64_t);
+ torture_assert_goto(tctx, ret == 0, ret, done,
+ "dalloc_add_copy failed\n");
+
+ ret = dalloc_add(array, cnids, sl_cnids_t);
+ torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
+
+ status = sl_pack_alloc(tctx, d, &request_blob, max_fragment_size);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "sl_pack_alloc() failed\n");
+
+ status = dcerpc_mdssvc_cmd(b,
+ state,
+ &state->ph,
+ 0,
+ state->dev,
+ state->mdscmd_open.unkn2,
+ 0,
+ state->flags,
+ request_blob,
+ 0,
+ max_fragment_size,
+ 1,
+ max_fragment_size,
+ 0,
+ 0,
+ &state->mdscmd_cmd.fragment,
+ &response_blob,
+ &state->mdscmd_cmd.unkn9);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "dcerpc_mdssvc_cmd failed\n");
+
+ mds_reply = dalloc_new(state);
+ torture_assert_not_null_goto(tctx, mds_reply, ret, done,
+ "dalloc_zero failed\n");
+
+ ok = sl_unpack(mds_reply,
+ (char *)response_blob.spotlight_blob,
+ response_blob.length);
+ torture_assert_goto(tctx, ok, ret, done, "dalloc_add failed\n");
+
+ torture_comment(tctx, "%s", dalloc_dump(mds_reply, 0));
+
+ path = dalloc_get(mds_reply,
+ "DALLOC_CTX", 0,
+ "DALLOC_CTX", 2,
+ "DALLOC_CTX", 0,
+ "sl_nil_t", 1);
+ torture_assert_not_null_goto(tctx, path, ret, done,
+ "dalloc_get path failed\n");
+
+ path_type = talloc_get_name(path);
+
+ torture_assert_str_equal_goto(tctx, path_type, "sl_nil_t", ret, done,
+ "Wrong dalloc object type\n");
+
+done:
+ return ok;
+}
+
+struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ mem_ctx, "mdssvc");
+ struct torture_tcase *tcase = NULL;
+
+ tcase = torture_suite_add_tcase(suite, "rpccmd");
+ if (tcase == NULL) {
+ return NULL;
+ }
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_mdssvc_setup,
+ torture_rpc_mdssvc_teardown);
+
+ torture_tcase_add_simple_test(tcase,
+ "open_unknown_share",
+ test_mdssvc_open_unknown_share);
+
+ torture_tcase_add_simple_test(tcase,
+ "open_spotlight_disabled",
+ test_mdssvc_open_spotlight_disabled);
+
+ torture_tcase_add_simple_test(tcase,
+ "close",
+ test_mdssvc_close);
+
+ torture_tcase_add_simple_test(tcase,
+ "null_ph",
+ test_mdssvc_null_ph);
+
+ tcase = torture_suite_add_tcase(suite, "disconnect1");
+ if (tcase == NULL) {
+ return NULL;
+ }
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_mdssvc_open,
+ torture_rpc_mdssvc_close);
+
+ torture_tcase_add_simple_test(tcase,
+ "invalid_ph_unknown1",
+ test_mdssvc_invalid_ph_unknown1);
+
+ tcase = torture_suite_add_tcase(suite, "disconnect2");
+ if (tcase == NULL) {
+ return NULL;
+ }
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_mdssvc_open,
+ torture_rpc_mdssvc_close);
+
+ torture_tcase_add_simple_test(tcase,
+ "invalid_ph_cmd",
+ test_mdssvc_invalid_ph_cmd);
+
+ tcase = torture_suite_add_tcase(suite, "disconnect3");
+ if (tcase == NULL) {
+ return NULL;
+ }
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_mdssvc_open,
+ torture_rpc_mdssvc_close);
+
+ torture_tcase_add_simple_test(tcase,
+ "invalid_ph_close",
+ test_mdssvc_invalid_ph_close);
+
+ tcase = torture_suite_add_tcase(suite, "mdscmd");
+ if (tcase == NULL) {
+ return NULL;
+ }
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_mdssvc_open,
+ torture_rpc_mdssvc_close);
+
+ torture_tcase_add_simple_test(tcase,
+ "fetch_unknown_cnid",
+ test_mdssvc_fetch_attr_unknown_cnid);
+
+ torture_tcase_add_simple_test(tcase,
+ "mdssvc_sl_unpack_loop",
+ test_mdssvc_sl_unpack_loop);
+
+ torture_tcase_add_simple_test(tcase,
+ "sl_dict_type_safety",
+ test_sl_dict_type_safety);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/mgmt.c b/source4/torture/rpc/mgmt.c
new file mode 100644
index 0000000..e873d4b
--- /dev/null
+++ b/source4/torture/rpc/mgmt.c
@@ -0,0 +1,328 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for mgmt rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_mgmt_c.h"
+#include "auth/gensec/gensec.h"
+#include "librpc/ndr/ndr_table.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+
+/*
+ ask the server what interface IDs are available on this endpoint
+*/
+bool test_inq_if_ids(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ bool (*per_id_test)(struct torture_context *,
+ const struct ndr_interface_table *iface,
+ TALLOC_CTX *mem_ctx,
+ struct ndr_syntax_id *id),
+ const void *priv)
+{
+ struct mgmt_inq_if_ids r;
+ struct rpc_if_id_vector_t *vector;
+ int i;
+
+ vector = talloc(mem_ctx, struct rpc_if_id_vector_t);
+ r.out.if_id_vector = &vector;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_mgmt_inq_if_ids_r(b, mem_ctx, &r),
+ "inq_if_ids failed");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "inq_if_ids gave unexpected error code");
+
+ if (!vector) {
+ torture_comment(tctx, "inq_if_ids gave NULL if_id_vector\n");
+ return false;
+ }
+
+ for (i=0;i<vector->count;i++) {
+ struct ndr_syntax_id *id = vector->if_id[i].id;
+ if (!id) continue;
+
+ torture_comment(tctx, "\tuuid %s version 0x%08x '%s'\n",
+ GUID_string(mem_ctx, &id->uuid),
+ id->if_version,
+ ndr_interface_name(&id->uuid, id->if_version));
+
+ if (per_id_test) {
+ per_id_test(tctx, priv, mem_ctx, id);
+ }
+ }
+
+ return true;
+}
+
+static bool test_inq_stats(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx)
+{
+ struct mgmt_inq_stats r;
+ struct mgmt_statistics statistics;
+
+ r.in.max_count = MGMT_STATS_ARRAY_MAX_SIZE;
+ r.in.unknown = 0;
+ r.out.statistics = &statistics;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_mgmt_inq_stats_r(b, mem_ctx, &r),
+ "inq_stats failed");
+
+ if (statistics.count != MGMT_STATS_ARRAY_MAX_SIZE) {
+ torture_comment(tctx, "Unexpected array size %d\n", statistics.count);
+ return false;
+ }
+
+ torture_comment(tctx, "\tcalls_in %6d calls_out %6d\n\tpkts_in %6d pkts_out %6d\n",
+ statistics.statistics[MGMT_STATS_CALLS_IN],
+ statistics.statistics[MGMT_STATS_CALLS_OUT],
+ statistics.statistics[MGMT_STATS_PKTS_IN],
+ statistics.statistics[MGMT_STATS_PKTS_OUT]);
+
+ return true;
+}
+
+static bool test_inq_princ_name_size(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t authn_proto,
+ const char *expected_princ_name)
+{
+ struct mgmt_inq_princ_name r;
+ uint32_t len, i;
+
+ len = strlen(expected_princ_name);
+
+ r.in.authn_proto = authn_proto;
+
+ /*
+ * 0 gives NT_STATUS_RPC_BAD_STUB_DATA
+ */
+ r.in.princ_name_size = 0;
+
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_mgmt_inq_princ_name_r(b, tctx, &r),
+ NT_STATUS_RPC_BAD_STUB_DATA,
+ "mgmt_inq_princ_name failed");
+
+ for (i=1; i <= len; i++) {
+ r.in.princ_name_size = i;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_mgmt_inq_princ_name_r(b, tctx, &r),
+ "mgmt_inq_princ_name failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INSUFFICIENT_BUFFER,
+ "mgmt_inq_princ_name failed");
+ }
+
+ r.in.princ_name_size = len + 1;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_mgmt_inq_princ_name_r(b, tctx, &r),
+ "mgmt_inq_princ_name failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "mgmt_inq_princ_name failed");
+
+ return true;
+}
+
+static bool test_inq_princ_name(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ struct mgmt_inq_princ_name r;
+ int i;
+ bool ret = false;
+
+ for (i=0;i<256;i++) {
+ r.in.authn_proto = i; /* DCERPC_AUTH_TYPE_* */
+ r.in.princ_name_size = 100;
+
+ status = dcerpc_mgmt_inq_princ_name_r(b, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ continue;
+ }
+ if (W_ERROR_IS_OK(r.out.result)) {
+ const char *name = gensec_get_name_by_authtype(NULL, i);
+ ret = true;
+ if (name) {
+ torture_comment(tctx, "\tprinciple name for proto %u (%s) is '%s'\n",
+ i, name, r.out.princ_name);
+ } else {
+ torture_comment(tctx, "\tprinciple name for proto %u is '%s'\n",
+ i, r.out.princ_name);
+ }
+
+ switch (i) {
+ case DCERPC_AUTH_TYPE_KRB5:
+ case DCERPC_AUTH_TYPE_NTLMSSP:
+ case DCERPC_AUTH_TYPE_SPNEGO:
+ torture_assert(tctx,
+ test_inq_princ_name_size(tctx, b, i, r.out.princ_name),
+ "failed");
+ break;
+ case DCERPC_AUTH_TYPE_SCHANNEL:
+ /*
+ * for some reason schannel behaves differently
+ *
+ */
+ default:
+ break;
+ }
+ }
+ }
+
+ if (!ret) {
+ torture_comment(tctx, "\tno principle names?\n");
+ }
+
+ return true;
+}
+
+static bool test_is_server_listening(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx)
+{
+ struct mgmt_is_server_listening r;
+ r.out.status = talloc(mem_ctx, uint32_t);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_mgmt_is_server_listening_r(b, mem_ctx, &r),
+ "is_server_listening failed");
+
+ if (*r.out.status != 0 || r.out.result == 0) {
+ torture_comment(tctx, "\tserver is NOT listening\n");
+ } else {
+ torture_comment(tctx, "\tserver is listening\n");
+ }
+
+ return true;
+}
+
+static bool test_stop_server_listening(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx)
+{
+ struct mgmt_stop_server_listening r;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_mgmt_stop_server_listening_r(b, mem_ctx, &r),
+ "stop_server_listening failed");
+
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "\tserver refused to stop listening - %s\n", win_errstr(r.out.result));
+ } else {
+ torture_comment(tctx, "\tserver allowed a stop_server_listening request\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_rpc_mgmt(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx, *loop_ctx;
+ bool ret = true;
+ const struct ndr_interface_list *l;
+ struct dcerpc_binding *b;
+
+ mem_ctx = talloc_init("torture_rpc_mgmt");
+
+ status = torture_rpc_binding(tctx, &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ for (l=ndr_table_list();l;l=l->next) {
+ struct dcerpc_binding_handle *bh;
+
+ loop_ctx = talloc_named(mem_ctx, 0, "torture_rpc_mgmt loop context");
+
+ /* some interfaces are not mappable */
+ if (l->table->num_calls == 0 ||
+ strcmp(l->table->name, "mgmt") == 0) {
+ talloc_free(loop_ctx);
+ continue;
+ }
+
+ torture_comment(tctx, "\nTesting pipe '%s'\n", l->table->name);
+
+ status = dcerpc_epm_map_binding(loop_ctx, b, l->table,
+ tctx->ev, tctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to map port for uuid %s\n",
+ GUID_string(loop_ctx, &l->table->syntax_id.uuid));
+ talloc_free(loop_ctx);
+ continue;
+ }
+
+ lpcfg_set_cmdline(tctx->lp_ctx, "torture:binding", dcerpc_binding_string(loop_ctx, b));
+
+ status = torture_rpc_connection(tctx, &p, &ndr_table_mgmt);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ torture_comment(tctx, "Interface not available - skipping\n");
+ talloc_free(loop_ctx);
+ continue;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(loop_ctx);
+ torture_comment(tctx, "Interface not available (%s) - skipping\n", nt_errstr(status));
+ ret = false;
+ continue;
+ }
+ bh = p->binding_handle;
+
+ if (!test_is_server_listening(tctx, bh, loop_ctx)) {
+ ret = false;
+ }
+
+ if (!test_stop_server_listening(tctx, bh, loop_ctx)) {
+ ret = false;
+ }
+
+ if (!test_inq_stats(tctx, bh, loop_ctx)) {
+ ret = false;
+ }
+
+ if (!test_inq_princ_name(tctx, bh, loop_ctx)) {
+ ret = false;
+ }
+
+ if (!test_inq_if_ids(tctx, bh, loop_ctx, NULL, NULL)) {
+ ret = false;
+ }
+
+ }
+
+ return ret;
+}
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
new file mode 100644
index 0000000..c371561
--- /dev/null
+++ b/source4/torture/rpc/netlogon.c
@@ -0,0 +1,6038 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for netlogon rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "../lib/crypto/crypto.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "param/param.h"
+#include "libcli/security/security.h"
+#include <ldb.h>
+#include "lib/util/util_ldb.h"
+#include "ldb_wrap.h"
+#include "lib/replace/system/network.h"
+#include "dsdb/samdb/samdb.h"
+
+#undef strcasecmp
+
+#define TEST_MACHINE_NAME "torturetest"
+
+static bool test_netr_broken_binding_handle(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_DsRGetSiteName r;
+ const char *site = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.computer_name = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.out.site = &site;
+
+ torture_comment(tctx,
+ "Testing netlogon request with correct binding handle: %s\n",
+ r.in.computer_name);
+
+ status = dcerpc_netr_DsRGetSiteName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Netlogon request with broken binding handle");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "Netlogon request with broken binding handle");
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx,
+ "Skipping broken binding handle check against Samba");
+ }
+
+ r.in.computer_name = talloc_asprintf(tctx, "\\\\\\\\%s",
+ dcerpc_server_name(p));
+
+ torture_comment(tctx,
+ "Testing netlogon request with broken binding handle: %s\n",
+ r.in.computer_name);
+
+ status = dcerpc_netr_DsRGetSiteName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Netlogon request with broken binding handle");
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_INVALID_COMPUTERNAME,
+ "Netlogon request with broken binding handle");
+
+ r.in.computer_name = "\\\\\\\\THIS_IS_NOT_VALID";
+
+ torture_comment(tctx,
+ "Testing netlogon request with broken binding handle: %s\n",
+ r.in.computer_name);
+
+ status = dcerpc_netr_DsRGetSiteName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Netlogon request with broken binding handle");
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_INVALID_COMPUTERNAME,
+ "Netlogon request with broken binding handle");
+
+ return true;
+}
+
+static bool test_LogonUasLogon(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_LogonUasLogon r;
+ struct netr_UasInfo *info = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.account_name = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ r.in.workstation = TEST_MACHINE_NAME;
+ r.out.info = &info;
+
+ status = dcerpc_netr_LogonUasLogon_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonUasLogon");
+
+ return true;
+}
+
+static bool test_LogonUasLogoff(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_LogonUasLogoff r;
+ struct netr_UasLogoffInfo info;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.account_name = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ r.in.workstation = TEST_MACHINE_NAME;
+ r.out.info = &info;
+
+ status = dcerpc_netr_LogonUasLogoff_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonUasLogoff");
+
+ return true;
+}
+
+bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ const struct samr_Password *mach_password;
+ const char *machine_name;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+ machine_name = cli_credentials_get_workstation(credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(credentials);
+ a.in.computer_name = machine_name;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ mach_password, &credentials3,
+ 0);
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+
+ torture_comment(tctx, "Testing ServerAuthenticate\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate_r(b, tctx, &a),
+ "ServerAuthenticate failed");
+
+ /* This allows the tests to continue against the more fussy windows 2008 */
+ if (NT_STATUS_EQUAL(a.out.result, NT_STATUS_DOWNGRADE_DETECTED)) {
+ return test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ credentials,
+ cli_credentials_get_secure_channel_type(credentials),
+ creds_out);
+ }
+
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3),
+ "Credential chaining failed");
+
+ *creds_out = creds;
+ return true;
+}
+
+bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ const char *computer_name,
+ enum netr_SchannelType sec_chan_type,
+ NTSTATUS expected_result,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate2 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ const struct samr_Password *mach_password;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *account_name = cli_credentials_get_username(machine_credentials);
+
+ mach_password = cli_credentials_get_nt_hash(machine_credentials, tctx);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = computer_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ a.in.server_name = NULL;
+ a.in.account_name = account_name;
+ a.in.secure_channel_type = sec_chan_type;
+ a.in.computer_name = computer_name;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ mach_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+ "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(tctx, a.out.result, expected_result,
+ "ServerAuthenticate2 unexpected");
+
+ if (NT_STATUS_IS_OK(expected_result)) {
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3),
+ "Credential chaining failed");
+ } else {
+ torture_assert(tctx, !netlogon_creds_client_check(creds, &credentials3),
+ "Credential chaining passed unexpected");
+ }
+
+ torture_comment(tctx, "negotiate_flags=0x%08x\n", negotiate_flags);
+
+ *creds_out = creds;
+ return true;
+}
+
+bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ enum netr_SchannelType sec_chan_type,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ const char *computer_name =
+ cli_credentials_get_workstation(machine_credentials);
+
+ return test_SetupCredentials2ex(p, tctx, negotiate_flags,
+ machine_credentials,
+ computer_name,
+ sec_chan_type,
+ NT_STATUS_OK,
+ creds_out);
+}
+
+bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (p == NULL) {
+ return false;
+ }
+
+ b = p->binding_handle;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ torture_comment(tctx, "negotiate_flags=0x%08x\n", negotiate_flags);
+
+ /* Prove that requesting a challenge again won't break it */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ *creds_out = creds;
+ return true;
+}
+
+bool test_SetupCredentialsDowngrade(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t negotiate_flags = 0;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_DOWNGRADE_DETECTED, "ServerAuthenticate3 should have failed");
+
+ negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 should succeed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ torture_comment(tctx, "negotiate_flags=0x%08x\n", negotiate_flags);
+
+ /* Prove that requesting a challenge again won't break it */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ return true;
+}
+
+bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1,
+ struct torture_context *tctx,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState *creds,
+ uint32_t additional_flags,
+ struct dcerpc_pipe **_p2)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *b2 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
+
+ b2 = dcerpc_binding_dup(tctx, p1->binding);
+ torture_assert(tctx, b2 != NULL, "dcerpc_binding_dup");
+ dcerpc_binding_set_flags(b2,
+ DCERPC_SCHANNEL | additional_flags,
+ DCERPC_AUTH_OPTIONS);
+
+ cli_credentials_set_netlogon_creds(machine_credentials, creds);
+ status = dcerpc_pipe_connect_b(tctx, &p2, b2,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx);
+ cli_credentials_set_netlogon_creds(machine_credentials, NULL);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b schannel");
+
+ *_p2 = p2;
+ return true;
+}
+
+static bool test_ServerReqChallenge(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ const char *machine_name;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct netr_ServerAuthenticate2 a;
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ uint32_t out_negotiate_flags = 0;
+ const struct samr_Password *mach_password = NULL;
+ enum netr_SchannelType sec_chan_type = 0;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ const char *account_name = NULL;
+
+ machine_name = cli_credentials_get_workstation(credentials);
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+ account_name = cli_credentials_get_username(credentials);
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(
+ tctx,
+ r.out.result,
+ "ServerReqChallenge failed");
+ a.in.server_name = NULL;
+ a.in.account_name = account_name;
+ a.in.secure_channel_type = sec_chan_type;
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &in_negotiate_flags;
+ a.out.negotiate_flags = &out_negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ mach_password, &credentials3,
+ in_negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+ "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(
+ tctx,
+ a.out.result,
+ NT_STATUS_OK,
+ "ServerAuthenticate2 unexpected");
+
+ return true;
+}
+
+static bool test_ServerReqChallenge_zero_challenge(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ const char *machine_name;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct netr_ServerAuthenticate2 a;
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ uint32_t out_negotiate_flags = 0;
+ const struct samr_Password *mach_password = NULL;
+ enum netr_SchannelType sec_chan_type = 0;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ const char *account_name = NULL;
+
+ machine_name = cli_credentials_get_workstation(credentials);
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+ account_name = cli_credentials_get_username(credentials);
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ /*
+ * Set the client challenge to zero, this should fail
+ * CVE-2020-1472(ZeroLogon)
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
+ */
+ ZERO_STRUCT(credentials1);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(
+ tctx,
+ r.out.result,
+ "ServerReqChallenge failed");
+ a.in.server_name = NULL;
+ a.in.account_name = account_name;
+ a.in.secure_channel_type = sec_chan_type;
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &in_negotiate_flags;
+ a.out.negotiate_flags = &out_negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ mach_password, &credentials3,
+ in_negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+ "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(
+ tctx,
+ a.out.result,
+ NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate2 unexpected");
+
+ return true;
+}
+
+static bool test_ServerReqChallenge_5_repeats(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ const char *machine_name;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct netr_ServerAuthenticate2 a;
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ uint32_t out_negotiate_flags = 0;
+ const struct samr_Password *mach_password = NULL;
+ enum netr_SchannelType sec_chan_type = 0;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ const char *account_name = NULL;
+
+ machine_name = cli_credentials_get_workstation(credentials);
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+ account_name = cli_credentials_get_username(credentials);
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ /*
+ * Set the first 5 bytes of the client challenge to the same value,
+ * this should fail CVE-2020-1472(ZeroLogon)
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
+ */
+ credentials1.data[0] = 'A';
+ credentials1.data[1] = 'A';
+ credentials1.data[2] = 'A';
+ credentials1.data[3] = 'A';
+ credentials1.data[4] = 'A';
+ credentials1.data[5] = 'B';
+ credentials1.data[6] = 'C';
+ credentials1.data[7] = 'D';
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(
+ tctx,
+ r.out.result,
+ "ServerReqChallenge failed");
+ a.in.server_name = NULL;
+ a.in.account_name = account_name;
+ a.in.secure_channel_type = sec_chan_type;
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &in_negotiate_flags;
+ a.out.negotiate_flags = &out_negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ mach_password, &credentials3,
+ in_negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+ "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(
+ tctx,
+ a.out.result,
+ NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate2 unexpected");
+
+ return true;
+}
+
+static bool test_ServerReqChallenge_4_repeats(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ const char *machine_name;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct netr_ServerAuthenticate2 a;
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ uint32_t out_negotiate_flags = 0;
+ const struct samr_Password *mach_password = NULL;
+ enum netr_SchannelType sec_chan_type = 0;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ const char *account_name = NULL;
+
+ machine_name = cli_credentials_get_workstation(credentials);
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
+ account_name = cli_credentials_get_username(credentials);
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ /*
+ * Set the first 4 bytes of the client challenge to the same
+ * value, this should pass as 5 bytes identical are needed to
+ * fail for CVE-2020-1472(ZeroLogon)
+ *
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
+ */
+ credentials1.data[0] = 'A';
+ credentials1.data[1] = 'A';
+ credentials1.data[2] = 'A';
+ credentials1.data[3] = 'A';
+ credentials1.data[4] = 'B';
+ credentials1.data[5] = 'C';
+ credentials1.data[6] = 'D';
+ credentials1.data[7] = 'E';
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(
+ tctx,
+ r.out.result,
+ "ServerReqChallenge failed");
+ a.in.server_name = NULL;
+ a.in.account_name = account_name;
+ a.in.secure_channel_type = sec_chan_type;
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &in_negotiate_flags;
+ a.out.negotiate_flags = &out_negotiate_flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ mach_password, &credentials3,
+ in_negotiate_flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+ "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(
+ tctx,
+ a.out.result,
+ NT_STATUS_OK,
+ "ServerAuthenticate2 unexpected");
+
+ return true;
+}
+
+/*
+ * Establish a NetLogon session, using a session key that encrypts the
+ * target character to zero
+ */
+static bool test_ServerAuthenticate2_encrypts_to_zero(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials,
+ const char target,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ const char *computer_name =
+ cli_credentials_get_workstation(machine_credentials);
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate2 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ const struct samr_Password *mach_password;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *account_name = cli_credentials_get_username(
+ machine_credentials);
+ uint32_t flags =
+ NETLOGON_NEG_AUTH2_ADS_FLAGS |
+ NETLOGON_NEG_SUPPORTS_AES;
+ enum netr_SchannelType sec_chan_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ /*
+ * Limit the number of attempts to generate a suitable session key.
+ */
+ const unsigned MAX_ITER = 4096;
+ unsigned i = 0;
+
+ mach_password = cli_credentials_get_nt_hash(machine_credentials, tctx);
+
+ r.in.server_name = NULL;
+ r.in.computer_name = computer_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+ credentials1.data[0] = target;
+ i = 0;
+ torture_comment(tctx, "Generating candidate session keys\n");
+ do {
+ TALLOC_FREE(creds);
+ i++;
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(
+ tctx,
+ r.out.result,
+ "ServerReqChallenge failed");
+
+ a.in.server_name = NULL;
+ a.in.account_name = account_name;
+ a.in.secure_channel_type = sec_chan_type;
+ a.in.computer_name = computer_name;
+ a.in.negotiate_flags = &flags;
+ a.out.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+
+ creds = netlogon_creds_client_init(
+ tctx,
+ a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1,
+ &credentials2,
+ mach_password,
+ &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+ } while (credentials3.data[0] != 0 && i < MAX_ITER);
+
+ if (i >= MAX_ITER) {
+ torture_comment(
+ tctx,
+ "Unable to obtain a suitable session key, "
+ "after [%u] attempts\n",
+ i);
+ torture_fail(tctx, "Unable to obtain suitable session key");
+ }
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
+ "ServerAuthenticate2 failed");
+ torture_assert_ntstatus_equal(
+ tctx,
+ a.out.result,
+ NT_STATUS_OK,
+ "ServerAuthenticate2 unexpected result code");
+
+ *creds_out = creds;
+ return true;
+}
+
+/*
+ try a change password for our machine account
+*/
+static bool test_SetPassword(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet r;
+ const char *password;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator credential, return_authenticator;
+ struct samr_Password new_password;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ password = generate_random_password(tctx, 8, 255);
+ E_md4hash(password, new_password.hash);
+
+ netlogon_creds_des_encrypt(creds, &new_password);
+
+ torture_comment(tctx, "Testing ServerPasswordSet on machine account\n");
+ torture_comment(tctx, "Changing machine account password to '%s'\n",
+ password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet_r(b, tctx, &r),
+ "ServerPasswordSet failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ /* by changing the machine password twice we test the
+ credentials chaining fully, and we verify that the server
+ allows the password to be set to the same value twice in a
+ row (match win2k3) */
+ torture_comment(tctx,
+ "Testing a second ServerPasswordSet on machine account\n");
+ torture_comment(tctx,
+ "Changing machine account password to '%s' (same as previous run)\n", password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet_r(b, tctx, &r),
+ "ServerPasswordSet (2) failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet (2) failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
+
+ torture_assert(tctx,
+ test_SetupCredentials(p, tctx, machine_credentials, &creds),
+ "ServerPasswordSet failed to actually change the password");
+
+ return true;
+}
+
+/*
+ try a change password for our machine account
+*/
+static bool test_SetPassword_flags(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials,
+ uint32_t negotiate_flags)
+{
+ struct netr_ServerPasswordSet r;
+ const char *password;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator credential, return_authenticator;
+ struct samr_Password new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
+ machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ password = generate_random_password(tctx, 8, 255);
+ E_md4hash(password, new_password.hash);
+
+ netlogon_creds_des_encrypt(creds, &new_password);
+
+ torture_comment(tctx, "Testing ServerPasswordSet on machine account\n");
+ torture_comment(tctx, "Changing machine account password to '%s'\n",
+ password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet_r(b, tctx, &r),
+ "ServerPasswordSet failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ /* by changing the machine password twice we test the
+ credentials chaining fully, and we verify that the server
+ allows the password to be set to the same value twice in a
+ row (match win2k3) */
+ torture_comment(tctx,
+ "Testing a second ServerPasswordSet on machine account\n");
+ torture_comment(tctx,
+ "Changing machine account password to '%s' (same as previous run)\n", password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet_r(b, tctx, &r),
+ "ServerPasswordSet (2) failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet (2) failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
+
+ torture_assert(tctx,
+ test_SetupCredentials(p, tctx, machine_credentials, &creds),
+ "ServerPasswordSet failed to actually change the password");
+
+ return true;
+}
+
+
+/*
+ generate a random password for password change tests
+*/
+static DATA_BLOB netlogon_very_rand_pass(TALLOC_CTX *mem_ctx, int len)
+{
+ int i;
+ DATA_BLOB password = data_blob_talloc(mem_ctx, NULL, len * 2 /* number of unicode chars */);
+ generate_random_buffer(password.data, password.length);
+
+ for (i=0; i < len; i++) {
+ if (((uint16_t *)password.data)[i] == 0) {
+ ((uint16_t *)password.data)[i] = 1;
+ }
+ }
+
+ return password;
+}
+
+/*
+ try a change password for our machine account
+*/
+static bool test_SetPassword2_with_flags(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials,
+ uint32_t flags)
+{
+ struct netr_ServerPasswordSet2 r;
+ const char *password;
+ DATA_BLOB new_random_pass;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct samr_Password nt_hash;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (!test_SetupCredentials2(p1, tctx, flags, machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ password = generate_random_password(tctx, 8, 255);
+ encode_pw_buffer(password_buf.data, password, STR_UNICODE);
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+ }
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(tctx, "Testing ServerPasswordSet2 on machine account\n");
+ torture_comment(tctx, "Changing machine account password to '%s'\n", password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet2 failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
+
+ /*
+ * As a consequence of CVE-2020-1472(ZeroLogon)
+ * Samba explicitly disallows the setting of an empty machine account
+ * password.
+ *
+ * Note that this may fail against Windows, and leave a machine account
+ * with an empty password.
+ */
+ password = "";
+ encode_pw_buffer(password_buf.data, password, STR_UNICODE);
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+ }
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(tctx,
+ "Testing ServerPasswordSet2 on machine account\n");
+ torture_comment(tctx,
+ "Changing machine account password to '%s'\n", password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 failed");
+ torture_assert_ntstatus_equal(
+ tctx,
+ r.out.result,
+ NT_STATUS_WRONG_PASSWORD,
+ "ServerPasswordSet2 did not return NT_STATUS_WRONG_PASSWORD");
+
+ /* now try a random password */
+ password = generate_random_password(tctx, 8, 255);
+ encode_pw_buffer(password_buf.data, password, STR_UNICODE);
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+ }
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(tctx, "Testing second ServerPasswordSet2 on machine account\n");
+ torture_comment(tctx, "Changing machine account password to '%s'\n", password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 (2) failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet2 (2) failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ /* by changing the machine password twice we test the
+ credentials chaining fully, and we verify that the server
+ allows the password to be set to the same value twice in a
+ row (match win2k3) */
+ torture_comment(tctx,
+ "Testing a second ServerPasswordSet2 on machine account\n");
+ torture_comment(tctx,
+ "Changing machine account password to '%s' (same as previous run)\n", password);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet (3) failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet (3) failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
+
+ torture_assert (tctx,
+ test_SetupCredentials(p, tctx, machine_credentials, &creds),
+ "ServerPasswordSet failed to actually change the password");
+
+ new_random_pass = netlogon_very_rand_pass(tctx, 128);
+
+ /* now try a random stream of bytes for a password */
+ set_pw_in_buffer(password_buf.data, &new_random_pass);
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+ }
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(tctx,
+ "Testing a third ServerPasswordSet2 on machine account, with a completely random password\n");
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet (3) failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet (3) failed");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ mdfour(nt_hash.hash, new_random_pass.data, new_random_pass.length);
+
+ cli_credentials_set_password(machine_credentials, NULL, CRED_UNINITIALISED);
+ cli_credentials_set_nt_hash(machine_credentials, &nt_hash, CRED_SPECIFIED);
+
+ torture_assert (tctx,
+ test_SetupCredentials(p, tctx, machine_credentials, &creds),
+ "ServerPasswordSet failed to actually change the password");
+
+ return true;
+}
+
+/*
+ try to change the password of our machine account using a buffer of all zeros,
+ and a session key that encrypts that to all zeros.
+
+Note: The test does use sign and seal, it's purpose is to exercise
+ the detection code in dcesrv_netr_ServerPasswordSet2
+*/
+static bool test_SetPassword2_encrypted_to_all_zeros(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet2 r;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (!test_ServerAuthenticate2_encrypts_to_zero(
+ tctx,
+ p1,
+ machine_credentials,
+ '\0',
+ &creds)) {
+
+ return false;
+ }
+
+ if (!test_SetupCredentialsPipe(
+ p1,
+ tctx,
+ machine_credentials,
+ creds,
+ DCERPC_SIGN | DCERPC_SEAL,
+ &p))
+ {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(
+ tctx,
+ "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ ZERO_STRUCT(password_buf);
+
+ if (!(creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)) {
+ torture_fail(tctx, "NETLOGON_NEG_SUPPORTS_AES not set");
+ }
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+ if(!all_zero(password_buf.data, 516)) {
+ torture_fail(tctx, "Password did not encrypt to all zeros\n");
+ }
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+ torture_assert_int_equal(
+ tctx,
+ new_password.length,
+ 0,
+ "Length should have encrypted to 0");
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 zero length check failed");
+ torture_assert_ntstatus_equal(
+ tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "");
+
+ return true;
+}
+
+/*
+ * Choose a session key that encrypts a password of all zeros to all zeros.
+ * Then try to set the password, using a zeroed buffer, with a non zero
+ * length.
+ *
+ * This exercises the password self encryption check.
+ *
+ * Note: The test does use sign and seal, it's purpose is to exercise
+ * the detection code in dcesrv_netr_ServerPasswordSet2
+*/
+static bool test_SetPassword2_password_encrypts_to_zero(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet2 r;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (!test_ServerAuthenticate2_encrypts_to_zero(
+ tctx,
+ p1,
+ machine_credentials,
+ 0x00,
+ &creds)) {
+
+ return false;
+ }
+
+ if (!test_SetupCredentialsPipe(
+ p1,
+ tctx,
+ machine_credentials,
+ creds,
+ DCERPC_SIGN | DCERPC_SEAL,
+ &p))
+ {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(
+ tctx,
+ "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ ZERO_STRUCT(password_buf);
+ SIVAL(password_buf.data, 512, 512);
+
+ if (!(creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)) {
+ torture_fail(tctx, "NETLOGON_NEG_SUPPORTS_AES not set");
+ }
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 password encrypts to zero check failed");
+ torture_assert_ntstatus_equal(
+ tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "");
+
+ return true;
+}
+
+/*
+ * Check that an all zero confounder, that encrypts to all zeros is
+ * rejected.
+ *
+ * Note: The test does use sign and seal, it's purpose is to exercise
+ * the detection code in dcesrv_netr_ServerPasswordSet2
+ */
+static bool test_SetPassword2_confounder(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet2 r;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (!test_ServerAuthenticate2_encrypts_to_zero(
+ tctx,
+ p1,
+ machine_credentials,
+ '\0',
+ &creds)) {
+
+ return false;
+ }
+
+ if (!test_SetupCredentialsPipe(
+ p1,
+ tctx,
+ machine_credentials,
+ creds,
+ DCERPC_SIGN | DCERPC_SEAL,
+ &p))
+ {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(
+ tctx,
+ "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ ZERO_STRUCT(password_buf);
+ password_buf.data[511] = 'A';
+ SIVAL(password_buf.data, 512, 2);
+
+ if (!(creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)) {
+ torture_fail(tctx, "NETLOGON_NEG_SUPPORTS_AES not set");
+ }
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 confounder check failed");
+ torture_assert_ntstatus_equal(
+ tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "");
+
+ return true;
+}
+
+/*
+ * try a change password for our machine account, using an all zero
+ * request. This should fail on the zero length check.
+ *
+ * Note: This test uses ARC4 encryption to exercise the desired check.
+ */
+static bool test_SetPassword2_all_zeros(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet2 r;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ uint32_t flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; /* no AES desired here */
+
+ if (!test_SetupCredentials2(
+ p1,
+ tctx,
+ flags,
+ machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds))
+ {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(
+ p1,
+ tctx,
+ machine_credentials,
+ creds,
+ DCERPC_SIGN | DCERPC_SEAL,
+ &p))
+ {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(
+ tctx,
+ "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ ZERO_STRUCT(password_buf.data);
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ torture_fail(tctx, "NETLOGON_NEG_SUPPORTS_AES enabled\n");
+ }
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(
+ tctx,
+ "Testing ServerPasswordSet2 on machine account\n");
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 zero length check failed");
+ torture_assert_ntstatus_equal(
+ tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "");
+
+ return true;
+}
+
+/*
+ try a change password for our machine account, using a maximum length
+ password
+*/
+static bool test_SetPassword2_maximum_length_password(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet2 r;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ uint32_t flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ DATA_BLOB new_random_pass = data_blob_null;
+
+ if (!test_SetupCredentials2(
+ p1,
+ tctx,
+ flags,
+ machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds))
+ {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(
+ p1,
+ tctx,
+ machine_credentials,
+ creds,
+ DCERPC_SIGN | DCERPC_SEAL,
+ &p))
+ {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(
+ tctx,
+ "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ new_random_pass = netlogon_very_rand_pass(tctx, 256);
+ set_pw_in_buffer(password_buf.data, &new_random_pass);
+ SIVAL(password_buf.data, 512, 512);
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+ }
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(
+ tctx,
+ "Testing ServerPasswordSet2 on machine account\n");
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 zero length check failed");
+ torture_assert_ntstatus_equal(
+ tctx, r.out.result, NT_STATUS_OK, "");
+
+ return true;
+}
+
+/*
+ try a change password for our machine account, using a password of
+ all zeros, and a non zero password length.
+
+ This test relies on the buffer being encrypted with ARC4, to
+ trigger the appropriate check in the rpc server code
+*/
+static bool test_SetPassword2_all_zero_password(
+ struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordSet2 r;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_CryptPassword password_buf;
+ struct netr_Authenticator credential, return_authenticator;
+ struct netr_CryptPassword new_password;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ uint32_t flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; /* no AES desired here */
+
+ if (!test_SetupCredentials2(
+ p1,
+ tctx,
+ flags,
+ machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds))
+ {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(
+ p1,
+ tctx,
+ machine_credentials,
+ creds,
+ DCERPC_SIGN | DCERPC_SEAL,
+ &p))
+ {
+ return false;
+ }
+ b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(
+ tctx,
+ "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ ZERO_STRUCT(password_buf.data);
+ SIVAL(password_buf.data, 512, 128);
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ torture_fail(tctx, "NETLOGON_NEG_SUPPORTS_AES set");
+ }
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+
+ memcpy(new_password.data, password_buf.data, 512);
+ new_password.length = IVAL(password_buf.data, 512);
+
+ torture_comment(
+ tctx,
+ "Testing ServerPasswordSet2 on machine account\n");
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(
+ tctx,
+ dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
+ "ServerPasswordSet2 all zero password check failed");
+ torture_assert_ntstatus_equal(
+ tctx, r.out.result, NT_STATUS_WRONG_PASSWORD, "");
+
+ return true;
+}
+
+
+static bool test_SetPassword2(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ return test_SetPassword2_with_flags(tctx, p, machine_credentials, NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_SetPassword2_AES(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ return test_SetPassword2_with_flags(tctx, p, machine_credentials, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+
+static bool test_GetPassword(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerPasswordGet r;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator credential;
+ NTSTATUS status;
+ struct netr_Authenticator return_authenticator;
+ struct samr_Password password;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.password = &password;
+
+ status = dcerpc_netr_ServerPasswordGet_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "ServerPasswordGet");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordGet");
+
+ return true;
+}
+
+static bool test_GetTrustPasswords(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_ServerTrustPasswordsGet r;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ struct samr_Password password, password2;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.new_owf_password = &password;
+ r.out.old_owf_password = &password2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerTrustPasswordsGet_r(b, tctx, &r),
+ "ServerTrustPasswordsGet failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerTrustPasswordsGet failed");
+
+ return true;
+}
+
+/*
+ try a netlogon SamLogon
+*/
+static bool test_netlogon_ops_args(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct netlogon_creds_CredentialState *creds,
+ bool null_domain)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogon r;
+ struct netr_Authenticator auth, auth2;
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative;
+ struct netr_NetworkInfo ninfo;
+ DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ int flags = CLI_CRED_NTLM_AUTH;
+ if (lpcfg_client_lanman_auth(tctx->lp_ctx)) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+
+ if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx) && !null_domain) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+ }
+
+ cli_credentials_get_ntlm_username_domain(samba_cmdline_get_creds(),
+ tctx,
+ &ninfo.identity_info.account_name.string,
+ &ninfo.identity_info.domain_name.string);
+
+ if (null_domain) {
+ ninfo.identity_info.domain_name.string = NULL;
+ }
+
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ chal = data_blob_const(ninfo.challenge,
+ sizeof(ninfo.challenge));
+
+ names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials),
+ cli_credentials_get_domain(credentials));
+
+ status = cli_credentials_get_ntlm_response(
+ samba_cmdline_get_creds(), tctx,
+ &flags,
+ chal,
+ NULL, /* server_timestamp */
+ names_blob,
+ &lm_resp, &nt_resp,
+ NULL, NULL);
+ torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
+
+ ninfo.lm.data = lm_resp.data;
+ ninfo.lm.length = lm_resp.length;
+
+ ninfo.nt.data = nt_resp.data;
+ ninfo.nt.length = nt_resp.length;
+
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
+
+ logon.network = &ninfo;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.logon = &logon;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+
+ d_printf("Testing LogonSamLogon with name %s\n", ninfo.identity_info.account_name.string);
+
+ for (i=2;i<=3;i++) {
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+
+ r.in.validation_level = i;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+ torture_assert_int_equal(tctx, *r.out.authoritative, 1,
+ "LogonSamLogon invalid *r.out.authoritative");
+ }
+
+ /* this makes sure we get the unmarshalling right for invalid levels */
+ for (i=52;i<53;i++) {
+ ZERO_STRUCT(auth2);
+ /* the authenticator should be ignored by the server */
+ generate_random_buffer((uint8_t *) &auth, sizeof(auth));
+
+ r.in.validation_level = i;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result,
+ NT_STATUS_INVALID_INFO_CLASS,
+ "LogonSamLogon failed");
+
+ torture_assert_int_equal(tctx, *r.out.authoritative, 1,
+ "LogonSamLogon invalid *r.out.authoritative");
+ torture_assert(tctx,
+ all_zero((uint8_t *)&auth2, sizeof(auth2)),
+ "Return authenticator non zero");
+ }
+
+ for (i=2;i<=3;i++) {
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+
+ r.in.validation_level = i;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+ torture_assert_int_equal(tctx, *r.out.authoritative, 1,
+ "LogonSamLogon invalid *r.out.authoritative");
+ }
+
+ r.in.logon_level = 52;
+
+ for (i=2;i<=3;i++) {
+ ZERO_STRUCT(auth2);
+ /* the authenticator should be ignored by the server */
+ generate_random_buffer((uint8_t *) &auth, sizeof(auth));
+
+ r.in.validation_level = i;
+
+ torture_comment(tctx, "Testing SamLogon with validation level %d and a NULL credential\n", i);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER,
+ "LogonSamLogon expected INVALID_PARAMETER");
+
+ torture_assert(tctx,
+ all_zero((uint8_t *)&auth2, sizeof(auth2)),
+ "Return authenticator non zero");
+ torture_assert_int_equal(tctx, *r.out.authoritative, 1,
+ "LogonSamLogon invalid *r.out.authoritative");
+ }
+
+ r.in.credential = NULL;
+
+ for (i=2;i<=3;i++) {
+ ZERO_STRUCT(auth2);
+
+ r.in.validation_level = i;
+
+ torture_comment(tctx, "Testing SamLogon with validation level %d and a NULL credential\n", i);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER,
+ "LogonSamLogon expected INVALID_PARAMETER");
+
+ torture_assert(tctx,
+ all_zero((uint8_t *)&auth2, sizeof(auth2)),
+ "Return authenticator non zero");
+ torture_assert_int_equal(tctx, *r.out.authoritative, 1,
+ "LogonSamLogon invalid *r.out.authoritative");
+ }
+
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.credential = &auth;
+
+ for (i=2;i<=3;i++) {
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+
+ r.in.validation_level = i;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+ torture_assert_int_equal(tctx, *r.out.authoritative, 1,
+ "LogonSamLogon invalid *r.out.authoritative");
+ }
+
+ return true;
+}
+
+bool test_netlogon_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct netlogon_creds_CredentialState *creds)
+{
+ return test_netlogon_ops_args(p, tctx, credentials, creds, false);
+}
+
+/*
+ try a netlogon GetCapabilities
+*/
+bool test_netlogon_capabilities(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+ struct netr_LogonGetCapabilities r;
+ union netr_Capabilities capabilities;
+ struct netr_Authenticator auth, return_auth;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &return_auth;
+ r.in.query_level = 1;
+ r.out.capabilities = &capabilities;
+ r.out.return_authenticator = &return_auth;
+
+ torture_comment(tctx, "Testing LogonGetCapabilities with query_level=0\n");
+
+ r.in.query_level = 0;
+ ZERO_STRUCT(return_auth);
+
+ /*
+ * we need to operate on a temporary copy of creds
+ * because dcerpc_netr_LogonGetCapabilities with
+ * an unknown query level returns DCERPC_NCA_S_FAULT_INVALID_TAG
+ * => NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
+ * without looking at the authenticator.
+ */
+ tmp_creds = *creds;
+ netlogon_creds_client_authenticator(&tmp_creds, &auth);
+
+ status = dcerpc_netr_LogonGetCapabilities_r(b, tctx, &r);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE,
+ "LogonGetCapabilities query_level=0 failed");
+
+ torture_comment(tctx, "Testing LogonGetCapabilities with query_level=3\n");
+
+ r.in.query_level = 3;
+ ZERO_STRUCT(return_auth);
+
+ /*
+ * we need to operate on a temporary copy of creds
+ * because dcerpc_netr_LogonGetCapabilities with
+ * an unknown query level returns DCERPC_NCA_S_FAULT_INVALID_TAG
+ * => NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
+ * without looking at the authenticator.
+ */
+ tmp_creds = *creds;
+ netlogon_creds_client_authenticator(&tmp_creds, &auth);
+
+ status = dcerpc_netr_LogonGetCapabilities_r(b, tctx, &r);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE,
+ "LogonGetCapabilities query_level=0 failed");
+
+ torture_comment(tctx, "Testing LogonGetCapabilities with query_level=1\n");
+
+ r.in.query_level = 1;
+ ZERO_STRUCT(return_auth);
+
+ /*
+ * we need to operate on a temporary copy of creds
+ * because dcerpc_netr_LogonGetCapabilities was
+ * dcerpc_netr_DummyFunction and returns NT_STATUS_NOT_IMPLEMENTED
+ * without looking at the authenticator.
+ */
+ tmp_creds = *creds;
+ netlogon_creds_client_authenticator(&tmp_creds, &auth);
+
+ status = dcerpc_netr_LogonGetCapabilities_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonGetCapabilities failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
+ return true;
+ }
+
+ *creds = tmp_creds;
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ torture_assert_int_equal(tctx, creds->negotiate_flags,
+ capabilities.server_capabilities,
+ "negotiate flags");
+
+ torture_comment(tctx, "Testing LogonGetCapabilities with query_level=2\n");
+
+ r.in.query_level = 2;
+ ZERO_STRUCT(return_auth);
+
+ /*
+ * we need to operate on a temporary copy of creds
+ * because dcerpc_netr_LogonGetCapabilities with
+ * an query level 2 may returns DCERPC_NCA_S_FAULT_INVALID_TAG
+ * => NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
+ * without looking at the authenticator.
+ */
+ tmp_creds = *creds;
+ netlogon_creds_client_authenticator(&tmp_creds, &auth);
+
+ status = dcerpc_netr_LogonGetCapabilities_r(b, tctx, &r);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
+ /*
+ * an server without KB5028166 returns
+ * DCERPC_NCA_S_FAULT_INVALID_TAG =>
+ * NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
+ */
+ return true;
+ }
+ torture_assert_ntstatus_ok(tctx, status, "LogonGetCapabilities query_level=2 failed");
+
+ *creds = tmp_creds;
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ torture_assert_int_equal(tctx, creds->negotiate_flags,
+ capabilities.server_capabilities,
+ "negotiate flags");
+
+ return true;
+}
+
+/*
+ try a netlogon SamLogon
+*/
+static bool test_SamLogon(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netlogon_creds_CredentialState *creds;
+
+ if (!test_SetupCredentials(p, tctx, credentials, &creds)) {
+ return false;
+ }
+
+ return test_netlogon_ops(p, tctx, credentials, creds);
+}
+
+static bool test_invalidAuthenticate2(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netlogon_creds_CredentialState *creds;
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+
+ torture_comment(tctx, "Testing invalidAuthenticate2\n");
+
+ if (!test_SetupCredentials2(p, tctx, flags,
+ credentials,
+ cli_credentials_get_secure_channel_type(credentials),
+ &creds)) {
+ return false;
+ }
+
+ if (!test_SetupCredentials2ex(p, tctx, flags,
+ credentials,
+ "1234567890123456",
+ cli_credentials_get_secure_channel_type(credentials),
+ STATUS_BUFFER_OVERFLOW,
+ &creds)) {
+ return false;
+ }
+
+ if (!test_SetupCredentials2ex(p, tctx, flags,
+ credentials,
+ "123456789012345",
+ cli_credentials_get_secure_channel_type(credentials),
+ NT_STATUS_OK,
+ &creds)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_ServerReqChallengeGlobal(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b1 = p1->binding_handle;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b2 = NULL;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b2 = p2->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 on b2\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+ "ServerAuthenticate3 failed on b2");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b2");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ return true;
+}
+
+/*
+ * Test the re-use of the challenge is not possible on a third
+ * connection, after first using it second one.
+ */
+
+static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b1 = p1->binding_handle;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b2 = NULL;
+ struct dcerpc_pipe *p3 = NULL;
+ struct dcerpc_binding_handle *b3 = NULL;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b2 = p2->binding_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p3, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b3 = p3->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 on b2\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+ "ServerAuthenticate3 failed on b2");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b2");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ /* We have to re-run this part */
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b3, tctx, &a),
+ "ServerAuthenticate3 failed on b3");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate3 should have failed on b3, due to credential reuse");
+ return true;
+}
+
+/*
+ * Test if use of the per-pipe challenge will wipe out the globally cached challenge
+ */
+static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b1 = p1->binding_handle;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b2 = NULL;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b2 = p2->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 on b2\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b1, tctx, &a),
+ "ServerAuthenticate3 failed on b");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ /* We have to re-run this part */
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+ "ServerAuthenticate3 failed on b2");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate3 should have failed on b2, due to credential reuse");
+ return true;
+}
+
+/*
+ * Test if use of the globally cached challenge will wipe out the
+ * per-pipe challenge
+ */
+static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b1 = p1->binding_handle;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b2 = NULL;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b2 = p2->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 on b2\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+ "ServerAuthenticate3 failed on b2");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ /* We have to re-run this part */
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b1, tctx, &a),
+ "ServerAuthenticate3 failed on b1");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate3 should have failed on b1, due to credential reuse");
+ return true;
+}
+
+/*
+ * Test if more than one globally cached challenge works
+ */
+static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials1_random,
+ credentials2, credentials3, credentials_discard;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b1 = p1->binding_handle;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b2 = NULL;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p2, p1->binding,
+ &ndr_table_netlogon,
+ machine_credentials,
+ tctx->ev, tctx->lp_ctx),
+ "dcerpc_pipe_connect_b failed");
+ b2 = p2->binding_handle;
+
+ r.in.server_name = NULL;
+ r.in.computer_name = "CHALTEST1";
+ r.in.credentials = &credentials1_random;
+ r.out.return_credentials = &credentials_discard;
+
+ netlogon_creds_random_challenge(&credentials1_random);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ /* Now ask for the actual client name */
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = "CHALTEST2";
+ r.in.credentials = &credentials1_random;
+ r.out.return_credentials = &credentials_discard;
+
+ netlogon_creds_random_challenge(&credentials1_random);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
+ "ServerReqChallenge failed on b1");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 on b2 (must use global credentials)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b2, tctx, &a),
+ "ServerAuthenticate3 failed on b2");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed on b2");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ /* We have to re-run this part */
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b1, tctx, &a),
+ "ServerAuthenticate3 failed on b1");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate3 should have failed on b1, due to credential reuse");
+ return true;
+}
+
+static bool test_ServerReqChallengeReuse(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags = NETLOGON_NEG_AUTH2_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential credentials1, credentials2, credentials3;
+ struct netlogon_creds_CredentialState *creds;
+ struct samr_Password mach_password;
+ uint32_t rid;
+ const char *machine_name;
+ const char *plain_pass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert(tctx, machine_name != NULL, "machine_name");
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert(tctx, plain_pass != NULL, "plain_pass");
+
+ torture_comment(tctx, "Testing ServerReqChallenge on b1\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &credentials1;
+ r.out.return_credentials = &credentials2;
+
+ netlogon_creds_random_challenge(&credentials1);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed on b1");
+
+ E_md4hash(plain_pass, mach_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &flags;
+ a.in.credentials = &credentials3;
+ a.out.return_credentials = &credentials3;
+ a.out.negotiate_flags = &flags;
+ a.out.rid = &rid;
+
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "ServerAuthenticate3 failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &credentials3), "Credential chaining failed");
+
+ /* We have to re-run this part */
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate3 should have failed on b3, due to credential reuse");
+
+ ZERO_STRUCT(credentials1.data);
+ ZERO_STRUCT(credentials2.data);
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &credentials1, &credentials2,
+ &mach_password, &credentials3,
+ flags);
+
+ torture_assert(tctx, creds != NULL, "memory allocation");
+
+ torture_comment(tctx, "Testing ServerAuthenticate3 with zero'ed challenge\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a),
+ "ServerAuthenticate3 failed");
+ torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_ACCESS_DENIED,
+ "ServerAuthenticate3 should have failed on b3, due to credential reuse");
+ return true;
+}
+
+static bool test_SamLogon_NULL_domain(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ struct netlogon_creds_CredentialState *creds;
+
+ if (!test_SetupCredentials(p, tctx, credentials, &creds)) {
+ return false;
+ }
+
+ return test_netlogon_ops_args(p, tctx, credentials, creds, true);
+}
+
+/* we remember the sequence numbers so we can easily do a DatabaseDelta */
+static uint64_t sequence_nums[3];
+
+/*
+ try a netlogon DatabaseSync
+*/
+static bool test_DatabaseSync(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_DatabaseSync r;
+ struct netlogon_creds_CredentialState *creds;
+ const uint32_t database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS};
+ int i;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ struct netr_Authenticator credential, return_authenticator;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.preferredmaximumlength = (uint32_t)-1;
+ r.in.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+ r.out.return_authenticator = &return_authenticator;
+
+ for (i=0;i<ARRAY_SIZE(database_ids);i++) {
+
+ uint32_t sync_context = 0;
+
+ r.in.database_id = database_ids[i];
+ r.in.sync_context = &sync_context;
+ r.out.sync_context = &sync_context;
+
+ torture_comment(tctx, "Testing DatabaseSync of id %d\n", r.in.database_id);
+
+ do {
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ r.in.credential = &credential;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_DatabaseSync_r(b, tctx, &r),
+ "DatabaseSync failed");
+ if (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES))
+ break;
+
+ /* Native mode servers don't do this */
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_SUPPORTED)) {
+ return true;
+ }
+ torture_assert_ntstatus_ok(tctx, r.out.result, "DatabaseSync");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ if (delta_enum_array &&
+ delta_enum_array->num_deltas > 0 &&
+ delta_enum_array->delta_enum[0].delta_type == NETR_DELTA_DOMAIN &&
+ delta_enum_array->delta_enum[0].delta_union.domain) {
+ sequence_nums[r.in.database_id] =
+ delta_enum_array->delta_enum[0].delta_union.domain->sequence_num;
+ torture_comment(tctx, "\tsequence_nums[%d]=%llu\n",
+ r.in.database_id,
+ (unsigned long long)sequence_nums[r.in.database_id]);
+ }
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return true;
+}
+
+
+/*
+ try a netlogon DatabaseDeltas
+*/
+static bool test_DatabaseDeltas(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_DatabaseDeltas r;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ const uint32_t database_ids[] = {0, 1, 2};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.preferredmaximumlength = (uint32_t)-1;
+ ZERO_STRUCT(r.in.return_authenticator);
+ r.out.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+
+ for (i=0;i<ARRAY_SIZE(database_ids);i++) {
+ r.in.database_id = database_ids[i];
+ r.in.sequence_num = &sequence_nums[r.in.database_id];
+
+ if (*r.in.sequence_num == 0) continue;
+
+ *r.in.sequence_num -= 1;
+
+ torture_comment(tctx, "Testing DatabaseDeltas of id %d at %llu\n",
+ r.in.database_id, (unsigned long long)*r.in.sequence_num);
+
+ do {
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_DatabaseDeltas_r(b, tctx, &r),
+ "DatabaseDeltas failed");
+ if (NT_STATUS_EQUAL(r.out.result,
+ NT_STATUS_SYNCHRONIZATION_REQUIRED)) {
+ torture_comment(tctx, "not considering %s to be an error\n",
+ nt_errstr(r.out.result));
+ return true;
+ }
+ if (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES))
+ break;
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "DatabaseDeltas");
+
+ if (!netlogon_creds_client_check(creds, &return_authenticator.cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ (*r.in.sequence_num)++;
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return true;
+}
+
+static bool test_DatabaseRedo(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_DatabaseRedo r;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ struct netr_ChangeLogEntry e;
+ struct dom_sid null_sid, *sid;
+ int i,d;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(null_sid);
+
+ sid = dom_sid_parse_talloc(tctx, "S-1-5-21-1111111111-2222222222-333333333-500");
+
+ {
+
+ struct {
+ uint32_t rid;
+ uint16_t flags;
+ uint8_t db_index;
+ uint8_t delta_type;
+ struct dom_sid sid;
+ const char *name;
+ NTSTATUS expected_error;
+ uint32_t expected_num_results;
+ uint8_t expected_delta_type_1;
+ uint8_t expected_delta_type_2;
+ const char *comment;
+ } changes[] = {
+
+ /* SAM_DATABASE_DOMAIN */
+
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_MODIFY_COUNT,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_SYNCHRONIZATION_REQUIRED,
+ .expected_num_results = 0,
+ .comment = "NETR_DELTA_MODIFY_COUNT"
+ },
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = 0,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DOMAIN,
+ .comment = "NULL DELTA"
+ },
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_DOMAIN,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DOMAIN,
+ .comment = "NETR_DELTA_DOMAIN"
+ },
+ {
+ .rid = DOMAIN_RID_ADMINISTRATOR,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_USER,
+ .comment = "NETR_DELTA_USER by rid 500"
+ },
+ {
+ .rid = DOMAIN_RID_GUEST,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_USER,
+ .comment = "NETR_DELTA_USER by rid 501"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = *sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_USER,
+ .comment = "NETR_DELTA_USER by sid and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_USER,
+ .comment = "NETR_DELTA_USER by null_sid and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_NAME_INCLUDED,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = null_sid,
+ .name = "administrator",
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_USER,
+ .comment = "NETR_DELTA_USER by name 'administrator'"
+ },
+ {
+ .rid = DOMAIN_RID_ADMINS,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_GROUP,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 2,
+ .expected_delta_type_1 = NETR_DELTA_GROUP,
+ .expected_delta_type_2 = NETR_DELTA_GROUP_MEMBER,
+ .comment = "NETR_DELTA_GROUP by rid 512"
+ },
+ {
+ .rid = DOMAIN_RID_ADMINS,
+ .flags = 0,
+ .db_index = SAM_DATABASE_DOMAIN,
+ .delta_type = NETR_DELTA_GROUP_MEMBER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 2,
+ .expected_delta_type_1 = NETR_DELTA_GROUP,
+ .expected_delta_type_2 = NETR_DELTA_GROUP_MEMBER,
+ .comment = "NETR_DELTA_GROUP_MEMBER by rid 512"
+ },
+
+
+ /* SAM_DATABASE_BUILTIN */
+
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_MODIFY_COUNT,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_SYNCHRONIZATION_REQUIRED,
+ .expected_num_results = 0,
+ .comment = "NETR_DELTA_MODIFY_COUNT"
+ },
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_DOMAIN,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DOMAIN,
+ .comment = "NETR_DELTA_DOMAIN"
+ },
+ {
+ .rid = DOMAIN_RID_ADMINISTRATOR,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_USER,
+ .comment = "NETR_DELTA_USER by rid 500"
+ },
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_USER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_USER,
+ .comment = "NETR_DELTA_USER"
+ },
+ {
+ .rid = 544,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_ALIAS,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 2,
+ .expected_delta_type_1 = NETR_DELTA_ALIAS,
+ .expected_delta_type_2 = NETR_DELTA_ALIAS_MEMBER,
+ .comment = "NETR_DELTA_ALIAS by rid 544"
+ },
+ {
+ .rid = 544,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_ALIAS_MEMBER,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 2,
+ .expected_delta_type_1 = NETR_DELTA_ALIAS,
+ .expected_delta_type_2 = NETR_DELTA_ALIAS_MEMBER,
+ .comment = "NETR_DELTA_ALIAS_MEMBER by rid 544"
+ },
+ {
+ .rid = 544,
+ .flags = 0,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = 0,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DOMAIN,
+ .comment = "NULL DELTA by rid 544"
+ },
+ {
+ .rid = 544,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = 0,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-5-32-544"),
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DOMAIN,
+ .comment = "NULL DELTA by rid 544 sid S-1-5-32-544 and flags"
+ },
+ {
+ .rid = 544,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_ALIAS,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-5-32-544"),
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 2,
+ .expected_delta_type_1 = NETR_DELTA_ALIAS,
+ .expected_delta_type_2 = NETR_DELTA_ALIAS_MEMBER,
+ .comment = "NETR_DELTA_ALIAS by rid 544 and sid S-1-5-32-544 and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_BUILTIN,
+ .delta_type = NETR_DELTA_ALIAS,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-5-32-544"),
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_ALIAS,
+ .comment = "NETR_DELTA_ALIAS by sid S-1-5-32-544 and flags"
+ },
+
+ /* SAM_DATABASE_PRIVS */
+
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = 0,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_ACCESS_DENIED,
+ .expected_num_results = 0,
+ .comment = "NULL DELTA"
+ },
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_MODIFY_COUNT,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_SYNCHRONIZATION_REQUIRED,
+ .expected_num_results = 0,
+ .comment = "NETR_DELTA_MODIFY_COUNT"
+ },
+ {
+ .rid = 0,
+ .flags = 0,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_POLICY,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_POLICY,
+ .comment = "NETR_DELTA_POLICY"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_POLICY,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_POLICY,
+ .comment = "NETR_DELTA_POLICY by null sid and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_POLICY,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-5-32"),
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_POLICY,
+ .comment = "NETR_DELTA_POLICY by sid S-1-5-32 and flags"
+ },
+ {
+ .rid = DOMAIN_RID_ADMINISTRATOR,
+ .flags = 0,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_ACCOUNT,
+ .sid = null_sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_SYNCHRONIZATION_REQUIRED, /* strange */
+ .expected_num_results = 0,
+ .comment = "NETR_DELTA_ACCOUNT by rid 500"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_ACCOUNT,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-1-0"),
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_ACCOUNT,
+ .comment = "NETR_DELTA_ACCOUNT by sid S-1-1-0 and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED |
+ NETR_CHANGELOG_IMMEDIATE_REPL_REQUIRED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_ACCOUNT,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-1-0"),
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_ACCOUNT,
+ .comment = "NETR_DELTA_ACCOUNT by sid S-1-1-0 and 2 flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_SID_INCLUDED |
+ NETR_CHANGELOG_NAME_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_ACCOUNT,
+ .sid = *dom_sid_parse_talloc(tctx, "S-1-1-0"),
+ .name = NULL,
+ .expected_error = NT_STATUS_INVALID_PARAMETER,
+ .expected_num_results = 0,
+ .comment = "NETR_DELTA_ACCOUNT by sid S-1-1-0 and invalid flags"
+ },
+ {
+ .rid = DOMAIN_RID_ADMINISTRATOR,
+ .flags = NETR_CHANGELOG_SID_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_ACCOUNT,
+ .sid = *sid,
+ .name = NULL,
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_ACCOUNT,
+ .comment = "NETR_DELTA_ACCOUNT by rid 500, sid and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_NAME_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_SECRET,
+ .sid = null_sid,
+ .name = "IsurelydontexistIhope",
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_DELETE_SECRET,
+ .comment = "NETR_DELTA_SECRET by name 'IsurelydontexistIhope' and flags"
+ },
+ {
+ .rid = 0,
+ .flags = NETR_CHANGELOG_NAME_INCLUDED,
+ .db_index = SAM_DATABASE_PRIVS,
+ .delta_type = NETR_DELTA_SECRET,
+ .sid = null_sid,
+ .name = "G$BCKUPKEY_P",
+ .expected_error = NT_STATUS_OK,
+ .expected_num_results = 1,
+ .expected_delta_type_1 = NETR_DELTA_SECRET,
+ .comment = "NETR_DELTA_SECRET by name 'G$BCKUPKEY_P' and flags"
+ }
+ };
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.return_authenticator = &return_authenticator;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+
+ for (d=0; d<3; d++) {
+ const char *database = NULL;
+
+ switch (d) {
+ case 0:
+ database = "SAM";
+ break;
+ case 1:
+ database = "BUILTIN";
+ break;
+ case 2:
+ database = "LSA";
+ break;
+ default:
+ break;
+ }
+
+ torture_comment(tctx, "Testing DatabaseRedo\n");
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ for (i=0;i<ARRAY_SIZE(changes);i++) {
+
+ if (d != changes[i].db_index) {
+ continue;
+ }
+
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ r.in.credential = &credential;
+
+ e.serial_number1 = 0;
+ e.serial_number2 = 0;
+ e.object_rid = changes[i].rid;
+ e.flags = changes[i].flags;
+ e.db_index = changes[i].db_index;
+ e.delta_type = changes[i].delta_type;
+
+ switch (changes[i].flags & (NETR_CHANGELOG_NAME_INCLUDED | NETR_CHANGELOG_SID_INCLUDED)) {
+ case NETR_CHANGELOG_SID_INCLUDED:
+ e.object.object_sid = changes[i].sid;
+ break;
+ case NETR_CHANGELOG_NAME_INCLUDED:
+ e.object.object_name = changes[i].name;
+ break;
+ default:
+ break;
+ }
+
+ r.in.change_log_entry = e;
+
+ torture_comment(tctx, "Testing DatabaseRedo with database %s and %s\n",
+ database, changes[i].comment);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_DatabaseRedo_r(b, tctx, &r),
+ "DatabaseRedo failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_SUPPORTED)) {
+ return true;
+ }
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, changes[i].expected_error, changes[i].comment);
+ if (delta_enum_array) {
+ torture_assert_int_equal(tctx,
+ delta_enum_array->num_deltas,
+ changes[i].expected_num_results,
+ changes[i].comment);
+ if (delta_enum_array->num_deltas > 0) {
+ torture_assert_int_equal(tctx,
+ delta_enum_array->delta_enum[0].delta_type,
+ changes[i].expected_delta_type_1,
+ changes[i].comment);
+ }
+ if (delta_enum_array->num_deltas > 1) {
+ torture_assert_int_equal(tctx,
+ delta_enum_array->delta_enum[1].delta_type,
+ changes[i].expected_delta_type_2,
+ changes[i].comment);
+ }
+ }
+
+ if (!netlogon_creds_client_check(creds, &return_authenticator.cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/*
+ try a netlogon AccountDeltas
+*/
+static bool test_AccountDeltas(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_AccountDeltas r;
+ struct netlogon_creds_CredentialState *creds;
+
+ struct netr_AccountBuffer buffer;
+ uint32_t count_returned = 0;
+ uint32_t total_entries = 0;
+ struct netr_UAS_INFO_0 recordid;
+ struct netr_Authenticator return_authenticator;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.return_authenticator = &return_authenticator;
+ netlogon_creds_client_authenticator(creds, &r.in.credential);
+ ZERO_STRUCT(r.in.uas);
+ r.in.count=10;
+ r.in.level=0;
+ r.in.buffersize=100;
+ r.out.buffer = &buffer;
+ r.out.count_returned = &count_returned;
+ r.out.total_entries = &total_entries;
+ r.out.recordid = &recordid;
+ r.out.return_authenticator = &return_authenticator;
+
+ /* w2k3 returns "NOT IMPLEMENTED" for this call */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_AccountDeltas_r(b, tctx, &r),
+ "AccountDeltas failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_IMPLEMENTED, "AccountDeltas");
+
+ return true;
+}
+
+/*
+ try a netlogon AccountSync
+*/
+static bool test_AccountSync(struct torture_context *tctx, struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_AccountSync r;
+ struct netlogon_creds_CredentialState *creds;
+
+ struct netr_AccountBuffer buffer;
+ uint32_t count_returned = 0;
+ uint32_t total_entries = 0;
+ uint32_t next_reference = 0;
+ struct netr_UAS_INFO_0 recordid;
+ struct netr_Authenticator return_authenticator;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(recordid);
+ ZERO_STRUCT(return_authenticator);
+
+ if (!test_SetupCredentials(p, tctx, machine_credentials, &creds)) {
+ return false;
+ }
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.return_authenticator = &return_authenticator;
+ netlogon_creds_client_authenticator(creds, &r.in.credential);
+ r.in.recordid = &recordid;
+ r.in.reference=0;
+ r.in.level=0;
+ r.in.buffersize=100;
+ r.out.buffer = &buffer;
+ r.out.count_returned = &count_returned;
+ r.out.total_entries = &total_entries;
+ r.out.next_reference = &next_reference;
+ r.out.recordid = &recordid;
+ r.out.return_authenticator = &return_authenticator;
+
+ /* w2k3 returns "NOT IMPLEMENTED" for this call */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_AccountSync_r(b, tctx, &r),
+ "AccountSync failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_IMPLEMENTED, "AccountSync");
+
+ return true;
+}
+
+/*
+ try a netlogon GetDcName
+*/
+static bool test_GetDcName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct netr_GetDcName r;
+ const char *dcname = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.domainname = lpcfg_workgroup(tctx->lp_ctx);
+ r.out.dcname = &dcname;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_GetDcName_r(b, tctx, &r),
+ "GetDcName failed");
+ torture_assert_werr_ok(tctx, r.out.result, "GetDcName failed");
+
+ torture_comment(tctx, "\tDC is at '%s'\n", dcname);
+
+ return true;
+}
+
+static const char *function_code_str(TALLOC_CTX *mem_ctx,
+ enum netr_LogonControlCode function_code)
+{
+ switch (function_code) {
+ case NETLOGON_CONTROL_QUERY:
+ return "NETLOGON_CONTROL_QUERY";
+ case NETLOGON_CONTROL_REPLICATE:
+ return "NETLOGON_CONTROL_REPLICATE";
+ case NETLOGON_CONTROL_SYNCHRONIZE:
+ return "NETLOGON_CONTROL_SYNCHRONIZE";
+ case NETLOGON_CONTROL_PDC_REPLICATE:
+ return "NETLOGON_CONTROL_PDC_REPLICATE";
+ case NETLOGON_CONTROL_REDISCOVER:
+ return "NETLOGON_CONTROL_REDISCOVER";
+ case NETLOGON_CONTROL_TC_QUERY:
+ return "NETLOGON_CONTROL_TC_QUERY";
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
+ return "NETLOGON_CONTROL_TRANSPORT_NOTIFY";
+ case NETLOGON_CONTROL_FIND_USER:
+ return "NETLOGON_CONTROL_FIND_USER";
+ case NETLOGON_CONTROL_CHANGE_PASSWORD:
+ return "NETLOGON_CONTROL_CHANGE_PASSWORD";
+ case NETLOGON_CONTROL_TC_VERIFY:
+ return "NETLOGON_CONTROL_TC_VERIFY";
+ case NETLOGON_CONTROL_FORCE_DNS_REG:
+ return "NETLOGON_CONTROL_FORCE_DNS_REG";
+ case NETLOGON_CONTROL_QUERY_DNS_REG:
+ return "NETLOGON_CONTROL_QUERY_DNS_REG";
+ case NETLOGON_CONTROL_BACKUP_CHANGE_LOG:
+ return "NETLOGON_CONTROL_BACKUP_CHANGE_LOG";
+ case NETLOGON_CONTROL_TRUNCATE_LOG:
+ return "NETLOGON_CONTROL_TRUNCATE_LOG";
+ case NETLOGON_CONTROL_SET_DBFLAG:
+ return "NETLOGON_CONTROL_SET_DBFLAG";
+ case NETLOGON_CONTROL_BREAKPOINT:
+ return "NETLOGON_CONTROL_BREAKPOINT";
+ default:
+ return talloc_asprintf(mem_ctx, "unknown function code: %d",
+ function_code);
+ }
+}
+
+
+/*
+ try a netlogon LogonControl
+*/
+static bool test_LogonControl(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+
+{
+ NTSTATUS status;
+ struct netr_LogonControl r;
+ union netr_CONTROL_QUERY_INFORMATION query;
+ int i,f;
+ enum netr_SchannelType secure_channel_type = SEC_CHAN_NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint32_t function_codes[] = {
+ NETLOGON_CONTROL_QUERY,
+ NETLOGON_CONTROL_REPLICATE,
+ NETLOGON_CONTROL_SYNCHRONIZE,
+ NETLOGON_CONTROL_PDC_REPLICATE,
+ NETLOGON_CONTROL_REDISCOVER,
+ NETLOGON_CONTROL_TC_QUERY,
+ NETLOGON_CONTROL_TRANSPORT_NOTIFY,
+ NETLOGON_CONTROL_FIND_USER,
+ NETLOGON_CONTROL_CHANGE_PASSWORD,
+ NETLOGON_CONTROL_TC_VERIFY,
+ NETLOGON_CONTROL_FORCE_DNS_REG,
+ NETLOGON_CONTROL_QUERY_DNS_REG,
+ NETLOGON_CONTROL_BACKUP_CHANGE_LOG,
+ NETLOGON_CONTROL_TRUNCATE_LOG,
+ NETLOGON_CONTROL_SET_DBFLAG,
+ NETLOGON_CONTROL_BREAKPOINT
+ };
+
+ if (machine_credentials) {
+ secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ }
+
+ torture_comment(tctx, "Testing LogonControl with secure channel type: %d\n",
+ secure_channel_type);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.function_code = 1;
+ r.out.query = &query;
+
+ for (f=0;f<ARRAY_SIZE(function_codes); f++) {
+ for (i=1;i<5;i++) {
+
+ r.in.function_code = function_codes[f];
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl");
+
+ switch (r.in.level) {
+ case 1:
+ switch (r.in.function_code) {
+ case NETLOGON_CONTROL_REPLICATE:
+ case NETLOGON_CONTROL_SYNCHRONIZE:
+ case NETLOGON_CONTROL_PDC_REPLICATE:
+ case NETLOGON_CONTROL_BREAKPOINT:
+ case NETLOGON_CONTROL_BACKUP_CHANGE_LOG:
+ if ((secure_channel_type == SEC_CHAN_BDC) ||
+ (secure_channel_type == SEC_CHAN_WKSTA)) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED,
+ "LogonControl returned unexpected error code");
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "LogonControl returned unexpected error code");
+ }
+ break;
+
+ case NETLOGON_CONTROL_REDISCOVER:
+ case NETLOGON_CONTROL_TC_QUERY:
+ case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
+ case NETLOGON_CONTROL_FIND_USER:
+ case NETLOGON_CONTROL_CHANGE_PASSWORD:
+ case NETLOGON_CONTROL_TC_VERIFY:
+ case NETLOGON_CONTROL_FORCE_DNS_REG:
+ case NETLOGON_CONTROL_QUERY_DNS_REG:
+ case NETLOGON_CONTROL_SET_DBFLAG:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "LogonControl returned unexpected error code");
+ break;
+ case NETLOGON_CONTROL_TRUNCATE_LOG:
+ if ((secure_channel_type == SEC_CHAN_BDC) ||
+ (secure_channel_type == SEC_CHAN_WKSTA)) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED,
+ "LogonControl returned unexpected error code");
+ } else if (!W_ERROR_EQUAL(r.out.result, WERR_NOT_SUPPORTED)) {
+ torture_assert_werr_ok(tctx, r.out.result,
+ "LogonControl returned unexpected result");
+ }
+ break;
+ default:
+ torture_assert_werr_ok(tctx, r.out.result,
+ "LogonControl returned unexpected result");
+ break;
+ }
+ break;
+ case 2:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "LogonControl returned unexpected error code");
+ break;
+ default:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL,
+ "LogonControl returned unexpected error code");
+ break;
+ }
+ }
+ }
+
+ r.in.level = 52;
+ torture_comment(tctx, "Testing LogonControl function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+ status = dcerpc_netr_LogonControl_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL, "LogonControl");
+
+ return true;
+}
+
+
+/*
+ try a netlogon GetAnyDCName
+*/
+static bool test_GetAnyDCName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_GetAnyDCName r;
+ const char *dcname = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.domainname = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.out.dcname = &dcname;
+
+ status = dcerpc_netr_GetAnyDCName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetAnyDCName");
+ if ((!W_ERROR_IS_OK(r.out.result)) &&
+ (!W_ERROR_EQUAL(r.out.result, WERR_NO_SUCH_DOMAIN))) {
+ return false;
+ }
+
+ if (dcname) {
+ torture_comment(tctx, "\tDC is at '%s'\n", dcname);
+ }
+
+ r.in.domainname = NULL;
+
+ status = dcerpc_netr_GetAnyDCName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetAnyDCName");
+ if ((!W_ERROR_IS_OK(r.out.result)) &&
+ (!W_ERROR_EQUAL(r.out.result, WERR_NO_SUCH_DOMAIN))) {
+ return false;
+ }
+
+ r.in.domainname = "";
+
+ status = dcerpc_netr_GetAnyDCName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetAnyDCName");
+ if ((!W_ERROR_IS_OK(r.out.result)) &&
+ (!W_ERROR_EQUAL(r.out.result, WERR_NO_SUCH_DOMAIN))) {
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+ try a netlogon LogonControl2
+*/
+static bool test_LogonControl2(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+
+{
+ NTSTATUS status;
+ struct netr_LogonControl2 r;
+ union netr_CONTROL_DATA_INFORMATION data;
+ union netr_CONTROL_QUERY_INFORMATION query;
+ enum netr_SchannelType secure_channel_type = SEC_CHAN_NULL;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ data.domain = lpcfg_workgroup(tctx->lp_ctx);
+
+ if (machine_credentials) {
+ secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ }
+
+ torture_comment(tctx, "Testing LogonControl2 with secure channel type: %d\n",
+ secure_channel_type);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ r.in.function_code = NETLOGON_CONTROL_REDISCOVER;
+ r.in.data = &data;
+ r.out.query = &query;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2 function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2");
+ }
+
+ data.domain = lpcfg_workgroup(tctx->lp_ctx);
+
+ r.in.function_code = NETLOGON_CONTROL_TC_QUERY;
+ r.in.data = &data;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2 function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2");
+ }
+
+ data.domain = lpcfg_workgroup(tctx->lp_ctx);
+
+ r.in.function_code = NETLOGON_CONTROL_TRANSPORT_NOTIFY;
+ r.in.data = &data;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2 function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2");
+ }
+
+ data.debug_level = ~0;
+
+ r.in.function_code = NETLOGON_CONTROL_SET_DBFLAG;
+ r.in.data = &data;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2 function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2");
+ }
+
+ ZERO_STRUCT(data);
+ r.in.function_code = 52;
+ r.in.data = &data;
+
+ torture_comment(tctx, "Testing LogonControl2 function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2");
+ switch (secure_channel_type) {
+ case SEC_CHAN_NULL:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED, "LogonControl2");
+ break;
+ default:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED, "LogonControl2");
+ break;
+ }
+ data.debug_level = ~0;
+
+ r.in.function_code = NETLOGON_CONTROL_SET_DBFLAG;
+ r.in.data = &data;
+
+ r.in.level = 52;
+ torture_comment(tctx, "Testing LogonControl2 function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL, "LogonControl2");
+
+ return true;
+}
+
+/*
+ try a netlogon DatabaseSync2
+*/
+static bool test_DatabaseSync2(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_DatabaseSync2 r;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ struct netr_Authenticator return_authenticator, credential;
+
+ struct netlogon_creds_CredentialState *creds;
+ const uint32_t database_ids[] = {0, 1, 2};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_FLAGS,
+ machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds)) {
+ return false;
+ }
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.preferredmaximumlength = (uint32_t)-1;
+ r.in.return_authenticator = &return_authenticator;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+
+ for (i=0;i<ARRAY_SIZE(database_ids);i++) {
+
+ uint32_t sync_context = 0;
+
+ r.in.database_id = database_ids[i];
+ r.in.sync_context = &sync_context;
+ r.out.sync_context = &sync_context;
+ r.in.restart_state = 0;
+
+ torture_comment(tctx, "Testing DatabaseSync2 of id %d\n", r.in.database_id);
+
+ do {
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ r.in.credential = &credential;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_DatabaseSync2_r(b, tctx, &r),
+ "DatabaseSync2 failed");
+ if (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES))
+ break;
+
+ /* Native mode servers don't do this */
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_SUPPORTED)) {
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "DatabaseSync2");
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return true;
+}
+
+
+/*
+ try a netlogon LogonControl2Ex
+*/
+static bool test_LogonControl2Ex(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+
+{
+ NTSTATUS status;
+ struct netr_LogonControl2Ex r;
+ union netr_CONTROL_DATA_INFORMATION data;
+ union netr_CONTROL_QUERY_INFORMATION query;
+ enum netr_SchannelType secure_channel_type = SEC_CHAN_NULL;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ data.domain = lpcfg_workgroup(tctx->lp_ctx);
+
+ if (machine_credentials) {
+ secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ }
+
+ torture_comment(tctx, "Testing LogonControl2Ex with secure channel type: %d\n",
+ secure_channel_type);
+
+ r.in.logon_server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ r.in.function_code = NETLOGON_CONTROL_REDISCOVER;
+ r.in.data = &data;
+ r.out.query = &query;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2Ex function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2Ex_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2Ex");
+ }
+
+ data.domain = lpcfg_workgroup(tctx->lp_ctx);
+
+ r.in.function_code = NETLOGON_CONTROL_TC_QUERY;
+ r.in.data = &data;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2Ex function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2Ex_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2Ex");
+ }
+
+ data.domain = lpcfg_workgroup(tctx->lp_ctx);
+
+ r.in.function_code = NETLOGON_CONTROL_TRANSPORT_NOTIFY;
+ r.in.data = &data;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2Ex function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2Ex_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2Ex");
+ }
+
+ data.debug_level = ~0;
+
+ r.in.function_code = NETLOGON_CONTROL_SET_DBFLAG;
+ r.in.data = &data;
+
+ for (i=1;i<4;i++) {
+ r.in.level = i;
+
+ torture_comment(tctx, "Testing LogonControl2Ex function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2Ex_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2Ex");
+ }
+
+ ZERO_STRUCT(data);
+ r.in.function_code = 52;
+ r.in.data = &data;
+
+ torture_comment(tctx, "Testing LogonControl2Ex function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2Ex_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2Ex");
+ switch (secure_channel_type) {
+ case SEC_CHAN_NULL:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED, "LogonControl2Ex");
+ break;
+ default:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED, "LogonControl2Ex");
+ break;
+ }
+ data.debug_level = ~0;
+
+ r.in.function_code = NETLOGON_CONTROL_SET_DBFLAG;
+ r.in.data = &data;
+
+ r.in.level = 52;
+ torture_comment(tctx, "Testing LogonControl2Ex function code %s (%d) level %d\n",
+ function_code_str(tctx, r.in.function_code), r.in.function_code, r.in.level);
+
+ status = dcerpc_netr_LogonControl2Ex_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonControl2Ex");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL, "LogonControl2Ex");
+
+ return true;
+}
+
+static bool test_netr_GetForestTrustInformation(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_GetForestTrustInformation r;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator a;
+ struct netr_Authenticator return_authenticator;
+ struct lsa_ForestTrustInformation *forest_trust_info;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ machine_credentials, &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ netlogon_creds_client_authenticator(creds, &a);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &a;
+ r.in.flags = 0;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.forest_trust_info = &forest_trust_info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_GetForestTrustInformation_r(b, tctx, &r),
+ "netr_GetForestTrustInformation failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
+ torture_comment(tctx, "not considering NT_STATUS_NOT_IMPLEMENTED as an error\n");
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "netr_GetForestTrustInformation failed");
+ }
+
+ torture_assert(tctx,
+ netlogon_creds_client_check(creds, &return_authenticator.cred),
+ "Credential chaining failed");
+
+ return true;
+}
+
+static bool test_netr_DsRGetForestTrustInformation(struct torture_context *tctx,
+ struct dcerpc_pipe *p, const char *trusted_domain_name)
+{
+ NTSTATUS status;
+ struct netr_DsRGetForestTrustInformation r;
+ struct lsa_ForestTrustInformation info, *info_ptr;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ info_ptr = &info;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.trusted_domain_name = trusted_domain_name;
+ r.in.flags = 0;
+ r.out.forest_trust_info = &info_ptr;
+
+ torture_comment(tctx ,"Testing netr_DsRGetForestTrustInformation\n");
+
+ status = dcerpc_netr_DsRGetForestTrustInformation_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "DsRGetForestTrustInformation");
+ torture_assert_werr_ok(tctx, r.out.result, "DsRGetForestTrustInformation");
+
+ return true;
+}
+
+/*
+ try a netlogon netr_DsrEnumerateDomainTrusts
+*/
+static bool test_DsrEnumerateDomainTrusts(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_DsrEnumerateDomainTrusts r;
+ struct netr_DomainTrustList trusts;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.trust_flags = 0x3f;
+ r.out.trusts = &trusts;
+
+ status = dcerpc_netr_DsrEnumerateDomainTrusts_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "DsrEnumerateDomaintrusts");
+ torture_assert_werr_ok(tctx, r.out.result, "DsrEnumerateDomaintrusts");
+
+ /* when trusted_domain_name is NULL, netr_DsRGetForestTrustInformation
+ * will show non-forest trusts and all UPN suffixes of the own forest
+ * as LSA_FOREST_TRUST_TOP_LEVEL_NAME types */
+
+ if (r.out.trusts->count) {
+ if (!test_netr_DsRGetForestTrustInformation(tctx, p, NULL)) {
+ return false;
+ }
+ }
+
+ for (i=0; i<r.out.trusts->count; i++) {
+
+ /* get info for transitive forest trusts */
+
+ if (r.out.trusts->array[i].trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
+ if (!test_netr_DsRGetForestTrustInformation(tctx, p,
+ r.out.trusts->array[i].dns_name)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_netr_NetrEnumerateTrustedDomains(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_NetrEnumerateTrustedDomains r;
+ struct netr_Blob trusted_domains_blob;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.out.trusted_domains_blob = &trusted_domains_blob;
+
+ status = dcerpc_netr_NetrEnumerateTrustedDomains_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_NetrEnumerateTrustedDomains");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "NetrEnumerateTrustedDomains");
+
+ return true;
+}
+
+static bool test_netr_NetrEnumerateTrustedDomainsEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_NetrEnumerateTrustedDomainsEx r;
+ struct netr_DomainTrustList dom_trust_list;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.out.dom_trust_list = &dom_trust_list;
+
+ status = dcerpc_netr_NetrEnumerateTrustedDomainsEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_NetrEnumerateTrustedDomainsEx");
+ torture_assert_werr_ok(tctx, r.out.result, "NetrEnumerateTrustedDomainsEx");
+
+ return true;
+}
+
+
+static bool test_netr_DsRGetSiteName(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *computer_name,
+ const char *expected_site)
+{
+ NTSTATUS status;
+ struct netr_DsRGetSiteName r;
+ const char *site = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.computer_name = computer_name;
+ r.out.site = &site;
+ torture_comment(tctx, "Testing netr_DsRGetSiteName\n");
+
+ status = dcerpc_netr_DsRGetSiteName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "DsRGetSiteName");
+ torture_assert_werr_ok(tctx, r.out.result, "DsRGetSiteName");
+ torture_assert_str_equal(tctx, expected_site, site, "netr_DsRGetSiteName");
+
+ return true;
+}
+
+/*
+ try a netlogon netr_DsRGetDCName
+*/
+static bool test_netr_DsRGetDCName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_DsRGetDCName r;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.domain_name = lpcfg_dnsdomain(tctx->lp_ctx);
+ r.in.domain_guid = NULL;
+ r.in.site_guid = NULL;
+ r.in.flags = DS_RETURN_DNS_NAME;
+ r.out.info = &info;
+
+ status = dcerpc_netr_DsRGetDCName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "DsRGetDCName");
+ torture_assert_werr_ok(tctx, r.out.result, "DsRGetDCName");
+
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_CONTROLLER)),
+ DS_DNS_CONTROLLER,
+ "DsRGetDCName");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_DOMAIN)),
+ DS_DNS_DOMAIN,
+ "DsRGetDCName");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_FOREST_ROOT)),
+ DS_DNS_FOREST_ROOT,
+ "DsRGetDCName");
+
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.flags = 0;
+
+ status = dcerpc_netr_DsRGetDCName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "DsRGetDCName");
+ torture_assert_werr_ok(tctx, r.out.result, "DsRGetDCName");
+
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_CONTROLLER)), 0,
+ "DsRGetDCName");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_DOMAIN)), 0,
+ "DsRGetDCName");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_FOREST_ROOT)),
+ DS_DNS_FOREST_ROOT,
+ "DsRGetDCName");
+
+ if (strcasecmp(info->dc_site_name, info->client_site_name) == 0) {
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_SERVER_CLOSEST)),
+ DS_SERVER_CLOSEST,
+ "DsRGetDCName");
+ }
+
+ return test_netr_DsRGetSiteName(p, tctx,
+ info->dc_unc,
+ info->dc_site_name);
+}
+
+/*
+ try a netlogon netr_DsRGetDCNameEx
+*/
+static bool test_netr_DsRGetDCNameEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_DsRGetDCNameEx r;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.domain_name = lpcfg_dnsdomain(tctx->lp_ctx);
+ r.in.domain_guid = NULL;
+ r.in.site_name = NULL;
+ r.in.flags = DS_RETURN_DNS_NAME;
+ r.out.info = &info;
+
+ status = dcerpc_netr_DsRGetDCNameEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_DsRGetDCNameEx");
+ torture_assert_werr_ok(tctx, r.out.result, "netr_DsRGetDCNameEx");
+
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_CONTROLLER)),
+ DS_DNS_CONTROLLER,
+ "DsRGetDCNameEx");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_DOMAIN)),
+ DS_DNS_DOMAIN,
+ "DsRGetDCNameEx");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_FOREST_ROOT)),
+ DS_DNS_FOREST_ROOT,
+ "DsRGetDCNameEx");
+
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.flags = 0;
+
+ status = dcerpc_netr_DsRGetDCNameEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_DsRGetDCNameEx");
+ torture_assert_werr_ok(tctx, r.out.result, "netr_DsRGetDCNameEx");
+
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_CONTROLLER)), 0,
+ "DsRGetDCNameEx");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_DOMAIN)), 0,
+ "DsRGetDCNameEx");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_FOREST_ROOT)),
+ DS_DNS_FOREST_ROOT,
+ "DsRGetDCNameEx");
+
+ if (strcasecmp(info->dc_site_name, info->client_site_name) == 0) {
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_SERVER_CLOSEST)),
+ DS_SERVER_CLOSEST,
+ "DsRGetDCNameEx");
+ }
+
+ return test_netr_DsRGetSiteName(p, tctx, info->dc_unc,
+ info->dc_site_name);
+}
+
+/*
+ try a netlogon netr_DsRGetDCNameEx2
+*/
+static bool test_netr_DsRGetDCNameEx2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct netr_DsRGetDCNameEx2 r;
+ struct netr_DsRGetDCNameInfo *info = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing netr_DsRGetDCNameEx2 with no inputs\n");
+ ZERO_STRUCT(r.in);
+ r.in.flags = DS_RETURN_DNS_NAME;
+ r.out.info = &info;
+
+ status = dcerpc_netr_DsRGetDCNameEx2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_DsRGetDCNameEx2");
+ torture_assert_werr_ok(tctx, r.out.result, "netr_DsRGetDCNameEx2");
+
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_CONTROLLER)),
+ DS_DNS_CONTROLLER,
+ "DsRGetDCNameEx2");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_DOMAIN)),
+ DS_DNS_DOMAIN,
+ "DsRGetDCNameEx2");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_FOREST_ROOT)),
+ DS_DNS_FOREST_ROOT,
+ "DsRGetDCNameEx2");
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.client_account = NULL;
+ r.in.mask = 0x00000000;
+ r.in.domain_name = lpcfg_dnsdomain(tctx->lp_ctx);
+ r.in.domain_guid = NULL;
+ r.in.site_name = NULL;
+ r.in.flags = DS_RETURN_DNS_NAME;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing netr_DsRGetDCNameEx2 without client account\n");
+
+ status = dcerpc_netr_DsRGetDCNameEx2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_DsRGetDCNameEx2");
+ torture_assert_werr_ok(tctx, r.out.result, "netr_DsRGetDCNameEx2");
+
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.flags = 0;
+
+ status = dcerpc_netr_DsRGetDCNameEx2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_DsRGetDCNameEx2");
+ torture_assert_werr_ok(tctx, r.out.result, "netr_DsRGetDCNameEx2");
+
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_CONTROLLER)), 0,
+ "DsRGetDCNameEx2");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_DOMAIN)), 0,
+ "DsRGetDCNameEx2");
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_DNS_FOREST_ROOT)),
+ DS_DNS_FOREST_ROOT,
+ "DsRGetDCNameEx2");
+
+ if (strcasecmp(info->dc_site_name, info->client_site_name) == 0) {
+ torture_assert_int_equal(tctx,
+ (info->dc_flags & (DS_SERVER_CLOSEST)),
+ DS_SERVER_CLOSEST,
+ "DsRGetDCNameEx2");
+ }
+
+ torture_comment(tctx, "Testing netr_DsRGetDCNameEx2 with client account\n");
+ r.in.client_account = TEST_MACHINE_NAME"$";
+ r.in.mask = ACB_SVRTRUST;
+ r.in.flags = DS_RETURN_FLAT_NAME;
+ r.out.info = &info;
+
+ status = dcerpc_netr_DsRGetDCNameEx2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "netr_DsRGetDCNameEx2");
+ torture_assert_werr_ok(tctx, r.out.result, "netr_DsRGetDCNameEx2");
+
+ return test_netr_DsRGetSiteName(p, tctx, info->dc_unc,
+ info->dc_site_name);
+}
+
+/* This is a substitution for "samdb_server_site_name" which relies on the
+ * correct "lp_ctx" and therefore can't be used here. */
+static const char *server_site_name(struct torture_context *tctx,
+ struct ldb_context *ldb)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn, *server_dn;
+ const struct ldb_val *site_name_val;
+ const char *server_dn_str, *site_name;
+
+ tmp_ctx = talloc_new(ldb);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, ldb, "");
+ if (dn == NULL) {
+ goto failed;
+ }
+
+ server_dn_str = samdb_search_string(ldb, tmp_ctx, dn, "serverName",
+ NULL);
+ if (server_dn_str == NULL) {
+ goto failed;
+ }
+
+ server_dn = ldb_dn_new(tmp_ctx, ldb, server_dn_str);
+ if (server_dn == NULL) {
+ goto failed;
+ }
+
+ /* CN=<Server name>, CN=Servers, CN=<Site name>, CN=Sites, ... */
+ site_name_val = ldb_dn_get_component_val(server_dn, 2);
+ if (site_name_val == NULL) {
+ goto failed;
+ }
+
+ site_name = (const char *) site_name_val->data;
+
+ talloc_steal(tctx, site_name);
+ talloc_free(tmp_ctx);
+
+ return site_name;
+
+failed:
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+static bool test_netr_DsrGetDcSiteCoverageW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ char *url;
+ struct ldb_context *sam_ctx = NULL;
+ NTSTATUS status;
+ struct netr_DsrGetDcSiteCoverageW r;
+ struct DcSitesCtr *ctr = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "This does only pass with the default site\n");
+
+ /* We won't double-check this when we are over 'local' transports */
+ if (dcerpc_server_name(p)) {
+ /* Set up connection to SAMDB on DC */
+ url = talloc_asprintf(tctx, "ldap://%s", dcerpc_server_name(p));
+ sam_ctx = ldb_wrap_connect(tctx, tctx->ev, tctx->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+
+ torture_assert(tctx, sam_ctx, "Connection to the SAMDB on DC failed!");
+ }
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.out.ctr = &ctr;
+
+ status = dcerpc_netr_DsrGetDcSiteCoverageW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ torture_assert(tctx, ctr->num_sites == 1,
+ "we should per default only get the default site");
+ if (sam_ctx != NULL) {
+ torture_assert_casestr_equal(tctx, ctr->sites[0].string,
+ server_site_name(tctx, sam_ctx),
+ "didn't return default site");
+ }
+
+ return true;
+}
+
+static bool test_netr_DsRAddressToSitenamesW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ char *url;
+ struct ldb_context *sam_ctx = NULL;
+ NTSTATUS status;
+ struct netr_DsRAddressToSitenamesW r;
+ struct netr_DsRAddress addrs[6];
+ struct sockaddr_in *addr;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *addr6;
+#endif
+ struct netr_DsRAddressToSitenamesWCtr *ctr;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t i;
+ int ret;
+
+ torture_comment(tctx, "This does only pass with the default site\n");
+
+ /* We won't double-check this when we are over 'local' transports */
+ if (dcerpc_server_name(p)) {
+ /* Set up connection to SAMDB on DC */
+ url = talloc_asprintf(tctx, "ldap://%s", dcerpc_server_name(p));
+ sam_ctx = ldb_wrap_connect(tctx, tctx->ev, tctx->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+
+ torture_assert(tctx, sam_ctx, "Connection to the SAMDB on DC failed!");
+ }
+
+ /* First try valid IP addresses */
+
+ addrs[0].size = sizeof(struct sockaddr_in);
+ addrs[0].buffer = talloc_zero_array(tctx, uint8_t, addrs[0].size);
+ addr = (struct sockaddr_in *) addrs[0].buffer;
+ addrs[0].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "127.0.0.1", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[1].size = sizeof(struct sockaddr_in);
+ addrs[1].buffer = talloc_zero_array(tctx, uint8_t, addrs[1].size);
+ addr = (struct sockaddr_in *) addrs[1].buffer;
+ addrs[1].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "0.0.0.0", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[2].size = sizeof(struct sockaddr_in);
+ addrs[2].buffer = talloc_zero_array(tctx, uint8_t, addrs[2].size);
+ addr = (struct sockaddr_in *) addrs[2].buffer;
+ addrs[2].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "255.255.255.255", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+#ifdef HAVE_IPV6
+ addrs[3].size = sizeof(struct sockaddr_in6);
+ addrs[3].buffer = talloc_zero_array(tctx, uint8_t, addrs[3].size);
+ addr6 = (struct sockaddr_in6 *) addrs[3].buffer;
+ addrs[3].buffer[0] = AF_INET6;
+ ret = inet_pton(AF_INET6, "::1", &addr6->sin6_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[4].size = sizeof(struct sockaddr_in6);
+ addrs[4].buffer = talloc_zero_array(tctx, uint8_t, addrs[4].size);
+ addr6 = (struct sockaddr_in6 *) addrs[4].buffer;
+ addrs[4].buffer[0] = AF_INET6;
+ ret = inet_pton(AF_INET6, "::", &addr6->sin6_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[5].size = sizeof(struct sockaddr_in6);
+ addrs[5].buffer = talloc_zero_array(tctx, uint8_t, addrs[5].size);
+ addr6 = (struct sockaddr_in6 *) addrs[5].buffer;
+ addrs[5].buffer[0] = AF_INET6;
+ ret = inet_pton(AF_INET6, "ff02::1", &addr6->sin6_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+#else
+ /* the test cases are repeated to have exactly 6. This is for
+ * compatibility with IPv4-only machines */
+ addrs[3].size = sizeof(struct sockaddr_in);
+ addrs[3].buffer = talloc_zero_array(tctx, uint8_t, addrs[3].size);
+ addr = (struct sockaddr_in *) addrs[3].buffer;
+ addrs[3].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "127.0.0.1", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[4].size = sizeof(struct sockaddr_in);
+ addrs[4].buffer = talloc_zero_array(tctx, uint8_t, addrs[4].size);
+ addr = (struct sockaddr_in *) addrs[4].buffer;
+ addrs[4].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "0.0.0.0", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[5].size = sizeof(struct sockaddr_in);
+ addrs[5].buffer = talloc_zero_array(tctx, uint8_t, addrs[5].size);
+ addr = (struct sockaddr_in *) addrs[5].buffer;
+ addrs[5].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "255.255.255.255", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+#endif
+
+ ctr = talloc(tctx, struct netr_DsRAddressToSitenamesWCtr);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.count = 6;
+ r.in.addresses = addrs;
+ r.out.ctr = &ctr;
+
+ status = dcerpc_netr_DsRAddressToSitenamesW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ if (sam_ctx != NULL) {
+ for (i = 0; i < 3; i++) {
+ torture_assert_casestr_equal(tctx,
+ ctr->sitename[i].string,
+ server_site_name(tctx, sam_ctx),
+ "didn't return default site");
+ }
+ for (i = 3; i < 6; i++) {
+ /* Windows returns "NULL" for the sitename if it isn't
+ * IPv6 configured */
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_assert_casestr_equal(tctx,
+ ctr->sitename[i].string,
+ server_site_name(tctx, sam_ctx),
+ "didn't return default site");
+ }
+ }
+ }
+
+ /* Now try invalid ones (too short buffers) */
+
+ addrs[0].size = 0;
+ addrs[1].size = 1;
+ addrs[2].size = 4;
+
+ addrs[3].size = 0;
+ addrs[4].size = 1;
+ addrs[5].size = 4;
+
+ status = dcerpc_netr_DsRAddressToSitenamesW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ for (i = 0; i < 6; i++) {
+ torture_assert(tctx, ctr->sitename[i].string == NULL,
+ "sitename should be null");
+ }
+
+ /* Now try invalid ones (wrong address types) */
+
+ addrs[0].size = 10;
+ addrs[0].buffer[0] = AF_UNSPEC;
+ addrs[1].size = 10;
+ addrs[1].buffer[0] = AF_UNIX; /* AF_LOCAL = AF_UNIX */
+ addrs[2].size = 10;
+ addrs[2].buffer[0] = AF_UNIX;
+
+ addrs[3].size = 10;
+ addrs[3].buffer[0] = 250;
+ addrs[4].size = 10;
+ addrs[4].buffer[0] = 251;
+ addrs[5].size = 10;
+ addrs[5].buffer[0] = 252;
+
+ status = dcerpc_netr_DsRAddressToSitenamesW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ for (i = 0; i < 6; i++) {
+ torture_assert(tctx, ctr->sitename[i].string == NULL,
+ "sitename should be null");
+ }
+
+ return true;
+}
+
+static bool test_netr_DsRAddressToSitenamesExW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ char *url;
+ struct ldb_context *sam_ctx = NULL;
+ NTSTATUS status;
+ struct netr_DsRAddressToSitenamesExW r;
+ struct netr_DsRAddress addrs[6];
+ struct sockaddr_in *addr;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *addr6;
+#endif
+ struct netr_DsRAddressToSitenamesExWCtr *ctr;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t i;
+ int ret;
+
+ torture_comment(tctx, "This does pass with the default site\n");
+
+ /* We won't double-check this when we are over 'local' transports */
+ if (dcerpc_server_name(p)) {
+ /* Set up connection to SAMDB on DC */
+ url = talloc_asprintf(tctx, "ldap://%s", dcerpc_server_name(p));
+ sam_ctx = ldb_wrap_connect(tctx, tctx->ev, tctx->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+
+ torture_assert(tctx, sam_ctx, "Connection to the SAMDB on DC failed!");
+ }
+
+ /* First try valid IP addresses */
+
+ addrs[0].size = sizeof(struct sockaddr_in);
+ addrs[0].buffer = talloc_zero_array(tctx, uint8_t, addrs[0].size);
+ addr = (struct sockaddr_in *) addrs[0].buffer;
+ addrs[0].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "127.0.0.1", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[1].size = sizeof(struct sockaddr_in);
+ addrs[1].buffer = talloc_zero_array(tctx, uint8_t, addrs[1].size);
+ addr = (struct sockaddr_in *) addrs[1].buffer;
+ addrs[1].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "0.0.0.0", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[2].size = sizeof(struct sockaddr_in);
+ addrs[2].buffer = talloc_zero_array(tctx, uint8_t, addrs[2].size);
+ addr = (struct sockaddr_in *) addrs[2].buffer;
+ addrs[2].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "255.255.255.255", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+#ifdef HAVE_IPV6
+ addrs[3].size = sizeof(struct sockaddr_in6);
+ addrs[3].buffer = talloc_zero_array(tctx, uint8_t, addrs[3].size);
+ addr6 = (struct sockaddr_in6 *) addrs[3].buffer;
+ addrs[3].buffer[0] = AF_INET6;
+ ret = inet_pton(AF_INET6, "::1", &addr6->sin6_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[4].size = sizeof(struct sockaddr_in6);
+ addrs[4].buffer = talloc_zero_array(tctx, uint8_t, addrs[4].size);
+ addr6 = (struct sockaddr_in6 *) addrs[4].buffer;
+ addrs[4].buffer[0] = AF_INET6;
+ ret = inet_pton(AF_INET6, "::", &addr6->sin6_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[5].size = sizeof(struct sockaddr_in6);
+ addrs[5].buffer = talloc_zero_array(tctx, uint8_t, addrs[5].size);
+ addr6 = (struct sockaddr_in6 *) addrs[5].buffer;
+ addrs[5].buffer[0] = AF_INET6;
+ ret = inet_pton(AF_INET6, "ff02::1", &addr6->sin6_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+#else
+ /* the test cases are repeated to have exactly 6. This is for
+ * compatibility with IPv4-only machines */
+ addrs[3].size = sizeof(struct sockaddr_in);
+ addrs[3].buffer = talloc_zero_array(tctx, uint8_t, addrs[3].size);
+ addr = (struct sockaddr_in *) addrs[3].buffer;
+ addrs[3].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "127.0.0.1", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[4].size = sizeof(struct sockaddr_in);
+ addrs[4].buffer = talloc_zero_array(tctx, uint8_t, addrs[4].size);
+ addr = (struct sockaddr_in *) addrs[4].buffer;
+ addrs[4].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "0.0.0.0", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+
+ addrs[5].size = sizeof(struct sockaddr_in);
+ addrs[5].buffer = talloc_zero_array(tctx, uint8_t, addrs[5].size);
+ addr = (struct sockaddr_in *) addrs[5].buffer;
+ addrs[5].buffer[0] = AF_INET;
+ ret = inet_pton(AF_INET, "255.255.255.255", &addr->sin_addr);
+ torture_assert(tctx, ret > 0, "inet_pton failed");
+#endif
+
+ ctr = talloc(tctx, struct netr_DsRAddressToSitenamesExWCtr);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.count = 6;
+ r.in.addresses = addrs;
+ r.out.ctr = &ctr;
+
+ status = dcerpc_netr_DsRAddressToSitenamesExW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ if (sam_ctx != NULL) {
+ for (i = 0; i < 3; i++) {
+ torture_assert_casestr_equal(tctx,
+ ctr->sitename[i].string,
+ server_site_name(tctx, sam_ctx),
+ "didn't return default site");
+ torture_assert(tctx, ctr->subnetname[i].string == NULL,
+ "subnet should be null");
+ }
+ for (i = 3; i < 6; i++) {
+ /* Windows returns "NULL" for the sitename if it isn't
+ * IPv6 configured */
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_assert_casestr_equal(tctx,
+ ctr->sitename[i].string,
+ server_site_name(tctx, sam_ctx),
+ "didn't return default site");
+ }
+ torture_assert(tctx, ctr->subnetname[i].string == NULL,
+ "subnet should be null");
+ }
+ }
+
+ /* Now try invalid ones (too short buffers) */
+
+ addrs[0].size = 0;
+ addrs[1].size = 1;
+ addrs[2].size = 4;
+
+ addrs[3].size = 0;
+ addrs[4].size = 1;
+ addrs[5].size = 4;
+
+ status = dcerpc_netr_DsRAddressToSitenamesExW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ for (i = 0; i < 6; i++) {
+ torture_assert(tctx, ctr->sitename[i].string == NULL,
+ "sitename should be null");
+ torture_assert(tctx, ctr->subnetname[i].string == NULL,
+ "subnet should be null");
+ }
+
+ addrs[0].size = 10;
+ addrs[0].buffer[0] = AF_UNSPEC;
+ addrs[1].size = 10;
+ addrs[1].buffer[0] = AF_UNIX; /* AF_LOCAL = AF_UNIX */
+ addrs[2].size = 10;
+ addrs[2].buffer[0] = AF_UNIX;
+
+ addrs[3].size = 10;
+ addrs[3].buffer[0] = 250;
+ addrs[4].size = 10;
+ addrs[4].buffer[0] = 251;
+ addrs[5].size = 10;
+ addrs[5].buffer[0] = 252;
+
+ status = dcerpc_netr_DsRAddressToSitenamesExW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "failed");
+ torture_assert_werr_ok(tctx, r.out.result, "failed");
+
+ for (i = 0; i < 6; i++) {
+ torture_assert(tctx, ctr->sitename[i].string == NULL,
+ "sitename should be null");
+ torture_assert(tctx, ctr->subnetname[i].string == NULL,
+ "subnet should be null");
+ }
+
+ return true;
+}
+
+static bool test_netr_ServerGetTrustInfo_flags(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials,
+ uint32_t negotiate_flags)
+{
+ struct netr_ServerGetTrustInfo r;
+
+ struct netr_Authenticator a;
+ struct netr_Authenticator return_authenticator;
+ struct samr_Password new_owf_password;
+ struct samr_Password old_owf_password;
+ struct netr_TrustInfo *trust_info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ struct samr_Password nt_hash;
+
+ if (!test_SetupCredentials3(p1, tctx, negotiate_flags,
+ machine_credentials, &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ netlogon_creds_client_authenticator(creds, &a);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = cli_credentials_get_secure_channel_type(machine_credentials);
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &a;
+
+ r.out.return_authenticator = &return_authenticator;
+ r.out.new_owf_password = &new_owf_password;
+ r.out.old_owf_password = &old_owf_password;
+ r.out.trust_info = &trust_info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerGetTrustInfo_r(b, tctx, &r),
+ "ServerGetTrustInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerGetTrustInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &return_authenticator.cred), "Credential chaining failed");
+
+ E_md4hash(cli_credentials_get_password(machine_credentials), nt_hash.hash);
+
+ netlogon_creds_des_decrypt(creds, &new_owf_password);
+
+ dump_data(1, new_owf_password.hash, 16);
+ dump_data(1, nt_hash.hash, 16);
+
+ torture_assert_mem_equal(tctx, new_owf_password.hash, nt_hash.hash, 16,
+ "received unexpected owf password\n");
+
+ return true;
+}
+
+static bool test_netr_ServerGetTrustInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ return test_netr_ServerGetTrustInfo_flags(tctx, p, machine_credentials,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_netr_ServerGetTrustInfo_AES(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ return test_netr_ServerGetTrustInfo_flags(tctx, p, machine_credentials,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+
+static bool test_GetDomainInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ struct netr_LogonGetDomainInfo r;
+ struct netr_WorkstationInformation q1;
+ struct netr_Authenticator a;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_OsVersion os;
+ union netr_WorkstationInfo query;
+ union netr_DomainInfo info;
+ const char* const attrs[] = { "dNSHostName", "operatingSystem",
+ "operatingSystemServicePack", "operatingSystemVersion",
+ "servicePrincipalName", NULL };
+ char *url;
+ struct ldb_context *sam_ctx = NULL;
+ struct ldb_message **res;
+ struct ldb_message_element *spn_el;
+ int ret, i;
+ char *version_str;
+ const char *old_dnsname = NULL;
+ char **spns = NULL;
+ int num_spns = 0;
+ char *temp_str = NULL;
+ char *temp_str2 = NULL;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ struct netr_OneDomainInfo *odi1 = NULL;
+ struct netr_OneDomainInfo *odi2 = NULL;
+ struct netr_trust_extension_info *tex2 = NULL;
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo\n");
+
+ if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ machine_credentials, &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ /* We won't double-check this when we are over 'local' transports */
+ if (dcerpc_server_name(p)) {
+ /* Set up connection to SAMDB on DC */
+ url = talloc_asprintf(tctx, "ldap://%s", dcerpc_server_name(p));
+ sam_ctx = ldb_wrap_connect(tctx, tctx->ev, tctx->lp_ctx, url,
+ NULL,
+ samba_cmdline_get_creds(),
+ 0);
+
+ torture_assert(tctx, sam_ctx, "Connection to the SAMDB on DC failed!");
+ }
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 1st call (no variation of DNS hostname)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ ZERO_STRUCT(r);
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &a;
+ r.in.level = 1;
+ r.in.return_authenticator = &a;
+ r.in.query = &query;
+ r.out.return_authenticator = &a;
+ r.out.info = &info;
+
+ ZERO_STRUCT(os);
+ os.os.MajorVersion = 123;
+ os.os.MinorVersion = 456;
+ os.os.BuildNumber = 789;
+ os.os.CSDVersion = "Service Pack 10";
+ os.os.ServicePackMajor = 10;
+ os.os.ServicePackMinor = 1;
+ os.os.SuiteMask = NETR_VER_SUITE_SINGLEUSERTS;
+ os.os.ProductType = NETR_VER_NT_SERVER;
+ os.os.Reserved = 0;
+
+ version_str = talloc_asprintf(tctx, "%d.%d (%d)", os.os.MajorVersion,
+ os.os.MinorVersion, os.os.BuildNumber);
+
+ ZERO_STRUCT(q1);
+ q1.dns_hostname = talloc_asprintf(tctx, "%s.%s", TEST_MACHINE_NAME,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ q1.sitename = "Default-First-Site-Name";
+ q1.os_version.os = &os;
+ q1.os_name.string = talloc_asprintf(tctx,
+ "Tortured by Samba4 RPC-NETLOGON: %s",
+ timestring(tctx, time(NULL)));
+
+ /* The workstation handles the "servicePrincipalName" and DNS hostname
+ updates */
+ q1.workstation_flags = NETR_WS_FLAG_HANDLES_SPN_UPDATE;
+
+ query.workstation_info = &q1;
+
+ if (sam_ctx) {
+ /* Gets back the old DNS hostname in AD */
+ ret = gendb_search(sam_ctx, tctx, NULL, &res, attrs,
+ "(sAMAccountName=%s$)", TEST_MACHINE_NAME);
+ old_dnsname =
+ ldb_msg_find_attr_as_string(res[0], "dNSHostName", NULL);
+
+ /* Gets back the "servicePrincipalName"s in AD */
+ spn_el = ldb_msg_find_element(res[0], "servicePrincipalName");
+ if (spn_el != NULL) {
+ for (i=0; i < spn_el->num_values; i++) {
+ spns = talloc_realloc(tctx, spns, char *, i + 1);
+ spns[i] = (char *) spn_el->values[i].data;
+ }
+ num_spns = i;
+ }
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ smb_msleep(250);
+
+ if (sam_ctx) {
+ /* AD workstation infos entry check */
+ ret = gendb_search(sam_ctx, tctx, NULL, &res, attrs,
+ "(sAMAccountName=%s$)", TEST_MACHINE_NAME);
+ torture_assert(tctx, ret == 1, "Test machine account not found in SAMDB on DC! Has the workstation been joined?");
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystem", NULL),
+ q1.os_name.string, "'operatingSystem' wrong!");
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystemServicePack", NULL),
+ os.os.CSDVersion, "'operatingSystemServicePack' wrong!");
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystemVersion", NULL),
+ version_str, "'operatingSystemVersion' wrong!");
+
+ if (old_dnsname != NULL) {
+ /* If before a DNS hostname was set then it should remain
+ the same in combination with the "servicePrincipalName"s.
+ The DNS hostname should also be returned by our
+ "LogonGetDomainInfo" call (in the domain info structure). */
+
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "dNSHostName", NULL),
+ old_dnsname, "'DNS hostname' was not set!");
+
+ spn_el = ldb_msg_find_element(res[0], "servicePrincipalName");
+ torture_assert(tctx, ((spns != NULL) && (spn_el != NULL)),
+ "'servicePrincipalName's not set!");
+ torture_assert(tctx, spn_el->num_values == num_spns,
+ "'servicePrincipalName's incorrect!");
+ for (i=0; (i < spn_el->num_values) && (i < num_spns); i++)
+ torture_assert_str_equal(tctx,
+ (char *) spn_el->values[i].data,
+ spns[i], "'servicePrincipalName's incorrect!");
+
+ torture_assert_str_equal(tctx,
+ info.domain_info->dns_hostname.string,
+ old_dnsname,
+ "Out 'DNS hostname' doesn't match the old one!");
+ } else {
+ /* If no DNS hostname was set then also now none should be set,
+ the "servicePrincipalName"s should remain empty and no DNS
+ hostname should be returned by our "LogonGetDomainInfo"
+ call (in the domain info structure). */
+
+ torture_assert(tctx,
+ ldb_msg_find_attr_as_string(res[0], "dNSHostName", NULL) == NULL,
+ "'DNS hostname' was set!");
+
+ spn_el = ldb_msg_find_element(res[0], "servicePrincipalName");
+ torture_assert(tctx, ((spns == NULL) && (spn_el == NULL)),
+ "'servicePrincipalName's were set!");
+
+ torture_assert(tctx,
+ info.domain_info->dns_hostname.string == NULL,
+ "Out 'DNS host name' was set!");
+ }
+ }
+
+ /* Checks "workstation flags" */
+ torture_assert(tctx,
+ info.domain_info->workstation_flags
+ == NETR_WS_FLAG_HANDLES_SPN_UPDATE,
+ "Out 'workstation flags' don't match!");
+
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 2nd call (variation of DNS hostname doesn't work)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ /* Wipe out the CSDVersion, and prove which values still 'stick' */
+ os.os.CSDVersion = "";
+
+ /* Change also the DNS hostname to test differences in behaviour */
+ talloc_free(discard_const_p(char, q1.dns_hostname));
+ q1.dns_hostname = talloc_asprintf(tctx, "%s2.%s", TEST_MACHINE_NAME,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+
+ /* The workstation handles the "servicePrincipalName" and DNS hostname
+ updates */
+ q1.workstation_flags = NETR_WS_FLAG_HANDLES_SPN_UPDATE;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ smb_msleep(250);
+
+ if (sam_ctx) {
+ /* AD workstation infos entry check */
+ ret = gendb_search(sam_ctx, tctx, NULL, &res, attrs,
+ "(sAMAccountName=%s$)", TEST_MACHINE_NAME);
+ torture_assert(tctx, ret == 1, "Test machine account not found in SAMDB on DC! Has the workstation been joined?");
+
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystem", NULL),
+ q1.os_name.string, "'operatingSystem' should stick!");
+ torture_assert(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystemServicePack", NULL) == NULL,
+ "'operatingSystemServicePack' shouldn't stick!");
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystemVersion", NULL),
+ version_str, "'operatingSystemVersion' wrong!");
+
+ /* The DNS host name shouldn't have been updated by the server */
+
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "dNSHostName", NULL),
+ old_dnsname, "'DNS host name' did change!");
+
+ /* Find the two "servicePrincipalName"s which the DC shouldn't have been
+ updated (HOST/<Netbios name> and HOST/<FQDN name>) - see MS-NRPC
+ 3.5.4.3.9 */
+ spn_el = ldb_msg_find_element(res[0], "servicePrincipalName");
+ torture_assert(tctx, spn_el != NULL,
+ "There should exist 'servicePrincipalName's in AD!");
+ temp_str = talloc_asprintf(tctx, "HOST/%s", TEST_MACHINE_NAME);
+ for (i=0; i < spn_el->num_values; i++)
+ if (strcasecmp((char *) spn_el->values[i].data, temp_str) == 0)
+ break;
+ torture_assert(tctx, i != spn_el->num_values,
+ "'servicePrincipalName' HOST/<Netbios name> not found!");
+ temp_str = talloc_asprintf(tctx, "HOST/%s", old_dnsname);
+ for (i=0; i < spn_el->num_values; i++)
+ if (strcasecmp((char *) spn_el->values[i].data, temp_str) == 0)
+ break;
+ torture_assert(tctx, i != spn_el->num_values,
+ "'servicePrincipalName' HOST/<FQDN name> not found!");
+
+ /* Check that the out DNS hostname was set properly */
+ torture_assert_str_equal(tctx, info.domain_info->dns_hostname.string,
+ old_dnsname, "Out 'DNS hostname' doesn't match the old one!");
+ }
+
+ /* Checks "workstation flags" */
+ torture_assert(tctx,
+ info.domain_info->workstation_flags == NETR_WS_FLAG_HANDLES_SPN_UPDATE,
+ "Out 'workstation flags' don't match!");
+
+
+ /* Now try the same but the workstation flags set to 0 */
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 3rd call (variation of DNS hostname doesn't work)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ /* Change also the DNS hostname to test differences in behaviour */
+ talloc_free(discard_const_p(char, q1.dns_hostname));
+ q1.dns_hostname = talloc_asprintf(tctx, "%s2.%s", TEST_MACHINE_NAME,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+
+ /* Wipe out the osVersion, and prove which values still 'stick' */
+ q1.os_version.os = NULL;
+
+ /* Let the DC handle the "servicePrincipalName" and DNS hostname
+ updates */
+ q1.workstation_flags = 0;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ smb_msleep(250);
+
+ if (sam_ctx) {
+ /* AD workstation infos entry check */
+ ret = gendb_search(sam_ctx, tctx, NULL, &res, attrs,
+ "(sAMAccountName=%s$)", TEST_MACHINE_NAME);
+ torture_assert(tctx, ret == 1, "Test machine account not found in SAMDB on DC! Has the workstation been joined?");
+
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystem", NULL),
+ q1.os_name.string, "'operatingSystem' should stick!");
+ torture_assert(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystemServicePack", NULL) == NULL,
+ "'operatingSystemServicePack' shouldn't stick!");
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "operatingSystemVersion", NULL),
+ version_str, "'operatingSystemVersion' wrong!");
+
+ /* The DNS host name shouldn't have been updated by the server */
+
+ torture_assert_str_equal(tctx,
+ ldb_msg_find_attr_as_string(res[0], "dNSHostName", NULL),
+ old_dnsname, "'DNS host name' did change!");
+
+ /* Find the two "servicePrincipalName"s which the DC shouldn't have been
+ updated (HOST/<Netbios name> and HOST/<FQDN name>) - see MS-NRPC
+ 3.5.4.3.9 */
+ spn_el = ldb_msg_find_element(res[0], "servicePrincipalName");
+ torture_assert(tctx, spn_el != NULL,
+ "There should exist 'servicePrincipalName's in AD!");
+ temp_str = talloc_asprintf(tctx, "HOST/%s", TEST_MACHINE_NAME);
+ for (i=0; i < spn_el->num_values; i++)
+ if (strcasecmp((char *) spn_el->values[i].data, temp_str) == 0)
+ break;
+ torture_assert(tctx, i != spn_el->num_values,
+ "'servicePrincipalName' HOST/<Netbios name> not found!");
+ temp_str = talloc_asprintf(tctx, "HOST/%s", old_dnsname);
+ for (i=0; i < spn_el->num_values; i++)
+ if (strcasecmp((char *) spn_el->values[i].data, temp_str) == 0)
+ break;
+ torture_assert(tctx, i != spn_el->num_values,
+ "'servicePrincipalName' HOST/<FQDN name> not found!");
+
+ /* Here the server gives us NULL as the out DNS hostname */
+ torture_assert(tctx, info.domain_info->dns_hostname.string == NULL,
+ "Out 'DNS hostname' should be NULL!");
+ }
+
+ /* Checks "workstation flags" */
+ torture_assert(tctx,
+ info.domain_info->workstation_flags == 0,
+ "Out 'workstation flags' don't match!");
+
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 4th call (verification of DNS hostname and check for trusted domains)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ /* Put the DNS hostname back */
+ talloc_free(discard_const_p(char, q1.dns_hostname));
+ q1.dns_hostname = talloc_asprintf(tctx, "%s.%s", TEST_MACHINE_NAME,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+
+ /* The workstation handles the "servicePrincipalName" and DNS hostname
+ updates */
+ q1.workstation_flags = NETR_WS_FLAG_HANDLES_SPN_UPDATE;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ smb_msleep(250);
+
+ /* Now the in/out DNS hostnames should be the same */
+ torture_assert_str_equal(tctx,
+ info.domain_info->dns_hostname.string,
+ query.workstation_info->dns_hostname,
+ "In/Out 'DNS hostnames' don't match!");
+ old_dnsname = info.domain_info->dns_hostname.string;
+
+ /* Checks "workstation flags" */
+ torture_assert(tctx,
+ info.domain_info->workstation_flags
+ == NETR_WS_FLAG_HANDLES_SPN_UPDATE,
+ "Out 'workstation flags' don't match!");
+
+ /* Checks for trusted domains */
+ torture_assert(tctx,
+ (info.domain_info->trusted_domain_count != 0)
+ && (info.domain_info->trusted_domains != NULL),
+ "Trusted domains have been requested!");
+
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 5th call (check for trusted domains)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ /* The workstation handles the "servicePrincipalName" and DNS hostname
+ updates and requests inbound trusts */
+ q1.workstation_flags = NETR_WS_FLAG_HANDLES_SPN_UPDATE
+ | NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ smb_msleep(250);
+
+ /* Checks "workstation flags" */
+ torture_assert(tctx,
+ info.domain_info->workstation_flags
+ == (NETR_WS_FLAG_HANDLES_SPN_UPDATE
+ | NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS),
+ "Out 'workstation flags' don't match!");
+
+ /* Checks for trusted domains */
+ torture_assert(tctx,
+ (info.domain_info->trusted_domain_count != 0)
+ && (info.domain_info->trusted_domains != NULL),
+ "Trusted domains have been requested!");
+
+ odi1 = &info.domain_info->primary_domain;
+
+ torture_assert(tctx, !GUID_all_zero(&odi1->domain_guid),
+ "primary domain_guid needs to be valid");
+
+ for (i=0; i < info.domain_info->trusted_domain_count; i++) {
+ struct netr_OneDomainInfo *odiT =
+ &info.domain_info->trusted_domains[i];
+ struct netr_trust_extension_info *texT = NULL;
+
+ torture_assert_int_equal(tctx, odiT->trust_extension.length, 16,
+ "trust_list should have extension");
+ torture_assert(tctx, odiT->trust_extension.info != NULL,
+ "trust_list should have extension");
+ texT = &odiT->trust_extension.info->info;
+
+ if (GUID_equal(&odiT->domain_guid, &odi1->domain_guid)) {
+ odi2 = odiT;
+ tex2 = texT;
+ continue;
+ }
+
+ torture_assert_int_equal(tctx,
+ texT->flags & NETR_TRUST_FLAG_PRIMARY,
+ 0,
+ "trust_list flags should not have PRIMARY");
+
+ torture_assert(tctx, odiT->domainname.string != NULL,
+ "trust_list domainname should be valid");
+ if (texT->trust_type == LSA_TRUST_TYPE_DOWNLEVEL ||
+ texT->trust_type == LSA_TRUST_TYPE_MIT)
+ {
+ torture_assert(tctx, odiT->dns_domainname.string == NULL,
+ "trust_list dns_domainname should be NULL for downlevel or MIT");
+ } else {
+ torture_assert(tctx, odiT->dns_domainname.string != NULL,
+ "trust_list dns_domainname should be valid for uplevel");
+ }
+ torture_assert(tctx, odiT->dns_forestname.string == NULL,
+ "trust_list dns_forestname needs to be NULL");
+
+ torture_assert(tctx, odiT->domain_sid != NULL,
+ "trust_list domain_sid needs to be valid");
+ }
+
+ torture_assert(tctx, odi2 != NULL,
+ "trust_list primary domain not found.");
+
+ torture_assert_str_equal(tctx,
+ odi1->domainname.string,
+ odi2->domainname.string,
+ "netbios name should match");
+
+ temp_str = talloc_strdup(tctx, odi1->dns_domainname.string);
+ torture_assert(tctx, temp_str != NULL,
+ "primary_domain dns_domainname copy");
+ temp_str2 = strrchr(temp_str, '.');
+ torture_assert(tctx, temp_str2 != NULL && temp_str2[1] == '\0',
+ "primary_domain dns_domainname needs trailing '.'");
+ temp_str2[0] = '\0';
+ torture_assert_str_equal(tctx,
+ temp_str,
+ odi2->dns_domainname.string,
+ "dns domainname should match "
+ "(without trailing '.')");
+
+ temp_str = talloc_strdup(tctx, odi1->dns_forestname.string);
+ torture_assert(tctx, temp_str != NULL,
+ "primary_domain dns_forestname copy");
+ temp_str2 = strrchr(temp_str, '.');
+ torture_assert(tctx, temp_str2 != NULL && temp_str2[1] == '\0',
+ "primary_domain dns_forestname needs trailing '.'");
+ temp_str2[0] = '\0';
+ torture_assert(tctx, odi2->dns_forestname.string == NULL,
+ "trust_list dns_forestname needs to be NULL");
+
+ torture_assert_guid_equal(tctx, odi1->domain_guid, odi2->domain_guid,
+ "domain_guid should match");
+ torture_assert(tctx, odi1->domain_sid != NULL,
+ "primary domain_sid needs to be valid");
+ torture_assert(tctx, odi2->domain_sid != NULL,
+ "trust_list domain_sid needs to be valid");
+ torture_assert_sid_equal(tctx, odi1->domain_sid, odi2->domain_sid,
+ "domain_sid should match");
+
+ torture_assert_int_equal(tctx, odi1->trust_extension.length, 0,
+ "primary_domain should not have extension");
+ torture_assert_int_equal(tctx, odi2->trust_extension.length, 16,
+ "trust_list should have extension");
+ torture_assert(tctx, odi2->trust_extension.info != NULL,
+ "trust_list should have extension");
+ tex2 = &odi2->trust_extension.info->info;
+ torture_assert_int_equal(tctx,
+ tex2->flags & NETR_TRUST_FLAG_PRIMARY,
+ NETR_TRUST_FLAG_PRIMARY,
+ "trust_list flags should have PRIMARY");
+ torture_assert_int_equal(tctx,
+ tex2->flags & NETR_TRUST_FLAG_IN_FOREST,
+ NETR_TRUST_FLAG_IN_FOREST,
+ "trust_list flags should have IN_FOREST");
+ torture_assert_int_equal(tctx,
+ tex2->flags & NETR_TRUST_FLAG_NATIVE,
+ NETR_TRUST_FLAG_NATIVE,
+ "trust_list flags should have NATIVE");
+ torture_assert_int_equal(tctx,
+ tex2->flags & ~NETR_TRUST_FLAG_TREEROOT,
+ NETR_TRUST_FLAG_IN_FOREST |
+ NETR_TRUST_FLAG_PRIMARY |
+ NETR_TRUST_FLAG_NATIVE,
+ "trust_list flags IN_FOREST, PRIMARY, NATIVE "
+ "(TREEROOT optional)");
+ if (strcmp(odi1->dns_domainname.string, odi1->dns_forestname.string) == 0) {
+ torture_assert_int_equal(tctx,
+ tex2->flags & NETR_TRUST_FLAG_TREEROOT,
+ NETR_TRUST_FLAG_TREEROOT,
+ "trust_list flags TREEROOT on forest root");
+ torture_assert_int_equal(tctx,
+ tex2->parent_index, 0,
+ "trust_list no parent on forest root");
+ }
+ torture_assert_int_equal(tctx,
+ tex2->trust_type, LSA_TRUST_TYPE_UPLEVEL,
+ "trust_list uplevel");
+ torture_assert_int_equal(tctx,
+ tex2->trust_attributes, 0,
+ "trust_list no attributes");
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 6th call (no DNS hostname)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ query.workstation_info->dns_hostname = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ /* The old DNS hostname should stick */
+ torture_assert_str_equal(tctx,
+ info.domain_info->dns_hostname.string,
+ old_dnsname,
+ "'DNS hostname' changed!");
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 7th call (extra workstation flags)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ q1.workstation_flags = NETR_WS_FLAG_HANDLES_SPN_UPDATE
+ | NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS | 0x4;
+
+ /* Put the DNS hostname back */
+ talloc_free(discard_const_p(char, q1.dns_hostname));
+ q1.dns_hostname = talloc_asprintf(tctx, "%s.%s", TEST_MACHINE_NAME,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+
+ /* Checks "workstation flags" */
+ torture_assert(tctx,
+ info.domain_info->workstation_flags
+ == (NETR_WS_FLAG_HANDLES_SPN_UPDATE
+ | NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS),
+ "Out 'workstation flags' don't match!");
+
+ if (!torture_setting_bool(tctx, "dangerous", false)) {
+ torture_comment(tctx, "Not testing netr_LogonGetDomainInfo 8th call (no workstation info) - enable dangerous tests in order to do so\n");
+ } else {
+ /* Try a call without the workstation information structure */
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo 8th call (no workstation info)\n");
+ netlogon_creds_client_authenticator(creds, &a);
+
+ query.workstation_info = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonGetDomainInfo_r(b, tctx, &r),
+ "LogonGetDomainInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonGetDomainInfo failed");
+ torture_assert(tctx, netlogon_creds_client_check(creds, &a.cred), "Credential chaining failed");
+ }
+
+ return true;
+}
+
+static bool test_GetDomainInfo_async(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *machine_credentials)
+{
+ NTSTATUS status;
+ struct netr_LogonGetDomainInfo r;
+ struct netr_WorkstationInformation q1;
+ struct netr_Authenticator a;
+#define ASYNC_COUNT 100
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState *creds_async[ASYNC_COUNT];
+ struct tevent_req *req[ASYNC_COUNT];
+ int i;
+ union netr_WorkstationInfo query;
+ union netr_DomainInfo info;
+ struct dcerpc_pipe *p = NULL;
+
+ torture_comment(tctx, "Testing netr_LogonGetDomainInfo - async count %d\n", ASYNC_COUNT);
+
+ if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES,
+ machine_credentials, &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, machine_credentials, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+
+ ZERO_STRUCT(r);
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &a;
+ r.in.level = 1;
+ r.in.return_authenticator = &a;
+ r.in.query = &query;
+ r.out.return_authenticator = &a;
+ r.out.info = &info;
+
+ ZERO_STRUCT(q1);
+ q1.dns_hostname = talloc_asprintf(tctx, "%s.%s", TEST_MACHINE_NAME,
+ lpcfg_dnsdomain(tctx->lp_ctx));
+ q1.sitename = "Default-First-Site-Name";
+ q1.os_name.string = "UNIX/Linux or similar";
+
+ query.workstation_info = &q1;
+
+ for (i=0;i<ASYNC_COUNT;i++) {
+ netlogon_creds_client_authenticator(creds, &a);
+
+ creds_async[i] = (struct netlogon_creds_CredentialState *)talloc_memdup(creds, creds, sizeof(*creds));
+ req[i] = dcerpc_netr_LogonGetDomainInfo_r_send(tctx, tctx->ev, p->binding_handle, &r);
+
+ /* even with this flush per request a w2k3 server seems to
+ clag with multiple outstanding requests. bleergh. */
+ torture_assert_int_equal(tctx, tevent_loop_once(tctx->ev), 0,
+ "tevent_loop_once failed");
+ }
+
+ for (i=0;i<ASYNC_COUNT;i++) {
+ torture_assert_int_equal(tctx, tevent_req_poll(req[i], tctx->ev), true,
+ "tevent_req_poll() failed");
+
+ status = dcerpc_netr_LogonGetDomainInfo_r_recv(req[i], tctx);
+
+ torture_assert_ntstatus_ok(tctx, status, "netr_LogonGetDomainInfo_async");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "netr_LogonGetDomainInfo_async");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds_async[i], &a.cred),
+ "Credential chaining failed at async");
+ }
+
+ torture_comment(tctx,
+ "Testing netr_LogonGetDomainInfo - async count %d OK\n", ASYNC_COUNT);
+
+ return true;
+}
+
+static bool test_ManyGetDCName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct cli_credentials *anon_creds;
+ struct dcerpc_binding *binding2;
+ struct dcerpc_pipe *p2;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 o;
+ struct policy_handle lsa_handle;
+ struct lsa_DomainList domains;
+
+ struct lsa_EnumTrustDom t;
+ uint32_t resume_handle = 0;
+ struct netr_GetAnyDCName d;
+ const char *dcname = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_binding_handle *b2;
+
+ int i;
+
+ if (p->conn->transport.transport != NCACN_NP) {
+ torture_skip(tctx, "test_ManyGetDCName works only with NCACN_NP");
+ }
+
+ torture_comment(tctx, "Torturing GetDCName\n");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon failed");
+
+ binding2 = dcerpc_binding_dup(tctx, p->binding);
+ /* Swap the binding details from NETLOGON to LSA */
+ status = dcerpc_epm_map_binding(tctx, binding2, &ndr_table_lsarpc, tctx->ev, tctx->lp_ctx);
+ dcerpc_binding_set_assoc_group_id(binding2, 0);
+ torture_assert_ntstatus_ok(tctx, status, "epm map");
+
+ status = dcerpc_secondary_auth_connection(p, binding2, &ndr_table_lsarpc,
+ anon_creds, tctx->lp_ctx,
+ tctx, &p2);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
+ b2 = p2->binding_handle;
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ o.in.system_name = "\\";
+ o.in.attr = &attr;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.out.handle = &lsa_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenPolicy2_r(b2, tctx, &o),
+ "OpenPolicy2 failed");
+ torture_assert_ntstatus_ok(tctx, o.out.result, "OpenPolicy2 failed");
+
+ t.in.handle = &lsa_handle;
+ t.in.resume_handle = &resume_handle;
+ t.in.max_size = 1000;
+ t.out.domains = &domains;
+ t.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumTrustDom_r(b2, tctx, &t),
+ "EnumTrustDom failed");
+
+ if ((!NT_STATUS_IS_OK(t.out.result) &&
+ (!NT_STATUS_EQUAL(t.out.result, NT_STATUS_NO_MORE_ENTRIES))))
+ torture_fail(tctx, "Could not list domains");
+
+ talloc_free(p2);
+
+ d.in.logon_server = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ d.out.dcname = &dcname;
+
+ for (i=0; i<domains.count * 4; i++) {
+ struct lsa_DomainInfo *info =
+ &domains.domains[rand()%domains.count];
+
+ d.in.domainname = info->name.string;
+
+ status = dcerpc_netr_GetAnyDCName_r(b, tctx, &d);
+ torture_assert_ntstatus_ok(tctx, status, "GetAnyDCName");
+
+ torture_comment(tctx, "\tDC for domain %s is %s\n", info->name.string,
+ dcname ? dcname : "unknown");
+ }
+
+ return true;
+}
+
+static bool test_lsa_over_netlogon(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct cli_credentials *anon_creds;
+ const struct dcerpc_binding *binding2;
+ struct dcerpc_pipe *p2;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 o;
+ struct policy_handle lsa_handle;
+
+ struct dcerpc_binding_handle *b2;
+
+
+ if (p->conn->transport.transport != NCACN_NP) {
+ torture_skip(tctx, "test_lsa_over_netlogon works only with NCACN_NP");
+ }
+
+ torture_comment(tctx, "Testing if we can access the LSA server over\n"
+ " \\\\pipe\\netlogon rather than \\\\pipe\\lsarpc\n");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon failed");
+
+ binding2 = p->binding;
+
+ status = dcerpc_secondary_auth_connection(p, binding2, &ndr_table_lsarpc,
+ anon_creds, tctx->lp_ctx,
+ tctx, &p2);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
+ b2 = p2->binding_handle;
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ o.in.system_name = "\\";
+ o.in.attr = &attr;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.out.handle = &lsa_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenPolicy2_r(b2, tctx, &o),
+ "OpenPolicy2 failed");
+ torture_assert_ntstatus_ok(tctx, o.out.result, "OpenPolicy2 failed");
+
+ talloc_free(p2);
+
+ return true;
+}
+
+static bool test_SetPassword_with_flags(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t flags[] = { 0, NETLOGON_NEG_STRONG_KEYS };
+ struct netlogon_creds_CredentialState *creds;
+ int i;
+
+ if (!test_SetupCredentials2(p, tctx, 0,
+ machine_credentials,
+ cli_credentials_get_secure_channel_type(machine_credentials),
+ &creds)) {
+ torture_skip(tctx, "DC does not support negotiation of 64bit session keys");
+ }
+
+ for (i=0; i < ARRAY_SIZE(flags); i++) {
+ torture_assert(tctx,
+ test_SetPassword_flags(tctx, p, machine_credentials, flags[i]),
+ talloc_asprintf(tctx, "failed to test SetPassword negotiating with 0x%08x flags", flags[i]));
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "netlogon");
+ struct torture_rpc_tcase *tcase;
+ struct torture_test *test;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netlogon",
+ &ndr_table_netlogon, TEST_MACHINE_NAME);
+
+ torture_rpc_tcase_add_test_creds(tcase, "SetupCredentialsDowngrade", test_SetupCredentialsDowngrade);
+ torture_rpc_tcase_add_test(tcase, "lsa_over_netlogon", test_lsa_over_netlogon);
+
+ torture_rpc_tcase_add_test_creds(tcase, "GetForestTrustInformation", test_netr_GetForestTrustInformation);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerGetTrustInfo_AES", test_netr_ServerGetTrustInfo_AES);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerGetTrustInfo", test_netr_ServerGetTrustInfo);
+ torture_rpc_tcase_add_test(tcase, "DsRAddressToSitenamesExW", test_netr_DsRAddressToSitenamesExW);
+ torture_rpc_tcase_add_test(tcase, "DsRAddressToSitenamesW", test_netr_DsRAddressToSitenamesW);
+ torture_rpc_tcase_add_test(tcase, "DsrGetDcSiteCoverageW", test_netr_DsrGetDcSiteCoverageW);
+ torture_rpc_tcase_add_test(tcase, "DsRGetDCNameEx2", test_netr_DsRGetDCNameEx2);
+ torture_rpc_tcase_add_test(tcase, "DsRGetDCNameEx", test_netr_DsRGetDCNameEx);
+ torture_rpc_tcase_add_test(tcase, "DsRGetDCName", test_netr_DsRGetDCName);
+ test = torture_rpc_tcase_add_test_creds(tcase, "GetDomainInfo_async", test_GetDomainInfo_async);
+ test->dangerous = true;
+ torture_rpc_tcase_add_test(tcase, "NetrEnumerateTrustedDomainsEx", test_netr_NetrEnumerateTrustedDomainsEx);
+ torture_rpc_tcase_add_test(tcase, "NetrEnumerateTrustedDomains", test_netr_NetrEnumerateTrustedDomains);
+ torture_rpc_tcase_add_test(tcase, "DsrEnumerateDomainTrusts", test_DsrEnumerateDomainTrusts);
+ torture_rpc_tcase_add_test_creds(tcase, "DatabaseSync2", test_DatabaseSync2);
+ torture_rpc_tcase_add_test(tcase, "GetAnyDCName", test_GetAnyDCName);
+ torture_rpc_tcase_add_test(tcase, "ManyGetDCName", test_ManyGetDCName);
+ torture_rpc_tcase_add_test(tcase, "GetDcName", test_GetDcName);
+ torture_rpc_tcase_add_test_creds(tcase, "AccountSync", test_AccountSync);
+ torture_rpc_tcase_add_test_creds(tcase, "AccountDeltas", test_AccountDeltas);
+ torture_rpc_tcase_add_test_creds(tcase, "DatabaseRedo", test_DatabaseRedo);
+ torture_rpc_tcase_add_test_creds(tcase, "DatabaseDeltas", test_DatabaseDeltas);
+ torture_rpc_tcase_add_test_creds(tcase, "DatabaseSync", test_DatabaseSync);
+ torture_rpc_tcase_add_test_creds(tcase, "GetDomainInfo", test_GetDomainInfo);
+ torture_rpc_tcase_add_test_creds(tcase, "GetTrustPasswords", test_GetTrustPasswords);
+ torture_rpc_tcase_add_test_creds(tcase, "GetPassword", test_GetPassword);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword2_AES", test_SetPassword2_AES);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword2", test_SetPassword2);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword", test_SetPassword);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeReuse", test_ServerReqChallengeReuse);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeReuseGlobal4", test_ServerReqChallengeReuseGlobal4);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeReuseGlobal3", test_ServerReqChallengeReuseGlobal3);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeReuseGlobal2", test_ServerReqChallengeReuseGlobal2);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeReuseGlobal", test_ServerReqChallengeReuseGlobal);
+ torture_rpc_tcase_add_test_creds(tcase, "ServerReqChallengeGlobal", test_ServerReqChallengeGlobal);
+ torture_rpc_tcase_add_test_creds(tcase, "invalidAuthenticate2", test_invalidAuthenticate2);
+ torture_rpc_tcase_add_test_creds(tcase, "SamLogon", test_SamLogon);
+ torture_rpc_tcase_add_test(tcase, "LogonUasLogoff", test_LogonUasLogoff);
+ torture_rpc_tcase_add_test(tcase, "LogonUasLogon", test_LogonUasLogon);
+
+ torture_rpc_tcase_add_test(tcase, "Broken RPC binding handle",
+ test_netr_broken_binding_handle);
+
+ return suite;
+}
+
+struct torture_suite *torture_rpc_netlogon_s3(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "netlogon-s3");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netlogon",
+ &ndr_table_netlogon, TEST_MACHINE_NAME);
+
+ torture_rpc_tcase_add_test_creds(tcase, "SamLogon", test_SamLogon);
+ torture_rpc_tcase_add_test_creds(tcase, "SamLogon_NULL_domain", test_SamLogon_NULL_domain);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword", test_SetPassword);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword_with_flags", test_SetPassword_with_flags);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword2", test_SetPassword2);
+ torture_rpc_tcase_add_test_creds(tcase, "SetPassword2_AES", test_SetPassword2_AES);
+ torture_rpc_tcase_add_test(tcase, "NetrEnumerateTrustedDomains", test_netr_NetrEnumerateTrustedDomains);
+
+ return suite;
+}
+
+struct torture_suite *torture_rpc_netlogon_zerologon(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ mem_ctx,
+ "netlogon.zerologon");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(
+ suite,
+ "netlogon",
+ &ndr_table_netlogon,
+ TEST_MACHINE_NAME);
+
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "ServerReqChallenge",
+ test_ServerReqChallenge);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "ServerReqChallenge_zero_challenge",
+ test_ServerReqChallenge_zero_challenge);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "ServerReqChallenge_5_repeats",
+ test_ServerReqChallenge_5_repeats);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "ServerReqChallenge_4_repeats",
+ test_ServerReqChallenge_4_repeats);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "test_SetPassword2_encrypted_to_all_zeros",
+ test_SetPassword2_encrypted_to_all_zeros);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "test_SetPassword2_password_encrypts_to_zero",
+ test_SetPassword2_password_encrypts_to_zero);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "test_SetPassword2_confounder",
+ test_SetPassword2_confounder);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "test_SetPassword2_all_zeros",
+ test_SetPassword2_all_zeros);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "test_SetPassword2_all_zero_password",
+ test_SetPassword2_all_zero_password);
+ torture_rpc_tcase_add_test_creds(
+ tcase,
+ "test_SetPassword2_maximum_length_password",
+ test_SetPassword2_maximum_length_password);
+
+ return suite;
+}
+
+struct torture_suite *torture_rpc_netlogon_admin(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "netlogon.admin");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "bdc",
+ &ndr_table_netlogon, TEST_MACHINE_NAME);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl", test_LogonControl);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl2", test_LogonControl2);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl2Ex", test_LogonControl2Ex);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "wkst",
+ &ndr_table_netlogon, TEST_MACHINE_NAME);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl", test_LogonControl);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl2", test_LogonControl2);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl2Ex", test_LogonControl2Ex);
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "admin",
+ &ndr_table_netlogon);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl", test_LogonControl);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl2", test_LogonControl2);
+ torture_rpc_tcase_add_test_creds(tcase, "LogonControl2Ex", test_LogonControl2Ex);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/netlogon.h b/source4/torture/rpc/netlogon.h
new file mode 100644
index 0000000..a4ab8f0
--- /dev/null
+++ b/source4/torture/rpc/netlogon.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+bool test_SetupCredentials2(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ int sec_chan_type,
+ struct netlogon_creds_CredentialState **creds_out);
+
+bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState **creds_out);
+
+bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1,
+ struct torture_context *tctx,
+ struct cli_credentials *machine_credentials,
+ struct netlogon_creds_CredentialState *creds,
+ uint32_t additional_flags,
+ struct dcerpc_pipe **_p2);
diff --git a/source4/torture/rpc/netlogon_crypto.c b/source4/torture/rpc/netlogon_crypto.c
new file mode 100644
index 0000000..8584460
--- /dev/null
+++ b/source4/torture/rpc/netlogon_crypto.c
@@ -0,0 +1,274 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for netlogon rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Matthias Dieter Wallnöfer 2009-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/replace/system/network.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "param/param.h"
+#include "lib/param/loadparm.h"
+#include "libcli/security/security.h"
+
+#undef strcasecmp
+
+#define TEST_MACHINE_NAME "torturetest"
+
+static bool test_ServerAuth3Crypto(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ uint32_t negotiate_flags,
+ struct cli_credentials *machine_credentials,
+ bool force_client_rc4)
+{
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate3 a;
+ struct netr_Credential netr_creds1 = {
+ .data = {0},
+ };
+ struct netr_Credential netr_creds2 = {
+ .data = {0},
+ };
+ struct netr_Credential netr_creds3 = {
+ .data = {0},
+ };
+ struct netlogon_creds_CredentialState *creds_state = NULL;
+ struct samr_Password machine_password = {
+ .hash = {0},
+ };
+ const char *machine_name = NULL;
+ const char *plain_pass = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ uint32_t rid = 0;
+ NTSTATUS status;
+ bool weak_crypto_allowed =
+ (lpcfg_weak_crypto(tctx->lp_ctx) ==
+ SAMBA_WEAK_CRYPTO_ALLOWED);
+
+ if (p == NULL) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(a);
+
+ torture_comment(tctx, "client negotiate_flags=0x%08x\n", negotiate_flags);
+
+ machine_name = cli_credentials_get_workstation(machine_credentials);
+ torture_assert_not_null(tctx, machine_name, "machine name is not set");
+
+ plain_pass = cli_credentials_get_password(machine_credentials);
+ torture_assert_not_null(tctx, plain_pass, "plain_pass is not set");
+
+
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+ r.in.server_name = NULL;
+ r.in.computer_name = machine_name;
+ r.in.credentials = &netr_creds1;
+ r.out.return_credentials = &netr_creds2;
+
+ netlogon_creds_random_challenge(&netr_creds1);
+
+ status = dcerpc_netr_ServerReqChallenge_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx,
+ r.out.result,
+ "ServerReqChallenge failed");
+
+ E_md4hash(plain_pass, machine_password.hash);
+
+ a.in.server_name = NULL;
+ a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+ a.in.secure_channel_type =
+ cli_credentials_get_secure_channel_type(machine_credentials);
+ a.in.computer_name = machine_name;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &netr_creds3;
+ a.out.return_credentials = &netr_creds3;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.out.rid = &rid;
+
+ if (force_client_rc4) {
+ GNUTLS_FIPS140_SET_LAX_MODE();
+ }
+ creds_state = netlogon_creds_client_init(tctx,
+ a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ &netr_creds1,
+ &netr_creds2,
+ &machine_password,
+ &netr_creds3,
+ negotiate_flags);
+ GNUTLS_FIPS140_SET_STRICT_MODE();
+ /* Test that we fail to encrypt with RC4 */
+ if (creds_state == NULL &&
+ !weak_crypto_allowed && !force_client_rc4 &&
+ (negotiate_flags & NETLOGON_NEG_ARCFOUR)) {
+ return false;
+ }
+ torture_assert_not_null(tctx,
+ creds_state,
+ "Failed init netlogon client creds");
+
+
+ torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+ status = dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "ServerAuthenticate3 failed");
+
+ /* Check that the server denies RC4 */
+ if (!NT_STATUS_IS_OK(a.out.result) &&
+ !weak_crypto_allowed &&
+ force_client_rc4) {
+ torture_assert_ntstatus_equal(tctx,
+ a.out.result,
+ NT_STATUS_DOWNGRADE_DETECTED,
+ "Unexpected status code");
+ return false;
+ }
+ torture_assert_ntstatus_ok(tctx,
+ a.out.result,
+ "ServerAuthenticate3 failed");
+ torture_assert(tctx,
+ netlogon_creds_client_check(creds_state, &netr_creds3),
+ "Credential chaining failed");
+
+ torture_comment(tctx,
+ "server negotiate_flags=0x%08x\n",
+ negotiate_flags);
+
+ if (!weak_crypto_allowed) {
+ torture_assert(tctx,
+ (negotiate_flags & NETLOGON_NEG_ARCFOUR) == 0,
+ "Server should not announce RC4 support");
+ }
+
+ /* Prove that requesting a challenge again won't break it */
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+ "ServerReqChallenge failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+ return true;
+}
+
+
+/* Test that we can successfully authenticate using AES. */
+static bool test_AES_Crypto(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t negotiate_flags =
+ NETLOGON_NEG_AUTH2_ADS_FLAGS|
+ NETLOGON_NEG_SUPPORTS_AES;
+ bool ok;
+
+ ok = test_ServerAuth3Crypto(p,
+ tctx,
+ negotiate_flags,
+ machine_credentials,
+ false);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+/* If we try to use RC4, the client code should fail to encrypt. */
+static bool test_RC4_Crypto_Fail(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t negotiate_flags =
+ NETLOGON_NEG_AUTH2_ADS_FLAGS|
+ NETLOGON_NEG_ARCFOUR;
+ bool ok;
+
+ ok = test_ServerAuth3Crypto(p,
+ tctx,
+ negotiate_flags,
+ machine_credentials,
+ false);
+ if (!ok) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Enforce the use of RC4 and try to authenticate. The server should fail
+ * in this case as it doesn't allow RC4
+ */
+static bool test_RC4_Crypto_Force(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ uint32_t negotiate_flags =
+ NETLOGON_NEG_AUTH2_ADS_FLAGS|
+ NETLOGON_NEG_ARCFOUR;
+ bool ok;
+
+ ok = test_ServerAuth3Crypto(p,
+ tctx,
+ negotiate_flags,
+ machine_credentials,
+ true);
+ if (!ok) {
+ return true;
+ }
+
+ return false;
+}
+
+struct torture_suite *torture_rpc_netlogon_crypto_fips(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx,
+ "fips.netlogon.crypto");
+ struct torture_rpc_tcase *tcase = NULL;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite,
+ "netlogon",
+ &ndr_table_netlogon,
+ TEST_MACHINE_NAME);
+
+ torture_rpc_tcase_add_test_creds(tcase,
+ "test_AES_Crytpo",
+ test_AES_Crypto);
+ torture_rpc_tcase_add_test_creds(tcase,
+ "test_RC4_Crytpo_Fail",
+ test_RC4_Crypto_Fail);
+ torture_rpc_tcase_add_test_creds(tcase,
+ "test_RC4_Crytpo_Force",
+ test_RC4_Crypto_Force);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/ntsvcs.c b/source4/torture/rpc/ntsvcs.c
new file mode 100644
index 0000000..a25129d
--- /dev/null
+++ b/source4/torture/rpc/ntsvcs.c
@@ -0,0 +1,189 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for rpc ntsvcs operations
+
+ Copyright (C) Guenther Deschner 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_ntsvcs_c.h"
+
+static bool test_PNP_GetVersion(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ struct PNP_GetVersion r;
+ uint16_t version = 0;
+
+ r.out.version = &version;
+
+ status = dcerpc_PNP_GetVersion_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "PNP_GetVersion");
+ torture_assert_werr_ok(tctx, r.out.result, "PNP_GetVersion");
+ torture_assert_int_equal(tctx, version, 0x400, "invalid version");
+
+ return true;
+}
+
+static bool test_PNP_GetDeviceListSize(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct PNP_GetDeviceListSize r;
+ uint32_t size = 0;
+
+ r.in.devicename = NULL;
+ r.in.flags = CM_GETIDLIST_FILTER_SERVICE;
+ r.out.size = &size;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_PNP_GetDeviceListSize_r(b, tctx, &r),
+ "PNP_GetDeviceListSize");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_CM_INVALID_POINTER,
+ "PNP_GetDeviceListSize");
+
+ r.in.devicename = "Spooler";
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_PNP_GetDeviceListSize_r(b, tctx, &r),
+ "PNP_GetDeviceListSize");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "PNP_GetDeviceListSize");
+
+ return true;
+}
+
+static bool test_PNP_GetDeviceList(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct PNP_GetDeviceList r;
+ uint16_t *buffer = NULL;
+ uint32_t length = 0;
+
+ buffer = talloc_array(tctx, uint16_t, 0);
+
+ r.in.filter = NULL;
+ r.in.flags = CM_GETIDLIST_FILTER_SERVICE;
+ r.in.length = &length;
+ r.out.length = &length;
+ r.out.buffer = buffer;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_PNP_GetDeviceList_r(b, tctx, &r),
+ "PNP_GetDeviceList failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_CM_INVALID_POINTER,
+ "PNP_GetDeviceList failed");
+
+ r.in.filter = "Spooler";
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_PNP_GetDeviceList_r(b, tctx, &r),
+ "PNP_GetDeviceList failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_CM_BUFFER_SMALL)) {
+ struct PNP_GetDeviceListSize s;
+
+ s.in.devicename = "Spooler";
+ s.in.flags = CM_GETIDLIST_FILTER_SERVICE;
+ s.out.size = &length;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_PNP_GetDeviceListSize_r(b, tctx, &s),
+ "PNP_GetDeviceListSize failed");
+ torture_assert_werr_ok(tctx, s.out.result,
+ "PNP_GetDeviceListSize failed");
+ }
+
+ buffer = talloc_array(tctx, uint16_t, length);
+
+ r.in.length = &length;
+ r.out.length = &length;
+ r.out.buffer = buffer;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_PNP_GetDeviceList_r(b, tctx, &r),
+ "PNP_GetDeviceList failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "PNP_GetDeviceList failed");
+
+ return true;
+}
+
+static bool test_PNP_GetDeviceRegProp(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ struct PNP_GetDeviceRegProp r;
+
+ enum winreg_Type reg_data_type = REG_NONE;
+ uint32_t buffer_size = 0;
+ uint32_t needed = 0;
+ uint8_t *buffer;
+
+ buffer = talloc(tctx, uint8_t);
+
+ r.in.devicepath = "ACPI\\ACPI0003\\1";
+ r.in.property = DEV_REGPROP_DESC;
+ r.in.flags = 0;
+ r.in.reg_data_type = &reg_data_type;
+ r.in.buffer_size = &buffer_size;
+ r.in.needed = &needed;
+ r.out.buffer = buffer;
+ r.out.reg_data_type = &reg_data_type;
+ r.out.buffer_size = &buffer_size;
+ r.out.needed = &needed;
+
+ status = dcerpc_PNP_GetDeviceRegProp_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "PNP_GetDeviceRegProp");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_CM_BUFFER_SMALL)) {
+
+ buffer = talloc_array(tctx, uint8_t, needed);
+ r.in.buffer_size = &needed;
+
+ status = dcerpc_PNP_GetDeviceRegProp_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "PNP_GetDeviceRegProp");
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_ntsvcs(TALLOC_CTX *mem_ctx)
+{
+ struct torture_rpc_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "ntsvcs");
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "ntsvcs",
+ &ndr_table_ntsvcs);
+
+ torture_rpc_tcase_add_test(tcase, "PNP_GetDeviceRegProp",
+ test_PNP_GetDeviceRegProp);
+ torture_rpc_tcase_add_test(tcase, "PNP_GetDeviceList",
+ test_PNP_GetDeviceList);
+ torture_rpc_tcase_add_test(tcase, "PNP_GetDeviceListSize",
+ test_PNP_GetDeviceListSize);
+ torture_rpc_tcase_add_test(tcase, "PNP_GetVersion",
+ test_PNP_GetVersion);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/object_uuid.c b/source4/torture/rpc/object_uuid.c
new file mode 100644
index 0000000..2209954
--- /dev/null
+++ b/source4/torture/rpc/object_uuid.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for behaviour of object uuids in rpc requests
+
+ Copyright (C) Stefan Metzmacher 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_dssetup.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "torture/rpc/torture_rpc.h"
+
+/*
+ this tests the send object uuids in the dcerpc request
+*/
+
+static bool test_random_uuid(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p1, *p2;
+ struct GUID uuid;
+ struct dssetup_DsRoleGetPrimaryDomainInformation r1;
+ struct lsa_GetUserName r2;
+ struct lsa_String *authority_name_p = NULL;
+ struct lsa_String *account_name_p = NULL;
+
+ torture_comment(torture, "RPC-OBJECTUUID-RANDOM\n");
+
+ status = torture_rpc_connection(torture, &p1, &ndr_table_dssetup);
+ torture_assert_ntstatus_ok(torture, status, "opening dsetup pipe1");
+
+ status = torture_rpc_connection(torture, &p2, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(torture, status, "opening lsa pipe1");
+
+ uuid = GUID_random();
+
+ r1.in.level = DS_ROLE_BASIC_INFORMATION;
+ status = dcerpc_binding_handle_call(p1->binding_handle,
+ &uuid,
+ &ndr_table_dssetup,
+ NDR_DSSETUP_DSROLEGETPRIMARYDOMAININFORMATION,
+ torture, &r1);
+ torture_assert_ntstatus_ok(torture, status, "DsRoleGetPrimaryDomainInformation failed");
+ torture_assert_werr_ok(torture, r1.out.result, "DsRoleGetPrimaryDomainInformation failed");
+
+ uuid = GUID_random();
+
+ r2.in.system_name = "\\";
+ r2.in.account_name = &account_name_p;
+ r2.in.authority_name = &authority_name_p;
+ r2.out.account_name = &account_name_p;
+ r2.out.authority_name = &authority_name_p;
+
+ status = dcerpc_binding_handle_call(p2->binding_handle,
+ &uuid,
+ &ndr_table_lsarpc,
+ NDR_LSA_GETUSERNAME,
+ torture, &r2);
+ torture_assert_ntstatus_ok(torture, status, "lsaClose failed");
+ torture_assert_ntstatus_ok(torture, r2.out.result, "lsaClose failed");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_object_uuid(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ suite = torture_suite_create(mem_ctx, "objectuuid");
+ torture_suite_add_simple_test(suite, "random-uuid", test_random_uuid);
+ return suite;
+}
diff --git a/source4/torture/rpc/remote_pac.c b/source4/torture/rpc/remote_pac.c
new file mode 100644
index 0000000..8f4ee2b
--- /dev/null
+++ b/source4/torture/rpc/remote_pac.c
@@ -0,0 +1,1425 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for netlogon PAC operations
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "auth/auth.h"
+#include "auth/auth_sam_reply.h"
+#include "auth/gensec/gensec.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_krb5pac.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include <ldb.h>
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+
+#define TEST_MACHINE_NAME_BDC "torturepacbdc"
+#define TEST_MACHINE_NAME_WKSTA "torturepacwksta"
+#define TEST_MACHINE_NAME_S4U2SELF_BDC "tests4u2selfbdc"
+#define TEST_MACHINE_NAME_S4U2SELF_WKSTA "tests4u2selfwk"
+#define TEST_MACHINE_NAME_S4U2PROXY_WKSTA "tests4u2proxywk"
+
+struct pac_data {
+ DATA_BLOB pac_blob;
+ struct PAC_SIGNATURE_DATA *pac_srv_sig;
+ struct PAC_SIGNATURE_DATA *pac_kdc_sig;
+};
+
+/* A helper function which avoids touching the local databases to
+ * generate the session info, as we just want to verify the PAC
+ * details, not the full local token */
+static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ DATA_BLOB *pac_blob,
+ const char *principal_name,
+ const struct tsocket_address *remote_address,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS nt_status;
+ struct auth_user_info_dc *user_info_dc;
+ TALLOC_CTX *tmp_ctx;
+ struct pac_data *pac_data;
+
+ if (pac_blob == NULL) {
+ DBG_ERR("pac_blob missing\n");
+ return NT_STATUS_NO_IMPERSONATION_TOKEN;
+ }
+
+ tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data);
+
+ pac_data->pac_blob = data_blob_dup_talloc(pac_data, *pac_blob);
+ if (pac_data->pac_blob.length != pac_blob->length) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pac_data->pac_srv_sig = talloc(tmp_ctx, struct PAC_SIGNATURE_DATA);
+ if (!pac_data->pac_srv_sig) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ pac_data->pac_kdc_sig = talloc(tmp_ctx, struct PAC_SIGNATURE_DATA);
+ if (!pac_data->pac_kdc_sig) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
+ *pac_blob,
+ smb_krb5_context->krb5_context,
+ &user_info_dc,
+ pac_data->pac_srv_sig,
+ pac_data->pac_kdc_sig);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ talloc_steal(pac_data, pac_data->pac_srv_sig);
+ talloc_steal(pac_data, pac_data->pac_kdc_sig);
+
+ if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
+ session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+ }
+
+ session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
+ nt_status = auth_generate_session_info(mem_ctx,
+ NULL,
+ NULL,
+ user_info_dc, session_info_flags,
+ session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ talloc_free(tmp_ctx);
+ return nt_status;
+}
+
+/* Check to see if we can pass the PAC across to the NETLOGON server for validation */
+
+static const struct PAC_BUFFER *get_pac_buffer(const struct PAC_DATA *pac_data,
+ enum PAC_TYPE type)
+{
+ const struct PAC_BUFFER *pac_buf = NULL;
+ uint32_t i;
+
+ for (i = 0; i < pac_data->num_buffers; ++i) {
+ pac_buf = &pac_data->buffers[i];
+
+ if (pac_buf->type == type) {
+ break;
+ }
+ }
+
+ return pac_buf;
+}
+
+/* Also happens to be a really good one-step verification of our Kerberos stack */
+
+static bool netlogon_validate_pac(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *server_creds,
+ enum netr_SchannelType secure_channel_type,
+ const char *test_machine_name,
+ uint32_t negotiate_flags,
+ struct pac_data *pac_data,
+ struct auth_session_info *session_info);
+
+static bool test_PACVerify(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials,
+ enum netr_SchannelType secure_channel_type,
+ const char *test_machine_name,
+ uint32_t negotiate_flags)
+{
+ NTSTATUS status;
+ bool ok;
+ const char *pkinit_ccache = torture_setting_string(tctx, "pkinit_ccache", NULL);
+ bool pkinit_in_use = pkinit_ccache != NULL;
+ bool expect_pac_upn_dns_info = torture_setting_bool(tctx, "expect_pac_upn_dns_info", true);
+ size_t num_pac_buffers;
+ struct gensec_security *gensec_client_context;
+ struct gensec_security *gensec_server_context;
+ struct cli_credentials *client_creds;
+ struct cli_credentials *server_creds;
+
+ DATA_BLOB client_to_server, server_to_client;
+ struct PAC_DATA pac_data_struct;
+ enum ndr_err_code ndr_err;
+
+ struct auth4_context *auth_context;
+ struct auth_session_info *session_info;
+ struct pac_data *pac_data;
+ const struct PAC_BUFFER *pac_buf = NULL;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
+
+ torture_comment(tctx,
+ "Testing PAC Verify (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
+ secure_channel_type, test_machine_name, negotiate_flags);
+
+ if (pkinit_in_use) {
+ struct cli_credentials *tmp_creds = NULL;
+ const char *error_string = NULL;
+ int rc;
+
+ torture_comment(tctx,
+ "Using pkinit_ccache=%s\n",
+ pkinit_ccache);
+
+ tmp_creds = cli_credentials_init(tctx);
+ torture_assert(tctx, tmp_creds, "Failed to create credentials");
+
+ rc = cli_credentials_set_ccache(tmp_creds,
+ tctx->lp_ctx,
+ pkinit_ccache,
+ CRED_SPECIFIED,
+ &error_string);
+ torture_assert_int_equal(tctx,
+ rc,
+ 0,
+ "cli_credentials_set_ccache failed");
+ cli_credentials_set_kerberos_state(tmp_creds,
+ CRED_USE_KERBEROS_REQUIRED,
+ CRED_SPECIFIED);
+
+ /*
+ * Copy the credentials in order to use a different MEMORY krb5
+ * ccache for each client/server setup. The MEMORY cache
+ * identifier is a pointer to the creds container. If we copy
+ * it the pointer changes and we will get a new clean memory
+ * cache.
+ */
+ client_creds =
+ cli_credentials_shallow_copy(tmp_ctx, tmp_creds);
+ torture_assert(tctx,
+ client_creds,
+ "Failed to copy of credentials");
+ } else {
+ /*
+ * Copy the credentials in order to use a different MEMORY krb5
+ * ccache for each client/server setup. The MEMORY cache
+ * identifier is a pointer to the creds container. If we copy
+ * it the pointer changes and we will get a new clean memory
+ * cache.
+ */
+ client_creds =
+ cli_credentials_shallow_copy(tmp_ctx,
+ samba_cmdline_get_creds());
+ torture_assert(tctx,
+ client_creds,
+ "Failed to copy of credentials");
+ cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED);
+ }
+
+
+ server_creds = cli_credentials_shallow_copy(tmp_ctx,
+ credentials);
+ torture_assert(tctx, server_creds, "Failed to copy of credentials");
+
+ auth_context = talloc_zero(tmp_ctx, struct auth4_context);
+ torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
+
+ auth_context->generate_session_info_pac = test_generate_session_info_pac;
+
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
+
+ status = gensec_set_credentials(gensec_client_context, client_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ status = gensec_server_start(tctx,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ auth_context, &gensec_server_context);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+ status = gensec_set_credentials(gensec_server_context, server_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ do {
+ /* Do a client-server update dance */
+ status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ } while (1);
+
+ /* Extract the PAC using Samba's code */
+
+ status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+ pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
+
+ torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context");
+ torture_assert(tctx, pac_data->pac_srv_sig != NULL, "pac_srv_sig not present");
+ torture_assert(tctx, pac_data->pac_kdc_sig != NULL, "pac_kdc_sig not present");
+
+ ndr_err = ndr_pull_struct_blob(&pac_data->pac_blob, tmp_ctx, &pac_data_struct,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
+
+ num_pac_buffers = 7;
+ if (expect_pac_upn_dns_info) {
+ num_pac_buffers += 1;
+ }
+ if (pkinit_in_use) {
+ num_pac_buffers += 1;
+ }
+
+ torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
+ torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_INFO");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_LOGON_INFO info");
+
+ if (pkinit_in_use) {
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CREDENTIAL_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CREDENTIAL_INFO");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_CREDENTIAL_INFO info");
+ }
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_NAME);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_NAME");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_LOGON_NAME info");
+
+ if (expect_pac_upn_dns_info) {
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_UPN_DNS_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_UPN_DNS_INFO");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_UPN_DNS_INFO info");
+ }
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_SRV_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_SRV_CHECKSUM");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_SRV_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_KDC_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_KDC_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_TICKET_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_TICKET_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_FULL_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_FULL_CHECKSUM");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_FULL_CHECKSUM info");
+
+ ok = netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
+ negotiate_flags, pac_data, session_info);
+
+ talloc_free(tmp_ctx);
+
+ return ok;
+}
+
+static bool netlogon_validate_pac(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *server_creds,
+ enum netr_SchannelType secure_channel_type,
+ const char *test_machine_name,
+ uint32_t negotiate_flags,
+ struct pac_data *pac_data,
+ struct auth_session_info *session_info)
+{
+ struct PAC_Validate pac_wrapped_struct;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ struct netr_Authenticator return_authenticator;
+ struct netr_Authenticator auth, auth2;
+ struct netr_GenericInfo generic;
+ struct netr_LogonSamLogon r;
+ union netr_Validation validation;
+ union netr_LogonLevel logon;
+ uint8_t authoritative;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB payload, pac_wrapped;
+
+ if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
+ server_creds, secure_channel_type,
+ &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
+ pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
+ pac_wrapped_struct.SignatureLength = pac_data->pac_kdc_sig->signature.length;
+ pac_wrapped_struct.ChecksumAndSignature = payload
+ = data_blob_talloc(tctx, NULL,
+ pac_wrapped_struct.ChecksumLength
+ + pac_wrapped_struct.SignatureLength);
+ memcpy(&payload.data[0],
+ pac_data->pac_srv_sig->signature.data,
+ pac_wrapped_struct.ChecksumLength);
+ memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
+ pac_data->pac_kdc_sig->signature.data,
+ pac_wrapped_struct.SignatureLength);
+
+ ndr_err = ndr_push_struct_blob(&pac_wrapped, tctx, &pac_wrapped_struct,
+ (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");
+
+ torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, pac_wrapped.data, pac_wrapped.length);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);
+ }
+
+ generic.length = pac_wrapped.length;
+ generic.data = pac_wrapped.data;
+
+ /* Validate it over the netlogon pipe */
+
+ generic.identity_info.parameter_control = 0;
+ generic.identity_info.logon_id = 0;
+ generic.identity_info.domain_name.string = session_info->info->domain_name;
+ generic.identity_info.account_name.string = session_info->info->account_name;
+ generic.identity_info.workstation.string = test_machine_name;
+
+ generic.package_name.string = "Kerberos";
+
+ logon.generic = &generic;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon = &logon;
+ r.in.logon_level = NetlogonGenericInformation;
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
+ r.in.validation_level = NetlogonValidationGenericInfo2;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+ r.out.return_authenticator = &return_authenticator;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
+
+ /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */
+ generic.data[generic.length-1]++;
+
+ logon.generic = &generic;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonGenericInformation;
+ r.in.logon = &logon;
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
+ r.in.validation_level = NetlogonValidationGenericInfo2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */
+ generic.length--;
+
+ logon.generic = &generic;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonGenericInformation;
+ r.in.logon = &logon;
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
+ r.in.validation_level = NetlogonValidationGenericInfo2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
+ pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
+
+ /* Break the SignatureType */
+ pac_wrapped_struct.SignatureType++;
+
+ pac_wrapped_struct.SignatureLength = pac_data->pac_kdc_sig->signature.length;
+ pac_wrapped_struct.ChecksumAndSignature = payload
+ = data_blob_talloc(tctx, NULL,
+ pac_wrapped_struct.ChecksumLength
+ + pac_wrapped_struct.SignatureLength);
+ memcpy(&payload.data[0],
+ pac_data->pac_srv_sig->signature.data,
+ pac_wrapped_struct.ChecksumLength);
+ memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
+ pac_data->pac_kdc_sig->signature.data,
+ pac_wrapped_struct.SignatureLength);
+
+ ndr_err = ndr_push_struct_blob(&pac_wrapped, tctx, &pac_wrapped_struct,
+ (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");
+
+ torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, pac_wrapped.data, pac_wrapped.length);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);
+ }
+
+ generic.length = pac_wrapped.length;
+ generic.data = pac_wrapped.data;
+
+ logon.generic = &generic;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonGenericInformation;
+ r.in.logon = &logon;
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
+ r.in.validation_level = NetlogonValidationGenericInfo2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ pac_wrapped_struct.ChecksumLength = pac_data->pac_srv_sig->signature.length;
+ pac_wrapped_struct.SignatureType = pac_data->pac_kdc_sig->type;
+ pac_wrapped_struct.SignatureLength = pac_data->pac_kdc_sig->signature.length;
+
+ pac_wrapped_struct.ChecksumAndSignature = payload
+ = data_blob_talloc(tctx, NULL,
+ pac_wrapped_struct.ChecksumLength
+ + pac_wrapped_struct.SignatureLength);
+ memcpy(&payload.data[0],
+ pac_data->pac_srv_sig->signature.data,
+ pac_wrapped_struct.ChecksumLength);
+ memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
+ pac_data->pac_kdc_sig->signature.data,
+ pac_wrapped_struct.SignatureLength);
+
+ /* Break the signature length */
+ pac_wrapped_struct.SignatureLength++;
+
+ ndr_err = ndr_push_struct_blob(&pac_wrapped, tctx, &pac_wrapped_struct,
+ (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");
+
+ torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, pac_wrapped.data, pac_wrapped.length);
+ } else {
+ netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);
+ }
+
+ generic.length = pac_wrapped.length;
+ generic.data = pac_wrapped.data;
+
+ logon.generic = &generic;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonGenericInformation;
+ r.in.logon = &logon;
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
+ r.in.validation_level = NetlogonValidationGenericInfo2;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogon_r(b, tctx, &r),
+ "LogonSamLogon failed");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ return true;
+}
+
+static bool test_PACVerify_bdc_arcfour(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_PACVerify(tctx, p, credentials, SEC_CHAN_BDC,
+ TEST_MACHINE_NAME_BDC,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_PACVerify_bdc_aes(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_PACVerify(tctx, p, credentials, SEC_CHAN_BDC,
+ TEST_MACHINE_NAME_BDC,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+
+static bool test_PACVerify_workstation_arcfour(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_PACVerify(tctx, p, credentials, SEC_CHAN_WKSTA,
+ TEST_MACHINE_NAME_WKSTA,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_PACVerify_workstation_aes(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_PACVerify(tctx, p, credentials, SEC_CHAN_WKSTA,
+ TEST_MACHINE_NAME_WKSTA,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+
+#ifdef SAMBA4_USES_HEIMDAL
+static NTSTATUS check_primary_group_in_validation(TALLOC_CTX *mem_ctx,
+ uint16_t validation_level,
+ const union netr_Validation *validation)
+{
+ const struct netr_SamBaseInfo *base = NULL;
+ int i;
+ switch (validation_level) {
+ case 2:
+ if (!validation || !validation->sam2) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ base = &validation->sam2->base;
+ break;
+ case 3:
+ if (!validation || !validation->sam3) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ base = &validation->sam3->base;
+ break;
+ case 6:
+ if (!validation || !validation->sam6) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ base = &validation->sam6->base;
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ for (i = 0; i < base->groups.count; i++) {
+ if (base->groups.rids[i].rid == base->primary_gid) {
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/* Check various ways to get the PAC, in particular check the group membership and
+ * other details between the PAC from a normal kinit, S4U2Self and a SamLogon */
+static bool test_S4U2Self(struct torture_context *tctx,
+ struct dcerpc_pipe *p1,
+ struct cli_credentials *credentials,
+ enum netr_SchannelType secure_channel_type,
+ const char *test_machine_name,
+ uint32_t negotiate_flags)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_binding_handle *b = NULL;
+
+ struct netr_LogonSamLogon r;
+
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative;
+
+ struct netr_Authenticator auth, auth2;
+
+ DATA_BLOB client_to_server, server_to_client;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct gensec_security *gensec_client_context;
+ struct gensec_security *gensec_server_context;
+ struct cli_credentials *client_creds;
+ struct cli_credentials *server_creds;
+
+ struct auth4_context *auth_context;
+ struct auth_session_info *kinit_session_info;
+ struct auth_session_info *s4u2self_session_info;
+ struct auth_user_info_dc *netlogon_user_info_dc;
+
+ struct netr_NetworkInfo ninfo = {};
+ DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+ size_t i;
+ size_t j;
+ size_t k;
+ int flags = CLI_CRED_NTLMv2_AUTH;
+
+ struct dom_sid *builtin_domain;
+
+ struct dom_sid *ai_auth_authority = NULL;
+ struct dom_sid *ai_service = NULL;
+ struct dom_sid *ai_claims_valid = NULL;
+ size_t ai_auth_authority_count = 0;
+ size_t ai_service_count = 0;
+ size_t ai_claims_valid_count = 0;
+ size_t kinit_asserted_identity_index = 0;
+ size_t kinit_claims_valid_index = 0;
+ size_t s4u2self_asserted_identity_index = 0;
+ size_t s4u2self_claims_valid_index = 0;
+ bool ok;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+
+ torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
+
+ torture_comment(tctx,
+ "Testing S4U2SELF (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
+ secure_channel_type, test_machine_name, negotiate_flags);
+
+ /*
+ * Copy the credentials in order to use a different MEMORY krb5 ccache
+ * for each client/server setup. The MEMORY cache identifier is a
+ * pointer to the creds container. If we copy it the pointer changes and
+ * we will get a new clean memory cache.
+ */
+ client_creds = cli_credentials_shallow_copy(tmp_ctx,
+ samba_cmdline_get_creds());
+ torture_assert(tctx, client_creds, "Failed to copy of credentials");
+ /* We use cli_credentials_get_ntlm_response(), so relax krb5 requirements. */
+ cli_credentials_set_kerberos_state(client_creds,
+ CRED_USE_KERBEROS_DESIRED,
+ CRED_SPECIFIED);
+
+ server_creds = cli_credentials_shallow_copy(tmp_ctx,
+ credentials);
+ torture_assert(tctx, server_creds, "Failed to copy of credentials");
+
+ if (!test_SetupCredentials2(p1, tctx, negotiate_flags,
+ server_creds, secure_channel_type,
+ &creds)) {
+ return false;
+ }
+ if (!test_SetupCredentialsPipe(p1, tctx, server_creds, creds,
+ DCERPC_SIGN | DCERPC_SEAL, &p)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ auth_context = talloc_zero(tmp_ctx, struct auth4_context);
+ torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
+
+ auth_context->generate_session_info_pac = test_generate_session_info_pac;
+
+ /* First, do a normal Kerberos connection */
+
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
+
+ status = gensec_set_credentials(gensec_client_context, client_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ status = gensec_server_start(tctx,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ auth_context, &gensec_server_context);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+ status = gensec_set_credentials(gensec_server_context, server_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ do {
+ /* Do a client-server update dance */
+ status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ } while (1);
+
+ /* Extract the PAC using Samba's code */
+
+ status = gensec_session_info(gensec_server_context, gensec_server_context, &kinit_session_info);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+
+ /* Now do the dance with S4U2Self */
+
+ /* Wipe out any existing ccache */
+ cli_credentials_invalidate_ccache(client_creds, CRED_SPECIFIED);
+ cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
+ cli_credentials_set_impersonate_principal(server_creds,
+ cli_credentials_get_principal(client_creds, tmp_ctx),
+ talloc_asprintf(tmp_ctx, "host/%s", test_machine_name));
+
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ status = gensec_set_target_hostname(gensec_client_context, test_machine_name);
+
+ /* We now set the same credentials on both client and server contexts */
+ status = gensec_set_credentials(gensec_client_context, server_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ status = gensec_server_start(tctx,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ auth_context, &gensec_server_context);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+ status = gensec_set_credentials(gensec_server_context, server_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ do {
+ /* Do a client-server update dance */
+ status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ } while (1);
+
+ /* Don't pollute the remaining tests with the changed credentials */
+ cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
+ cli_credentials_set_target_service(server_creds, NULL);
+ cli_credentials_set_impersonate_principal(server_creds, NULL, NULL);
+
+ /* Extract the PAC using Samba's code */
+
+ status = gensec_session_info(gensec_server_context, gensec_server_context, &s4u2self_session_info);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+ cli_credentials_get_ntlm_username_domain(client_creds, tctx,
+ &ninfo.identity_info.account_name.string,
+ &ninfo.identity_info.domain_name.string);
+
+ /* Now try with SamLogon */
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ chal = data_blob_const(ninfo.challenge,
+ sizeof(ninfo.challenge));
+
+ names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(server_creds),
+ cli_credentials_get_domain(server_creds));
+
+ status = cli_credentials_get_ntlm_response(client_creds, tctx,
+ &flags,
+ chal,
+ NULL, /* server_timestamp */
+ names_blob,
+ &lm_resp, &nt_resp,
+ NULL, NULL);
+ torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
+
+ ninfo.lm.data = lm_resp.data;
+ ninfo.lm.length = lm_resp.length;
+
+ ninfo.nt.data = nt_resp.data;
+ ninfo.nt.length = nt_resp.length;
+
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.workstation.string = cli_credentials_get_workstation(server_creds);
+
+ logon.network = &ninfo;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(server_creds);
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.logon = &logon;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+
+ r.in.validation_level = 3;
+
+ status = dcerpc_netr_LogonSamLogon_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed");
+
+ torture_assert(tctx, netlogon_creds_client_check(creds,
+ &r.out.return_authenticator->cred),
+ "Credential chaining failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
+
+ status = make_user_info_dc_netlogon_validation(tmp_ctx,
+ ninfo.identity_info.account_name.string,
+ r.in.validation_level,
+ r.out.validation,
+ true, /* This user was authenticated */
+ &netlogon_user_info_dc);
+
+ torture_assert_ntstatus_ok(tctx, status, "make_user_info_dc_netlogon_validation failed");
+
+ /* Check that the primary group is present in validation's RID array */
+ status = check_primary_group_in_validation(tmp_ctx, r.in.validation_level, r.out.validation);
+ torture_assert_ntstatus_ok(tctx, status, "check_primary_group_in_validation failed");
+
+ torture_assert_str_equal(tctx, netlogon_user_info_dc->info->account_name == NULL ? "" : netlogon_user_info_dc->info->account_name,
+ kinit_session_info->info->account_name, "Account name differs for kinit-based PAC");
+ torture_assert_str_equal(tctx,netlogon_user_info_dc->info->account_name == NULL ? "" : netlogon_user_info_dc->info->account_name,
+ s4u2self_session_info->info->account_name, "Account name differs for S4U2Self");
+ torture_assert_str_equal(tctx, netlogon_user_info_dc->info->full_name == NULL ? "" : netlogon_user_info_dc->info->full_name, kinit_session_info->info->full_name, "Full name differs for kinit-based PAC");
+ torture_assert_str_equal(tctx, netlogon_user_info_dc->info->full_name == NULL ? "" : netlogon_user_info_dc->info->full_name, s4u2self_session_info->info->full_name, "Full name differs for S4U2Self");
+
+ builtin_domain = dom_sid_parse_talloc(tmp_ctx, SID_BUILTIN);
+ torture_assert_not_null(tctx, builtin_domain, "failed to parse SID");
+
+ /* KRB5 might have an additional sid, the asserted identity */
+ ai_auth_authority = dom_sid_parse_talloc(
+ tmp_ctx,
+ SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY);
+ torture_assert_not_null(tctx, ai_auth_authority, "failed to parse SID");
+
+ ai_service = dom_sid_parse_talloc(
+ tmp_ctx,
+ SID_SERVICE_ASSERTED_IDENTITY);
+ torture_assert_not_null(tctx, ai_service, "failed to parse SID");
+
+ /* ...and the Claims Valid SID. */
+ ai_claims_valid = dom_sid_parse_talloc(
+ tmp_ctx,
+ SID_CLAIMS_VALID);
+ torture_assert_not_null(tctx, ai_claims_valid, "failed to parse SID");
+
+ ai_auth_authority_count = 0;
+ ai_service_count = 0;
+ ai_claims_valid_count = 0;
+ for (i = 0; i < kinit_session_info->torture->num_dc_sids; i++) {
+ ok = dom_sid_equal(&kinit_session_info->torture->dc_sids[i].sid,
+ ai_auth_authority);
+ if (ok) {
+ ai_auth_authority_count++;
+ kinit_asserted_identity_index = i;
+ }
+
+ ok = dom_sid_equal(&kinit_session_info->torture->dc_sids[i].sid,
+ ai_service);
+ if (ok) {
+ ai_service_count++;
+ kinit_asserted_identity_index = i;
+ }
+
+ ok = dom_sid_equal(&kinit_session_info->torture->dc_sids[i].sid,
+ ai_claims_valid);
+ if (ok) {
+ ai_claims_valid_count++;
+ kinit_claims_valid_index = i;
+ }
+ }
+
+ torture_assert_int_equal(tctx, ai_auth_authority_count, 1,
+ "Kinit authority asserted identity should be (1)");
+ torture_assert_int_equal(tctx, ai_service_count, 0,
+ "Kinit service asserted identity should be (0)");
+ torture_assert_int_equal(tctx, ai_claims_valid_count, 1,
+ "Kinit Claims Valid should be (1)");
+
+ ai_auth_authority_count = 0;
+ ai_service_count = 0;
+ ai_claims_valid_count = 0;
+ for (i = 0; i < s4u2self_session_info->torture->num_dc_sids; i++) {
+ ok = dom_sid_equal(&s4u2self_session_info->torture->dc_sids[i].sid,
+ ai_auth_authority);
+ if (ok) {
+ ai_auth_authority_count++;
+ s4u2self_asserted_identity_index = i;
+ }
+
+ ok = dom_sid_equal(&s4u2self_session_info->torture->dc_sids[i].sid,
+ ai_service);
+ if (ok) {
+ ai_service_count++;
+ s4u2self_asserted_identity_index = i;
+ }
+
+ ok = dom_sid_equal(&s4u2self_session_info->torture->dc_sids[i].sid,
+ ai_claims_valid);
+ if (ok) {
+ ai_claims_valid_count++;
+ s4u2self_claims_valid_index = i;
+ }
+ }
+
+ torture_assert_int_equal(tctx, ai_auth_authority_count, 0,
+ "S4U2Self authority asserted identity should be (0)");
+ torture_assert_int_equal(tctx, ai_service_count, 1,
+ "S4U2Self service asserted identity should be (1)");
+ torture_assert_int_equal(tctx, ai_claims_valid_count, 1,
+ "S4U2Self Claims Valid should be (1)");
+
+ /*
+ * Subtract 2 to account for the Asserted Identity and Claims Valid
+ * SIDs.
+ */
+ torture_assert_int_equal(tctx, netlogon_user_info_dc->num_sids, kinit_session_info->torture->num_dc_sids - 2, "Different numbers of domain groups for kinit-based PAC");
+ torture_assert_int_equal(tctx, netlogon_user_info_dc->num_sids, s4u2self_session_info->torture->num_dc_sids - 2, "Different numbers of domain groups for S4U2Self");
+
+ /* Loop over all three SID arrays. */
+ for (i = 0, j = 0, k = 0; i < netlogon_user_info_dc->num_sids; i++, j++, k++) {
+ while (j == kinit_asserted_identity_index || j == kinit_claims_valid_index) {
+ /* Skip over the asserted identity and Claims Valid SIDs. */
+ ++j;
+ }
+ while (k == s4u2self_asserted_identity_index || k == s4u2self_claims_valid_index) {
+ /* Skip over the asserted identity and Claims Valid SIDs. */
+ ++k;
+ }
+ torture_assert_sid_equal(tctx, &netlogon_user_info_dc->sids[i].sid, &kinit_session_info->torture->dc_sids[j].sid, "Different domain groups for kinit-based PAC");
+ torture_assert_u32_equal(tctx, netlogon_user_info_dc->sids[i].attrs, kinit_session_info->torture->dc_sids[j].attrs, "Different domain group attrs for kinit-based PAC");
+ torture_assert_sid_equal(tctx, &netlogon_user_info_dc->sids[i].sid, &s4u2self_session_info->torture->dc_sids[k].sid, "Different domain groups for S4U2Self");
+ torture_assert_u32_equal(tctx, netlogon_user_info_dc->sids[i].attrs, s4u2self_session_info->torture->dc_sids[k].attrs, "Different domain group attrs for S4U2Self");
+ torture_assert(tctx, !dom_sid_in_domain(builtin_domain, &s4u2self_session_info->torture->dc_sids[k].sid), "Returned BUILTIN domain in groups for S4U2Self");
+ torture_assert(tctx, !dom_sid_in_domain(builtin_domain, &kinit_session_info->torture->dc_sids[j].sid), "Returned BUILTIN domain in groups kinit-based PAC");
+ torture_assert(tctx, !dom_sid_in_domain(builtin_domain, &netlogon_user_info_dc->sids[i].sid), "Returned BUILTIN domain in groups from NETLOGON SamLogon reply");
+ }
+
+ return true;
+}
+
+static bool test_S4U2Self_bdc_arcfour(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_S4U2Self(tctx, p, credentials, SEC_CHAN_BDC,
+ TEST_MACHINE_NAME_S4U2SELF_BDC,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_S4U2Self_bdc_aes(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_S4U2Self(tctx, p, credentials, SEC_CHAN_BDC,
+ TEST_MACHINE_NAME_S4U2SELF_BDC,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+
+static bool test_S4U2Self_workstation_arcfour(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_S4U2Self(tctx, p, credentials, SEC_CHAN_WKSTA,
+ TEST_MACHINE_NAME_S4U2SELF_WKSTA,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_S4U2Self_workstation_aes(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials)
+{
+ return test_S4U2Self(tctx, p, credentials, SEC_CHAN_WKSTA,
+ TEST_MACHINE_NAME_S4U2SELF_WKSTA,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+
+static bool test_S4U2Proxy(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials,
+ enum netr_SchannelType secure_channel_type,
+ const char *test_machine_name,
+ uint32_t negotiate_flags)
+{
+ NTSTATUS status;
+ struct gensec_security *gensec_client_context = NULL;
+ struct gensec_security *gensec_server_context = NULL;
+ struct cli_credentials *server_creds = NULL;
+ size_t num_pac_buffers;
+ struct auth4_context *auth_context = NULL;
+ struct auth_session_info *session_info = NULL;
+ struct pac_data *pac_data = NULL;
+ const struct PAC_BUFFER *pac_buf = NULL;
+ char *impersonate_princ = NULL, *self_princ = NULL, *target_princ = NULL;
+ enum ndr_err_code ndr_err;
+ struct PAC_DATA pac_data_struct;
+ struct PAC_CONSTRAINED_DELEGATION *deleg = NULL;
+
+ DATA_BLOB client_to_server, server_to_client;
+
+ auth_context = talloc_zero(tctx, struct auth4_context);
+ torture_assert_not_null(tctx, auth_context, "talloc_new() failed");
+
+ auth_context->generate_session_info_pac = test_generate_session_info_pac;
+
+ torture_comment(tctx,
+ "Testing S4U2Proxy (secure_channel_type: %d, machine: %s, negotiate_flags: 0x%08x\n",
+ secure_channel_type, test_machine_name, negotiate_flags);
+
+ impersonate_princ = cli_credentials_get_principal(samba_cmdline_get_creds(), tctx);
+ torture_assert_not_null(tctx, impersonate_princ, "Failed to get impersonate client name");
+
+ server_creds = cli_credentials_shallow_copy(tctx, credentials);
+ torture_assert_not_null(tctx, server_creds, "Failed to copy of credentials");
+
+ self_princ = talloc_asprintf(tctx, "host/%s", test_machine_name);
+ cli_credentials_invalidate_ccache(server_creds, CRED_SPECIFIED);
+ cli_credentials_set_impersonate_principal(server_creds, impersonate_princ, self_princ);
+
+ /* Trigger S4U2Proxy by setting a target_service different than self_principal */
+ target_princ = talloc_asprintf(tctx, "%s$", test_machine_name);
+ cli_credentials_set_target_service(server_creds, target_princ);
+
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ status = gensec_set_target_principal(gensec_client_context, target_princ);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
+
+ /* We now set the same credentials on both client and server contexts */
+ status = gensec_set_credentials(gensec_client_context, server_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+
+ status = gensec_server_start(tctx,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ auth_context, &gensec_server_context);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+ status = gensec_set_credentials(gensec_server_context, server_creds);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+ status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+
+ server_to_client = data_blob(NULL, 0);
+
+ do {
+ /* Do a client-server update dance */
+ status = gensec_update(gensec_client_context, tctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ status = gensec_update(gensec_server_context, tctx, client_to_server, &server_to_client);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ } while (1);
+
+ /* Extract the PAC using Samba's code */
+
+ status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+ pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
+
+ torture_assert_not_null(tctx, pac_data, "gensec_update failed to fill in pac_data in auth_context");
+ torture_assert_not_null(tctx, pac_data->pac_srv_sig, "pac_srv_sig not present");
+ torture_assert_not_null(tctx, pac_data->pac_kdc_sig, "pac_kdc_sig not present");
+
+ ndr_err = ndr_pull_struct_blob(&pac_data->pac_blob, tctx, &pac_data_struct,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
+ torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
+
+ num_pac_buffers = 9;
+
+ torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
+ torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_INFO");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_LOGON_INFO info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_LOGON_NAME);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_LOGON_NAME");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_LOGON_NAME info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_UPN_DNS_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_UPN_DNS_INFO");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_UPN_DNS_INFO info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_SRV_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_SRV_CHECKSUM");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_SRV_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_KDC_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_KDC_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_TICKET_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_TICKET_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_FULL_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_FULL_CHECKSUM");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_FULL_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CLIENT_CLAIMS_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CLIENT_CLAIMS_INFO");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_CLIENT_CLAIMS_INFO info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CONSTRAINED_DELEGATION);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CONSTRAINED_DELEGATION");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_CONSTRAINED_DELEGATION info");
+
+ deleg = pac_buf->info->constrained_delegation.info;
+ torture_assert_str_equal(tctx, deleg->proxy_target.string, target_princ, "wrong proxy_target");
+ torture_assert_int_equal(tctx, deleg->num_transited_services, 1, "wrong transited_services number");
+ torture_assert_str_equal(tctx, deleg->transited_services[0].string,
+ talloc_asprintf(tctx, "%s@%s", self_princ, cli_credentials_get_realm(credentials)),
+ "wrong transited_services[0]");
+
+ return netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
+ negotiate_flags, pac_data, session_info);
+}
+
+static bool setup_constrained_delegation(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct test_join *join_ctx,
+ const char *machine_name)
+{
+ struct samr_SetUserInfo r;
+ union samr_UserInfo user_info;
+ struct dcerpc_pipe *samr_pipe = torture_join_samr_pipe(join_ctx);
+ const char *server_dn_str = NULL;
+ struct ldb_context *sam_ctx = NULL;
+ struct ldb_dn *server_dn = NULL;
+ struct ldb_message *msg = NULL;
+ char *url = NULL;
+ int ret;
+
+ url = talloc_asprintf(tctx, "ldap://%s", dcerpc_server_name(p));
+ sam_ctx = ldb_wrap_connect(tctx, tctx->ev, tctx->lp_ctx, url, NULL, samba_cmdline_get_creds(), 0);
+ torture_assert_not_null(tctx, sam_ctx, "Connection to the SAMDB on DC failed!");
+
+ server_dn_str = samdb_search_string(sam_ctx, tctx, ldb_get_default_basedn(sam_ctx), "distinguishedName",
+ "samaccountname=%s$", machine_name);
+ torture_assert_not_null(tctx, server_dn_str, "samdb_search_string()");
+
+ server_dn = ldb_dn_new(tctx, sam_ctx, server_dn_str);
+ torture_assert_not_null(tctx, server_dn, "ldb_dn_new()");
+
+ msg = ldb_msg_new(tctx);
+ torture_assert_not_null(tctx, msg, "ldb_msg_new()");
+
+ msg->dn = server_dn;
+ ret = ldb_msg_add_string(msg, "msDS-AllowedToDelegateTo", talloc_asprintf(tctx, "%s$", machine_name));
+ torture_assert_int_equal(tctx, ret, 0, "ldb_msg_add_string())");
+
+ ret = ldb_modify(sam_ctx, msg);
+ torture_assert_int_equal(tctx, ret, 0, "ldb_modify()");
+
+ /* Allow forwardable flag in S4U2Self */
+ user_info.info16.acct_flags = ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION | ACB_WSTRUST;
+ r.in.user_handle = torture_join_samr_user_policy(join_ctx);
+ r.in.level = 16;
+ r.in.info = &user_info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(samr_pipe->binding_handle, tctx, &r),
+ "failed to set ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION info account flags");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to set ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION into account flags");
+
+ return true;
+}
+
+static bool test_S4U2Proxy_workstation_arcfour(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials,
+ struct test_join *join_ctx)
+{
+ torture_assert(tctx, setup_constrained_delegation(tctx, p, join_ctx,
+ TEST_MACHINE_NAME_S4U2PROXY_WKSTA),
+ "setup_constrained_delegation() failed");
+ return test_S4U2Proxy(tctx, p, credentials, SEC_CHAN_WKSTA,
+ TEST_MACHINE_NAME_S4U2PROXY_WKSTA,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS);
+}
+
+static bool test_S4U2Proxy_workstation_aes(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *credentials,
+ struct test_join *join_ctx)
+{
+ torture_assert(tctx, setup_constrained_delegation(tctx, p, join_ctx,
+ TEST_MACHINE_NAME_S4U2PROXY_WKSTA),
+ "setup_constrained_delegation() failed");
+ return test_S4U2Proxy(tctx, p, credentials, SEC_CHAN_WKSTA,
+ TEST_MACHINE_NAME_S4U2PROXY_WKSTA,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES);
+}
+#endif
+
+struct torture_suite *torture_rpc_remote_pac(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "pac");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_BDC);
+ torture_rpc_tcase_add_test_creds(tcase, "verify-sig-arcfour", test_PACVerify_bdc_arcfour);
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-aes",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_BDC);
+ torture_rpc_tcase_add_test_creds(tcase, "verify-sig-aes", test_PACVerify_bdc_aes);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-arcfour",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA);
+ torture_rpc_tcase_add_test_creds(tcase, "verify-sig-arcfour", test_PACVerify_workstation_arcfour);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_WKSTA);
+ torture_rpc_tcase_add_test_creds(tcase, "verify-sig-aes", test_PACVerify_workstation_aes);
+
+#ifdef SAMBA4_USES_HEIMDAL
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bdc-arcfour",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_BDC);
+ torture_rpc_tcase_add_test_creds(tcase, "s4u2self-arcfour", test_S4U2Self_bdc_arcfour);
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "netr-bcd-aes",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_BDC);
+ torture_rpc_tcase_add_test_creds(tcase, "s4u2self-aes", test_S4U2Self_bdc_aes);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-arcfour",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_WKSTA);
+ torture_rpc_tcase_add_test_creds(tcase, "s4u2self-arcfour", test_S4U2Self_workstation_arcfour);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2SELF_WKSTA);
+ torture_rpc_tcase_add_test_creds(tcase, "s4u2self-aes", test_S4U2Self_workstation_aes);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-arcfour",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2PROXY_WKSTA);
+ torture_rpc_tcase_add_test_join(tcase, "s4u2proxy-arcfour", test_S4U2Proxy_workstation_arcfour);
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "netr-mem-aes",
+ &ndr_table_netlogon, TEST_MACHINE_NAME_S4U2PROXY_WKSTA);
+ torture_rpc_tcase_add_test_join(tcase, "s4u2proxy-aes", test_S4U2Proxy_workstation_aes);
+#endif
+ return suite;
+}
diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c
new file mode 100644
index 0000000..ea214e0
--- /dev/null
+++ b/source4/torture/rpc/rpc.c
@@ -0,0 +1,661 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "torture/smbtorture.h"
+#include "librpc/ndr/ndr_table.h"
+#include "../lib/util/dlinklist.h"
+
+static bool torture_rpc_teardown (struct torture_context *tcase,
+ void *data)
+{
+ struct torture_rpc_tcase_data *tcase_data =
+ (struct torture_rpc_tcase_data *)data;
+ if (tcase_data->join_ctx != NULL)
+ torture_leave_domain(tcase, tcase_data->join_ctx);
+ talloc_free(tcase_data);
+ return true;
+}
+
+/**
+ * Obtain the DCE/RPC binding context associated with a torture context.
+ *
+ * @param tctx Torture context
+ * @param binding Pointer to store DCE/RPC binding
+ */
+NTSTATUS torture_rpc_binding(struct torture_context *tctx,
+ struct dcerpc_binding **binding)
+{
+ NTSTATUS status;
+ const char *binding_string = torture_setting_string(tctx, "binding",
+ NULL);
+
+ if (binding_string == NULL) {
+ torture_comment(tctx,
+ "You must specify a DCE/RPC binding string\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = dcerpc_parse_binding(tctx, binding_string, binding);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx,
+ "Failed to parse dcerpc binding '%s'\n",
+ binding_string);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * open a rpc connection to the chosen binding string
+ */
+_PUBLIC_ NTSTATUS torture_rpc_connection(struct torture_context *tctx,
+ struct dcerpc_pipe **p,
+ const struct ndr_interface_table *table)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+
+ status = torture_rpc_binding(tctx, &binding);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ return torture_rpc_connection_with_binding(tctx, binding, p, table);
+}
+
+/**
+ * open a rpc connection to the chosen binding string
+ */
+_PUBLIC_ NTSTATUS torture_rpc_connection_with_binding(struct torture_context *tctx,
+ struct dcerpc_binding *binding,
+ struct dcerpc_pipe **p,
+ const struct ndr_interface_table *table)
+{
+ NTSTATUS status;
+
+ dcerpc_init();
+
+ status = dcerpc_pipe_connect_b(tctx,
+ p, binding, table,
+ samba_cmdline_get_creds(),
+ tctx->ev, tctx->lp_ctx);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_warning(tctx, "Failed to connect to remote server: %s %s\n",
+ dcerpc_binding_string(tctx, binding), nt_errstr(status));
+ }
+
+ return status;
+}
+
+/**
+ * open a rpc connection to a specific transport
+ */
+NTSTATUS torture_rpc_connection_transport(struct torture_context *tctx,
+ struct dcerpc_pipe **p,
+ const struct ndr_interface_table *table,
+ enum dcerpc_transport_t transport,
+ uint32_t assoc_group_id,
+ uint32_t extra_flags)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+
+ *p = NULL;
+
+ status = torture_rpc_binding(tctx, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_binding_set_transport(binding, transport);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_binding_set_assoc_group_id(binding, assoc_group_id);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_binding_set_flags(binding, extra_flags, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcerpc_pipe_connect_b(tctx, p, binding, table,
+ samba_cmdline_get_creds(),
+ tctx->ev, tctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ *p = NULL;
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static bool torture_rpc_setup_machine_workstation(struct torture_context *tctx,
+ void **data)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ struct torture_rpc_tcase *tcase = talloc_get_type(tctx->active_tcase,
+ struct torture_rpc_tcase);
+ struct torture_rpc_tcase_data *tcase_data;
+
+ status = torture_rpc_binding(tctx, &binding);
+ if (NT_STATUS_IS_ERR(status))
+ return false;
+
+ *data = tcase_data = talloc_zero(tctx, struct torture_rpc_tcase_data);
+ tcase_data->credentials = samba_cmdline_get_creds();
+ tcase_data->join_ctx = torture_join_domain(tctx, tcase->machine_name,
+ ACB_WSTRUST,
+ &tcase_data->credentials);
+ if (tcase_data->join_ctx == NULL)
+ torture_fail(tctx, "Failed to join as WORKSTATION");
+
+ status = dcerpc_pipe_connect_b(tctx,
+ &(tcase_data->pipe),
+ binding,
+ tcase->table,
+ tcase_data->credentials, tctx->ev, tctx->lp_ctx);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ return NT_STATUS_IS_OK(status);
+}
+
+static bool torture_rpc_setup_machine_bdc(struct torture_context *tctx,
+ void **data)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ struct torture_rpc_tcase *tcase = talloc_get_type(tctx->active_tcase,
+ struct torture_rpc_tcase);
+ struct torture_rpc_tcase_data *tcase_data;
+
+ status = torture_rpc_binding(tctx, &binding);
+ if (NT_STATUS_IS_ERR(status))
+ return false;
+
+ *data = tcase_data = talloc_zero(tctx, struct torture_rpc_tcase_data);
+ tcase_data->credentials = samba_cmdline_get_creds();
+ tcase_data->join_ctx = torture_join_domain(tctx, tcase->machine_name,
+ ACB_SVRTRUST,
+ &tcase_data->credentials);
+ if (tcase_data->join_ctx == NULL)
+ torture_fail(tctx, "Failed to join as BDC");
+
+ status = dcerpc_pipe_connect_b(tctx,
+ &(tcase_data->pipe),
+ binding,
+ tcase->table,
+ tcase_data->credentials, tctx->ev, tctx->lp_ctx);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ return NT_STATUS_IS_OK(status);
+}
+
+_PUBLIC_ struct torture_rpc_tcase *torture_suite_add_machine_workstation_rpc_iface_tcase(
+ struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table,
+ const char *machine_name)
+{
+ struct torture_rpc_tcase *tcase = talloc(suite,
+ struct torture_rpc_tcase);
+
+ torture_suite_init_rpc_tcase(suite, tcase, name, table);
+
+ tcase->machine_name = talloc_strdup(tcase, machine_name);
+ tcase->tcase.setup = torture_rpc_setup_machine_workstation;
+ tcase->tcase.teardown = torture_rpc_teardown;
+
+ return tcase;
+}
+
+_PUBLIC_ struct torture_rpc_tcase *torture_suite_add_machine_bdc_rpc_iface_tcase(
+ struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table,
+ const char *machine_name)
+{
+ struct torture_rpc_tcase *tcase = talloc(suite,
+ struct torture_rpc_tcase);
+
+ torture_suite_init_rpc_tcase(suite, tcase, name, table);
+
+ tcase->machine_name = talloc_strdup(tcase, machine_name);
+ tcase->tcase.setup = torture_rpc_setup_machine_bdc;
+ tcase->tcase.teardown = torture_rpc_teardown;
+
+ return tcase;
+}
+
+_PUBLIC_ bool torture_suite_init_rpc_tcase(struct torture_suite *suite,
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ const struct ndr_interface_table *table)
+{
+ if (!torture_suite_init_tcase(suite, (struct torture_tcase *)tcase, name))
+ return false;
+
+ tcase->table = table;
+
+ return true;
+}
+
+static bool torture_rpc_setup_anonymous(struct torture_context *tctx,
+ void **data)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ struct torture_rpc_tcase_data *tcase_data;
+ struct torture_rpc_tcase *tcase = talloc_get_type(tctx->active_tcase,
+ struct torture_rpc_tcase);
+
+ status = torture_rpc_binding(tctx, &binding);
+ if (NT_STATUS_IS_ERR(status))
+ return false;
+
+ *data = tcase_data = talloc_zero(tctx, struct torture_rpc_tcase_data);
+ tcase_data->credentials = cli_credentials_init_anon(tctx);
+
+ status = dcerpc_pipe_connect_b(tctx,
+ &(tcase_data->pipe),
+ binding,
+ tcase->table,
+ tcase_data->credentials, tctx->ev, tctx->lp_ctx);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ return NT_STATUS_IS_OK(status);
+}
+
+static bool torture_rpc_setup (struct torture_context *tctx, void **data)
+{
+ NTSTATUS status;
+ struct torture_rpc_tcase *tcase = talloc_get_type(
+ tctx->active_tcase, struct torture_rpc_tcase);
+ struct torture_rpc_tcase_data *tcase_data;
+
+ *data = tcase_data = talloc_zero(tctx, struct torture_rpc_tcase_data);
+ tcase_data->credentials = samba_cmdline_get_creds();
+
+ status = torture_rpc_connection(tctx,
+ &(tcase_data->pipe),
+ tcase->table);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+
+_PUBLIC_ struct torture_rpc_tcase *torture_suite_add_anon_rpc_iface_tcase(struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table)
+{
+ struct torture_rpc_tcase *tcase = talloc(suite, struct torture_rpc_tcase);
+
+ torture_suite_init_rpc_tcase(suite, tcase, name, table);
+
+ tcase->tcase.setup = torture_rpc_setup_anonymous;
+ tcase->tcase.teardown = torture_rpc_teardown;
+
+ return tcase;
+}
+
+
+_PUBLIC_ struct torture_rpc_tcase *torture_suite_add_rpc_iface_tcase(struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table)
+{
+ struct torture_rpc_tcase *tcase = talloc(suite, struct torture_rpc_tcase);
+
+ torture_suite_init_rpc_tcase(suite, tcase, name, table);
+
+ tcase->tcase.setup = torture_rpc_setup;
+ tcase->tcase.teardown = torture_rpc_teardown;
+
+ return tcase;
+}
+
+static bool torture_rpc_wrap_test(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *);
+ struct torture_rpc_tcase_data *tcase_data =
+ (struct torture_rpc_tcase_data *)tcase->data;
+
+ fn = test->fn;
+
+ return fn(tctx, tcase_data->pipe);
+}
+
+static bool torture_rpc_wrap_test_ex(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *, const void *);
+ struct torture_rpc_tcase_data *tcase_data =
+ (struct torture_rpc_tcase_data *)tcase->data;
+
+ fn = test->fn;
+
+ return fn(tctx, tcase_data->pipe, test->data);
+}
+
+
+static bool torture_rpc_wrap_test_creds(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *, struct cli_credentials *);
+ struct torture_rpc_tcase_data *tcase_data =
+ (struct torture_rpc_tcase_data *)tcase->data;
+
+ fn = test->fn;
+
+ return fn(tctx, tcase_data->pipe, tcase_data->credentials);
+}
+
+static bool torture_rpc_wrap_test_join(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *, struct cli_credentials *, struct test_join *);
+ struct torture_rpc_tcase_data *tcase_data =
+ (struct torture_rpc_tcase_data *)tcase->data;
+
+ fn = test->fn;
+
+ return fn(tctx, tcase_data->pipe, tcase_data->credentials, tcase_data->join_ctx);
+}
+
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *))
+{
+ struct torture_test *test;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = torture_rpc_wrap_test;
+ test->dangerous = false;
+ test->data = NULL;
+ test->fn = fn;
+
+ DLIST_ADD_END(tcase->tcase.tests, test);
+
+ return test;
+}
+
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_creds(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *, struct cli_credentials *))
+{
+ struct torture_test *test;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = torture_rpc_wrap_test_creds;
+ test->dangerous = false;
+ test->data = NULL;
+ test->fn = fn;
+
+ DLIST_ADD_END(tcase->tcase.tests, test);
+
+ return test;
+}
+
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_join(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *,
+ struct cli_credentials *, struct test_join *))
+{
+ struct torture_test *test;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = torture_rpc_wrap_test_join;
+ test->dangerous = false;
+ test->data = NULL;
+ test->fn = fn;
+
+ DLIST_ADD_END(tcase->tcase.tests, test);
+
+ return test;
+}
+
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_ex(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *,
+ void *),
+ void *userdata)
+{
+ struct torture_test *test;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = torture_rpc_wrap_test_ex;
+ test->dangerous = false;
+ test->data = userdata;
+ test->fn = fn;
+
+ DLIST_ADD_END(tcase->tcase.tests, test);
+
+ return test;
+}
+
+static bool torture_rpc_wrap_test_setup(struct torture_context *tctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn)(struct torture_context *, struct dcerpc_pipe *, const void *);
+ struct torture_rpc_tcase *rpc_tcase = talloc_get_type_abort(
+ tctx->active_tcase, struct torture_rpc_tcase);
+ struct torture_rpc_tcase_data *tcase_data = talloc_get_type_abort(
+ tcase->data, struct torture_rpc_tcase_data);
+ void *data = discard_const_p(void, test->data);
+ bool ok;
+
+ ok = rpc_tcase->setup_fn(tctx, tcase_data->pipe, data);
+ if (!ok) {
+ return false;
+ }
+
+ fn = test->fn;
+
+ ok = fn(tctx, tcase_data->pipe, data);
+ if (!ok) {
+ return false;
+ }
+
+ ok = rpc_tcase->teardown_fn(tctx, tcase_data->pipe, data);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_setup(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *),
+ void *userdata)
+{
+ struct torture_test *test = NULL;
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = torture_rpc_wrap_test_setup;
+ test->dangerous = false;
+ test->data = userdata;
+ test->fn = fn;
+
+ DLIST_ADD_END(tcase->tcase.tests, test);
+
+ return test;
+}
+
+_PUBLIC_ struct torture_rpc_tcase *torture_suite_add_rpc_setup_tcase(
+ struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table,
+ bool (*setup_fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *),
+ bool (*teardown_fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *))
+{
+ struct torture_rpc_tcase *tcase = talloc(
+ suite, struct torture_rpc_tcase);
+
+ torture_suite_init_rpc_tcase(suite, tcase, name, table);
+
+ tcase->setup_fn = setup_fn;
+ tcase->teardown_fn = teardown_fn;
+ tcase->tcase.setup = torture_rpc_setup;
+ tcase->tcase.teardown = torture_rpc_teardown;
+
+ return tcase;
+}
+
+NTSTATUS torture_rpc_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "rpc");
+
+ ndr_table_init();
+
+ torture_suite_add_simple_test(suite, "lsa", torture_rpc_lsa);
+ torture_suite_add_simple_test(suite, "lsalookup", torture_rpc_lsa_lookup);
+ torture_suite_add_simple_test(suite, "lsa-getuser", torture_rpc_lsa_get_user);
+ torture_suite_add_suite(suite, torture_rpc_lsa_lookup_sids(suite));
+ torture_suite_add_suite(suite, torture_rpc_lsa_lookup_names(suite));
+ torture_suite_add_suite(suite, torture_rpc_lsa_secrets(suite));
+ torture_suite_add_suite(suite, torture_rpc_lsa_trusted_domains(suite));
+ torture_suite_add_suite(suite, torture_rpc_lsa_forest_trust(suite));
+ torture_suite_add_suite(suite, torture_rpc_lsa_privileges(suite));
+ torture_suite_add_suite(suite, torture_rpc_echo(suite));
+ torture_suite_add_suite(suite, torture_rpc_dfs(suite));
+ torture_suite_add_suite(suite, torture_rpc_frsapi(suite));
+ torture_suite_add_suite(suite, torture_rpc_unixinfo(suite));
+ torture_suite_add_suite(suite, torture_rpc_eventlog(suite));
+ torture_suite_add_suite(suite, torture_rpc_atsvc(suite));
+ torture_suite_add_suite(suite, torture_rpc_wkssvc(suite));
+ torture_suite_add_suite(suite, torture_rpc_handles(suite));
+ torture_suite_add_suite(suite, torture_rpc_object_uuid(suite));
+ torture_suite_add_suite(suite, torture_rpc_winreg(suite));
+ torture_suite_add_suite(suite, torture_rpc_spoolss(suite));
+#ifdef WITH_NTVFS_FILESERVER
+ torture_suite_add_suite(suite, torture_rpc_spoolss_notify(suite));
+#endif
+ torture_suite_add_suite(suite, torture_rpc_spoolss_win(suite));
+ torture_suite_add_suite(suite, torture_rpc_spoolss_driver(suite));
+ torture_suite_add_suite(suite, torture_rpc_spoolss_access(suite));
+ torture_suite_add_suite(suite, torture_rpc_iremotewinspool(suite));
+ torture_suite_add_suite(suite, torture_rpc_iremotewinspool_drv(suite));
+ torture_suite_add_simple_test(suite, "samr", torture_rpc_samr);
+ torture_suite_add_simple_test(suite, "samr.users", torture_rpc_samr_users);
+ torture_suite_add_simple_test(suite, "samr.passwords.default", torture_rpc_samr_passwords);
+ torture_suite_add_suite(suite, torture_rpc_netlogon(suite));
+ torture_suite_add_suite(suite, torture_rpc_netlogon_s3(suite));
+ torture_suite_add_suite(suite, torture_rpc_netlogon_admin(suite));
+ torture_suite_add_suite(suite, torture_rpc_netlogon_zerologon(suite));
+ torture_suite_add_suite(suite, torture_rpc_netlogon_crypto_fips(suite));
+ torture_suite_add_suite(suite, torture_rpc_remote_pac(suite));
+ torture_suite_add_simple_test(suite, "samlogon", torture_rpc_samlogon);
+ torture_suite_add_simple_test(suite, "samsync", torture_rpc_samsync);
+ torture_suite_add_simple_test(suite, "schannel", torture_rpc_schannel);
+ torture_suite_add_simple_test(suite, "schannel2", torture_rpc_schannel2);
+ torture_suite_add_simple_test(suite, "bench-schannel1", torture_rpc_schannel_bench1);
+ torture_suite_add_simple_test(suite, "schannel_anon_setpw", torture_rpc_schannel_anon_setpw);
+ torture_suite_add_suite(suite, torture_rpc_srvsvc(suite));
+ torture_suite_add_suite(suite, torture_rpc_svcctl(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_accessmask(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_handletype(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_workstation_auth(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_passwords_pwdlastset(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_passwords_badpwdcount(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_passwords_lockout(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_passwords_validate(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_user_privileges(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_large_dc(suite));
+ torture_suite_add_suite(suite, torture_rpc_samr_priv(suite));
+ torture_suite_add_suite(suite, torture_rpc_epmapper(suite));
+ torture_suite_add_suite(suite, torture_rpc_initshutdown(suite));
+ torture_suite_add_simple_test(suite, "mgmt", torture_rpc_mgmt);
+ torture_suite_add_simple_test(suite, "scanner", torture_rpc_scanner);
+ torture_suite_add_simple_test(suite, "countcalls", torture_rpc_countcalls);
+ torture_suite_add_simple_test(suite, "authcontext", torture_bind_authcontext);
+ torture_suite_add_suite(suite, torture_rpc_samba3(suite));
+ torture_rpc_drsuapi_tcase(suite);
+ torture_rpc_drsuapi_w2k8_tcase(suite);
+ torture_rpc_drsuapi_cracknames_tcase(suite);
+ torture_suite_add_suite(suite, torture_rpc_dssetup(suite));
+ torture_suite_add_suite(suite, torture_rpc_browser(suite));
+ torture_suite_add_simple_test(suite, "altercontext", torture_rpc_alter_context);
+ torture_suite_add_simple_test(suite, "join", torture_rpc_join);
+ torture_drs_rpc_dsgetinfo_tcase(suite);
+ torture_suite_add_simple_test(suite, "bench-rpc", torture_bench_rpc);
+ torture_suite_add_simple_test(suite, "asyncbind", torture_async_bind);
+ torture_suite_add_suite(suite, torture_rpc_ntsvcs(suite));
+ torture_suite_add_suite(suite, torture_rpc_bind(suite));
+#ifdef AD_DC_BUILD_IS_ENABLED
+ torture_suite_add_suite(suite, torture_rpc_backupkey(suite));
+#endif
+ torture_suite_add_suite(suite, torture_rpc_fsrvp(suite));
+ torture_suite_add_suite(suite, torture_rpc_clusapi(suite));
+ torture_suite_add_suite(suite, torture_rpc_witness(suite));
+ torture_suite_add_suite(suite, torture_rpc_mdssvc(suite));
+
+ suite->description = talloc_strdup(suite, "DCE/RPC protocol and interface tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c
new file mode 100644
index 0000000..10f0fcc
--- /dev/null
+++ b/source4/torture/rpc/samba3rpc.c
@@ -0,0 +1,4729 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc torture tests, designed to walk Samba3 code paths
+
+ Copyright (C) Volker Lendecke 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "torture/util.h"
+#include "libcli/rap/rap.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "librpc/gen_ndr/ndr_winreg_c.h"
+#include "librpc/gen_ndr/ndr_wkssvc_c.h"
+#include "librpc/gen_ndr/ndr_svcctl_c.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/libcli.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "param/param.h"
+#include "lib/registry/registry.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/ndr/ndr.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "source3/rpc_client/init_samr.h"
+
+/*
+ * open pipe and bind, given an IPC$ context
+ */
+
+static NTSTATUS pipe_bind_smb(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_tree *tree,
+ const char *pipe_name,
+ const struct ndr_interface_table *iface,
+ struct dcerpc_pipe **p)
+{
+ struct dcerpc_pipe *result;
+ NTSTATUS status;
+
+ if (!(result = dcerpc_pipe_init(mem_ctx, tctx->ev))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_pipe_open_smb(result, tree, pipe_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_pipe_open_smb failed: %s\n",
+ nt_errstr(status));
+ talloc_free(result);
+ return status;
+ }
+
+ status = dcerpc_bind_auth_none(result, iface);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_bind_auth_none failed: %s\n", nt_errstr(status));
+ talloc_free(result);
+ return status;
+ }
+
+ *p = result;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pipe_bind_smb2(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ const char *pipe_name,
+ const struct ndr_interface_table *iface,
+ struct dcerpc_pipe **p)
+{
+ struct dcerpc_pipe *result;
+ NTSTATUS status;
+
+ if (!(result = dcerpc_pipe_init(mem_ctx, tctx->ev))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_pipe_open_smb2(result, tree, pipe_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_pipe_open_smb2 failed: %s\n",
+ nt_errstr(status));
+ talloc_free(result);
+ return status;
+ }
+
+ status = dcerpc_bind_auth_none(result, iface);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_bind_auth_none failed: %s\n", nt_errstr(status));
+ talloc_free(result);
+ return status;
+ }
+
+ *p = result;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS pipe_bind_smb_auth(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_tree *tree,
+ struct cli_credentials *creds,
+ uint8_t auth_type,
+ uint8_t auth_level,
+ const char *pipe_name,
+ const struct ndr_interface_table *iface,
+ struct dcerpc_pipe **p)
+{
+ struct dcerpc_pipe *result;
+ NTSTATUS status;
+
+ if (!(result = dcerpc_pipe_init(mem_ctx, tctx->ev))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_pipe_open_smb(result, tree, pipe_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_pipe_open_smb failed: %s\n",
+ nt_errstr(status));
+ talloc_free(result);
+ return status;
+ }
+
+ status = dcerpc_bind_auth(result, iface, creds,
+ lpcfg_gensec_settings(tctx->lp_ctx, tctx->lp_ctx),
+ auth_type, auth_level, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_bind_auth failed: %s\n", nt_errstr(status));
+ talloc_free(result);
+ return status;
+ }
+
+ *p = result;
+ return NT_STATUS_OK;
+}
+
+/*
+ * This tests a RPC call using an invalid vuid
+ */
+
+bool torture_bind_authcontext(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct lsa_ObjectAttribute objectattr;
+ struct lsa_OpenPolicy2 openpolicy;
+ struct policy_handle handle;
+ struct lsa_Close close_handle;
+ struct smbcli_session *tmp;
+ uint16_t tmp_vuid;
+ struct smbcli_session *session2;
+ struct smbcli_state *cli;
+ struct dcerpc_pipe *lsa_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct cli_credentials *anon_creds;
+ struct smb_composite_sesssetup setup;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ mem_ctx = talloc_init("torture_bind_authcontext");
+
+ if (mem_ctx == NULL) {
+ torture_comment(torture, "talloc_init failed\n");
+ return false;
+ }
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(mem_ctx, &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "smbcli_full_connection failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = pipe_bind_smb(torture, mem_ctx, cli->tree, "\\lsarpc",
+ &ndr_table_lsarpc, &lsa_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "pipe_bind_smb failed");
+ lsa_handle = lsa_pipe->binding_handle;
+
+ openpolicy.in.system_name =talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(lsa_pipe));
+ ZERO_STRUCT(objectattr);
+ openpolicy.in.attr = &objectattr;
+ openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ openpolicy.out.handle = &handle;
+
+ status = dcerpc_lsa_OpenPolicy2_r(lsa_handle, mem_ctx, &openpolicy);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "dcerpc_lsa_OpenPolicy2 failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(openpolicy.out.result)) {
+ torture_comment(torture, "dcerpc_lsa_OpenPolicy2 failed: %s\n",
+ nt_errstr(openpolicy.out.result));
+ goto done;
+ }
+
+ close_handle.in.handle = &handle;
+ close_handle.out.handle = &handle;
+
+ status = dcerpc_lsa_Close_r(lsa_handle, mem_ctx, &close_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "dcerpc_lsa_Close failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(close_handle.out.result)) {
+ torture_comment(torture, "dcerpc_lsa_Close failed: %s\n",
+ nt_errstr(close_handle.out.result));
+ goto done;
+ }
+
+ session2 = smbcli_session_init(cli->transport, mem_ctx, false, session_options);
+ if (session2 == NULL) {
+ torture_comment(torture, "smbcli_session_init failed\n");
+ goto done;
+ }
+
+ if (!(anon_creds = cli_credentials_init_anon(mem_ctx))) {
+ torture_comment(torture, "create_anon_creds failed\n");
+ goto done;
+ }
+
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities;
+ setup.in.workgroup = "";
+ setup.in.credentials = anon_creds;
+ setup.in.gensec_settings = lpcfg_gensec_settings(torture, torture->lp_ctx);
+
+ status = smb_composite_sesssetup(session2, &setup);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "anon session setup failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ session2->vuid = setup.out.vuid;
+
+ tmp = cli->tree->session;
+ tmp_vuid = smb1cli_session_current_id(tmp->smbXcli);
+ smb1cli_session_set_id(tmp->smbXcli, session2->vuid);
+ cli->tree->session = session2;
+
+ status = dcerpc_lsa_OpenPolicy2_r(lsa_handle, mem_ctx, &openpolicy);
+
+ torture_assert(torture, smbXcli_conn_is_connected(cli->transport->conn),
+ "smb still connected");
+ torture_assert(torture, !dcerpc_binding_handle_is_connected(lsa_handle),
+ "dcerpc disconnected");
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
+ torture_comment(torture, "dcerpc_lsa_OpenPolicy2 with wrong vuid gave %s, "
+ "expected NT_STATUS_CONNECTION_DISCONNECTED\n",
+ nt_errstr(status));
+ status = NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR)) {
+ torture_comment(torture, "dcerpc_lsa_OpenPolicy2 with wrong vuid gave %s, "
+ "expected NT_STATUS_CONNECTION_DISCONNECTED\n",
+ nt_errstr(status));
+ status = NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_CONNECTION_DISCONNECTED,
+ "lsa connection disconnected");
+
+ smb1cli_session_set_id(tmp->smbXcli, tmp_vuid);
+ cli->tree->session = tmp;
+ talloc_free(lsa_pipe);
+ lsa_pipe = NULL;
+
+ ret = true;
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Bind to lsa using a specific auth method
+ */
+
+static bool bindtest(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct cli_credentials *credentials,
+ uint8_t auth_type, uint8_t auth_level)
+{
+ TALLOC_CTX *mem_ctx;
+ bool ret = false;
+ NTSTATUS status;
+
+ struct dcerpc_pipe *lsa_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_ObjectAttribute objectattr;
+ struct lsa_OpenPolicy2 openpolicy;
+ struct lsa_QueryInfoPolicy query;
+ union lsa_PolicyInformation *info = NULL;
+ struct policy_handle handle;
+ struct lsa_Close close_handle;
+
+ if ((mem_ctx = talloc_init("bindtest")) == NULL) {
+ torture_comment(tctx, "talloc_init failed\n");
+ return false;
+ }
+
+ status = pipe_bind_smb_auth(tctx, mem_ctx, cli->tree,
+ credentials, auth_type, auth_level,
+ "\\lsarpc", &ndr_table_lsarpc, &lsa_pipe);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "pipe_bind_smb_auth failed");
+ lsa_handle = lsa_pipe->binding_handle;
+
+ openpolicy.in.system_name =talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(lsa_pipe));
+ ZERO_STRUCT(objectattr);
+ openpolicy.in.attr = &objectattr;
+ openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ openpolicy.out.handle = &handle;
+
+ status = dcerpc_lsa_OpenPolicy2_r(lsa_handle, mem_ctx, &openpolicy);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_lsa_OpenPolicy2 failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(openpolicy.out.result)) {
+ torture_comment(tctx, "dcerpc_lsa_OpenPolicy2 failed: %s\n",
+ nt_errstr(openpolicy.out.result));
+ goto done;
+ }
+
+ query.in.handle = &handle;
+ query.in.level = LSA_POLICY_INFO_DOMAIN;
+ query.out.info = &info;
+
+ status = dcerpc_lsa_QueryInfoPolicy_r(lsa_handle, mem_ctx, &query);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_lsa_QueryInfoPolicy failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(query.out.result)) {
+ torture_comment(tctx, "dcerpc_lsa_QueryInfoPolicy failed: %s\n",
+ nt_errstr(query.out.result));
+ goto done;
+ }
+
+ close_handle.in.handle = &handle;
+ close_handle.out.handle = &handle;
+
+ status = dcerpc_lsa_Close_r(lsa_handle, mem_ctx, &close_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_lsa_Close failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(close_handle.out.result)) {
+ torture_comment(tctx, "dcerpc_lsa_Close failed: %s\n",
+ nt_errstr(close_handle.out.result));
+ goto done;
+ }
+
+
+ ret = true;
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * test authenticated RPC binds with the variants Samba3 does support
+ */
+
+static bool torture_bind_samba3(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_state *cli;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ mem_ctx = talloc_init("torture_bind_authcontext");
+
+ if (mem_ctx == NULL) {
+ torture_comment(torture, "talloc_init failed\n");
+ return false;
+ }
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(mem_ctx, &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "smbcli_full_connection failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ ret = true;
+
+ ret &= bindtest(torture, cli, samba_cmdline_get_creds(),
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ DCERPC_AUTH_LEVEL_INTEGRITY);
+ ret &= bindtest(torture, cli, samba_cmdline_get_creds(),
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ DCERPC_AUTH_LEVEL_PRIVACY);
+ ret &= bindtest(torture, cli, samba_cmdline_get_creds(),
+ DCERPC_AUTH_TYPE_SPNEGO,
+ DCERPC_AUTH_LEVEL_INTEGRITY);
+ ret &= bindtest(torture, cli, samba_cmdline_get_creds(),
+ DCERPC_AUTH_TYPE_SPNEGO,
+ DCERPC_AUTH_LEVEL_PRIVACY);
+
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Lookup or create a user and return all necessary info
+ */
+
+static bool get_usr_handle(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials *admin_creds,
+ uint8_t auth_type,
+ uint8_t auth_level,
+ const char *username,
+ char **domain,
+ struct dcerpc_pipe **result_pipe,
+ struct policy_handle **result_handle,
+ struct dom_sid **sid_p)
+{
+ struct dcerpc_pipe *samr_pipe;
+ struct dcerpc_binding_handle *samr_handle;
+ NTSTATUS status;
+ struct policy_handle conn_handle;
+ struct policy_handle domain_handle;
+ struct policy_handle *user_handle;
+ struct samr_Connect2 conn;
+ struct samr_EnumDomains enumdom;
+ uint32_t resume_handle = 0;
+ uint32_t num_entries = 0;
+ struct samr_SamArray *sam = NULL;
+ struct samr_LookupDomain l;
+ struct dom_sid2 *sid = NULL;
+ int dom_idx;
+ struct lsa_String domain_name;
+ struct lsa_String user_name;
+ struct samr_OpenDomain o;
+ struct samr_CreateUser2 c;
+ uint32_t user_rid,access_granted;
+
+ if (admin_creds != NULL) {
+ status = pipe_bind_smb_auth(tctx, mem_ctx, cli->tree,
+ admin_creds, auth_type, auth_level,
+ "\\samr", &ndr_table_samr, &samr_pipe);
+ torture_assert_ntstatus_ok(tctx, status, "pipe_bind_smb_auth failed");
+ } else {
+ /* We must have an authenticated SMB connection */
+ status = pipe_bind_smb(tctx, mem_ctx, cli->tree,
+ "\\samr", &ndr_table_samr, &samr_pipe);
+ torture_assert_ntstatus_ok(tctx, status, "pipe_bind_smb_auth failed");
+ }
+#if 0
+ samr_pipe->conn->flags |= DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT;
+#endif
+ samr_handle = samr_pipe->binding_handle;
+
+ conn.in.system_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(samr_pipe));
+ conn.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ conn.out.connect_handle = &conn_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Connect2_r(samr_handle, mem_ctx, &conn),
+ "samr_Connect2 failed");
+ torture_assert_ntstatus_ok(tctx, conn.out.result,
+ "samr_Connect2 failed");
+
+ enumdom.in.connect_handle = &conn_handle;
+ enumdom.in.resume_handle = &resume_handle;
+ enumdom.in.buf_size = (uint32_t)-1;
+ enumdom.out.resume_handle = &resume_handle;
+ enumdom.out.num_entries = &num_entries;
+ enumdom.out.sam = &sam;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_EnumDomains_r(samr_handle, mem_ctx, &enumdom),
+ "samr_EnumDomains failed");
+ torture_assert_ntstatus_ok(tctx, enumdom.out.result,
+ "samr_EnumDomains failed");
+
+ torture_assert_int_equal(tctx, *enumdom.out.num_entries, 2,
+ "samr_EnumDomains returned unexpected num_entries");
+
+ dom_idx = strequal(sam->entries[0].name.string,
+ "builtin") ? 1:0;
+
+ l.in.connect_handle = &conn_handle;
+ domain_name.string = sam->entries[dom_idx].name.string;
+ *domain = talloc_strdup(mem_ctx, domain_name.string);
+ l.in.domain_name = &domain_name;
+ l.out.sid = &sid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_LookupDomain_r(samr_handle, mem_ctx, &l),
+ "samr_LookupDomain failed");
+ torture_assert_ntstatus_ok(tctx, l.out.result,
+ "samr_LookupDomain failed");
+
+ o.in.connect_handle = &conn_handle;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.in.sid = *l.out.sid;
+ o.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenDomain_r(samr_handle, mem_ctx, &o),
+ "samr_OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, o.out.result,
+ "samr_OpenDomain failed");
+
+ c.in.domain_handle = &domain_handle;
+ user_name.string = username;
+ c.in.account_name = &user_name;
+ c.in.acct_flags = ACB_NORMAL;
+ c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ user_handle = talloc(mem_ctx, struct policy_handle);
+ c.out.user_handle = user_handle;
+ c.out.access_granted = &access_granted;
+ c.out.rid = &user_rid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_CreateUser2_r(samr_handle, mem_ctx, &c),
+ "samr_CreateUser2 failed");
+
+ if (NT_STATUS_EQUAL(c.out.result, NT_STATUS_USER_EXISTS)) {
+ struct samr_LookupNames ln;
+ struct samr_OpenUser ou;
+ struct samr_Ids rids, types;
+
+ ln.in.domain_handle = &domain_handle;
+ ln.in.num_names = 1;
+ ln.in.names = &user_name;
+ ln.out.rids = &rids;
+ ln.out.types = &types;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_LookupNames_r(samr_handle, mem_ctx, &ln),
+ "samr_LookupNames failed");
+ torture_assert_ntstatus_ok(tctx, ln.out.result,
+ "samr_LookupNames failed");
+
+ ou.in.domain_handle = &domain_handle;
+ ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ user_rid = ou.in.rid = ln.out.rids->ids[0];
+ ou.out.user_handle = user_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenUser_r(samr_handle, mem_ctx, &ou),
+ "samr_OpenUser failed");
+ status = ou.out.result;
+ } else {
+ status = c.out.result;
+ }
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "samr_CreateUser failed");
+
+ *result_pipe = samr_pipe;
+ *result_handle = user_handle;
+ if (sid_p != NULL) {
+ *sid_p = dom_sid_add_rid(mem_ctx, *l.out.sid, user_rid);
+ }
+ return true;
+
+}
+
+/*
+ * Create a test user
+ */
+
+static bool create_user(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct smbcli_state *cli,
+ struct cli_credentials *admin_creds,
+ const char *username, const char *password,
+ char **domain_name,
+ struct dom_sid **user_sid)
+{
+ TALLOC_CTX *tmp_ctx;
+ NTSTATUS status;
+ struct dcerpc_pipe *samr_pipe;
+ struct dcerpc_binding_handle *samr_handle;
+ struct policy_handle *wks_handle;
+ bool ret = false;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ torture_comment(tctx, "talloc_init failed\n");
+ return false;
+ }
+
+ ret = get_usr_handle(tctx, cli, tmp_ctx, admin_creds,
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ DCERPC_AUTH_LEVEL_INTEGRITY,
+ username, domain_name, &samr_pipe, &wks_handle,
+ user_sid);
+ if (ret == false) {
+ torture_comment(tctx, "get_usr_handle failed\n");
+ goto done;
+ }
+ samr_handle = samr_pipe->binding_handle;
+
+ {
+ struct samr_SetUserInfo2 sui2;
+ struct samr_SetUserInfo sui;
+ struct samr_QueryUserInfo qui;
+ union samr_UserInfo u_info;
+ union samr_UserInfo *info;
+ DATA_BLOB session_key;
+
+ ZERO_STRUCT(u_info);
+ encode_pw_buffer(u_info.info23.password.data, password,
+ STR_UNICODE);
+
+ status = dcerpc_fetch_session_key(samr_pipe, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed\n");
+ goto done;
+ }
+
+ status = init_samr_CryptPassword(password,
+ &session_key,
+ &u_info.info23.password);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "init_samr_CryptPassword failed\n");
+ goto done;
+ }
+
+ u_info.info23.info.password_expired = 0;
+ u_info.info23.info.fields_present = SAMR_FIELD_NT_PASSWORD_PRESENT |
+ SAMR_FIELD_LM_PASSWORD_PRESENT |
+ SAMR_FIELD_EXPIRED_FLAG;
+ sui2.in.user_handle = wks_handle;
+ sui2.in.info = &u_info;
+ sui2.in.level = 23;
+
+ status = dcerpc_samr_SetUserInfo2_r(samr_handle, tmp_ctx, &sui2);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "samr_SetUserInfo(23) failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(sui2.out.result)) {
+ torture_comment(tctx, "samr_SetUserInfo(23) failed: %s\n",
+ nt_errstr(sui2.out.result));
+ goto done;
+ }
+
+ u_info.info16.acct_flags = ACB_NORMAL;
+ sui.in.user_handle = wks_handle;
+ sui.in.info = &u_info;
+ sui.in.level = 16;
+
+ status = dcerpc_samr_SetUserInfo_r(samr_handle, tmp_ctx, &sui);
+ if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(sui.out.result)) {
+ torture_comment(tctx, "samr_SetUserInfo(16) failed\n");
+ goto done;
+ }
+
+ qui.in.user_handle = wks_handle;
+ qui.in.level = 21;
+ qui.out.info = &info;
+
+ status = dcerpc_samr_QueryUserInfo_r(samr_handle, tmp_ctx, &qui);
+ if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(qui.out.result)) {
+ torture_comment(tctx, "samr_QueryUserInfo(21) failed\n");
+ goto done;
+ }
+
+ info->info21.allow_password_change = 0;
+ info->info21.force_password_change = 0;
+ info->info21.account_name.string = NULL;
+ info->info21.rid = 0;
+ info->info21.acct_expiry = 0;
+ info->info21.fields_present = 0x81827fa; /* copy usrmgr.exe */
+
+ u_info.info21 = info->info21;
+ sui.in.user_handle = wks_handle;
+ sui.in.info = &u_info;
+ sui.in.level = 21;
+
+ status = dcerpc_samr_SetUserInfo_r(samr_handle, tmp_ctx, &sui);
+ if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(sui.out.result)) {
+ torture_comment(tctx, "samr_SetUserInfo(21) failed\n");
+ goto done;
+ }
+ }
+
+ *domain_name= talloc_steal(mem_ctx, *domain_name);
+ *user_sid = talloc_steal(mem_ctx, *user_sid);
+ ret = true;
+ done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ * Delete a test user
+ */
+
+static bool delete_user(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct cli_credentials *admin_creds,
+ const char *username)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ char *dom_name;
+ struct dcerpc_pipe *samr_pipe;
+ struct dcerpc_binding_handle *samr_handle;
+ struct policy_handle *user_handle;
+ bool ret = false;
+
+ if ((mem_ctx = talloc_init("leave")) == NULL) {
+ torture_comment(tctx, "talloc_init failed\n");
+ return false;
+ }
+
+ ret = get_usr_handle(tctx, cli, mem_ctx, admin_creds,
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ DCERPC_AUTH_LEVEL_INTEGRITY,
+ username, &dom_name, &samr_pipe,
+ &user_handle, NULL);
+ if (ret == false) {
+ torture_comment(tctx, "get_wks_handle failed\n");
+ goto done;
+ }
+ samr_handle = samr_pipe->binding_handle;
+
+ {
+ struct samr_DeleteUser d;
+
+ d.in.user_handle = user_handle;
+ d.out.user_handle = user_handle;
+
+ status = dcerpc_samr_DeleteUser_r(samr_handle, mem_ctx, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "samr_DeleteUser failed %s\n", nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ torture_comment(tctx, "samr_DeleteUser failed %s\n", nt_errstr(d.out.result));
+ goto done;
+ }
+
+ }
+
+ ret = true;
+
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Do a Samba3-style join
+ */
+
+static bool join3(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ bool use_level25,
+ struct cli_credentials *admin_creds,
+ struct cli_credentials *wks_creds)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ char *dom_name;
+ struct dcerpc_pipe *samr_pipe;
+ struct dcerpc_binding_handle *samr_handle;
+ struct policy_handle *wks_handle;
+ bool ret = false;
+ NTTIME last_password_change;
+
+ if ((mem_ctx = talloc_init("join3")) == NULL) {
+ torture_comment(tctx, "talloc_init failed\n");
+ return false;
+ }
+
+ ret = get_usr_handle(
+ tctx, cli, mem_ctx, admin_creds,
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ DCERPC_AUTH_LEVEL_PRIVACY,
+ talloc_asprintf(mem_ctx, "%s$",
+ cli_credentials_get_workstation(wks_creds)),
+ &dom_name, &samr_pipe, &wks_handle, NULL);
+ if (ret == false) {
+ torture_comment(tctx, "get_wks_handle failed\n");
+ goto done;
+ }
+ samr_handle = samr_pipe->binding_handle;
+ ret = false;
+ {
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+
+ q.in.user_handle = wks_handle;
+ q.in.level = 21;
+ q.out.info = &info;
+
+ status = dcerpc_samr_QueryUserInfo_r(samr_handle, mem_ctx, &q);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "QueryUserInfo failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_warning(tctx, "QueryUserInfo failed: %s\n",
+ nt_errstr(q.out.result));
+ goto done;
+ }
+
+
+ last_password_change = info->info21.last_password_change;
+ }
+
+ cli_credentials_set_domain(wks_creds, dom_name, CRED_SPECIFIED);
+
+ if (use_level25) {
+ struct samr_SetUserInfo2 sui2;
+ union samr_UserInfo u_info;
+ struct samr_UserInfo21 *i21 = &u_info.info25.info;
+ DATA_BLOB session_key;
+
+ ZERO_STRUCT(u_info);
+
+ i21->full_name.string = talloc_asprintf(
+ mem_ctx, "%s$",
+ cli_credentials_get_workstation(wks_creds));
+ i21->acct_flags = ACB_WSTRUST;
+ i21->fields_present = SAMR_FIELD_FULL_NAME |
+ SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_NT_PASSWORD_PRESENT;
+ /* this would break the test result expectations
+ i21->fields_present |= SAMR_FIELD_EXPIRED_FLAG;
+ i21->password_expired = 1;
+ */
+
+ status = dcerpc_fetch_session_key(samr_pipe, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = init_samr_CryptPasswordEx(cli_credentials_get_password(wks_creds),
+ &session_key,
+ &u_info.info25.password);
+
+ sui2.in.user_handle = wks_handle;
+ sui2.in.level = 25;
+ sui2.in.info = &u_info;
+
+ status = dcerpc_samr_SetUserInfo2_r(samr_handle, mem_ctx, &sui2);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "samr_SetUserInfo2(25) failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(sui2.out.result)) {
+ torture_comment(tctx, "samr_SetUserInfo2(25) failed: %s\n",
+ nt_errstr(sui2.out.result));
+ goto done;
+ }
+ } else {
+ struct samr_SetUserInfo2 sui2;
+ struct samr_SetUserInfo sui;
+ union samr_UserInfo u_info;
+ DATA_BLOB session_key;
+
+ encode_pw_buffer(u_info.info24.password.data,
+ cli_credentials_get_password(wks_creds),
+ STR_UNICODE);
+ /* just to make this test pass */
+ u_info.info24.password_expired = 1;
+
+ status = dcerpc_fetch_session_key(samr_pipe, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed\n");
+ goto done;
+ }
+
+ status = init_samr_CryptPassword(cli_credentials_get_password(wks_creds),
+ &session_key,
+ &u_info.info24.password);
+
+ sui2.in.user_handle = wks_handle;
+ sui2.in.info = &u_info;
+ sui2.in.level = 24;
+
+ status = dcerpc_samr_SetUserInfo2_r(samr_handle, mem_ctx, &sui2);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "samr_SetUserInfo(24) failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(sui2.out.result)) {
+ torture_comment(tctx, "samr_SetUserInfo(24) failed: %s\n",
+ nt_errstr(sui2.out.result));
+ goto done;
+ }
+
+ u_info.info16.acct_flags = ACB_WSTRUST;
+ sui.in.user_handle = wks_handle;
+ sui.in.info = &u_info;
+ sui.in.level = 16;
+
+ status = dcerpc_samr_SetUserInfo_r(samr_handle, mem_ctx, &sui);
+ if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(sui.out.result)) {
+ torture_comment(tctx, "samr_SetUserInfo(16) failed\n");
+ goto done;
+ }
+ }
+
+ {
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+
+ q.in.user_handle = wks_handle;
+ q.in.level = 21;
+ q.out.info = &info;
+
+ status = dcerpc_samr_QueryUserInfo_r(samr_handle, mem_ctx, &q);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "QueryUserInfo failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_warning(tctx, "QueryUserInfo failed: %s\n",
+ nt_errstr(q.out.result));
+ goto done;
+ }
+
+ if (use_level25) {
+ if (last_password_change
+ == info->info21.last_password_change) {
+ torture_warning(tctx, "last_password_change unchanged "
+ "during join, level25 must change "
+ "it\n");
+ goto done;
+ }
+ }
+ else {
+ if (last_password_change
+ != info->info21.last_password_change) {
+ torture_warning(tctx, "last_password_change changed "
+ "during join, level24 doesn't "
+ "change it\n");
+ goto done;
+ }
+ }
+ }
+
+ ret = true;
+
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Do a ReqChallenge/Auth2 and get the wks creds
+ */
+
+static bool auth2(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct cli_credentials *wks_cred)
+{
+ TALLOC_CTX *mem_ctx;
+ struct dcerpc_pipe *net_pipe;
+ struct dcerpc_binding_handle *net_handle;
+ bool result = false;
+ NTSTATUS status;
+ struct netr_ServerReqChallenge r;
+ struct netr_Credential netr_cli_creds;
+ struct netr_Credential netr_srv_creds;
+ uint32_t negotiate_flags;
+ struct netr_ServerAuthenticate2 a;
+ struct netlogon_creds_CredentialState *creds_state;
+ struct netr_Credential netr_cred;
+ struct samr_Password mach_pw;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ torture_comment(tctx, "talloc_new failed\n");
+ return false;
+ }
+
+ status = pipe_bind_smb(tctx, mem_ctx, cli->tree, "\\netlogon",
+ &ndr_table_netlogon, &net_pipe);
+ torture_assert_ntstatus_ok_goto(tctx, status, result, done,
+ "pipe_bind_smb failed");
+ net_handle = net_pipe->binding_handle;
+
+ r.in.computer_name = cli_credentials_get_workstation(wks_cred);
+ r.in.server_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(net_pipe));
+ if (r.in.server_name == NULL) {
+ torture_comment(tctx, "talloc_asprintf failed\n");
+ goto done;
+ }
+ generate_random_buffer(netr_cli_creds.data,
+ sizeof(netr_cli_creds.data));
+ r.in.credentials = &netr_cli_creds;
+ r.out.return_credentials = &netr_srv_creds;
+
+ status = dcerpc_netr_ServerReqChallenge_r(net_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "netr_ServerReqChallenge failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "netr_ServerReqChallenge failed: %s\n",
+ nt_errstr(r.out.result));
+ goto done;
+ }
+
+ negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
+ E_md4hash(cli_credentials_get_password(wks_cred), mach_pw.hash);
+
+ a.in.server_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(net_pipe));
+ a.in.account_name = talloc_asprintf(
+ mem_ctx, "%s$", cli_credentials_get_workstation(wks_cred));
+ a.in.computer_name = cli_credentials_get_workstation(wks_cred);
+ a.in.secure_channel_type = SEC_CHAN_WKSTA;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &netr_cred;
+ a.out.return_credentials = &netr_cred;
+
+ creds_state = netlogon_creds_client_init(mem_ctx,
+ a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ r.in.credentials,
+ r.out.return_credentials, &mach_pw,
+ &netr_cred, negotiate_flags);
+ torture_assert(tctx, (creds_state != NULL), "memory allocation failed");
+
+ status = dcerpc_netr_ServerAuthenticate2_r(net_handle, mem_ctx, &a);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "netr_ServerServerAuthenticate2 failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(a.out.result)) {
+ torture_comment(tctx, "netr_ServerServerAuthenticate2 failed: %s\n",
+ nt_errstr(a.out.result));
+ goto done;
+ }
+
+ if (!netlogon_creds_client_check(creds_state, a.out.return_credentials)) {
+ torture_comment(tctx, "creds_client_check failed\n");
+ goto done;
+ }
+
+ cli_credentials_set_netlogon_creds(wks_cred, creds_state);
+
+ result = true;
+
+ done:
+ talloc_free(mem_ctx);
+ return result;
+}
+
+/*
+ * Do a couple of schannel protected Netlogon ops: Interactive and Network
+ * login, and change the wks password
+ */
+
+static bool schan(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct cli_credentials *wks_creds,
+ struct cli_credentials *user_creds)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct dcerpc_pipe *net_pipe;
+ struct dcerpc_binding_handle *net_handle;
+ int i;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ torture_comment(tctx, "talloc_new failed\n");
+ return false;
+ }
+
+#if 1
+ status = pipe_bind_smb_auth(tctx, mem_ctx, cli->tree,
+ wks_creds,
+ DCERPC_AUTH_TYPE_SCHANNEL,
+ DCERPC_AUTH_LEVEL_PRIVACY,
+ "\\netlogon", &ndr_table_netlogon, &net_pipe);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "pipe_bind_smb_auth failed");
+ net_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
+#else
+ status = pipe_bind_smb(tctx, mem_ctx, cli->tree,
+ "\\netlogon", &ndr_table_netlogon, &net_pipe);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "pipe_bind_smb failed");
+#endif
+#if 0
+ net_pipe->conn->flags |= DCERPC_DEBUG_PRINT_IN |
+ DCERPC_DEBUG_PRINT_OUT;
+#endif
+ net_handle = net_pipe->binding_handle;
+
+
+ for (i=2; i<4; i++) {
+ int flags;
+ DATA_BLOB chal, nt_resp, lm_resp, names_blob;
+ struct netlogon_creds_CredentialState *creds_state;
+ struct netr_Authenticator netr_auth, netr_auth2;
+ struct netr_NetworkInfo ninfo;
+ struct netr_PasswordInfo pinfo;
+ struct netr_LogonSamLogon r;
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative;
+ struct netr_Authenticator return_authenticator;
+
+ flags = CLI_CRED_LANMAN_AUTH | CLI_CRED_NTLM_AUTH |
+ CLI_CRED_NTLMv2_AUTH;
+
+ chal = data_blob_talloc(mem_ctx, NULL, 8);
+ if (chal.data == NULL) {
+ torture_comment(tctx, "data_blob_talloc failed\n");
+ goto done;
+ }
+
+ generate_random_buffer(chal.data, chal.length);
+ names_blob = NTLMv2_generate_names_blob(
+ mem_ctx,
+ cli_credentials_get_workstation(wks_creds),
+ cli_credentials_get_domain(wks_creds));
+ status = cli_credentials_get_ntlm_response(
+ user_creds, mem_ctx, &flags, chal, NULL, names_blob,
+ &lm_resp, &nt_resp, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "cli_credentials_get_ntlm_response failed:"
+ " %s\n", nt_errstr(status));
+ goto done;
+ }
+
+ creds_state = cli_credentials_get_netlogon_creds(wks_creds);
+ netlogon_creds_client_authenticator(creds_state, &netr_auth);
+
+ ninfo.identity_info.account_name.string =
+ cli_credentials_get_username(user_creds);
+ ninfo.identity_info.domain_name.string =
+ cli_credentials_get_domain(user_creds);
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.workstation.string =
+ cli_credentials_get_workstation(user_creds);
+ memcpy(ninfo.challenge, chal.data, sizeof(ninfo.challenge));
+ ninfo.nt.length = nt_resp.length;
+ ninfo.nt.data = nt_resp.data;
+ ninfo.lm.length = lm_resp.length;
+ ninfo.lm.data = lm_resp.data;
+
+ logon.network = &ninfo;
+
+ r.in.server_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(net_pipe));
+ ZERO_STRUCT(netr_auth2);
+ r.in.computer_name =
+ cli_credentials_get_workstation(wks_creds);
+ r.in.credential = &netr_auth;
+ r.in.return_authenticator = &netr_auth2;
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.validation_level = i;
+ r.in.logon = &logon;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+ r.out.return_authenticator = &return_authenticator;
+
+ status = dcerpc_netr_LogonSamLogon_r(net_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "netr_LogonSamLogon failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "netr_LogonSamLogon failed: %s\n",
+ nt_errstr(r.out.result));
+ goto done;
+ }
+
+ if ((r.out.return_authenticator == NULL) ||
+ (!netlogon_creds_client_check(creds_state,
+ &r.out.return_authenticator->cred))) {
+ torture_comment(tctx, "Credentials check failed!\n");
+ goto done;
+ }
+
+ netlogon_creds_client_authenticator(creds_state, &netr_auth);
+
+ pinfo.identity_info = ninfo.identity_info;
+ ZERO_STRUCT(pinfo.lmpassword.hash);
+ E_md4hash(cli_credentials_get_password(user_creds),
+ pinfo.ntpassword.hash);
+
+ logon.password = &pinfo;
+
+ /*
+ * We don't use this here:
+ *
+ * netlogon_creds_encrypt_samlogon_logon(creds_state,
+ * NetlogonInteractiveInformation,
+ * &logon);
+ *
+ * in order to detect bugs
+ */
+ netlogon_creds_aes_encrypt(creds_state, pinfo.ntpassword.hash, 16);
+
+ r.in.logon_level = NetlogonInteractiveInformation;
+ r.in.logon = &logon;
+ r.out.return_authenticator = &return_authenticator;
+
+ status = dcerpc_netr_LogonSamLogon_r(net_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "netr_LogonSamLogon failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "netr_LogonSamLogon failed: %s\n",
+ nt_errstr(r.out.result));
+ goto done;
+ }
+
+ if ((r.out.return_authenticator == NULL) ||
+ (!netlogon_creds_client_check(creds_state,
+ &r.out.return_authenticator->cred))) {
+ torture_comment(tctx, "Credentials check failed!\n");
+ goto done;
+ }
+ }
+
+ {
+ struct netr_ServerPasswordSet s;
+ char *password = generate_random_password(wks_creds, 8, 255);
+ struct netlogon_creds_CredentialState *creds_state;
+ struct netr_Authenticator credential, return_authenticator;
+ struct samr_Password new_password;
+
+ s.in.server_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(net_pipe));
+ s.in.computer_name = cli_credentials_get_workstation(wks_creds);
+ s.in.account_name = talloc_asprintf(
+ mem_ctx, "%s$", s.in.computer_name);
+ s.in.secure_channel_type = SEC_CHAN_WKSTA;
+ s.in.credential = &credential;
+ s.in.new_password = &new_password;
+ s.out.return_authenticator = &return_authenticator;
+
+ E_md4hash(password, new_password.hash);
+
+ creds_state = cli_credentials_get_netlogon_creds(wks_creds);
+ netlogon_creds_des_encrypt(creds_state, &new_password);
+ netlogon_creds_client_authenticator(creds_state, &credential);
+
+ status = dcerpc_netr_ServerPasswordSet_r(net_handle, mem_ctx, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "ServerPasswordSet - %s\n", nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_comment(tctx, "ServerPasswordSet - %s\n", nt_errstr(s.out.result));
+ goto done;
+ }
+
+ if (!netlogon_creds_client_check(creds_state,
+ &s.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ cli_credentials_set_password(wks_creds, password,
+ CRED_SPECIFIED);
+ }
+
+ ret = true;
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Delete the wks account again
+ */
+
+static bool leave(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct cli_credentials *admin_creds,
+ struct cli_credentials *wks_creds)
+{
+ char *wks_name = talloc_asprintf(
+ NULL, "%s$", cli_credentials_get_workstation(wks_creds));
+ bool ret;
+
+ ret = delete_user(tctx, cli, admin_creds, wks_name);
+ talloc_free(wks_name);
+ return ret;
+}
+
+/*
+ * Test the Samba3 DC code a bit. Join, do some schan netlogon ops, leave
+ */
+
+static bool torture_netlogon_samba3(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct smbcli_state *cli;
+ struct cli_credentials *wks_creds;
+ const char *wks_name;
+ int i;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ wks_name = torture_setting_string(torture, "wksname", NULL);
+ torture_assert(torture, wks_name != NULL, "wksname not set");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(torture, &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok(torture, status, "smbcli_full_connection failed\n");
+
+ wks_creds = cli_credentials_init(torture);
+ if (wks_creds == NULL) {
+ torture_fail(torture, "cli_credentials_init failed\n");
+ }
+
+ cli_credentials_set_conf(wks_creds, torture->lp_ctx);
+ cli_credentials_set_secure_channel_type(wks_creds, SEC_CHAN_WKSTA);
+ cli_credentials_set_username(wks_creds, wks_name, CRED_SPECIFIED);
+ cli_credentials_set_workstation(wks_creds, wks_name, CRED_SPECIFIED);
+ cli_credentials_set_password(wks_creds,
+ generate_random_password(wks_creds, 8, 255),
+ CRED_SPECIFIED);
+
+ torture_assert(torture,
+ join3(torture, cli, false, NULL, wks_creds),
+ "join failed");
+
+ cli_credentials_set_domain(
+ samba_cmdline_get_creds(),
+ cli_credentials_get_domain(wks_creds),
+ CRED_SPECIFIED);
+
+ for (i=0; i<2; i++) {
+
+ /* Do this more than once, the routine "schan" changes
+ * the workstation password using the netlogon
+ * password change routine */
+
+ int j;
+
+ torture_assert(torture,
+ auth2(torture, cli, wks_creds),
+ "auth2 failed");
+
+ for (j=0; j<2; j++) {
+ torture_assert(torture,
+ schan(torture, cli, wks_creds,
+ samba_cmdline_get_creds()),
+ "schan failed");
+ }
+ }
+
+ torture_assert(torture,
+ leave(torture, cli, NULL, wks_creds),
+ "leave failed");
+
+ return true;
+}
+
+/*
+ * Do a simple join, testjoin and leave using specified smb and samr
+ * credentials
+ */
+
+static bool test_join3(struct torture_context *tctx,
+ bool use_level25,
+ struct cli_credentials *smb_creds,
+ struct cli_credentials *samr_creds,
+ const char *wks_name)
+{
+ NTSTATUS status;
+ struct smbcli_state *cli;
+ struct cli_credentials *wks_creds;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(tctx, &cli,
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ "IPC$", NULL, lpcfg_socket_options(tctx->lp_ctx),
+ smb_creds, lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status,
+ "smbcli_full_connection failed");
+
+ wks_creds = cli_credentials_init(cli);
+ torture_assert(tctx, wks_creds, "cli_credentials_init failed");
+
+ cli_credentials_set_conf(wks_creds, tctx->lp_ctx);
+ cli_credentials_set_secure_channel_type(wks_creds, SEC_CHAN_WKSTA);
+ cli_credentials_set_username(wks_creds, wks_name, CRED_SPECIFIED);
+ cli_credentials_set_workstation(wks_creds, wks_name, CRED_SPECIFIED);
+ cli_credentials_set_password(wks_creds,
+ generate_random_password(wks_creds, 8, 255),
+ CRED_SPECIFIED);
+
+ torture_assert(tctx,
+ join3(tctx, cli, use_level25, samr_creds, wks_creds),
+ "join failed");
+
+ cli_credentials_set_domain(
+ samba_cmdline_get_creds(),
+ cli_credentials_get_domain(wks_creds),
+ CRED_SPECIFIED);
+
+ torture_assert(tctx,
+ auth2(tctx, cli, wks_creds),
+ "auth2 failed");
+
+ torture_assert(tctx,
+ leave(tctx, cli, samr_creds, wks_creds),
+ "leave failed");
+
+ talloc_free(cli);
+
+ return true;
+}
+
+/*
+ * Test the different session key variants. Do it by joining, this uses the
+ * session key in the setpassword routine. Test the join by doing the auth2.
+ */
+
+static bool torture_samba3_sessionkey(struct torture_context *torture)
+{
+ struct cli_credentials *anon_creds;
+ const char *wks_name;
+
+
+ wks_name = torture_setting_string(torture, "wksname", NULL);
+ torture_assert(torture, wks_name != NULL, "wksname not set");
+
+ if (!(anon_creds = cli_credentials_init_anon(torture))) {
+ torture_fail(torture, "create_anon_creds failed\n");
+ }
+
+ cli_credentials_set_workstation(anon_creds, wks_name, CRED_SPECIFIED);
+
+
+ if (!torture_setting_bool(torture, "samba3", false)) {
+
+ /* Samba3 in the build farm right now does this happily. Need
+ * to fix :-) */
+
+ if (test_join3(torture, false, anon_creds, NULL, wks_name)) {
+ torture_fail(torture, "join using anonymous bind on an anonymous smb "
+ "connection succeeded -- HUH??\n");
+ }
+ }
+
+ torture_assert(torture,
+ test_join3(torture, false, samba_cmdline_get_creds(),
+ NULL, wks_name),
+ "join using anonymous bind on an authenticated smb connection failed");
+
+ /*
+ * The following two are tests for setuserinfolevel 25
+ */
+
+ torture_assert(torture,
+ test_join3(torture, true, samba_cmdline_get_creds(),
+ NULL, wks_name),
+ "join using anonymous bind on an authenticated smb connection failed");
+
+ return true;
+}
+
+/*
+ * Sane wrapper around lsa_LookupNames
+ */
+
+static struct dom_sid *name2sid(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ const char *domain)
+{
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 r;
+ struct lsa_Close c;
+ NTSTATUS status;
+ struct policy_handle handle;
+ struct lsa_LookupNames l;
+ struct lsa_TransSidArray sids;
+ struct lsa_RefDomainList *domains = NULL;
+ struct lsa_String lsa_name;
+ uint32_t count = 0;
+ struct dom_sid *result;
+ TALLOC_CTX *tmp_ctx;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ return NULL;
+ }
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = "\\";
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ status = dcerpc_lsa_OpenPolicy2_r(b, tmp_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "OpenPolicy2 failed - %s\n", nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "OpenPolicy2 failed - %s\n", nt_errstr(r.out.result));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ sids.count = 0;
+ sids.sids = NULL;
+
+ lsa_name.string = talloc_asprintf(tmp_ctx, "%s\\%s", domain, name);
+
+ l.in.handle = &handle;
+ l.in.num_names = 1;
+ l.in.names = &lsa_name;
+ l.in.sids = &sids;
+ l.in.level = 1;
+ l.in.count = &count;
+ l.out.count = &count;
+ l.out.sids = &sids;
+ l.out.domains = &domains;
+
+ status = dcerpc_lsa_LookupNames_r(b, tmp_ctx, &l);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "LookupNames of %s failed - %s\n", lsa_name.string,
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(l.out.result)) {
+ torture_comment(tctx, "LookupNames of %s failed - %s\n", lsa_name.string,
+ nt_errstr(l.out.result));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ result = dom_sid_add_rid(mem_ctx, domains->domains[0].sid,
+ l.out.sids->sids[0].rid);
+
+ c.in.handle = &handle;
+ c.out.handle = &handle;
+
+ status = dcerpc_lsa_Close_r(b, tmp_ctx, &c);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_lsa_Close failed - %s\n", nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(c.out.result)) {
+ torture_comment(tctx, "dcerpc_lsa_Close failed - %s\n", nt_errstr(c.out.result));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return result;
+}
+
+/*
+ * Find out the user SID on this connection
+ */
+
+static struct dom_sid *whoami(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_tree *tree)
+{
+ struct dcerpc_pipe *lsa;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_GetUserName r;
+ NTSTATUS status;
+ struct lsa_String *authority_name_p = NULL;
+ struct lsa_String *account_name_p = NULL;
+ struct dom_sid *result;
+
+ status = pipe_bind_smb(tctx, mem_ctx, tree, "\\pipe\\lsarpc",
+ &ndr_table_lsarpc, &lsa);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "Could not bind to LSA: %s\n",
+ nt_errstr(status));
+ return NULL;
+ }
+ lsa_handle = lsa->binding_handle;
+
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "GetUserName failed - %s\n",
+ nt_errstr(status));
+ talloc_free(lsa);
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_warning(tctx, "GetUserName failed - %s\n",
+ nt_errstr(r.out.result));
+ talloc_free(lsa);
+ return NULL;
+ }
+
+ result = name2sid(tctx, mem_ctx, lsa, account_name_p->string,
+ authority_name_p->string);
+
+ talloc_free(lsa);
+ return result;
+}
+
+static int destroy_tree(struct smbcli_tree *tree)
+{
+ smb_tree_disconnect(tree);
+ return 0;
+}
+
+/*
+ * Do a tcon, given a session
+ */
+
+static NTSTATUS secondary_tcon(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_session *session,
+ const char *sharename,
+ struct smbcli_tree **res)
+{
+ struct smbcli_tree *result;
+ TALLOC_CTX *tmp_ctx;
+ union smb_tcon tcon;
+ NTSTATUS status;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(result = smbcli_tree_init(session, mem_ctx, false))) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = sharename;
+ tcon.tconx.in.device = "?????";
+
+ status = smb_raw_tcon(result, tmp_ctx, &tcon);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smb_raw_tcon failed: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ result->tid = tcon.tconx.out.tid;
+
+ if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
+ smb1cli_session_protect_session_key(result->session->smbXcli);
+ }
+
+ result = talloc_steal(mem_ctx, result);
+ talloc_set_destructor(result, destroy_tree);
+ talloc_free(tmp_ctx);
+ *res = result;
+ return NT_STATUS_OK;
+}
+
+/*
+ * Test the getusername behaviour
+ */
+
+static bool torture_samba3_rpc_getusername(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct smbcli_state *cli;
+ bool ret = true;
+ struct dom_sid *user_sid;
+ struct dom_sid *created_sid;
+ struct cli_credentials *anon_creds;
+ struct cli_credentials *user_creds;
+ char *domain_name;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ if (!(anon_creds = cli_credentials_init_anon(torture))) {
+ torture_fail(torture, "create_anon_creds failed\n");
+ }
+
+ status = smbcli_full_connection(
+ torture, &cli, torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx), "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx), anon_creds,
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok(torture, status, "anon smbcli_full_connection failed\n");
+
+ if (!(user_sid = whoami(torture, torture, cli->tree))) {
+ torture_fail(torture, "whoami on anon connection failed\n");
+ }
+
+ torture_assert_sid_equal(torture, user_sid, dom_sid_parse_talloc(torture, "s-1-5-7"),
+ "Anon lsa_GetUserName returned unexpected SID");
+
+ talloc_free(cli);
+
+ status = smbcli_full_connection(
+ torture, &cli, torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL, lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx), torture->ev, &options,
+ &session_options, lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok(torture, status, "smbcli_full_connection failed\n");
+
+ if (!(user_sid = whoami(torture, torture, cli->tree))) {
+ torture_fail(torture, "whoami on auth'ed connection failed\n");
+ }
+
+ if (!(user_creds = cli_credentials_init(torture))) {
+ torture_fail(torture, "cli_credentials_init failed\n");
+ }
+
+ cli_credentials_set_conf(user_creds, torture->lp_ctx);
+ cli_credentials_set_username(user_creds, "torture_username",
+ CRED_SPECIFIED);
+ cli_credentials_set_password(user_creds,
+ generate_random_password(user_creds, 8, 255),
+ CRED_SPECIFIED);
+
+ if (!create_user(torture, torture, cli, NULL,
+ cli_credentials_get_username(user_creds),
+ cli_credentials_get_password(user_creds),
+ &domain_name, &created_sid)) {
+ torture_fail(torture, "create_user failed\n");
+ }
+
+ cli_credentials_set_domain(user_creds, domain_name,
+ CRED_SPECIFIED);
+
+ {
+ struct smbcli_session *session2;
+ struct smb_composite_sesssetup setup;
+ struct smbcli_tree *tree;
+
+ session2 = smbcli_session_init(cli->transport, torture, false, session_options);
+ if (session2 == NULL) {
+ torture_fail(torture, "smbcli_session_init failed\n");
+ }
+
+ setup.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.in.capabilities = cli->transport->negotiate.capabilities;
+ setup.in.workgroup = "";
+ setup.in.credentials = user_creds;
+ setup.in.gensec_settings = lpcfg_gensec_settings(torture, torture->lp_ctx);
+
+ status = smb_composite_sesssetup(session2, &setup);
+ torture_assert_ntstatus_ok(torture, status, "session setup with new user failed");
+
+ session2->vuid = setup.out.vuid;
+
+ if (!NT_STATUS_IS_OK(secondary_tcon(torture, torture, session2,
+ "IPC$", &tree))) {
+ torture_fail(torture, "secondary_tcon failed\n");
+ }
+
+ if (!(user_sid = whoami(torture, torture, tree))) {
+ torture_fail_goto(torture, del, "whoami on user connection failed\n");
+ ret = false;
+ goto del;
+ }
+
+ talloc_free(tree);
+ }
+
+ torture_comment(torture, "Created %s, found %s\n",
+ dom_sid_string(torture, created_sid),
+ dom_sid_string(torture, user_sid));
+
+ if (!dom_sid_equal(created_sid, user_sid)) {
+ ret = false;
+ }
+
+ del:
+ if (!delete_user(torture, cli,
+ NULL,
+ cli_credentials_get_username(user_creds))) {
+ torture_fail(torture, "delete_user failed\n");
+ }
+
+ return ret;
+}
+
+static bool test_NetShareGetInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *sharename)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareGetInfo r;
+ union srvsvc_NetShareInfo info;
+ uint32_t levels[] = { 0, 1, 2, 501, 502, 1004, 1005, 1006, 1007, 1501 };
+ int i;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.in.share_name = sharename;
+ r.out.info = &info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ r.in.level = levels[i];
+
+ torture_comment(tctx, "Testing NetShareGetInfo level %u on share '%s'\n",
+ r.in.level, r.in.share_name);
+
+ status = dcerpc_srvsvc_NetShareGetInfo_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "NetShareGetInfo level %u on share '%s' failed"
+ " - %s\n", r.in.level, r.in.share_name,
+ nt_errstr(status));
+ ret = false;
+ continue;
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_warning(tctx, "NetShareGetInfo level %u on share '%s' failed "
+ "- %s\n", r.in.level, r.in.share_name,
+ win_errstr(r.out.result));
+ ret = false;
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_NetShareEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char **one_sharename)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareEnum r;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr0 c0;
+ struct srvsvc_NetShareCtr1 c1;
+ struct srvsvc_NetShareCtr2 c2;
+ struct srvsvc_NetShareCtr501 c501;
+ struct srvsvc_NetShareCtr502 c502;
+ struct srvsvc_NetShareCtr1004 c1004;
+ struct srvsvc_NetShareCtr1005 c1005;
+ struct srvsvc_NetShareCtr1006 c1006;
+ struct srvsvc_NetShareCtr1007 c1007;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = { 0, 1, 2, 501, 502, 1004, 1005, 1006, 1007 };
+ int i;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ info_ctr.level = levels[i];
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ case 2:
+ ZERO_STRUCT(c2);
+ info_ctr.ctr.ctr2 = &c2;
+ break;
+ case 501:
+ ZERO_STRUCT(c501);
+ info_ctr.ctr.ctr501 = &c501;
+ break;
+ case 502:
+ ZERO_STRUCT(c502);
+ info_ctr.ctr.ctr502 = &c502;
+ break;
+ case 1004:
+ ZERO_STRUCT(c1004);
+ info_ctr.ctr.ctr1004 = &c1004;
+ break;
+ case 1005:
+ ZERO_STRUCT(c1005);
+ info_ctr.ctr.ctr1005 = &c1005;
+ break;
+ case 1006:
+ ZERO_STRUCT(c1006);
+ info_ctr.ctr.ctr1006 = &c1006;
+ break;
+ case 1007:
+ ZERO_STRUCT(c1007);
+ info_ctr.ctr.ctr1007 = &c1007;
+ break;
+ }
+
+ torture_comment(tctx, "Testing NetShareEnum level %u\n", info_ctr.level);
+
+ status = dcerpc_srvsvc_NetShareEnum_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "NetShareEnum level %u failed - %s\n",
+ info_ctr.level, nt_errstr(status));
+ ret = false;
+ continue;
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_warning(tctx, "NetShareEnum level %u failed - %s\n",
+ info_ctr.level, win_errstr(r.out.result));
+ continue;
+ }
+ if (info_ctr.level == 0) {
+ struct srvsvc_NetShareCtr0 *ctr = r.out.info_ctr->ctr.ctr0;
+ if (ctr->count > 0) {
+ *one_sharename = ctr->array[0].name;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool torture_samba3_rpc_srvsvc(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ const char *sharename = NULL;
+ bool ret = true;
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p, &ndr_table_srvsvc),
+ "failed to open srvsvc");
+
+ ret &= test_NetShareEnum(torture, p, &sharename);
+ if (sharename == NULL) {
+ torture_comment(torture, "did not get sharename\n");
+ } else {
+ ret &= test_NetShareGetInfo(torture, p, sharename);
+ }
+
+ return ret;
+}
+
+/*
+ * Do a ReqChallenge/Auth2 with a random wks name, make sure it returns
+ * NT_STATUS_NO_SAM_ACCOUNT
+ */
+
+static bool torture_samba3_rpc_randomauth2(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ struct dcerpc_pipe *net_pipe;
+ struct dcerpc_binding_handle *net_handle;
+ char *wksname;
+ bool result = false;
+ NTSTATUS status;
+ struct netr_ServerReqChallenge r;
+ struct netr_Credential netr_cli_creds;
+ struct netr_Credential netr_srv_creds;
+ uint32_t negotiate_flags;
+ struct netr_ServerAuthenticate2 a;
+ struct netlogon_creds_CredentialState *creds_state;
+ struct netr_Credential netr_cred;
+ struct samr_Password mach_pw;
+ struct smbcli_state *cli;
+
+ if (!(mem_ctx = talloc_new(torture))) {
+ torture_comment(torture, "talloc_new failed\n");
+ return false;
+ }
+
+ if (!(wksname = generate_random_str_list(
+ mem_ctx, 14, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"))) {
+ torture_comment(torture, "generate_random_str_list failed\n");
+ goto done;
+ }
+
+ if (!(torture_open_connection_share(
+ mem_ctx, &cli,
+ torture, torture_setting_string(torture, "host", NULL),
+ "IPC$", torture->ev))) {
+ torture_comment(torture, "IPC$ connection failed\n");
+ goto done;
+ }
+
+ status = pipe_bind_smb(torture, mem_ctx, cli->tree, "\\netlogon",
+ &ndr_table_netlogon, &net_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, result, done,
+ "pipe_bind_smb failed");
+ net_handle = net_pipe->binding_handle;
+
+ r.in.computer_name = wksname;
+ r.in.server_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(net_pipe));
+ if (r.in.server_name == NULL) {
+ torture_comment(torture, "talloc_asprintf failed\n");
+ goto done;
+ }
+ generate_random_buffer(netr_cli_creds.data,
+ sizeof(netr_cli_creds.data));
+ r.in.credentials = &netr_cli_creds;
+ r.out.return_credentials = &netr_srv_creds;
+
+ status = dcerpc_netr_ServerReqChallenge_r(net_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "netr_ServerReqChallenge failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(torture, "netr_ServerReqChallenge failed: %s\n",
+ nt_errstr(r.out.result));
+ goto done;
+ }
+
+ negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
+ E_md4hash("foobar", mach_pw.hash);
+
+ a.in.server_name = talloc_asprintf(
+ mem_ctx, "\\\\%s", dcerpc_server_name(net_pipe));
+ a.in.account_name = talloc_asprintf(
+ mem_ctx, "%s$", wksname);
+ a.in.computer_name = wksname;
+ a.in.secure_channel_type = SEC_CHAN_WKSTA;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.out.negotiate_flags = &negotiate_flags;
+ a.in.credentials = &netr_cred;
+ a.out.return_credentials = &netr_cred;
+
+ creds_state = netlogon_creds_client_init(mem_ctx,
+ a.in.account_name,
+ a.in.computer_name,
+ a.in.secure_channel_type,
+ r.in.credentials,
+ r.out.return_credentials, &mach_pw,
+ &netr_cred, negotiate_flags);
+ torture_assert(torture, (creds_state != NULL), "memory allocation failed");
+
+ status = dcerpc_netr_ServerAuthenticate2_r(net_handle, mem_ctx, &a);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ if (!NT_STATUS_EQUAL(a.out.result, NT_STATUS_NO_TRUST_SAM_ACCOUNT)) {
+ torture_comment(torture, "dcerpc_netr_ServerAuthenticate2 returned %s, "
+ "expected NT_STATUS_NO_TRUST_SAM_ACCOUNT\n",
+ nt_errstr(a.out.result));
+ goto done;
+ }
+
+ result = true;
+ done:
+ talloc_free(mem_ctx);
+ return result;
+}
+
+static struct security_descriptor *get_sharesec(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_session *sess,
+ const char *sharename)
+{
+ struct smbcli_tree *tree;
+ TALLOC_CTX *tmp_ctx;
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ NTSTATUS status;
+ struct srvsvc_NetShareGetInfo r;
+ union srvsvc_NetShareInfo info;
+ struct security_descriptor *result;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ torture_comment(tctx, "talloc_new failed\n");
+ return NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(secondary_tcon(tctx, tmp_ctx, sess, "IPC$", &tree))) {
+ torture_comment(tctx, "secondary_tcon failed\n");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ status = pipe_bind_smb(tctx, mem_ctx, tree, "\\pipe\\srvsvc",
+ &ndr_table_srvsvc, &p);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "could not bind to srvsvc pipe: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ b = p->binding_handle;
+
+#if 0
+ p->conn->flags |= DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT;
+#endif
+
+ r.in.server_unc = talloc_asprintf(tmp_ctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.in.share_name = sharename;
+ r.in.level = 502;
+ r.out.info = &info;
+
+ status = dcerpc_srvsvc_NetShareGetInfo_r(b, tmp_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "srvsvc_NetShareGetInfo failed: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "srvsvc_NetShareGetInfo failed: %s\n",
+ win_errstr(r.out.result));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ result = talloc_steal(mem_ctx, info.info502->sd_buf.sd);
+ talloc_free(tmp_ctx);
+ return result;
+}
+
+static NTSTATUS set_sharesec(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smbcli_session *sess,
+ const char *sharename,
+ struct security_descriptor *sd)
+{
+ struct smbcli_tree *tree;
+ TALLOC_CTX *tmp_ctx;
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ NTSTATUS status;
+ struct sec_desc_buf i;
+ struct srvsvc_NetShareSetInfo r;
+ union srvsvc_NetShareInfo info;
+ uint32_t error = 0;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ torture_comment(tctx, "talloc_new failed\n");
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!NT_STATUS_IS_OK(secondary_tcon(tctx, tmp_ctx, sess, "IPC$", &tree))) {
+ torture_comment(tctx, "secondary_tcon failed\n");
+ talloc_free(tmp_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ status = pipe_bind_smb(tctx, mem_ctx, tree, "\\pipe\\srvsvc",
+ &ndr_table_srvsvc, &p);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "could not bind to srvsvc pipe: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ b = p->binding_handle;
+
+#if 0
+ p->conn->flags |= DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT;
+#endif
+
+ r.in.server_unc = talloc_asprintf(tmp_ctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.in.share_name = sharename;
+ r.in.level = 1501;
+ i.sd = sd;
+ info.info1501 = &i;
+ r.in.info = &info;
+ r.in.parm_error = &error;
+
+ status = dcerpc_srvsvc_NetShareSetInfo_r(b, tmp_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "srvsvc_NetShareSetInfo failed: %s\n",
+ nt_errstr(status));
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "srvsvc_NetShareSetInfo failed: %s\n",
+ win_errstr(r.out.result));
+ status = werror_to_ntstatus(r.out.result);
+ }
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+bool try_tcon(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor *orig_sd,
+ struct smbcli_session *session,
+ const char *sharename, const struct dom_sid *user_sid,
+ unsigned int access_mask, NTSTATUS expected_tcon,
+ NTSTATUS expected_mkdir)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct smbcli_tree *rmdir_tree, *tree;
+ struct dom_sid *domain_sid;
+ uint32_t rid;
+ struct security_descriptor *sd;
+ NTSTATUS status;
+ bool ret = true;
+
+ if (!(tmp_ctx = talloc_new(mem_ctx))) {
+ torture_comment(tctx, "talloc_new failed\n");
+ return false;
+ }
+
+ status = secondary_tcon(tctx, tmp_ctx, session, sharename, &rmdir_tree);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "first tcon to delete dir failed\n");
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ smbcli_rmdir(rmdir_tree, "sharesec_testdir");
+
+ if (!NT_STATUS_IS_OK(dom_sid_split_rid(tmp_ctx, user_sid,
+ &domain_sid, &rid))) {
+ torture_comment(tctx, "dom_sid_split_rid failed\n");
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ sd = security_descriptor_dacl_create(
+ tmp_ctx, 0, "S-1-5-32-544",
+ dom_sid_string(mem_ctx, dom_sid_add_rid(mem_ctx, domain_sid,
+ DOMAIN_RID_USERS)),
+ dom_sid_string(mem_ctx, user_sid),
+ SEC_ACE_TYPE_ACCESS_ALLOWED, access_mask, 0, NULL);
+ if (sd == NULL) {
+ torture_comment(tctx, "security_descriptor_dacl_create failed\n");
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ status = set_sharesec(tctx, mem_ctx, session, sharename, sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "custom set_sharesec failed: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ status = secondary_tcon(tctx, tmp_ctx, session, sharename, &tree);
+ if (!NT_STATUS_EQUAL(status, expected_tcon)) {
+ torture_comment(tctx, "Expected %s, got %s\n", nt_errstr(expected_tcon),
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /* An expected non-access, no point in trying to write */
+ goto done;
+ }
+
+ status = smbcli_mkdir(tree, "sharesec_testdir");
+ if (!NT_STATUS_EQUAL(status, expected_mkdir)) {
+ torture_warning(tctx, "Expected %s, got %s\n",
+ nt_errstr(expected_mkdir), nt_errstr(status));
+ ret = false;
+ }
+
+ done:
+ smbcli_rmdir(rmdir_tree, "sharesec_testdir");
+
+ status = set_sharesec(tctx, mem_ctx, session, sharename, orig_sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "custom set_sharesec failed: %s\n",
+ nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static bool torture_samba3_rpc_sharesec(struct torture_context *torture)
+{
+ struct smbcli_state *cli = NULL;
+ struct security_descriptor *sd = NULL;
+ struct dom_sid *user_sid = NULL;
+ const char *testuser_passwd = NULL;
+ struct cli_credentials *test_credentials = NULL;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+ NTSTATUS status;
+ struct test_join *tj = NULL;
+ struct dcerpc_pipe *lsa_pipe = NULL;
+ const char *priv_array[1];
+
+ /* Create a new user. The normal user has SeBackup and SeRestore
+ privs so we can't lock them out with a share security descriptor. */
+ tj = torture_create_testuser(torture,
+ "sharesec_user",
+ torture_setting_string(torture, "workgroup", NULL),
+ ACB_NORMAL,
+ &testuser_passwd);
+ if (!tj) {
+ torture_fail(torture, "Creating sharesec_user failed\n");
+ }
+
+ /* Give them SeDiskOperatorPrivilege but no other privs. */
+ status = torture_rpc_connection(torture, &lsa_pipe, &ndr_table_lsarpc);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ torture_fail(torture, "Error connecting to LSA pipe");
+ }
+
+ priv_array[0] = "SeDiskOperatorPrivilege";
+ if (!torture_setup_privs(torture,
+ lsa_pipe,
+ 1,
+ priv_array,
+ torture_join_user_sid(tj))) {
+ talloc_free(lsa_pipe);
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ torture_fail(torture, "Failed to setup privs\n");
+ }
+ talloc_free(lsa_pipe);
+
+ test_credentials = cli_credentials_init(torture);
+ cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED);
+ cli_credentials_set_domain(test_credentials, lpcfg_workgroup(torture->lp_ctx),
+ CRED_SPECIFIED);
+ cli_credentials_set_username(test_credentials, "sharesec_user", CRED_SPECIFIED);
+ cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED);
+
+ ZERO_STRUCT(options);
+ ZERO_STRUCT(session_options);
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(torture,
+ &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ test_credentials,
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev,
+ &options,
+ &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(cli);
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ torture_fail(torture, "Failed to open connection\n");
+ }
+
+ if (!(user_sid = whoami(torture, torture, cli->tree))) {
+ talloc_free(cli);
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ torture_fail(torture, "whoami failed\n");
+ }
+
+ sd = get_sharesec(torture, torture, cli->session,
+ torture_setting_string(torture, "share", NULL));
+
+ if (!try_tcon(torture, torture, sd, cli->session,
+ torture_setting_string(torture, "share", NULL),
+ user_sid, 0, NT_STATUS_ACCESS_DENIED, NT_STATUS_OK)) {
+ talloc_free(cli);
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ torture_fail(torture, "failed to test tcon with 0 access_mask");
+ }
+
+ if (!try_tcon(torture, torture, sd, cli->session,
+ torture_setting_string(torture, "share", NULL),
+ user_sid, SEC_FILE_READ_DATA, NT_STATUS_OK,
+ NT_STATUS_MEDIA_WRITE_PROTECTED)) {
+ talloc_free(cli);
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ torture_fail(torture, "failed to test tcon with SEC_FILE_READ_DATA access_mask");
+ }
+
+ /* sharesec_user doesn't have any rights on the underlying file system.
+ Go back to the normal user. */
+
+ talloc_free(cli);
+ cli = NULL;
+ torture_delete_testuser(torture, tj, "sharesec_user");
+ talloc_free(tj);
+ tj = NULL;
+
+ if (!(torture_open_connection_share(
+ torture, &cli, torture, torture_setting_string(torture, "host", NULL),
+ "IPC$", torture->ev))) {
+ torture_fail(torture, "IPC$ connection failed\n");
+ }
+
+ if (!(user_sid = whoami(torture, torture, cli->tree))) {
+ torture_fail(torture, "whoami failed\n");
+ }
+ torture_assert(torture, try_tcon(
+ torture, torture, sd, cli->session,
+ torture_setting_string(torture, "share", NULL),
+ user_sid, SEC_FILE_ALL, NT_STATUS_OK, NT_STATUS_OK),
+ "failed to test tcon with SEC_FILE_ALL access_mask");
+
+ return true;
+}
+
+static bool torture_samba3_rpc_lsa(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ struct policy_handle lsa_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p, &ndr_table_lsarpc),
+ "failed to setup lsarpc");
+
+ b = p->binding_handle;
+
+ {
+ struct lsa_ObjectAttribute attr;
+ struct lsa_OpenPolicy2 o;
+ o.in.system_name = talloc_asprintf(
+ torture, "\\\\%s", dcerpc_server_name(p));
+ ZERO_STRUCT(attr);
+ o.in.attr = &attr;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.out.handle = &lsa_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_lsa_OpenPolicy2_r(b, torture, &o),
+ "dcerpc_lsa_OpenPolicy2 failed");
+ torture_assert_ntstatus_ok(torture, o.out.result,
+ "dcerpc_lsa_OpenPolicy2 failed");
+ }
+
+ {
+ int i;
+ int levels[] = { 2,3,5,6 };
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+ struct lsa_QueryInfoPolicy r;
+ union lsa_PolicyInformation *info = NULL;
+ r.in.handle = &lsa_handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_lsa_QueryInfoPolicy_r(b, torture, &r),
+ talloc_asprintf(torture, "dcerpc_lsa_QueryInfoPolicy level %d failed", levels[i]));
+ torture_assert_ntstatus_ok(torture, r.out.result,
+ talloc_asprintf(torture, "dcerpc_lsa_QueryInfoPolicy level %d failed", levels[i]));
+ }
+ }
+
+ return true;
+}
+
+static NTSTATUS get_servername(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree,
+ char **name)
+{
+ struct rap_WserverGetInfo r;
+ NTSTATUS status;
+ char servername[17];
+ size_t converted_size;
+
+ r.in.level = 0;
+ r.in.bufsize = 0xffff;
+
+ status = smbcli_rap_netservergetinfo(tree, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ memcpy(servername, r.out.info.info0.name, 16);
+ servername[16] = '\0';
+
+ if (!pull_ascii_talloc(mem_ctx, name, servername, &converted_size)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static bool rap_get_servername(struct torture_context *tctx,
+ char **servername)
+{
+ struct smbcli_state *cli;
+
+ torture_assert(tctx,
+ torture_open_connection_share(tctx, &cli, tctx, torture_setting_string(tctx, "host", NULL),
+ "IPC$", tctx->ev),
+ "IPC$ connection failed");
+
+ torture_assert_ntstatus_ok(tctx,
+ get_servername(tctx, cli->tree, servername),
+ "get_servername failed");
+
+ talloc_free(cli);
+
+ return true;
+}
+
+static bool find_printers(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char ***printers,
+ size_t *num_printers)
+{
+ struct srvsvc_NetShareEnum r;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr1 c1_in;
+ struct srvsvc_NetShareCtr1 *c1;
+ uint32_t totalentries = 0;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(c1_in);
+ info_ctr.level = 1;
+ info_ctr.ctr.ctr1 = &c1_in;
+
+ r.in.server_unc = talloc_asprintf(
+ tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_srvsvc_NetShareEnum_r(b, tctx, &r),
+ "NetShareEnum level 1 failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetShareEnum level 1 failed");
+
+ *printers = NULL;
+ *num_printers = 0;
+ c1 = r.out.info_ctr->ctr.ctr1;
+ for (i=0; i<c1->count; i++) {
+ if (c1->array[i].type != STYPE_PRINTQ) {
+ continue;
+ }
+ if (!add_string_to_array(tctx, c1->array[i].name,
+ printers, num_printers)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool enumprinters(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername, int level, int *num_printers)
+{
+ struct spoolss_EnumPrinters r;
+ DATA_BLOB blob;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+
+ r.in.flags = PRINTER_ENUM_LOCAL;
+ r.in.server = talloc_asprintf(tctx, "\\\\%s", servername);
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+ "dcerpc_spoolss_EnumPrinters failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "EnumPrinters unexpected return code should be WERR_INSUFFICIENT_BUFFER");
+
+ blob = data_blob_talloc_zero(tctx, needed);
+ if (blob.data == NULL) {
+ return false;
+ }
+
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+ "dcerpc_spoolss_EnumPrinters failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "dcerpc_spoolss_EnumPrinters failed");
+
+ *num_printers = count;
+
+ return true;
+}
+
+static bool getprinterinfo(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle, int level,
+ union spoolss_PrinterInfo **res)
+{
+ struct spoolss_GetPrinter r;
+ DATA_BLOB blob;
+ uint32_t needed;
+
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
+ "dcerpc_spoolss_GetPrinter failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "GetPrinter unexpected return code should be WERR_INSUFFICIENT_BUFFER");
+
+ r.in.handle = handle;
+ r.in.level = level;
+ blob = data_blob_talloc_zero(tctx, needed);
+ if (blob.data == NULL) {
+ return false;
+ }
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
+ "dcerpc_spoolss_GetPrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "dcerpc_spoolss_GetPrinter failed");
+
+ if (res != NULL) {
+ *res = talloc_steal(tctx, r.out.info);
+ }
+
+ return true;
+}
+
+static bool torture_samba3_rpc_spoolss(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p, *p2;
+ struct dcerpc_binding_handle *b;
+ struct policy_handle server_handle, printer_handle;
+ const char **printers;
+ size_t num_printers;
+ struct spoolss_UserLevel1 userlevel1;
+ char *servername;
+
+ torture_assert(torture,
+ rap_get_servername(torture, &servername),
+ "failed to rap servername");
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p2, &ndr_table_srvsvc),
+ "failed to setup srvsvc");
+
+ torture_assert(torture,
+ find_printers(torture, p2, &printers, &num_printers),
+ "failed to find printers via srvsvc");
+
+ talloc_free(p2);
+
+ if (num_printers == 0) {
+ torture_skip(torture, "Did not find printers\n");
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p, &ndr_table_spoolss),
+ "failed to setup spoolss");
+
+ b = p->binding_handle;
+
+ ZERO_STRUCT(userlevel1);
+ userlevel1.client = talloc_asprintf(
+ torture, "\\\\%s", lpcfg_netbios_name(torture->lp_ctx));
+ userlevel1.user = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ userlevel1.build = 2600;
+ userlevel1.major = 3;
+ userlevel1.minor = 0;
+ userlevel1.processor = 0;
+
+ {
+ struct spoolss_OpenPrinterEx r;
+
+ ZERO_STRUCT(r);
+ r.in.printername = talloc_asprintf(torture, "\\\\%s",
+ servername);
+ r.in.datatype = NULL;
+ r.in.access_mask = 0;
+ r.in.userlevel_ctr.level = 1;
+ r.in.userlevel_ctr.user_info.level1 = &userlevel1;
+ r.out.handle = &server_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_spoolss_OpenPrinterEx_r(b, torture, &r),
+ "dcerpc_spoolss_OpenPrinterEx failed");
+ torture_assert_werr_ok(torture, r.out.result,
+ "dcerpc_spoolss_OpenPrinterEx failed");
+ }
+
+ {
+ struct spoolss_ClosePrinter r;
+
+ r.in.handle = &server_handle;
+ r.out.handle = &server_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_spoolss_ClosePrinter_r(b, torture, &r),
+ "dcerpc_spoolss_ClosePrinter failed");
+ torture_assert_werr_ok(torture, r.out.result,
+ "dcerpc_spoolss_ClosePrinter failed");
+ }
+
+ {
+ struct spoolss_OpenPrinterEx r;
+
+ ZERO_STRUCT(r);
+ r.in.printername = talloc_asprintf(
+ torture, "\\\\%s\\%s", servername, printers[0]);
+ r.in.datatype = NULL;
+ r.in.access_mask = 0;
+ r.in.userlevel_ctr.level = 1;
+ r.in.userlevel_ctr.user_info.level1 = &userlevel1;
+ r.out.handle = &printer_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_spoolss_OpenPrinterEx_r(b, torture, &r),
+ "dcerpc_spoolss_OpenPrinterEx failed");
+ torture_assert_werr_ok(torture, r.out.result,
+ "dcerpc_spoolss_OpenPrinterEx failed");
+ }
+
+ {
+ int i;
+
+ for (i=0; i<8; i++) {
+ torture_assert(torture,
+ getprinterinfo(torture, b, &printer_handle, i, NULL),
+ talloc_asprintf(torture, "getprinterinfo %d failed", i));
+ }
+ }
+
+ {
+ struct spoolss_ClosePrinter r;
+
+ r.in.handle = &printer_handle;
+ r.out.handle = &printer_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_spoolss_ClosePrinter_r(b, torture, &r),
+ "dcerpc_spoolss_ClosePrinter failed");
+ torture_assert_werr_ok(torture, r.out.result,
+ "dcerpc_spoolss_ClosePrinter failed");
+ }
+
+ {
+ int num_enumerated;
+
+ torture_assert(torture,
+ enumprinters(torture, b, servername, 1, &num_enumerated),
+ "enumprinters failed");
+
+ torture_assert_int_equal(torture, num_printers, num_enumerated,
+ "netshareenum / enumprinters lvl 1 numprinter mismatch");
+ }
+
+ {
+ int num_enumerated;
+
+ torture_assert(torture,
+ enumprinters(torture, b, servername, 2, &num_enumerated),
+ "enumprinters failed");
+
+ torture_assert_int_equal(torture, num_printers, num_enumerated,
+ "netshareenum / enumprinters lvl 2 numprinter mismatch");
+ }
+
+ return true;
+}
+
+static bool torture_samba3_rpc_wkssvc(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ char *servername;
+
+ torture_assert(torture,
+ rap_get_servername(torture, &servername),
+ "failed to rap servername");
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p, &ndr_table_wkssvc),
+ "failed to setup wkssvc");
+
+ b = p->binding_handle;
+
+ {
+ struct wkssvc_NetWkstaInfo100 wks100;
+ union wkssvc_NetWkstaInfo info;
+ struct wkssvc_NetWkstaGetInfo r;
+
+ r.in.server_name = "\\foo";
+ r.in.level = 100;
+ info.info100 = &wks100;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_wkssvc_NetWkstaGetInfo_r(b, torture, &r),
+ "dcerpc_wkssvc_NetWksGetInfo failed");
+ torture_assert_werr_ok(torture, r.out.result,
+ "dcerpc_wkssvc_NetWksGetInfo failed");
+
+ torture_assert_str_equal(torture, servername, r.out.info->info100->server_name,
+ "servername RAP / DCERPC inconsistency");
+ }
+
+ return true;
+}
+
+static bool winreg_close(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct winreg_CloseKey c;
+
+ c.in.handle = c.out.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_CloseKey_r(b, tctx, &c),
+ "winreg_CloseKey failed");
+ torture_assert_werr_ok(tctx, c.out.result,
+ "winreg_CloseKey failed");
+
+ return true;
+}
+
+static bool enumvalues(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ uint32_t enum_index = 0;
+
+ while (1) {
+ struct winreg_EnumValue r;
+ struct winreg_ValNameBuf name;
+ enum winreg_Type type = 0;
+ uint8_t buf8[1024];
+ NTSTATUS status;
+ uint32_t size, length;
+
+ ZERO_STRUCT(buf8);
+ r.in.handle = handle;
+ r.in.enum_index = enum_index;
+ name.name = "";
+ name.size = 1024;
+ r.in.name = r.out.name = &name;
+ size = 1024;
+ length = 5;
+ r.in.type = &type;
+ r.in.value = buf8;
+ r.in.size = &size;
+ r.in.length = &length;
+
+ status = dcerpc_winreg_EnumValue_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
+ return true;
+ }
+ enum_index += 1;
+ }
+}
+
+static bool enumkeys(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ int depth)
+{
+ struct winreg_EnumKey r;
+ struct winreg_StringBuf kclass, name;
+ NTSTATUS status;
+ NTTIME t = 0;
+
+ if (depth <= 0) {
+ return true;
+ }
+
+ kclass.name = "";
+ kclass.size = 1024;
+
+ r.in.handle = handle;
+ r.in.enum_index = 0;
+ r.in.name = &name;
+ r.in.keyclass = &kclass;
+ r.out.name = &name;
+ r.in.last_changed_time = &t;
+
+ do {
+ struct winreg_OpenKey o;
+ struct policy_handle key_handle;
+ int i;
+
+ name.name = NULL;
+ name.size = 1024;
+
+ status = dcerpc_winreg_EnumKey_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
+ /* We're done enumerating */
+ return true;
+ }
+
+ for (i=0; i<10-depth; i++) {
+ torture_comment(tctx, " ");
+ }
+ torture_comment(tctx, "%s\n", r.out.name->name);
+
+ o.in.parent_handle = handle;
+ o.in.keyname.name = r.out.name->name;
+ o.in.options = 0;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.out.handle = &key_handle;
+
+ status = dcerpc_winreg_OpenKey_r(b, tctx, &o);
+ if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(o.out.result)) {
+ enumkeys(tctx, b, &key_handle, depth-1);
+ enumvalues(tctx, b, &key_handle);
+ torture_assert(tctx, winreg_close(tctx, b, &key_handle), "");
+ }
+
+ r.in.enum_index += 1;
+ } while(true);
+
+ return true;
+}
+
+typedef NTSTATUS (*winreg_open_fn)(struct dcerpc_binding_handle *, TALLOC_CTX *, void *);
+
+static bool test_Open3(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *name, winreg_open_fn open_fn)
+{
+ struct policy_handle handle;
+ struct winreg_OpenHKLM r;
+
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ open_fn(b, tctx, &r),
+ talloc_asprintf(tctx, "%s failed", name));
+ torture_assert_werr_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "%s failed", name));
+
+ enumkeys(tctx, b, &handle, 4);
+
+ torture_assert(tctx,
+ winreg_close(tctx, b, &handle),
+ "dcerpc_CloseKey failed");
+
+ return true;
+}
+
+static bool torture_samba3_rpc_winreg(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ bool ret = true;
+ struct {
+ const char *name;
+ winreg_open_fn fn;
+ } open_fns[] = {
+ {"OpenHKLM", (winreg_open_fn)dcerpc_winreg_OpenHKLM_r },
+ {"OpenHKU", (winreg_open_fn)dcerpc_winreg_OpenHKU_r },
+ {"OpenHKPD", (winreg_open_fn)dcerpc_winreg_OpenHKPD_r },
+ {"OpenHKPT", (winreg_open_fn)dcerpc_winreg_OpenHKPT_r },
+ {"OpenHKCR", (winreg_open_fn)dcerpc_winreg_OpenHKCR_r }};
+#if 0
+ int i;
+#endif
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p, &ndr_table_winreg),
+ "failed to setup winreg");
+
+ b = p->binding_handle;
+
+#if 1
+ ret = test_Open3(torture, b, open_fns[0].name, open_fns[0].fn);
+#else
+ for (i = 0; i < ARRAY_SIZE(open_fns); i++) {
+ if (!test_Open3(torture, b, open_fns[i].name, open_fns[i].fn))
+ ret = false;
+ }
+#endif
+ return ret;
+}
+
+static bool get_shareinfo(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ const char *share,
+ struct srvsvc_NetShareInfo502 **info502)
+{
+ struct srvsvc_NetShareGetInfo r;
+ union srvsvc_NetShareInfo info;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", servername);
+ r.in.share_name = share;
+ r.in.level = 502;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_srvsvc_NetShareGetInfo_r(b, tctx, &r),
+ "srvsvc_NetShareGetInfo failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "srvsvc_NetShareGetInfo failed");
+
+ *info502 = talloc_move(tctx, &info.info502);
+
+ return true;
+}
+
+/*
+ * Get us a handle on HKLM\
+ */
+
+static bool get_hklm_handle(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct winreg_OpenHKLM r;
+ struct policy_handle result;
+
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &result;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_OpenHKLM_r(b, tctx, &r),
+ "OpenHKLM failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "OpenHKLM failed");
+
+ *handle = result;
+
+ return true;
+}
+
+static bool torture_samba3_createshare(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *sharename)
+{
+ struct policy_handle hklm;
+ struct policy_handle new_handle;
+ struct winreg_CreateKey c;
+ struct winreg_CloseKey cl;
+ enum winreg_CreateAction action_taken = REG_ACTION_NONE;
+
+ ZERO_STRUCT(c);
+ ZERO_STRUCT(cl);
+ ZERO_STRUCT(hklm);
+ ZERO_STRUCT(new_handle);
+
+ c.in.handle = &hklm;
+ c.in.name.name = talloc_asprintf(
+ tctx, "software\\samba\\smbconf\\%s", sharename);
+ torture_assert(tctx, c.in.name.name, "talloc_asprintf failed");
+
+ c.in.keyclass.name = "";
+ c.in.options = 0;
+ c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ c.in.secdesc = NULL;
+ c.in.action_taken = &action_taken;
+ c.out.new_handle = &new_handle;
+ c.out.action_taken = &action_taken;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_CreateKey_r(b, tctx, &c),
+ "OpenKey failed");
+ torture_assert_werr_ok(tctx, c.out.result,
+ "OpenKey failed");
+
+ cl.in.handle = &new_handle;
+ cl.out.handle = &new_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_CloseKey_r(b, tctx, &cl),
+ "CloseKey failed");
+ torture_assert_werr_ok(tctx, cl.out.result,
+ "CloseKey failed");
+
+ return true;
+}
+
+static bool torture_samba3_deleteshare(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *sharename)
+{
+ struct policy_handle hklm;
+ struct winreg_DeleteKey d;
+
+ torture_assert(tctx,
+ get_hklm_handle(tctx, b, &hklm),
+ "get_hklm_handle failed");
+
+ d.in.handle = &hklm;
+ d.in.key.name = talloc_asprintf(
+ tctx, "software\\samba\\smbconf\\%s", sharename);
+ torture_assert(tctx, d.in.key.name, "talloc_asprintf failed");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_DeleteKey_r(b, tctx, &d),
+ "DeleteKey failed");
+ torture_assert_werr_ok(tctx, d.out.result,
+ "DeleteKey failed");
+
+ return true;
+}
+
+static bool torture_samba3_setconfig(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *sharename,
+ const char *parameter,
+ const char *value)
+{
+ struct policy_handle hklm, key_handle;
+ struct winreg_OpenKey o;
+ struct winreg_SetValue s;
+ uint32_t type;
+ DATA_BLOB val;
+
+ torture_assert(tctx,
+ get_hklm_handle(tctx, b, &hklm),
+ "get_hklm_handle failed");
+
+ o.in.parent_handle = &hklm;
+ o.in.keyname.name = talloc_asprintf(
+ tctx, "software\\samba\\smbconf\\%s", sharename);
+ torture_assert(tctx, o.in.keyname.name, "talloc_asprintf failed");
+
+ o.in.options = 0;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.out.handle = &key_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_OpenKey_r(b, tctx, &o),
+ "OpenKey failed");
+ torture_assert_werr_ok(tctx, o.out.result,
+ "OpenKey failed");
+
+ torture_assert(tctx,
+ reg_string_to_val(tctx, "REG_SZ", value, &type, &val),
+ "reg_string_to_val failed");
+
+ s.in.handle = &key_handle;
+ s.in.name.name = parameter;
+ s.in.type = type;
+ s.in.data = val.data;
+ s.in.size = val.length;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_SetValue_r(b, tctx, &s),
+ "SetValue failed");
+ torture_assert_werr_ok(tctx, s.out.result,
+ "SetValue failed");
+
+ return true;
+}
+
+static bool torture_samba3_regconfig(struct torture_context *torture)
+{
+ struct srvsvc_NetShareInfo502 *i = NULL;
+ const char *comment = "Dummer Kommentar";
+ struct dcerpc_pipe *srvsvc_pipe, *winreg_pipe;
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &srvsvc_pipe, &ndr_table_srvsvc),
+ "failed to setup srvsvc");
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &winreg_pipe, &ndr_table_winreg),
+ "failed to setup winreg");
+
+ torture_assert(torture,
+ torture_samba3_createshare(torture, winreg_pipe->binding_handle, "blubber"),
+ "torture_samba3_createshare failed");
+
+ torture_assert(torture,
+ torture_samba3_setconfig(torture, winreg_pipe->binding_handle, "blubber", "comment", comment),
+ "torture_samba3_setconfig failed");
+
+ torture_assert(torture,
+ get_shareinfo(torture, srvsvc_pipe->binding_handle, dcerpc_server_name(srvsvc_pipe), "blubber", &i),
+ "get_shareinfo failed");
+
+ torture_assert_str_equal(torture, comment, i->comment,
+ "got unexpected comment");
+
+ torture_assert(torture,
+ torture_samba3_deleteshare(torture, winreg_pipe->binding_handle, "blubber"),
+ "torture_samba3_deleteshare failed");
+
+ return true;
+}
+
+/*
+ * Test that even with a result of 0 rids the array is returned as a
+ * non-NULL pointer. Yes, XP does notice.
+ */
+
+bool torture_samba3_getaliasmembership_0(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ struct samr_Connect2 c;
+ struct samr_OpenDomain o;
+ struct dom_sid sid;
+ struct lsa_SidPtr ptr;
+ struct lsa_SidArray sids;
+ struct samr_GetAliasMembership g;
+ struct samr_Ids rids;
+ struct policy_handle samr, domain;
+
+ torture_assert_ntstatus_ok(torture,
+ torture_rpc_connection(torture, &p, &ndr_table_samr),
+ "failed to setup samr");
+
+ b = p->binding_handle;
+
+ c.in.system_name = NULL;
+ c.in.access_mask = SAMR_ACCESS_LOOKUP_DOMAIN;
+ c.out.connect_handle = &samr;
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_Connect2_r(b, torture, &c),
+ "");
+ torture_assert_ntstatus_ok(torture, c.out.result,
+ "");
+ dom_sid_parse("S-1-5-32", &sid);
+ o.in.connect_handle = &samr;
+ o.in.access_mask = SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS;
+ o.in.sid = &sid;
+ o.out.domain_handle = &domain;
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_OpenDomain_r(b, torture, &o),
+ "");
+ torture_assert_ntstatus_ok(torture, o.out.result,
+ "");
+ dom_sid_parse("S-1-2-3-4-5", &sid);
+ ptr.sid = &sid;
+ sids.num_sids = 1;
+ sids.sids = &ptr;
+ g.in.domain_handle = &domain;
+ g.in.sids = &sids;
+ g.out.rids = &rids;
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_GetAliasMembership_r(b, torture, &g),
+ "");
+ torture_assert_ntstatus_ok(torture, g.out.result,
+ "");
+ if (rids.ids == NULL) {
+ /* This is the piece to test here */
+ torture_fail(torture,
+ "torture_samba3_getaliasmembership_0: "
+ "Server returns NULL rids array\n");
+ }
+
+ return true;
+}
+
+/**
+ * Test smb reauthentication while rpc pipe is in use.
+ */
+static bool torture_rpc_smb_reauth1(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_state *cli;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ struct dcerpc_pipe *lsa_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_GetUserName r;
+ struct lsa_String *authority_name_p = NULL;
+ char *authority_name_saved = NULL;
+ struct lsa_String *account_name_p = NULL;
+ char *account_name_saved = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ struct smb_composite_sesssetup io;
+
+ mem_ctx = talloc_init("torture_samba3_reauth");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(mem_ctx, &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smbcli_full_connection failed");
+
+ status = pipe_bind_smb(torture, mem_ctx, cli->tree, "\\lsarpc",
+ &ndr_table_lsarpc, &lsa_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "pipe_bind_smb failed");
+ lsa_handle = lsa_pipe->binding_handle;
+
+ /* lsa getusername */
+
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_comment(torture, "lsa_GetUserName gave '%s\\%s'\n",
+ authority_name_p->string,
+ account_name_p->string);
+
+ account_name_saved = talloc_strdup(mem_ctx, account_name_p->string);
+ torture_assert_goto(torture, (account_name_saved != NULL), ret, done,
+ "talloc failed");
+ authority_name_saved = talloc_strdup(mem_ctx, authority_name_p->string);
+ torture_assert_goto(torture, (authority_name_saved != NULL), ret, done,
+ "talloc failed");
+
+ /* smb re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+
+ ZERO_STRUCT(io);
+ io.in.sesskey = cli->transport->negotiate.sesskey;
+ io.in.capabilities = cli->transport->negotiate.capabilities;
+ io.in.credentials = anon_creds;
+ io.in.workgroup = lpcfg_workgroup(torture->lp_ctx);
+ io.in.gensec_settings = lpcfg_gensec_settings(torture, torture->lp_ctx);
+
+ status = smb_composite_sesssetup(cli->session, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* re-do lsa getusername after reauth */
+
+ TALLOC_FREE(authority_name_p);
+ TALLOC_FREE(account_name_p);
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_assert_goto(torture, (strcmp(authority_name_p->string, authority_name_saved) == 0),
+ ret, done, "authority_name not equal after reauth to anon");
+ torture_assert_goto(torture, (strcmp(account_name_p->string, account_name_saved) == 0),
+ ret, done, "account_name not equal after reauth to anon");
+
+ /* smb re-auth again to the original user */
+
+ ZERO_STRUCT(io);
+ io.in.sesskey = cli->transport->negotiate.sesskey;
+ io.in.capabilities = cli->transport->negotiate.capabilities;
+ io.in.credentials = samba_cmdline_get_creds();
+ io.in.workgroup = lpcfg_workgroup(torture->lp_ctx);
+ io.in.gensec_settings = lpcfg_gensec_settings(torture, torture->lp_ctx);
+
+ status = smb_composite_sesssetup(cli->session, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* re-do lsa getusername */
+
+ TALLOC_FREE(authority_name_p);
+ TALLOC_FREE(account_name_p);
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_assert_goto(torture, (strcmp(authority_name_p->string, authority_name_saved) == 0),
+ ret, done, "authority_name not equal after reauth to anon");
+ torture_assert_goto(torture, (strcmp(account_name_p->string, account_name_saved) == 0),
+ ret, done, "account_name not equal after reauth to anon");
+
+ ret = true;
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * Test smb reauthentication while rpc pipe is in use.
+ * Open a second lsa bind after reauth to anon.
+ * Do lsa getusername on that second bind.
+ */
+static bool torture_rpc_smb_reauth2(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_state *cli;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ struct dcerpc_pipe *lsa_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_GetUserName r;
+ struct lsa_String *authority_name_p = NULL;
+ char *authority_name_saved = NULL;
+ struct lsa_String *account_name_p = NULL;
+ char *account_name_saved = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ struct smb_composite_sesssetup io;
+
+ mem_ctx = talloc_init("torture_samba3_reauth");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(mem_ctx, &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smbcli_full_connection failed");
+
+ /* smb re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+
+ ZERO_STRUCT(io);
+ io.in.sesskey = cli->transport->negotiate.sesskey;
+ io.in.capabilities = cli->transport->negotiate.capabilities;
+ io.in.credentials = anon_creds;
+ io.in.workgroup = lpcfg_workgroup(torture->lp_ctx);
+ io.in.gensec_settings = lpcfg_gensec_settings(torture, torture->lp_ctx);
+
+ status = smb_composite_sesssetup(cli->session, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* open the lsa pipe */
+
+ status = pipe_bind_smb(torture, mem_ctx, cli->tree, "\\lsarpc",
+ &ndr_table_lsarpc, &lsa_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "pipe_bind_smb failed");
+ lsa_handle = lsa_pipe->binding_handle;
+
+ /* lsa getusername */
+
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_comment(torture, "lsa_GetUserName gave '%s\\%s'\n",
+ authority_name_p->string,
+ account_name_p->string);
+
+ account_name_saved = talloc_strdup(mem_ctx, account_name_p->string);
+ torture_assert_goto(torture, (account_name_saved != NULL), ret, done,
+ "talloc failed");
+ authority_name_saved = talloc_strdup(mem_ctx, authority_name_p->string);
+ torture_assert_goto(torture, (authority_name_saved != NULL), ret, done,
+ "talloc failed");
+
+ /* smb re-auth again to the original user */
+
+ ZERO_STRUCT(io);
+ io.in.sesskey = cli->transport->negotiate.sesskey;
+ io.in.capabilities = cli->transport->negotiate.capabilities;
+ io.in.credentials = samba_cmdline_get_creds();
+ io.in.workgroup = lpcfg_workgroup(torture->lp_ctx);
+ io.in.gensec_settings = lpcfg_gensec_settings(torture, torture->lp_ctx);
+
+ status = smb_composite_sesssetup(cli->session, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* re-do lsa getusername after reauth */
+
+ TALLOC_FREE(authority_name_p);
+ TALLOC_FREE(account_name_p);
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_assert_goto(torture, (strcmp(authority_name_p->string, authority_name_saved) == 0),
+ ret, done, "authority_name not equal after reauth to anon");
+ torture_assert_goto(torture, (strcmp(account_name_p->string, account_name_saved) == 0),
+ ret, done, "account_name not equal after reauth to anon");
+
+ ret = true;
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * Test smb2 reauthentication while rpc pipe is in use.
+ */
+static bool torture_rpc_smb2_reauth1(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+
+ struct dcerpc_pipe *lsa_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_GetUserName r;
+ struct lsa_String *authority_name_p = NULL;
+ char *authority_name_saved = NULL;
+ struct lsa_String *account_name_p = NULL;
+ char *account_name_saved = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smb2_tree *tree;
+
+ mem_ctx = talloc_init("torture_samba3_reauth");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ status = pipe_bind_smb2(torture, mem_ctx, tree, "lsarpc",
+ &ndr_table_lsarpc, &lsa_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "pipe_bind_smb2 failed");
+ lsa_handle = lsa_pipe->binding_handle;
+
+ /* lsa getusername */
+
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_comment(torture, "lsa_GetUserName gave '%s\\%s'\n",
+ authority_name_p->string,
+ account_name_p->string);
+
+ account_name_saved = talloc_strdup(mem_ctx, account_name_p->string);
+ torture_assert_goto(torture, (account_name_saved != NULL), ret, done,
+ "talloc failed");
+ authority_name_saved = talloc_strdup(mem_ctx, authority_name_p->string);
+ torture_assert_goto(torture, (authority_name_saved != NULL), ret, done,
+ "talloc failed");
+
+ /* smb re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* re-do lsa getusername after reauth */
+
+ TALLOC_FREE(authority_name_p);
+ TALLOC_FREE(account_name_p);
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_assert_goto(torture, (strcmp(authority_name_p->string, authority_name_saved) == 0),
+ ret, done, "authority_name not equal after reauth to anon");
+ torture_assert_goto(torture, (strcmp(account_name_p->string, account_name_saved) == 0),
+ ret, done, "account_name not equal after reauth to anon");
+
+ /* smb re-auth again to the original user */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* re-do lsa getusername */
+
+ TALLOC_FREE(authority_name_p);
+ TALLOC_FREE(account_name_p);
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_assert_goto(torture, (strcmp(authority_name_p->string, authority_name_saved) == 0),
+ ret, done, "authority_name not equal after reauth to anon");
+ torture_assert_goto(torture, (strcmp(account_name_p->string, account_name_saved) == 0),
+ ret, done, "account_name not equal after reauth to anon");
+
+ ret = true;
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * Test smb2 reauthentication while rpc pipe is in use.
+ * Open a second lsa bind after reauth to anon.
+ * Do lsa getusername on that second bind.
+ */
+static bool torture_rpc_smb2_reauth2(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+
+ struct dcerpc_pipe *lsa_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_GetUserName r;
+ struct lsa_String *authority_name_p = NULL;
+ char *authority_name_saved = NULL;
+ struct lsa_String *account_name_p = NULL;
+ char *account_name_saved = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smb2_tree *tree;
+
+ mem_ctx = talloc_init("torture_samba3_reauth");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ /* smb re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* open the lsa pipe */
+
+ status = pipe_bind_smb2(torture, mem_ctx, tree, "lsarpc",
+ &ndr_table_lsarpc, &lsa_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "pipe_bind_smb2 failed");
+ lsa_handle = lsa_pipe->binding_handle;
+
+ /* lsa getusername */
+
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_comment(torture, "lsa_GetUserName gave '%s\\%s'\n",
+ authority_name_p->string,
+ account_name_p->string);
+
+ account_name_saved = talloc_strdup(mem_ctx, account_name_p->string);
+ torture_assert_goto(torture, (account_name_saved != NULL), ret, done,
+ "talloc failed");
+ authority_name_saved = talloc_strdup(mem_ctx, authority_name_p->string);
+ torture_assert_goto(torture, (authority_name_saved != NULL), ret, done,
+ "talloc failed");
+
+ /* smb re-auth again to the original user */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "session reauth to anon failed");
+
+ /* re-do lsa getusername */
+
+ TALLOC_FREE(authority_name_p);
+ TALLOC_FREE(account_name_p);
+ ZERO_STRUCT(r);
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ status = dcerpc_lsa_GetUserName_r(lsa_handle, mem_ctx, &r);
+
+ authority_name_p = *r.out.authority_name;
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "GetUserName failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result, ret, done,
+ "GetUserName failed");
+
+ torture_assert_goto(torture, (strcmp(authority_name_p->string, authority_name_saved) == 0),
+ ret, done, "authority_name not equal after reauth to anon");
+ torture_assert_goto(torture, (strcmp(account_name_p->string, account_name_saved) == 0),
+ ret, done, "account_name not equal after reauth to anon");
+
+ ret = true;
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool torture_rpc_smb1_pipe_name(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_state *cli;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+ union smb_open io;
+ union smb_close cl;
+ uint16_t fnum;
+
+ mem_ctx = talloc_init("torture_samba3_smb1_pipe_name");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+ lpcfg_smbcli_session_options(torture->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(mem_ctx, &cli,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(torture->lp_ctx),
+ torture->ev, &options, &session_options,
+ lpcfg_gensec_settings(torture, torture->lp_ctx));
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smbcli_full_connection failed");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.access_mask = DESIRED_ACCESS_PIPE;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.ntcreatex.in.security_flags = 0;
+
+ io.ntcreatex.in.fname = "__none__";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for '__none__'");
+
+ io.ntcreatex.in.fname = "pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for 'pipe\\srvsvc'");
+
+ io.ntcreatex.in.fname = "\\pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for '\\pipe\\srvsvc'");
+
+ io.ntcreatex.in.fname = "srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'srvsvc'");
+ fnum = io.ntcreatex.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.ntcreatex.in.fname = "\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\srvsvc'");
+ fnum = io.ntcreatex.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.ntcreatex.in.fname = "\\\\\\\\\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\\\\\\\\\srvsvc'");
+ fnum = io.ntcreatex.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_NTTRANS_CREATE;
+ io.nttrans.in.access_mask = DESIRED_ACCESS_PIPE;
+ io.nttrans.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.nttrans.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.nttrans.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.nttrans.in.security_flags = 0;
+
+ io.nttrans.in.fname = "__none__";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for '__none__'");
+
+ io.nttrans.in.fname = "pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for 'pipe\\srvsvc'");
+
+ io.nttrans.in.fname = "\\pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for '\\pipe\\srvsvc'");
+
+ io.nttrans.in.fname = "srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'srvsvc'");
+ fnum = io.nttrans.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.nttrans.in.fname = "\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\srvsvc'");
+ fnum = io.nttrans.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.nttrans.in.fname = "\\\\\\\\\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\\\\\\\\\srvsvc'");
+ fnum = io.nttrans.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_OPEN_OPENX;
+ io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+ io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+
+ io.openx.in.fname = "__none__";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+ ret, done,
+ "smb_raw_open for '__none__'");
+
+ io.openx.in.fname = "srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+ ret, done,
+ "smb_raw_open for 'srvsvc'");
+
+ io.openx.in.fname = "\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+ ret, done,
+ "smb_raw_open for '\\srvsvc'");
+
+ io.openx.in.fname = "\\pipesrvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+ ret, done,
+ "smb_raw_open for '\\pipesrvsvc'");
+
+ io.openx.in.fname = "pipe\\__none__";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for 'pipe\\__none__'");
+
+ io.openx.in.fname = "\\pipe\\__none__";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb_raw_open for '\\pipe\\__none__'");
+
+ io.openx.in.fname = "pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'pipe\\srvsvc'");
+ fnum = io.openx.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.openx.in.fname = "\\pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\pipe\\srvsvc'");
+ fnum = io.openx.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.openx.in.fname = "\\\\\\\\\\pipe\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\\\\\\\\\pipe\\srvsvc'");
+ fnum = io.openx.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+
+ io.openx.in.fname = "\\\\\\\\\\pipe\\\\\\\\\\srvsvc";
+ status = smb_raw_open(cli->tree, torture, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for '\\\\\\\\\\pipe\\\\\\\\\\srvsvc'");
+ fnum = io.openx.out.file.fnum;
+ ZERO_STRUCT(cl);
+ cl.generic.level = RAW_CLOSE_CLOSE;
+ cl.close.in.file.fnum = fnum;
+ status = smb_raw_close(cli->tree, &cl);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb_raw_close failed");
+ ret = true;
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool torture_rpc_smb2_pipe_name(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smb2_tree *tree;
+ struct smb2_handle h;
+ struct smb2_create io;
+
+ mem_ctx = talloc_init("torture_samba3_smb2_pipe_name");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = DESIRED_ACCESS_PIPE;
+ io.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+
+ io.in.fname = "__none__";
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_create for '__none__'");
+
+ io.in.fname = "\\srvsvc";
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_create for '\\srvsvc'");
+
+ io.in.fname = "\\pipe\\srvsvc";
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_create for '\\pipe\\srvsvc'");
+
+ io.in.fname = "pipe\\srvsvc";
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_create for 'pipe\\srvsvc'");
+
+ io.in.fname = "srvsvc";
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'srvsvc'");
+
+ h = io.out.file.handle;
+
+ status = smb2_util_close(tree, h);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_util_close failed");
+
+ ret = true;
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * Test behaviour of a waiting read call on a pipe when
+ * the pipe handle is closed:
+ * - open a pipe via smb2
+ * - trigger a read which hangs since there is nothing to read
+ * - close the pipe file handle
+ * - wait for the read to return and check the status
+ * (STATUS_PIPE_BROKEN)
+ */
+static bool torture_rpc_smb2_pipe_read_close(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smb2_tree *tree;
+ struct smb2_handle h;
+ struct smb2_request *smb2req;
+ struct smb2_create io;
+ struct smb2_read rd;
+
+ mem_ctx = talloc_init("torture_samba3_pipe_read_close");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = DESIRED_ACCESS_PIPE;
+ io.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = "lsarpc";
+
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'lsarpc'");
+
+ h = io.out.file.handle;
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 1024;
+ rd.in.offset = 0;
+ rd.in.min_count = 0;
+
+ smb2req = smb2_read_send(tree, &rd);
+ torture_assert_goto(torture, (smb2req != NULL), ret, done,
+ "smb2_read_send failed");
+
+ status = smb2_util_close(tree, h);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_util_close failed");
+
+ status = smb2_read_recv(smb2req, mem_ctx, &rd);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_PIPE_BROKEN, ret, done,
+ "smb2_read_recv: unexpected return code");
+
+ ret = true;
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * Test behaviour of a waiting read call on a pipe when
+ * the tree is disconnected.
+ * - open a pipe via smb2
+ * - trigger a read which hangs since there is nothing to read
+ * - do a tree disconnect
+ * - wait for the read to return and check the status
+ * (STATUS_PIPE_BROKEN)
+ */
+static bool torture_rpc_smb2_pipe_read_tdis(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smb2_tree *tree;
+ struct smb2_handle h;
+ struct smb2_request *smb2req;
+ struct smb2_create io;
+ struct smb2_read rd;
+
+ mem_ctx = talloc_init("torture_samba3_pipe_read_tdis");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = DESIRED_ACCESS_PIPE;
+ io.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = "lsarpc";
+
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'lsarpc'");
+
+ h = io.out.file.handle;
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 1024;
+ rd.in.offset = 0;
+ rd.in.min_count = 0;
+
+ smb2req = smb2_read_send(tree, &rd);
+ torture_assert_goto(torture, (smb2req != NULL), ret, done,
+ "smb2_read_send failed");
+
+ status = smb2_tdis(tree);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_tdis failed");
+
+ status = smb2_read_recv(smb2req, mem_ctx, &rd);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_PIPE_BROKEN, ret, done,
+ "smb2_read_recv: unexpected return code");
+
+ ret = true;
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * Test behaviour of a waiting read call on a pipe when
+ * the user logs off
+ * - open a pipe via smb2
+ * - trigger a read which hangs since there is nothing to read
+ * - do a logoff
+ * - wait for the read to return and check the status
+ * (STATUS_PIPE_BROKEN)
+ */
+static bool torture_rpc_smb2_pipe_read_logoff(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(torture, "host", NULL);
+ struct smb2_tree *tree;
+ struct smb2_handle h;
+ struct smb2_request *smb2req;
+ struct smb2_create io;
+ struct smb2_read rd;
+
+ mem_ctx = talloc_init("torture_samba3_pipe_read_tdis");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = DESIRED_ACCESS_PIPE;
+ io.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = "lsarpc";
+
+ status = smb2_create(tree, tree, &io);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed for 'lsarpc'");
+
+ h = io.out.file.handle;
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 1024;
+ rd.in.offset = 0;
+ rd.in.min_count = 0;
+
+ smb2req = smb2_read_send(tree, &rd);
+ torture_assert_goto(torture, (smb2req != NULL), ret, done,
+ "smb2_read_send failed");
+
+ status = smb2_logoff(tree->session);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_logoff failed");
+
+ status = smb2_read_recv(smb2req, mem_ctx, &rd);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_PIPE_BROKEN, ret, done,
+ "smb2_read_recv: unexpected return code");
+
+ ret = true;
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool torture_rpc_lsa_over_netlogon(struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ struct smb2_tree *tree;
+ struct dcerpc_pipe *netlogon_pipe;
+ struct dcerpc_binding_handle *lsa_handle;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 o;
+ struct policy_handle handle;
+
+ torture_comment(torture, "Testing if we can access LSA server over "
+ "\\\\pipe\\netlogon rather than \\\\pipe\\lsarpc\n");
+
+ mem_ctx = talloc_init("torture_samba3_rpc_lsa_over_netlogon");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ status = pipe_bind_smb2(torture, mem_ctx, tree, "netlogon",
+ &ndr_table_lsarpc, &netlogon_pipe);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "pipe_bind_smb2 failed");
+ lsa_handle = netlogon_pipe->binding_handle;
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ o.in.system_name = "\\";
+ o.in.attr = &attr;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_lsa_OpenPolicy2_r(lsa_handle, torture, &o),
+ "OpenPolicy2 failed");
+ torture_assert_ntstatus_ok(torture,
+ o.out.result,
+ "OpenPolicy2 failed");
+
+ ret = true;
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool torture_rpc_pipes_supported_interfaces(
+ struct torture_context *torture)
+{
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ struct smb2_tree *tree;
+ struct dcerpc_pipe *pipe1;
+ struct dcerpc_pipe *pipe2;
+ struct dcerpc_pipe *pipe3;
+
+ torture_comment(torture, "Testing only appropriate interfaces are "
+ "available in smb pipes\n");
+
+ mem_ctx = talloc_init("torture_samba3_rpc_pipes_supported_interfaces");
+ torture_assert(torture, (mem_ctx != NULL), "talloc_init failed");
+
+ lpcfg_smbcli_options(torture->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ torture_setting_string(torture, "host", NULL),
+ lpcfg_smb_ports(torture->lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(torture->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_connect failed");
+
+ /* Test embedded services pipes. The svcctl interface is
+ * not available if we open the winreg pipe. */
+ status = pipe_bind_smb2(torture, mem_ctx, tree, "winreg",
+ &ndr_table_svcctl, &pipe1);
+ torture_assert_ntstatus_equal(torture,
+ status,
+ NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX,
+ "svcctl interface not supported in winreg pipe");
+
+ /* Test it is not possible to bind to S4 server provided services */
+ status = pipe_bind_smb2(torture, mem_ctx, tree, "srvsvc",
+ &ndr_table_samr, &pipe2);
+ torture_assert_ntstatus_equal(torture,
+ status,
+ NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX,
+ "samr interface not supported in srvsvc pipe");
+
+ /* Test pipes in forked daemons like lsassd. The lsarpc interface is
+ * not available if we open the SAMR pipe. */
+ status = pipe_bind_smb2(torture, mem_ctx, tree, "samr",
+ &ndr_table_lsarpc, &pipe3);
+ torture_assert_ntstatus_equal(torture,
+ status,
+ NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX,
+ "lsarpc interface not supported in samr pipe");
+
+ ret = true;
+ done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samba3(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samba3");
+
+ torture_suite_add_simple_test(suite, "bind", torture_bind_samba3);
+ torture_suite_add_simple_test(suite, "netlogon", torture_netlogon_samba3);
+ torture_suite_add_simple_test(suite, "sessionkey", torture_samba3_sessionkey);
+ torture_suite_add_simple_test(suite, "srvsvc", torture_samba3_rpc_srvsvc);
+ torture_suite_add_simple_test(suite, "sharesec", torture_samba3_rpc_sharesec);
+ torture_suite_add_simple_test(suite, "getusername", torture_samba3_rpc_getusername);
+ torture_suite_add_simple_test(suite, "randomauth2", torture_samba3_rpc_randomauth2);
+ torture_suite_add_simple_test(suite, "lsa", torture_samba3_rpc_lsa);
+ torture_suite_add_simple_test(suite, "spoolss", torture_samba3_rpc_spoolss);
+ torture_suite_add_simple_test(suite, "wkssvc", torture_samba3_rpc_wkssvc);
+ torture_suite_add_simple_test(suite, "winreg", torture_samba3_rpc_winreg);
+ torture_suite_add_simple_test(suite, "getaliasmembership-0", torture_samba3_getaliasmembership_0);
+ torture_suite_add_simple_test(suite, "regconfig", torture_samba3_regconfig);
+ torture_suite_add_simple_test(suite, "smb-reauth1", torture_rpc_smb_reauth1);
+ torture_suite_add_simple_test(suite, "smb-reauth2", torture_rpc_smb_reauth2);
+ torture_suite_add_simple_test(suite, "smb2-reauth1", torture_rpc_smb2_reauth1);
+ torture_suite_add_simple_test(suite, "smb2-reauth2", torture_rpc_smb2_reauth2);
+ torture_suite_add_simple_test(suite, "smb1-pipe-name", torture_rpc_smb1_pipe_name);
+ torture_suite_add_simple_test(suite, "smb2-pipe-name", torture_rpc_smb2_pipe_name);
+ torture_suite_add_simple_test(suite, "smb2-pipe-read-close", torture_rpc_smb2_pipe_read_close);
+ torture_suite_add_simple_test(suite, "smb2-pipe-read-tdis", torture_rpc_smb2_pipe_read_tdis);
+ torture_suite_add_simple_test(suite, "smb2-pipe-read-logoff", torture_rpc_smb2_pipe_read_logoff);
+ torture_suite_add_simple_test(suite,
+ "lsa_over_netlogon",
+ torture_rpc_lsa_over_netlogon);
+ torture_suite_add_simple_test(suite,
+ "pipes_supported_interfaces",
+ torture_rpc_pipes_supported_interfaces);
+
+ suite->description = talloc_strdup(suite, "samba3 DCERPC interface tests");
+
+ return suite;
+}
diff --git a/source4/torture/rpc/samlogon.c b/source4/torture/rpc/samlogon.c
new file mode 100644
index 0000000..f16db64
--- /dev/null
+++ b/source4/torture/rpc/samlogon.c
@@ -0,0 +1,2121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for netlogon SamLogon operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "auth/gensec/gensec.h"
+#include "libcli/auth/libcli_auth.h"
+#include "param/param.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#define TEST_MACHINE_NAME "samlogontest"
+#define TEST_USER_NAME "samlogontestuser"
+#define TEST_USER_NAME_WRONG_WKS "samlogontest2"
+#define TEST_USER_NAME_WRONG_TIME "samlogontest3"
+
+enum ntlm_break {
+ BREAK_BOTH,
+ BREAK_NONE,
+ BREAK_LM,
+ BREAK_NT,
+ NO_LM,
+ NO_NT
+};
+
+struct samlogon_state {
+ TALLOC_CTX *mem_ctx;
+ struct torture_context *tctx;
+ const char *comment;
+ const char *account_name;
+ const char *account_domain;
+ const char *netbios_name;
+ const char *password;
+ const char *workgroup;
+ struct dcerpc_pipe *p;
+ int function_level;
+ uint32_t parameter_control;
+ struct netr_LogonSamLogon r;
+ struct netr_LogonSamLogonEx r_ex;
+ struct netr_LogonSamLogonWithFlags r_flags;
+ struct netr_Authenticator auth, auth2;
+ struct netlogon_creds_CredentialState *creds;
+ NTSTATUS expected_error;
+ bool old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */
+ DATA_BLOB chall;
+};
+
+/*
+ Authenticate a user with a challenge/response, checking session key
+ and valid authentication types
+*/
+static NTSTATUS check_samlogon(struct samlogon_state *samlogon_state,
+ enum ntlm_break break_which,
+ uint32_t parameter_control,
+ DATA_BLOB *chall,
+ DATA_BLOB *lm_response,
+ DATA_BLOB *nt_response,
+ uint8_t lm_key[8],
+ uint8_t user_session_key[16],
+ char **error_string)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogon *r = &samlogon_state->r;
+ struct netr_LogonSamLogonEx *r_ex = &samlogon_state->r_ex;
+ struct netr_LogonSamLogonWithFlags *r_flags = &samlogon_state->r_flags;
+ struct netr_NetworkInfo ninfo;
+ struct netr_SamBaseInfo *base = NULL;
+ uint16_t validation_level = 0;
+
+ samlogon_state->r.in.logon->network = &ninfo;
+ samlogon_state->r_ex.in.logon->network = &ninfo;
+ samlogon_state->r_flags.in.logon->network = &ninfo;
+
+ ninfo.identity_info.domain_name.string = samlogon_state->account_domain;
+ ninfo.identity_info.parameter_control = parameter_control;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.account_name.string = samlogon_state->account_name;
+ ninfo.identity_info.workstation.string = TEST_MACHINE_NAME;
+
+ memcpy(ninfo.challenge, chall->data, 8);
+
+ switch (break_which) {
+ case BREAK_NONE:
+ break;
+ case BREAK_LM:
+ if (lm_response && lm_response->data) {
+ lm_response->data[0]++;
+ }
+ break;
+ case BREAK_NT:
+ if (nt_response && nt_response->data) {
+ nt_response->data[0]++;
+ }
+ break;
+ case BREAK_BOTH:
+ if (lm_response && lm_response->data) {
+ lm_response->data[0]++;
+ }
+ if (nt_response && nt_response->data) {
+ nt_response->data[0]++;
+ }
+ break;
+ case NO_LM:
+ data_blob_free(lm_response);
+ break;
+ case NO_NT:
+ data_blob_free(nt_response);
+ break;
+ }
+
+ if (nt_response) {
+ ninfo.nt.data = nt_response->data;
+ ninfo.nt.length = nt_response->length;
+ } else {
+ ninfo.nt.data = NULL;
+ ninfo.nt.length = 0;
+ }
+
+ if (lm_response) {
+ ninfo.lm.data = lm_response->data;
+ ninfo.lm.length = lm_response->length;
+ } else {
+ ninfo.lm.data = NULL;
+ ninfo.lm.length = 0;
+ }
+
+ switch (samlogon_state->function_level) {
+ case NDR_NETR_LOGONSAMLOGON:
+ ZERO_STRUCT(samlogon_state->auth2);
+ netlogon_creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
+
+ r->out.return_authenticator = NULL;
+ status = dcerpc_netr_LogonSamLogon_r(samlogon_state->p->binding_handle,
+ samlogon_state->mem_ctx, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(status));
+ }
+ return status;
+ }
+ if (!r->out.return_authenticator ||
+ !netlogon_creds_client_check(samlogon_state->creds, &r->out.return_authenticator->cred)) {
+ torture_comment(samlogon_state->tctx, "Credential chaining failed\n");
+ }
+ if (!NT_STATUS_IS_OK(r->out.result)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(r->out.result));
+ }
+ return r->out.result;
+ }
+
+ validation_level = r->in.validation_level;
+
+ status = netlogon_creds_decrypt_samlogon_validation(samlogon_state->creds,
+ validation_level,
+ r->out.validation);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(status));
+ }
+ return status;
+ }
+
+ switch (validation_level) {
+ case 2:
+ base = &r->out.validation->sam2->base;
+ break;
+ case 3:
+ base = &r->out.validation->sam3->base;
+ break;
+ case 6:
+ base = &r->out.validation->sam6->base;
+ break;
+ }
+ break;
+ case NDR_NETR_LOGONSAMLOGONEX:
+ status = dcerpc_netr_LogonSamLogonEx_r(samlogon_state->p->binding_handle,
+ samlogon_state->mem_ctx, r_ex);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(status));
+ }
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(r_ex->out.result)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(r_ex->out.result));
+ }
+ return r_ex->out.result;
+ }
+
+ validation_level = r_ex->in.validation_level;
+
+ status = netlogon_creds_decrypt_samlogon_validation(samlogon_state->creds,
+ validation_level,
+ r_ex->out.validation);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(status));
+ }
+ return status;
+ }
+
+ switch (validation_level) {
+ case 2:
+ base = &r_ex->out.validation->sam2->base;
+ break;
+ case 3:
+ base = &r_ex->out.validation->sam3->base;
+ break;
+ case 6:
+ base = &r_ex->out.validation->sam6->base;
+ break;
+ }
+ break;
+ case NDR_NETR_LOGONSAMLOGONWITHFLAGS:
+ ZERO_STRUCT(samlogon_state->auth2);
+ netlogon_creds_client_authenticator(samlogon_state->creds, &samlogon_state->auth);
+
+ r_flags->out.return_authenticator = NULL;
+ status = dcerpc_netr_LogonSamLogonWithFlags_r(samlogon_state->p->binding_handle,
+ samlogon_state->mem_ctx, r_flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(status));
+ }
+ return status;
+ }
+ if (!r_flags->out.return_authenticator ||
+ !netlogon_creds_client_check(samlogon_state->creds, &r_flags->out.return_authenticator->cred)) {
+ torture_comment(samlogon_state->tctx, "Credential chaining failed\n");
+ }
+ if (!NT_STATUS_IS_OK(r_flags->out.result)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(r_flags->out.result));
+ }
+ return r_flags->out.result;
+ }
+
+ validation_level = r_flags->in.validation_level;
+
+ status = netlogon_creds_decrypt_samlogon_validation(samlogon_state->creds,
+ validation_level,
+ r_flags->out.validation);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (error_string) {
+ *error_string = strdup(nt_errstr(status));
+ }
+ return status;
+ }
+
+ switch (validation_level) {
+ case 2:
+ base = &r_flags->out.validation->sam2->base;
+ break;
+ case 3:
+ base = &r_flags->out.validation->sam3->base;
+ break;
+ case 6:
+ base = &r_flags->out.validation->sam6->base;
+ break;
+ }
+ break;
+ default:
+ /* can't happen */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!base) {
+ torture_comment(samlogon_state->tctx, "No user info returned from 'successful' SamLogon*() call!\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (user_session_key) {
+ memcpy(user_session_key, base->key.key, 16);
+ }
+ if (lm_key) {
+ memcpy(lm_key, base->LMSessKey.key, 8);
+ }
+
+ return status;
+}
+
+
+/*
+ * Test the normal 'LM and NTLM' combination
+ */
+
+static bool test_lm_ntlm_broken(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string)
+{
+ bool pass = true;
+ bool lm_good;
+ NTSTATUS nt_status;
+ DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+ DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+ DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
+
+ uint8_t lm_key[8];
+ uint8_t user_session_key[16];
+ uint8_t lm_hash[16];
+ uint8_t nt_hash[16];
+
+ ZERO_STRUCT(lm_key);
+ ZERO_STRUCT(user_session_key);
+
+ lm_good = SMBencrypt(samlogon_state->password, samlogon_state->chall.data, lm_response.data);
+ if (!lm_good) {
+ ZERO_STRUCT(lm_hash);
+ } else {
+ E_deshash(samlogon_state->password, lm_hash);
+ }
+
+ SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
+
+ E_md4hash(samlogon_state->password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash, session_key.data);
+
+ nt_status = check_samlogon(samlogon_state,
+ break_which,
+ samlogon_state->parameter_control,
+ &samlogon_state->chall,
+ &lm_response,
+ &nt_response,
+ lm_key,
+ user_session_key,
+ error_string);
+
+ data_blob_free(&lm_response);
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'long' passwords, the LM password is invalid */
+ if (break_which == NO_NT && !lm_good) {
+ return true;
+ }
+ /* for modern servers, the LM password is invalid */
+ if (break_which == NO_NT
+ && !torture_setting_bool(samlogon_state->tctx, "samba3", false)) {
+ return true;
+ }
+
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
+ } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ if (break_which == NO_NT && !lm_good) {
+ *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
+ return false;
+ }
+
+ /* for modern servers, the LM password is invalid */
+ if (break_which == NO_NT
+ && !torture_setting_bool(samlogon_state->tctx, "samba3", false)) {
+ *error_string = strdup("LM password is OK but should have failed against a modern server");
+ return false;
+ }
+
+ if (!all_zero(lm_key, sizeof(lm_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_key:\n");
+ dump_data(1, lm_key, 8);
+ torture_comment(samlogon_state->tctx, "expected (all zeros):\n");
+ pass = false;
+ }
+
+ switch (break_which) {
+ case NO_NT:
+ {
+ uint8_t lm_key_expected[16];
+ memcpy(lm_key_expected, session_key.data, 8);
+ memset(lm_key_expected+8, '\0', 8);
+ if (memcmp(lm_key_expected, user_session_key,
+ 16) != 0) {
+ *error_string = strdup("NT Session Key does not match expectations (should be first-8 session key)!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, sizeof(user_session_key));
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lm_key_expected, sizeof(lm_key_expected));
+ pass = false;
+ }
+ break;
+ }
+ default:
+ if (memcmp(session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ *error_string = strdup("NT Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, session_key.data, session_key.length);
+ pass = false;
+ }
+ }
+ return pass;
+}
+
+/*
+ * Test LM authentication, no NT response supplied
+ */
+
+static bool test_lm(struct samlogon_state *samlogon_state, char **error_string)
+{
+
+ return test_lm_ntlm_broken(samlogon_state, NO_NT, error_string);
+}
+
+/*
+ * Test the NTLM response only, no LM.
+ */
+
+static bool test_ntlm(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lm_ntlm_broken(samlogon_state, NO_LM, error_string);
+}
+
+/*
+ * Test the NTLM response only, but in the LM field.
+ */
+
+static bool test_ntlm_in_lm(struct samlogon_state *samlogon_state, char **error_string)
+{
+ bool lm_good;
+ bool pass = true;
+ NTSTATUS nt_status;
+ DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+ DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
+
+ uint8_t lm_key[8];
+ uint8_t lm_hash[16];
+ uint8_t user_session_key[16];
+ uint8_t nt_hash[16];
+
+ ZERO_STRUCT(lm_key);
+ ZERO_STRUCT(user_session_key);
+
+ SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data,
+ nt_response.data);
+ E_md4hash(samlogon_state->password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash,
+ session_key.data);
+
+ lm_good = E_deshash(samlogon_state->password, lm_hash);
+ if (!lm_good) {
+ ZERO_STRUCT(lm_hash);
+ }
+ nt_status = check_samlogon(samlogon_state,
+ BREAK_NONE,
+ samlogon_state->parameter_control,
+ &samlogon_state->chall,
+ &nt_response,
+ NULL,
+ lm_key,
+ user_session_key,
+ error_string);
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ return false;
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ if (torture_setting_bool(samlogon_state->tctx, "samba4", false)) {
+ if (!all_zero(lm_key, sizeof(lm_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_key:\n");
+ dump_data(1, lm_key, 8);
+ torture_comment(samlogon_state->tctx, "expected (all zeros):\n");
+ pass = false;
+ }
+
+
+ if (!all_zero(user_session_key, sizeof(user_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "NT Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, sizeof(user_session_key));
+ torture_comment(samlogon_state->tctx, "expected (all zeros):\n");
+ pass = false;
+ }
+ } else {
+ if (lm_good) {
+ if (memcmp(lm_hash, lm_key,
+ sizeof(lm_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_key:\n");
+ dump_data(1, lm_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lm_hash, 8);
+ pass = false;
+ }
+#if 0
+ } else {
+ if (memcmp(session_key.data, lm_key,
+ sizeof(lm_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM Key does not match expectations (first 8 session key)!\n");
+ torture_comment(samlogon_state->tctx, "lm_key:\n");
+ dump_data(1, lm_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, session_key.data, 8);
+ pass = false;
+ }
+#endif
+ }
+ if (lm_good && memcmp(lm_hash, user_session_key, 8) != 0) {
+ uint8_t lm_key_expected[16];
+ memcpy(lm_key_expected, lm_hash, 8);
+ memset(lm_key_expected+8, '\0', 8);
+ if (memcmp(lm_key_expected, user_session_key,
+ 16) != 0) {
+ torture_comment(samlogon_state->tctx, "NT Session Key does not match expectations (should be first-8 LM hash)!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, sizeof(user_session_key));
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lm_key_expected, sizeof(lm_key_expected));
+ pass = false;
+ }
+ }
+ }
+ return pass;
+}
+
+/*
+ * Test the NTLM response only, but in the both the NT and LM fields.
+ */
+
+static bool test_ntlm_in_both(struct samlogon_state *samlogon_state, char **error_string)
+{
+ bool pass = true;
+ bool lm_good;
+ NTSTATUS nt_status;
+ DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+ DATA_BLOB session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
+
+ uint8_t lm_key[8];
+ uint8_t lm_hash[16];
+ uint8_t user_session_key[16];
+ uint8_t nt_hash[16];
+
+ ZERO_STRUCT(lm_key);
+ ZERO_STRUCT(user_session_key);
+
+ SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data,
+ nt_response.data);
+ E_md4hash(samlogon_state->password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash,
+ session_key.data);
+
+ lm_good = E_deshash(samlogon_state->password, lm_hash);
+ if (!lm_good) {
+ ZERO_STRUCT(lm_hash);
+ }
+
+ nt_status = check_samlogon(samlogon_state,
+ BREAK_NONE,
+ samlogon_state->parameter_control,
+ &samlogon_state->chall,
+ NULL,
+ &nt_response,
+ lm_key,
+ user_session_key,
+ error_string);
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ return false;
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ if (!all_zero(lm_key,
+ sizeof(lm_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_key:\n");
+ dump_data(1, lm_key, 8);
+ torture_comment(samlogon_state->tctx, "expected (all zero)\n");
+ pass = false;
+ }
+ if (memcmp(session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "NT Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, session_key.data, session_key.length);
+ pass = false;
+ }
+
+
+ return pass;
+}
+
+/*
+ * Test the NTLMv2 and LMv2 responses
+ */
+
+enum ntlmv2_domain {
+ UPPER_DOMAIN,
+ NO_DOMAIN
+};
+
+static bool test_lmv2_ntlmv2_broken(struct samlogon_state *samlogon_state,
+ enum ntlm_break break_which,
+ enum ntlmv2_domain ntlmv2_domain,
+ char **error_string)
+{
+ bool pass = true;
+ NTSTATUS nt_status;
+ DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
+ DATA_BLOB lmv2_response = data_blob(NULL, 0);
+ DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
+ DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
+ DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, TEST_MACHINE_NAME, samlogon_state->workgroup);
+
+ uint8_t lm_session_key[8];
+ uint8_t user_session_key[16];
+
+ ZERO_STRUCT(lm_session_key);
+ ZERO_STRUCT(user_session_key);
+
+ switch (ntlmv2_domain) {
+ case UPPER_DOMAIN:
+ if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
+ samlogon_state->account_name, samlogon_state->account_domain,
+ samlogon_state->password, &samlogon_state->chall,
+ &names_blob,
+ &lmv2_response, &ntlmv2_response,
+ &lmv2_session_key, &ntlmv2_session_key)) {
+ data_blob_free(&names_blob);
+ return false;
+ }
+ break;
+ case NO_DOMAIN:
+ if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
+ samlogon_state->account_name, "",
+ samlogon_state->password, &samlogon_state->chall,
+ &names_blob,
+ &lmv2_response, &ntlmv2_response,
+ &lmv2_session_key, &ntlmv2_session_key)) {
+ data_blob_free(&names_blob);
+ return false;
+ }
+ break;
+ }
+ data_blob_free(&names_blob);
+
+ nt_status = check_samlogon(samlogon_state,
+ break_which,
+ samlogon_state->parameter_control,
+ &samlogon_state->chall,
+ &lmv2_response,
+ &ntlmv2_response,
+ lm_session_key,
+ user_session_key,
+ error_string);
+
+ data_blob_free(&lmv2_response);
+ data_blob_free(&ntlmv2_response);
+
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ return break_which == BREAK_BOTH;
+ } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+
+ switch (break_which) {
+ case NO_NT:
+ if (memcmp(lmv2_session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "USER (LMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
+ pass = false;
+ }
+ if (memcmp(lmv2_session_key.data, lm_session_key,
+ sizeof(lm_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM (LMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_session_key:\n");
+ dump_data(1, lm_session_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lmv2_session_key.data, 8);
+ pass = false;
+ }
+ break;
+ default:
+ if (memcmp(ntlmv2_session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ if (memcmp(lmv2_session_key.data, user_session_key,
+ sizeof(user_session_key)) == 0) {
+ torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key expected, got LMv2 session key instead:\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
+ pass = false;
+
+ } else {
+ torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlmv2_session_key.data, ntlmv2_session_key.length);
+ pass = false;
+ }
+ }
+ if (memcmp(ntlmv2_session_key.data, lm_session_key,
+ sizeof(lm_session_key)) != 0) {
+ if (memcmp(lmv2_session_key.data, lm_session_key,
+ sizeof(lm_session_key)) == 0) {
+ torture_comment(samlogon_state->tctx, "LM (NTLMv2) Session Key expected, got LMv2 session key instead:\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, lm_session_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlmv2_session_key.data, 8);
+ pass = false;
+ } else {
+ torture_comment(samlogon_state->tctx, "LM (NTLMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_session_key:\n");
+ dump_data(1, lm_session_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlmv2_session_key.data, 8);
+ pass = false;
+ }
+ }
+ }
+
+ return pass;
+}
+
+/*
+ * Test the NTLM and LMv2 responses
+ */
+
+static bool test_lmv2_ntlm_broken(struct samlogon_state *samlogon_state,
+ enum ntlm_break break_which,
+ enum ntlmv2_domain ntlmv2_domain,
+ char **error_string)
+{
+ bool pass = true;
+ NTSTATUS nt_status;
+ DATA_BLOB ntlmv2_response = data_blob(NULL, 0);
+ DATA_BLOB lmv2_response = data_blob(NULL, 0);
+ DATA_BLOB lmv2_session_key = data_blob(NULL, 0);
+ DATA_BLOB ntlmv2_session_key = data_blob(NULL, 0);
+ DATA_BLOB names_blob = NTLMv2_generate_names_blob(samlogon_state->mem_ctx, samlogon_state->netbios_name, samlogon_state->workgroup);
+
+ DATA_BLOB ntlm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+ DATA_BLOB ntlm_session_key = data_blob_talloc(samlogon_state->mem_ctx, NULL, 16);
+
+ bool lm_good;
+ uint8_t lm_hash[16];
+ uint8_t lm_session_key[8];
+ uint8_t user_session_key[16];
+ uint8_t nt_hash[16];
+
+ SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data,
+ ntlm_response.data);
+ E_md4hash(samlogon_state->password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash,
+ ntlm_session_key.data);
+
+ lm_good = E_deshash(samlogon_state->password, lm_hash);
+ if (!lm_good) {
+ ZERO_STRUCT(lm_hash);
+ }
+
+ ZERO_STRUCT(lm_session_key);
+ ZERO_STRUCT(user_session_key);
+
+ switch (ntlmv2_domain) {
+ case UPPER_DOMAIN:
+ /* TODO - test with various domain cases, and without domain */
+ if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
+ samlogon_state->account_name, samlogon_state->account_domain,
+ samlogon_state->password, &samlogon_state->chall,
+ &names_blob,
+ &lmv2_response, &ntlmv2_response,
+ &lmv2_session_key, &ntlmv2_session_key)) {
+ data_blob_free(&names_blob);
+ return false;
+ }
+ break;
+ case NO_DOMAIN:
+ /* TODO - test with various domain cases, and without domain */
+ if (!SMBNTLMv2encrypt(samlogon_state->mem_ctx,
+ samlogon_state->account_name, "",
+ samlogon_state->password, &samlogon_state->chall,
+ &names_blob,
+ &lmv2_response, &ntlmv2_response,
+ &lmv2_session_key, &ntlmv2_session_key)) {
+ data_blob_free(&names_blob);
+ return false;
+ }
+ break;
+ }
+
+ data_blob_free(&names_blob);
+
+ nt_status = check_samlogon(samlogon_state,
+ break_which,
+ samlogon_state->parameter_control,
+ &samlogon_state->chall,
+ &lmv2_response,
+ &ntlm_response,
+ lm_session_key,
+ user_session_key,
+ error_string);
+
+ data_blob_free(&lmv2_response);
+ data_blob_free(&ntlmv2_response);
+
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
+ } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ switch (break_which) {
+ case NO_NT:
+ if (memcmp(lmv2_session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "USER (LMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lmv2_session_key.data, ntlmv2_session_key.length);
+ pass = false;
+ }
+ if (memcmp(lmv2_session_key.data, lm_session_key,
+ sizeof(lm_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM (LMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_session_key:\n");
+ dump_data(1, lm_session_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, lmv2_session_key.data, 8);
+ pass = false;
+ }
+ break;
+ case BREAK_LM:
+ if (memcmp(ntlm_session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
+ pass = false;
+ }
+ if (!all_zero(lm_session_key,
+ sizeof(lm_session_key))) {
+ torture_comment(samlogon_state->tctx, "LM Session Key does not match expectations (zeros)!\n");
+ torture_comment(samlogon_state->tctx, "lm_session_key:\n");
+ dump_data(1, lm_session_key, 8);
+ pass = false;
+ }
+ break;
+ default:
+ if (memcmp(ntlm_session_key.data, user_session_key,
+ sizeof(user_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "USER (NTLMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, 16);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlm_session_key.data, ntlm_session_key.length);
+ pass = false;
+ }
+ if (memcmp(ntlm_session_key.data, lm_session_key,
+ sizeof(lm_session_key)) != 0) {
+ torture_comment(samlogon_state->tctx, "LM (NTLMv2) Session Key does not match expectations!\n");
+ torture_comment(samlogon_state->tctx, "lm_session_key:\n");
+ dump_data(1, lm_session_key, 8);
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, ntlm_session_key.data, 8);
+ pass = false;
+ }
+ }
+
+ return pass;
+}
+
+/*
+ * Test the NTLMv2 and LMv2 responses
+ */
+
+static bool test_lmv2_ntlmv2(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, UPPER_DOMAIN, error_string);
+}
+
+#if 0
+static bool test_lmv2_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NONE, NO_DOMAIN, error_string);
+}
+#endif
+
+/*
+ * Test the LMv2 response only
+ */
+
+static bool test_lmv2(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, UPPER_DOMAIN, error_string);
+}
+
+static bool test_lmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, NO_NT, NO_DOMAIN, error_string);
+}
+
+/*
+ * Test the NTLMv2 response only
+ */
+
+static bool test_ntlmv2(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, UPPER_DOMAIN, error_string);
+}
+
+static bool test_ntlmv2_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, NO_LM, NO_DOMAIN, error_string);
+}
+
+static bool test_lm_ntlm(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lm_ntlm_broken(samlogon_state, BREAK_NONE, error_string);
+}
+
+static bool test_ntlm_lm_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lm_ntlm_broken(samlogon_state, BREAK_LM, error_string);
+}
+
+static bool test_ntlm_ntlm_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lm_ntlm_broken(samlogon_state, BREAK_NT, error_string);
+}
+
+static bool test_lm_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lm_ntlm_broken(samlogon_state, BREAK_BOTH, error_string);
+}
+static bool test_ntlmv2_lmv2_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
+}
+
+static bool test_ntlmv2_lmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
+}
+
+static bool test_ntlmv2_ntlmv2_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
+}
+
+#if 0
+static bool test_ntlmv2_ntlmv2_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
+}
+#endif
+
+static bool test_ntlmv2_both_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
+}
+
+static bool test_ntlmv2_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlmv2_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
+}
+
+static bool test_lmv2_ntlm_both_broken(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, UPPER_DOMAIN, error_string);
+}
+
+static bool test_lmv2_ntlm_both_broken_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlm_broken(samlogon_state, BREAK_BOTH, NO_DOMAIN, error_string);
+}
+
+static bool test_lmv2_ntlm_break_ntlm(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, UPPER_DOMAIN, error_string);
+}
+
+static bool test_lmv2_ntlm_break_ntlm_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlm_broken(samlogon_state, BREAK_NT, NO_DOMAIN, error_string);
+}
+
+static bool test_lmv2_ntlm_break_lm(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, UPPER_DOMAIN, error_string);
+}
+
+static bool test_lmv2_ntlm_break_lm_no_dom(struct samlogon_state *samlogon_state, char **error_string)
+{
+ return test_lmv2_ntlm_broken(samlogon_state, BREAK_LM, NO_DOMAIN, error_string);
+}
+
+/*
+ * Test the NTLM2 response (extra challenge in LM field)
+ *
+ * This test is the same as the 'break LM' test, but checks that the
+ * server implements NTLM2 session security in the right place
+ * (NETLOGON is the wrong place).
+ */
+
+static bool test_ntlm2(struct samlogon_state *samlogon_state, char **error_string)
+{
+ bool pass = true;
+ NTSTATUS nt_status;
+ DATA_BLOB lm_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+ DATA_BLOB nt_response = data_blob_talloc(samlogon_state->mem_ctx, NULL, 24);
+
+ uint8_t lm_key[8];
+ uint8_t nt_hash[16];
+ uint8_t lm_hash[16];
+ uint8_t nt_key[16];
+ uint8_t user_session_key[16];
+ uint8_t expected_user_session_key[16];
+ uint8_t session_nonce_hash[16];
+ uint8_t client_chall[8];
+
+ gnutls_hmac_hd_t hmac_hnd;
+ gnutls_hash_hd_t hash_hnd;
+
+ ZERO_STRUCT(user_session_key);
+ ZERO_STRUCT(lm_key);
+ generate_random_buffer(client_chall, 8);
+
+ gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ gnutls_hash(hash_hnd, samlogon_state->chall.data, 8);
+ gnutls_hash(hash_hnd, client_chall, 8);
+ gnutls_hash_deinit(hash_hnd, session_nonce_hash);
+
+ E_md4hash(samlogon_state->password, (uint8_t *)nt_hash);
+ E_deshash(samlogon_state->password, (uint8_t *)lm_hash);
+ SMBsesskeygen_ntv1((const uint8_t *)nt_hash,
+ nt_key);
+
+ SMBNTencrypt(samlogon_state->password, samlogon_state->chall.data, nt_response.data);
+
+ memcpy(lm_response.data, session_nonce_hash, 8);
+ memset(lm_response.data + 8, 0, 16);
+
+ gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_MD5,
+ nt_key,
+ 16);
+ gnutls_hmac(hmac_hnd, samlogon_state->chall.data, 8);
+ gnutls_hmac(hmac_hnd, client_chall, 8);
+ gnutls_hmac_deinit(hmac_hnd, expected_user_session_key);
+
+ nt_status = check_samlogon(samlogon_state,
+ BREAK_NONE,
+ samlogon_state->parameter_control,
+ &samlogon_state->chall,
+ &lm_response,
+ &nt_response,
+ lm_key,
+ user_session_key,
+ error_string);
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ return false;
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ if (!all_zero(lm_key, sizeof(lm_key))) {
+ torture_comment(samlogon_state->tctx, "LM Session Key does not match expectations (zeros)!\n");
+ torture_comment(samlogon_state->tctx, "lm_key:\n");
+ dump_data(1, lm_key, 8);
+ pass = false;
+ }
+ if (memcmp(nt_key, user_session_key, 16) != 0) {
+ torture_comment(samlogon_state->tctx, "NT Session Key does not match expectations (should be NT Key)!\n");
+ torture_comment(samlogon_state->tctx, "user_session_key:\n");
+ dump_data(1, user_session_key, sizeof(user_session_key));
+ torture_comment(samlogon_state->tctx, "expected:\n");
+ dump_data(1, nt_key, sizeof(nt_key));
+ pass = false;
+ }
+ return pass;
+}
+
+static bool test_plaintext(struct samlogon_state *samlogon_state, enum ntlm_break break_which, char **error_string)
+{
+ NTSTATUS nt_status;
+ DATA_BLOB nt_response = data_blob(NULL, 0);
+ DATA_BLOB lm_response = data_blob(NULL, 0);
+ char *password;
+ char *dospw;
+ smb_ucs2_t *unicodepw;
+ size_t converted_size = 0;
+ uint8_t user_session_key[16];
+ uint8_t lm_key[16];
+ uint8_t lm_hash[16];
+ DATA_BLOB chall = data_blob_talloc_zero(samlogon_state->mem_ctx, 8);
+ bool lm_good = E_deshash(samlogon_state->password, lm_hash);
+
+ ZERO_STRUCT(user_session_key);
+
+ if (!push_ucs2_talloc(samlogon_state->mem_ctx,
+ &unicodepw, samlogon_state->password, &converted_size)) {
+ DEBUG(0, ("push_ucs2_allocate failed!\n"));
+ exit(1);
+ }
+
+ nt_response = data_blob_talloc(samlogon_state->mem_ctx, unicodepw, strlen_m(samlogon_state->password)*2);
+
+ password = strupper_talloc(samlogon_state->mem_ctx, samlogon_state->password);
+
+ if (!convert_string_talloc(samlogon_state->mem_ctx,
+ CH_UNIX, CH_DOS,
+ password, strlen(password)+1,
+ (void**)&dospw, &converted_size)) {
+ DEBUG(0, ("convert_string_talloc failed!\n"));
+ exit(1);
+ }
+
+ lm_response = data_blob_talloc(samlogon_state->mem_ctx, dospw, strlen(dospw));
+
+ nt_status = check_samlogon(samlogon_state,
+ break_which,
+ samlogon_state->parameter_control | MSV1_0_CLEARTEXT_PASSWORD_ALLOWED,
+ &chall,
+ &lm_response,
+ &nt_response,
+ lm_key,
+ user_session_key,
+ error_string);
+
+ if (NT_STATUS_EQUAL(NT_STATUS_WRONG_PASSWORD, nt_status)) {
+ /* for 'old' passwords, we allow the server to be OK or wrong password */
+ if (samlogon_state->old_password) {
+ return true;
+ }
+ /* for 'long' passwords, the LM password is invalid */
+ if (break_which == NO_NT && !lm_good) {
+ return true;
+ }
+ /* for modern servers, the LM password is invalid */
+ if (break_which == NO_NT
+ && !torture_setting_bool(samlogon_state->tctx, "samba3", false)) {
+ return true;
+ }
+
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH));
+ } else if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, nt_status) && strchr_m(samlogon_state->account_name, '@')) {
+ return ((break_which == BREAK_NT) || (break_which == BREAK_BOTH) || (break_which == NO_NT));
+ } else if (!NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status)) {
+ int ret;
+
+ SAFE_FREE(*error_string);
+ ret = asprintf(error_string, "Expected error: %s, got %s", nt_errstr(samlogon_state->expected_error), nt_errstr(nt_status));
+ if (ret == -1) {
+ *error_string = NULL;
+ }
+ return false;
+ } else if (NT_STATUS_EQUAL(samlogon_state->expected_error, nt_status) && !NT_STATUS_IS_OK(nt_status)) {
+ return true;
+ } else if (!NT_STATUS_IS_OK(nt_status)) {
+ return false;
+ }
+
+ if (break_which == NO_NT && !lm_good) {
+ *error_string = strdup("LM password is 'long' (> 14 chars and therefore invalid) but login did not fail!");
+ return false;
+ }
+
+ /* for modern servers, the LM password is invalid */
+ if (break_which == NO_NT
+ && !torture_setting_bool(samlogon_state->tctx, "samba3", false)) {
+ *error_string = strdup("LM password is OK but should have failed against a modern server");
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_plaintext_none_broken(struct samlogon_state *samlogon_state,
+ char **error_string) {
+ return test_plaintext(samlogon_state, BREAK_NONE, error_string);
+}
+
+static bool test_plaintext_lm_broken(struct samlogon_state *samlogon_state,
+ char **error_string) {
+ return test_plaintext(samlogon_state, BREAK_LM, error_string);
+}
+
+static bool test_plaintext_nt_broken(struct samlogon_state *samlogon_state,
+ char **error_string) {
+ return test_plaintext(samlogon_state, BREAK_NT, error_string);
+}
+
+static bool test_plaintext_nt_only(struct samlogon_state *samlogon_state,
+ char **error_string) {
+ return test_plaintext(samlogon_state, NO_LM, error_string);
+}
+
+static bool test_plaintext_lm_only(struct samlogon_state *samlogon_state,
+ char **error_string) {
+ return test_plaintext(samlogon_state, NO_NT, error_string);
+}
+
+/*
+ Tests:
+
+ - LM only
+ - NT and LM
+ - NT
+ - NT in LM field
+ - NT in both fields
+ - NTLMv2
+ - NTLMv2 and LMv2
+ - LMv2
+ - plaintext tests (in challenge-response fields)
+
+ check we get the correct session key in each case
+ check what values we get for the LM session key
+
+*/
+
+static const struct ntlm_tests {
+ bool (*fn)(struct samlogon_state *, char **);
+ const char *name;
+ bool expect_fail;
+} test_table[] = {
+ {test_lmv2_ntlmv2, "NTLMv2 and LMv2", false},
+#if 0
+ {test_lmv2_ntlmv2_no_dom, "NTLMv2 and LMv2 (no domain)", false},
+#endif
+ {test_lm, "LM", false},
+ {test_lm_ntlm, "LM and NTLM", false},
+ {test_lm_ntlm_both_broken, "LM and NTLM, both broken", false},
+ {test_ntlm, "NTLM", false},
+ {test_ntlm_in_lm, "NTLM in LM", false},
+ {test_ntlm_in_both, "NTLM in both", false},
+ {test_ntlmv2, "NTLMv2", false},
+ {test_ntlmv2_no_dom, "NTLMv2 (no domain)", false},
+ {test_lmv2, "LMv2", false},
+ {test_lmv2_no_dom, "LMv2 (no domain)", false},
+ {test_ntlmv2_lmv2_broken, "NTLMv2 and LMv2, LMv2 broken", false},
+ {test_ntlmv2_lmv2_broken_no_dom, "NTLMv2 and LMv2, LMv2 broken (no domain)", false},
+ {test_ntlmv2_ntlmv2_broken, "NTLMv2 and LMv2, NTLMv2 broken", false},
+#if 0
+ {test_ntlmv2_ntlmv2_broken_no_dom, "NTLMv2 and LMv2, NTLMv2 broken (no domain)", false},
+#endif
+ {test_ntlmv2_both_broken, "NTLMv2 and LMv2, both broken", false},
+ {test_ntlmv2_both_broken_no_dom, "NTLMv2 and LMv2, both broken (no domain)", false},
+ {test_ntlm_lm_broken, "NTLM and LM, LM broken", false},
+ {test_ntlm_ntlm_broken, "NTLM and LM, NTLM broken", false},
+ {test_ntlm2, "NTLM2 (NTLMv2 session security)", false},
+ {test_lmv2_ntlm_both_broken, "LMv2 and NTLM, both broken", false},
+ {test_lmv2_ntlm_both_broken_no_dom, "LMv2 and NTLM, both broken (no domain)", false},
+ {test_lmv2_ntlm_break_ntlm, "LMv2 and NTLM, NTLM broken", false},
+ {test_lmv2_ntlm_break_ntlm_no_dom, "LMv2 and NTLM, NTLM broken (no domain)", false},
+ {test_lmv2_ntlm_break_lm, "LMv2 and NTLM, LMv2 broken", false},
+ {test_lmv2_ntlm_break_lm_no_dom, "LMv2 and NTLM, LMv2 broken (no domain)", false},
+ {test_plaintext_none_broken, "Plaintext", false},
+ {test_plaintext_lm_broken, "Plaintext LM broken", false},
+ {test_plaintext_nt_broken, "Plaintext NT broken", false},
+ {test_plaintext_nt_only, "Plaintext NT only", false},
+ {test_plaintext_lm_only, "Plaintext LM only", false},
+ { .name = NULL, }
+};
+
+/*
+ try a netlogon SamLogon
+*/
+static bool test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct torture_context *tctx,
+ struct netlogon_creds_CredentialState *creds,
+ const char *comment,
+ const char *account_domain, const char *account_name,
+ const char *plain_pass, uint32_t parameter_control,
+ NTSTATUS expected_error, bool old_password,
+ int n_subtests)
+{
+ TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_SamLogon function-level context");
+ int i, v, l, f;
+ bool ret = true;
+ int validation_levels[] = {2,3,6};
+ int logon_levels[] = { NetlogonNetworkInformation, NetlogonNetworkTransitiveInformation };
+ int function_levels[] = {
+ NDR_NETR_LOGONSAMLOGON,
+ NDR_NETR_LOGONSAMLOGONEX,
+ NDR_NETR_LOGONSAMLOGONWITHFLAGS };
+ struct samlogon_state samlogon_state;
+
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative = 1;
+ uint32_t flags = 0;
+
+ ZERO_STRUCT(logon);
+
+ torture_comment(tctx, "Testing netr_LogonSamLogon and netr_LogonSamLogonWithFlags\n");
+
+ samlogon_state.comment = comment;
+ samlogon_state.account_name = account_name;
+ samlogon_state.account_domain = account_domain;
+ samlogon_state.password = plain_pass;
+ samlogon_state.workgroup = lpcfg_workgroup(tctx->lp_ctx);
+ samlogon_state.netbios_name = lpcfg_netbios_name(tctx->lp_ctx);
+ samlogon_state.p = p;
+ samlogon_state.creds = creds;
+ samlogon_state.expected_error = expected_error;
+ samlogon_state.chall = data_blob_talloc(fn_ctx, NULL, 8);
+ samlogon_state.parameter_control = parameter_control;
+ samlogon_state.old_password = old_password;
+ samlogon_state.tctx = tctx;
+
+ generate_random_buffer(samlogon_state.chall.data, 8);
+ samlogon_state.r_flags.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
+ samlogon_state.r_flags.in.computer_name = TEST_MACHINE_NAME;
+ samlogon_state.r_flags.in.credential = &samlogon_state.auth;
+ samlogon_state.r_flags.in.return_authenticator = &samlogon_state.auth2;
+ samlogon_state.r_flags.in.flags = &flags;
+ samlogon_state.r_flags.in.logon = &logon;
+ samlogon_state.r_flags.out.validation = &validation;
+ samlogon_state.r_flags.out.authoritative = &authoritative;
+ samlogon_state.r_flags.out.flags = &flags;
+
+ samlogon_state.r_ex.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
+ samlogon_state.r_ex.in.computer_name = TEST_MACHINE_NAME;
+ samlogon_state.r_ex.in.flags = &flags;
+ samlogon_state.r_ex.in.logon = &logon;
+ samlogon_state.r_ex.out.validation = &validation;
+ samlogon_state.r_ex.out.authoritative = &authoritative;
+ samlogon_state.r_ex.out.flags = &flags;
+
+ samlogon_state.r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
+ samlogon_state.r.in.computer_name = TEST_MACHINE_NAME;
+ samlogon_state.r.in.credential = &samlogon_state.auth;
+ samlogon_state.r.in.return_authenticator = &samlogon_state.auth2;
+ samlogon_state.r.in.logon = &logon;
+ samlogon_state.r.out.validation = &validation;
+ samlogon_state.r.out.authoritative = &authoritative;
+
+
+ for (f=0;f<ARRAY_SIZE(function_levels);f++) {
+ for (i=0; test_table[i].fn; i++) {
+ if (n_subtests && (i > n_subtests)) {
+ continue;
+ }
+ for (v=0;v<ARRAY_SIZE(validation_levels);v++) {
+ for (l=0;l<ARRAY_SIZE(logon_levels);l++) {
+ char *error_string = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_named(fn_ctx, 0, "test_SamLogon inner loop");
+ samlogon_state.mem_ctx = tmp_ctx;
+ samlogon_state.function_level = function_levels[f];
+ samlogon_state.r.in.validation_level = validation_levels[v];
+ samlogon_state.r.in.logon_level = logon_levels[l];
+ samlogon_state.r_ex.in.validation_level = validation_levels[v];
+ samlogon_state.r_ex.in.logon_level = logon_levels[l];
+ samlogon_state.r_flags.in.validation_level = validation_levels[v];
+ samlogon_state.r_flags.in.logon_level = logon_levels[l];
+ if (!test_table[i].fn(&samlogon_state, &error_string)) {
+ torture_comment(tctx, "Testing '%s' [%s]\\[%s] '%s' at validation level %d, logon level %d, function %d: \n",
+ samlogon_state.comment,
+ samlogon_state.account_domain,
+ samlogon_state.account_name,
+ test_table[i].name, validation_levels[v],
+ logon_levels[l], function_levels[f]);
+
+ if (test_table[i].expect_fail) {
+ torture_comment(tctx, " failed (expected, test incomplete): %s\n", error_string);
+ } else {
+ torture_comment(tctx, " failed: %s\n", error_string);
+ ret = false;
+ }
+ SAFE_FREE(error_string);
+ }
+ talloc_free(tmp_ctx);
+ }
+ }
+ }
+ }
+ talloc_free(fn_ctx);
+ return ret;
+}
+
+/*
+ test an ADS style interactive domain logon
+*/
+bool test_InteractiveLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct torture_context *tctx,
+ struct netlogon_creds_CredentialState *creds,
+ const char *comment,
+ const char *workstation_name,
+ const char *account_domain, const char *account_name,
+ const char *plain_pass, uint32_t parameter_control,
+ NTSTATUS expected_error)
+{
+ NTSTATUS status;
+ TALLOC_CTX *fn_ctx = talloc_named(mem_ctx, 0, "test_InteractiveLogon function-level context");
+ bool ret = true;
+ struct netr_LogonSamLogonWithFlags r;
+ struct netr_Authenticator a, ra;
+ struct netr_PasswordInfo pinfo;
+ uint32_t flags = 0;
+
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative = 1;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(a);
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(ra);
+
+ ZERO_STRUCT(logon);
+ ZERO_STRUCT(validation);
+
+ netlogon_creds_client_authenticator(creds, &a);
+
+ logon.password = &pinfo;
+
+ r.in.server_name = talloc_asprintf(fn_ctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &a;
+ r.in.return_authenticator = &ra;
+ r.in.logon_level = NetlogonInteractiveTransitiveInformation;
+ r.in.logon = &logon;
+ r.in.validation_level = 6;
+ r.in.flags = &flags;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+ r.out.flags = &flags;
+
+ pinfo.identity_info.domain_name.string = account_domain;
+ pinfo.identity_info.parameter_control = parameter_control;
+ pinfo.identity_info.logon_id = 0;
+ pinfo.identity_info.account_name.string = account_name;
+ pinfo.identity_info.workstation.string = workstation_name;
+
+ if (!E_deshash(plain_pass, pinfo.lmpassword.hash)) {
+ ZERO_STRUCT(pinfo.lmpassword.hash);
+ }
+ E_md4hash(plain_pass, pinfo.ntpassword.hash);
+
+ if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ netlogon_creds_arcfour_crypt(creds, pinfo.lmpassword.hash, 16);
+ netlogon_creds_arcfour_crypt(creds, pinfo.ntpassword.hash, 16);
+ } else {
+ netlogon_creds_des_encrypt(creds, &pinfo.lmpassword);
+ netlogon_creds_des_encrypt(creds, &pinfo.ntpassword);
+ }
+
+ torture_comment(tctx, "Testing netr_LogonSamLogonWithFlags '%s' (Interactive Logon)\n", comment);
+
+ status = dcerpc_netr_LogonSamLogonWithFlags_r(b, fn_ctx, &r);
+ torture_assert_ntstatus_ok_goto(tctx,
+ status,
+ ret, failed,
+ talloc_asprintf(tctx, "%s: netr_LogonSamLogonWithFlags - %s\n",
+ __location__, nt_errstr(status)));
+
+ if (!r.out.return_authenticator) {
+ talloc_free(fn_ctx);
+ torture_fail(tctx, "no authenticator returned");
+ }
+
+ torture_assert_goto(tctx,
+ netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
+ ret, failed,
+ "Credential chaining failed\n");
+
+ torture_assert_ntstatus_equal(tctx, r.out.result, expected_error,
+ talloc_asprintf(tctx, "[%s]\\[%s] netr_LogonSamLogonWithFlags - expected %s got %s\n",
+ account_domain, account_name, nt_errstr(expected_error), nt_errstr(r.out.result)));
+
+ ret = true;
+ failed:
+ talloc_free(fn_ctx);
+
+ return ret;
+}
+
+/* This sets and resets the "minPwdAge" (in order to allow immediate user
+ * password changes). The behaviour is controlled by the "set" boolean. */
+static bool handle_minPwdAge(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx, bool set)
+{
+ struct dcerpc_pipe *p;
+ struct policy_handle connect_handle, domain_handle;
+ struct samr_Connect c_r;
+ struct samr_LookupDomain ld_r;
+ struct samr_OpenDomain od_r;
+ struct samr_QueryDomainInfo qdi_r;
+ struct samr_SetDomainInfo sdi_r;
+ struct samr_Close cl_r;
+ struct lsa_String domName;
+ struct dom_sid *domSid = NULL;
+ union samr_DomainInfo *domInfo = NULL;
+ static int64_t old_minPwdAge = 0;
+ NTSTATUS status;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ c_r.in.system_name = 0;
+ c_r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ c_r.out.connect_handle = &connect_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_Connect_r(p->binding_handle, mem_ctx, &c_r),
+ "Connect failed");
+ torture_assert_ntstatus_ok(torture, c_r.out.result, "Connect failed");
+
+ ld_r.in.connect_handle = &connect_handle;
+ ld_r.in.domain_name = &domName;
+ ld_r.in.domain_name->string = lpcfg_workgroup(torture->lp_ctx);
+ ld_r.out.sid = &domSid;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_LookupDomain_r(p->binding_handle, mem_ctx, &ld_r),
+ "LookupDomain failed");
+ torture_assert_ntstatus_ok(torture, ld_r.out.result,
+ "LookupDomain failed");
+
+ od_r.in.connect_handle = &connect_handle;
+ od_r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ od_r.in.sid = *ld_r.out.sid;
+ od_r.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_OpenDomain_r(p->binding_handle, mem_ctx, &od_r),
+ "OpenDomain failed");
+ torture_assert_ntstatus_ok(torture, od_r.out.result,
+ "OpenDomain failed");
+
+ qdi_r.in.domain_handle = &domain_handle;
+ qdi_r.in.level = DomainPasswordInformation;
+ qdi_r.out.info = &domInfo;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_QueryDomainInfo_r(p->binding_handle, mem_ctx, &qdi_r),
+ "QueryDomainInfo failed");
+ torture_assert_ntstatus_ok(torture, qdi_r.out.result,
+ "QueryDomainInfo failed");
+
+ if (set) {
+ old_minPwdAge = domInfo->info1.min_password_age;
+ domInfo->info1.min_password_age = 0;
+ } else {
+ domInfo->info1.min_password_age = old_minPwdAge;
+ }
+
+ sdi_r.in.domain_handle = &domain_handle;
+ sdi_r.in.level = DomainPasswordInformation;
+ sdi_r.in.info = domInfo;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_SetDomainInfo_r(p->binding_handle, mem_ctx, &sdi_r),
+ "SetDomainInfo failed");
+ torture_assert_ntstatus_ok(torture, sdi_r.out.result,
+ "SetDomainInfo failed");
+
+ cl_r.in.handle = &connect_handle;
+ cl_r.out.handle = &connect_handle;
+
+ torture_assert_ntstatus_ok(torture,
+ dcerpc_samr_Close_r(p->binding_handle, mem_ctx, &cl_r),
+ "Close failed");
+ torture_assert_ntstatus_ok(torture, cl_r.out.result, "Close failed");
+
+ return true;
+}
+
+bool torture_rpc_samlogon(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding *b;
+ struct cli_credentials *machine_credentials;
+ TALLOC_CTX *mem_ctx = talloc_init("torture_rpc_netlogon");
+ bool ret = true;
+ struct test_join *join_ctx = NULL;
+ struct test_join *user_ctx = NULL, *user_ctx_wrong_wks = NULL, *user_ctx_wrong_time = NULL;
+ const char *old_user_password, *user_password_wrong_wks, *user_password_wrong_time;
+ char *user_password;
+ const char *userdomain;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ int i;
+ int ci;
+
+ unsigned int credential_flags[] = {
+ NETLOGON_NEG_AUTH2_FLAGS,
+ NETLOGON_NEG_ARCFOUR,
+ NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT,
+ NETLOGON_NEG_AUTH2_ADS_FLAGS,
+ 0 /* yes, this is a valid flag, causes the use of DES */
+ };
+
+ struct netlogon_creds_CredentialState *creds;
+ struct dcerpc_pipe *tmp_p = NULL;
+
+ torture_assert(torture, handle_minPwdAge(torture, mem_ctx, true),
+ "handle_minPwdAge error!");
+
+ /* We only need to join as a workstation here, and in future,
+ * if we wish to test against trusted domains, we must be a
+ * workstation here */
+ join_ctx = torture_join_domain(torture, TEST_MACHINE_NAME, ACB_WSTRUST,
+ &machine_credentials);
+ torture_assert(torture, join_ctx, "Failed to join as Workstation\n");
+
+ userdomain = torture_setting_string(torture, "userdomain", lpcfg_workgroup(torture->lp_ctx));
+
+ user_ctx = torture_create_testuser(torture,
+ TEST_USER_NAME,
+ userdomain,
+ ACB_NORMAL,
+ &old_user_password);
+ torture_assert(torture, user_ctx, "Failed to create a test user\n");
+
+ user_password = talloc_strdup(torture, old_user_password);
+ torture_assert(torture, user_password != NULL, "Failed to copy old_user_password\n");
+
+ tmp_p = torture_join_samr_pipe(user_ctx);
+ torture_assert(torture, tmp_p, "torture_join_samr_pipe failed\n");
+ test_ChangePasswordUser3(tmp_p, torture,
+ TEST_USER_NAME, 16 /* > 14 */, &user_password,
+ NULL, 0, false);
+
+ user_ctx_wrong_wks = torture_create_testuser(torture,
+ TEST_USER_NAME_WRONG_WKS,
+ userdomain,
+ ACB_NORMAL,
+ &user_password_wrong_wks);
+ torture_assert(torture, user_ctx_wrong_wks,
+ "Failed to create a test user (wrong workstation test)\n");
+
+ ZERO_STRUCT(u);
+ s.in.user_handle = torture_join_samr_user_policy(user_ctx_wrong_wks);
+ s.in.info = &u;
+ s.in.level = 21;
+
+ u.info21.fields_present = SAMR_FIELD_WORKSTATIONS;
+ u.info21.workstations.string = "not" TEST_MACHINE_NAME;
+
+ tmp_p = torture_join_samr_pipe(user_ctx_wrong_wks);
+ status = dcerpc_samr_SetUserInfo_r(tmp_p->binding_handle, mem_ctx, &s);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, failed,
+ talloc_asprintf(torture, "SetUserInfo (list of workstations) failed - %s\n", nt_errstr(status)));
+ torture_assert_ntstatus_ok_goto(torture, s.out.result, ret, failed,
+ talloc_asprintf(torture, "SetUserInfo (list of workstations) failed - %s\n", nt_errstr(s.out.result)));
+
+ user_ctx_wrong_time
+ = torture_create_testuser(torture, TEST_USER_NAME_WRONG_TIME,
+ userdomain,
+ ACB_NORMAL,
+ &user_password_wrong_time);
+ torture_assert(torture, user_ctx_wrong_time,
+ "Failed to create a test user (wrong workstation test)\n");
+
+ ZERO_STRUCT(u);
+ s.in.user_handle = torture_join_samr_user_policy(user_ctx_wrong_time);
+ s.in.info = &u;
+ s.in.level = 21;
+
+ u.info21.fields_present = SAMR_FIELD_WORKSTATIONS | SAMR_FIELD_LOGON_HOURS;
+ u.info21.workstations.string = TEST_MACHINE_NAME;
+ u.info21.logon_hours.units_per_week = 168;
+ u.info21.logon_hours.bits = talloc_zero_array(mem_ctx, uint8_t, 168);
+
+ tmp_p = torture_join_samr_pipe(user_ctx_wrong_time);
+ status = dcerpc_samr_SetUserInfo_r(tmp_p->binding_handle, mem_ctx, &s);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, failed,
+ talloc_asprintf(torture, "SetUserInfo (logon times and list of workstations) failed - %s\n", nt_errstr(status)));
+ torture_assert_ntstatus_ok_goto(torture, s.out.result, ret, failed,
+ talloc_asprintf(torture, "SetUserInfo (list of workstations) failed - %s\n", nt_errstr(s.out.result)));
+
+
+ torture_assert_ntstatus_ok_goto(torture,
+ torture_rpc_binding(torture, &b),
+ ret,
+ failed,
+ "Obtaining binding");
+
+ /* We have to use schannel, otherwise the SamLogonEx fails
+ * with INTERNAL_ERROR */
+
+ status = dcerpc_binding_set_flags(b,
+ DCERPC_SCHANNEL |
+ DCERPC_SIGN | DCERPC_SEAL |
+ DCERPC_SCHANNEL_128,
+ DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(torture, status, "set flags");
+
+ status = dcerpc_pipe_connect_b(mem_ctx, &p, b,
+ &ndr_table_netlogon,
+ machine_credentials, torture->ev, torture->lp_ctx);
+
+ torture_assert_ntstatus_ok_goto(torture, status, ret, failed,
+ talloc_asprintf(torture, "RPC pipe connect as domain member failed: %s\n", nt_errstr(status)));
+
+ torture_assert_not_null_goto(torture,
+ creds = cli_credentials_get_netlogon_creds(machine_credentials),
+ ret,
+ failed,
+ "obtaining credentials");
+
+ {
+
+ struct {
+ const char *comment;
+ const char *domain;
+ const char *username;
+ const char *password;
+ bool network_login;
+ NTSTATUS expected_interactive_error;
+ NTSTATUS expected_network_error;
+ uint32_t parameter_control;
+ bool old_password; /* Allow an old password to be accepted or rejected without error, as well as session key bugs */
+ } usercreds[] = {
+ {
+ .comment = "domain\\user",
+ .domain = cli_credentials_get_domain(
+ samba_cmdline_get_creds()),
+ .username = cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ .password = cli_credentials_get_password(
+ samba_cmdline_get_creds()),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "realm\\user",
+ .domain = cli_credentials_get_realm(
+ samba_cmdline_get_creds()),
+ .username = cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ .password = cli_credentials_get_password(
+ samba_cmdline_get_creds()),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "user@domain",
+ .domain = NULL,
+ .username = talloc_asprintf(mem_ctx,
+ "%s@%s",
+ cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ cli_credentials_get_domain(
+ samba_cmdline_get_creds())
+ ),
+ .password = cli_credentials_get_password(
+ samba_cmdline_get_creds()),
+ .network_login = false, /* works for some things, but not NTLMv2. Odd */
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "user@realm",
+ .domain = NULL,
+ .username = talloc_asprintf(mem_ctx,
+ "%s@%s",
+ cli_credentials_get_username(
+ samba_cmdline_get_creds()),
+ cli_credentials_get_realm(
+ samba_cmdline_get_creds())
+ ),
+ .password = cli_credentials_get_password(
+ samba_cmdline_get_creds()),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "machine domain\\user",
+ .domain = cli_credentials_get_domain(machine_credentials),
+ .username = cli_credentials_get_username(machine_credentials),
+ .password = cli_credentials_get_password(machine_credentials),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+ .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+ },
+ {
+ .comment = "machine domain\\user",
+ .domain = cli_credentials_get_domain(machine_credentials),
+ .username = cli_credentials_get_username(machine_credentials),
+ .password = cli_credentials_get_password(machine_credentials),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+ .expected_network_error = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "machine realm\\user",
+ .domain = cli_credentials_get_realm(machine_credentials),
+ .username = cli_credentials_get_username(machine_credentials),
+ .password = cli_credentials_get_password(machine_credentials),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+ .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+ },
+ {
+ .comment = "machine user@domain",
+ .domain = NULL,
+ .username = talloc_asprintf(mem_ctx,
+ "%s@%s",
+ cli_credentials_get_username(machine_credentials),
+ cli_credentials_get_domain(machine_credentials)
+ ),
+ .password = cli_credentials_get_password(machine_credentials),
+ .network_login = false, /* works for some things, but not NTLMv2. Odd */
+ .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+ .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+ },
+ {
+ .comment = "machine user@realm",
+ .domain = NULL,
+ .username = talloc_asprintf(mem_ctx,
+ "%s@%s",
+ cli_credentials_get_username(machine_credentials),
+ cli_credentials_get_realm(machine_credentials)
+ ),
+ .password = cli_credentials_get_password(machine_credentials),
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_NO_SUCH_USER,
+ .parameter_control = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
+ },
+ {
+ .comment = "test user (long pw): domain\\user",
+ .domain = userdomain,
+ .username = TEST_USER_NAME,
+ .password = user_password,
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "test user (long pw): user@realm",
+ .domain = NULL,
+ .username = talloc_asprintf(mem_ctx,
+ "%s@%s",
+ TEST_USER_NAME,
+ lpcfg_realm(torture->lp_ctx)),
+ .password = user_password,
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ {
+ .comment = "test user (long pw): user@domain",
+ .domain = NULL,
+ .username = talloc_asprintf(mem_ctx,
+ "%s@%s",
+ TEST_USER_NAME,
+ userdomain),
+ .password = user_password,
+ .network_login = false, /* works for some things, but not NTLMv2. Odd */
+ .expected_interactive_error = NT_STATUS_OK,
+ .expected_network_error = NT_STATUS_OK,
+ .parameter_control = 0,
+ },
+ /* Oddball, can we use the old password ? */
+ {
+ .comment = "test user: user\\domain OLD PASSWORD",
+ .domain = userdomain,
+ .username = TEST_USER_NAME,
+ .password = old_user_password,
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_WRONG_PASSWORD,
+ .expected_network_error = NT_STATUS_OK,
+ .old_password = true
+ },
+ {
+ .comment = "test user (wrong workstation): domain\\user",
+ .domain = userdomain,
+ .username = TEST_USER_NAME_WRONG_WKS,
+ .password = user_password_wrong_wks,
+ .network_login = true,
+ .expected_interactive_error = NT_STATUS_INVALID_WORKSTATION,
+ .expected_network_error = NT_STATUS_INVALID_WORKSTATION,
+ .parameter_control = 0,
+ }
+ };
+
+ /* Try all the tests for different username forms */
+ for (ci = 0; ci < ARRAY_SIZE(usercreds); ci++) {
+
+ torture_assert_goto(torture,
+ test_InteractiveLogon(p, mem_ctx, torture, creds,
+ usercreds[ci].comment,
+ TEST_MACHINE_NAME,
+ usercreds[ci].domain,
+ usercreds[ci].username,
+ usercreds[ci].password,
+ usercreds[ci].parameter_control,
+ usercreds[ci].expected_interactive_error),
+ ret,
+ failed,
+ talloc_asprintf(mem_ctx, "InteractiveLogon: %s",
+ usercreds[ci].comment));
+
+ if (usercreds[ci].network_login) {
+ torture_assert_goto(torture,
+ test_SamLogon(p, mem_ctx, torture, creds,
+ usercreds[ci].comment,
+ usercreds[ci].domain,
+ usercreds[ci].username,
+ usercreds[ci].password,
+ usercreds[ci].parameter_control,
+ usercreds[ci].expected_network_error,
+ usercreds[ci].old_password,
+ 0),
+ ret,
+ failed,
+ talloc_asprintf(mem_ctx, "SamLogon: %s",
+ usercreds[ci].comment));
+ }
+ }
+
+ /* Using the first username form, try the different
+ * credentials flag setups, on only one of the tests (checks
+ * session key encryption) */
+
+ for (i=0; i < ARRAY_SIZE(credential_flags); i++) {
+ /* TODO: Somehow we lost setting up the different credential flags here! */
+
+ torture_comment(torture,
+ "Testing with flags: 0x%08x\n",
+ credential_flags[i]);
+
+ torture_assert_goto(torture,
+ test_InteractiveLogon(p, mem_ctx, torture, creds,
+ usercreds[0].comment,
+ TEST_MACHINE_NAME,
+ usercreds[0].domain,
+ usercreds[0].username,
+ usercreds[0].password,
+ usercreds[0].parameter_control,
+ usercreds[0].expected_interactive_error),
+ ret,
+ failed,
+ talloc_asprintf(mem_ctx,
+ "Testing InteractiveLogon with flags: 0x%08x\n",
+ credential_flags[i]));
+
+ if (usercreds[0].network_login) {
+ torture_assert_goto(torture,
+ test_SamLogon(p, mem_ctx, torture, creds,
+ usercreds[0].comment,
+ usercreds[0].domain,
+ usercreds[0].username,
+ usercreds[0].password,
+ usercreds[0].parameter_control,
+ usercreds[0].expected_network_error,
+ usercreds[0].old_password,
+ 1),
+ ret,
+ failed,
+ talloc_asprintf(mem_ctx,
+ "Testing SamLogon with flags: 0x%08x\n",
+ credential_flags[i]));
+ }
+ }
+
+ }
+failed:
+ torture_assert(torture, handle_minPwdAge(torture, mem_ctx, false),
+ "handle_minPwdAge error!");
+
+ talloc_free(mem_ctx);
+
+ torture_leave_domain(torture, join_ctx);
+ torture_leave_domain(torture, user_ctx);
+ torture_leave_domain(torture, user_ctx_wrong_wks);
+ torture_leave_domain(torture, user_ctx_wrong_time);
+ return ret;
+}
diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c
new file mode 100644
index 0000000..22e0606
--- /dev/null
+++ b/source4/torture/rpc/samr.c
@@ -0,0 +1,9466 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for samr rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+ Copyright (C) Jelmer Vernooij 2005-2007
+ Copyright (C) Guenther Deschner 2008-2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include <tevent.h>
+#include "system/time.h"
+#include "system/network.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "lib/crypto/crypto.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_proto.h"
+#include "../libcli/auth/schannel.h"
+#include "torture/util.h"
+#include "source4/librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_samr.h"
+#include "source3/rpc_client/init_samr.h"
+#include "lib/crypto/gnutls_helpers.h"
+
+#undef strcasecmp
+
+#define TEST_ACCOUNT_NAME "samrtorturetest"
+#define TEST_ACCOUNT_NAME_PWD "samrpwdlastset"
+#define TEST_ALIASNAME "samrtorturetestalias"
+#define TEST_GROUPNAME "samrtorturetestgroup"
+#define TEST_MACHINENAME "samrtestmach$"
+#define TEST_DOMAINNAME "samrtestdom$"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+enum torture_samr_choice {
+ TORTURE_SAMR_PASSWORDS,
+ TORTURE_SAMR_PASSWORDS_PWDLASTSET,
+ TORTURE_SAMR_PASSWORDS_BADPWDCOUNT,
+ TORTURE_SAMR_PASSWORDS_LOCKOUT,
+ TORTURE_SAMR_USER_ATTRIBUTES,
+ TORTURE_SAMR_USER_PRIVILEGES,
+ TORTURE_SAMR_OTHER,
+ TORTURE_SAMR_MANY_ACCOUNTS,
+ TORTURE_SAMR_MANY_GROUPS,
+ TORTURE_SAMR_MANY_ALIASES
+};
+
+struct torture_samr_context {
+ struct policy_handle handle;
+ struct cli_credentials *machine_credentials;
+ enum torture_samr_choice choice;
+ uint32_t num_objects_large_dc;
+};
+
+static bool test_QueryUserInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle);
+
+static bool test_QueryUserInfo2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle);
+
+static bool test_QueryAliasInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle);
+
+static bool test_ChangePassword(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *acct_name,
+ struct policy_handle *domain_handle, char **password);
+
+static void init_lsa_String(struct lsa_String *string, const char *s)
+{
+ string->string = s;
+}
+
+static void init_lsa_StringLarge(struct lsa_StringLarge *string, const char *s)
+{
+ string->string = s;
+}
+
+static void init_lsa_BinaryString(struct lsa_BinaryString *string, const char *s, uint32_t length)
+{
+ string->length = length;
+ string->size = length;
+ string->array = (uint16_t *)discard_const(s);
+}
+
+bool test_samr_handle_Close(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_Close r;
+
+ r.in.handle = handle;
+ r.out.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Close_r(b, tctx, &r),
+ "Close failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "Close failed");
+
+ return true;
+}
+
+static bool test_Shutdown(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_Shutdown r;
+
+ if (!torture_setting_bool(tctx, "dangerous", false)) {
+ torture_skip(tctx, "samr_Shutdown disabled - enable dangerous tests to use\n");
+ return true;
+ }
+
+ r.in.connect_handle = handle;
+
+ torture_comment(tctx, "Testing samr_Shutdown\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Shutdown_r(b, tctx, &r),
+ "Shutdown failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "Shutdown failed");
+
+ return true;
+}
+
+static bool test_SetDsrmPassword(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_SetDsrmPassword r;
+ struct lsa_String string;
+ struct samr_Password hash;
+
+ if (!torture_setting_bool(tctx, "dangerous", false)) {
+ torture_skip(tctx, "samr_SetDsrmPassword disabled - enable dangerous tests to use");
+ }
+
+ E_md4hash("TeSTDSRM123", hash.hash);
+
+ init_lsa_String(&string, "Administrator");
+
+ r.in.name = &string;
+ r.in.unknown = 0;
+ r.in.hash = &hash;
+
+ torture_comment(tctx, "Testing samr_SetDsrmPassword\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDsrmPassword_r(b, tctx, &r),
+ "SetDsrmPassword failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_SUPPORTED, "SetDsrmPassword failed");
+
+ return true;
+}
+
+
+static bool test_QuerySecurity(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QuerySecurity r;
+ struct samr_SetSecurity s;
+ struct sec_desc_buf *sdbuf = NULL;
+
+ r.in.handle = handle;
+ r.in.sec_info = 7;
+ r.out.sdbuf = &sdbuf;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &r),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "QuerySecurity failed");
+
+ torture_assert(tctx, sdbuf != NULL, "sdbuf is NULL");
+
+ s.in.handle = handle;
+ s.in.sec_info = 7;
+ s.in.sdbuf = sdbuf;
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "skipping SetSecurity test against Samba4\n");
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetSecurity_r(b, tctx, &s),
+ "SetSecurity failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "SetSecurity failed");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &r),
+ "QuerySecurity failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "QuerySecurity failed");
+
+ return true;
+}
+
+
+static bool test_SetUserInfo(struct dcerpc_binding_handle *b, struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t base_acct_flags,
+ const char *base_account_name)
+{
+ struct samr_SetUserInfo s;
+ struct samr_SetUserInfo2 s2;
+ struct samr_QueryUserInfo q;
+ struct samr_QueryUserInfo q0;
+ union samr_UserInfo u;
+ union samr_UserInfo *info;
+ bool ret = true;
+ const char *test_account_name;
+
+ uint32_t user_extra_flags = 0;
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (base_acct_flags == ACB_NORMAL) {
+ /* When created, accounts are expired by default */
+ user_extra_flags = ACB_PW_EXPIRED;
+ }
+ }
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+
+ s2.in.user_handle = handle;
+ s2.in.info = &u;
+
+ q.in.user_handle = handle;
+ q.out.info = &info;
+ q0 = q;
+
+#define TESTCALL(call, r) \
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ ##call## _r(b, tctx, &r),\
+ #call " failed"); \
+ if (!NT_STATUS_IS_OK(r.out.result)) { \
+ torture_result(tctx, TORTURE_FAIL, #call " level %u failed - %s (%s)\n", \
+ r.in.level, nt_errstr(r.out.result), __location__); \
+ ret = false; \
+ break; \
+ }
+
+#define STRING_EQUAL(s1, s2, field) \
+ torture_assert_str_equal(tctx, s1, s2, "Failed to set " #field)
+
+#define MEM_EQUAL(s1, s2, length, field) \
+ torture_assert_mem_equal(tctx, s1, s2, length, "Failed to set " #field)
+
+#define INT_EQUAL(i1, i2, field) \
+ torture_assert_int_equal(tctx, i1, i2, "Failed to set " #field)
+
+#define TEST_USERINFO_STRING(lvl1, field1, lvl2, field2, value, fpval) do { \
+ torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
+ q.in.level = lvl1; \
+ TESTCALL(QueryUserInfo, q) \
+ s.in.level = lvl1; \
+ s2.in.level = lvl1; \
+ u = *info; \
+ if (lvl1 == 21) { \
+ ZERO_STRUCT(u.info21); \
+ u.info21.fields_present = fpval; \
+ } \
+ init_lsa_String(&u.info ## lvl1.field1, value); \
+ TESTCALL(SetUserInfo, s) \
+ TESTCALL(SetUserInfo2, s2) \
+ init_lsa_String(&u.info ## lvl1.field1, ""); \
+ TESTCALL(QueryUserInfo, q); \
+ u = *info; \
+ STRING_EQUAL(u.info ## lvl1.field1.string, value, field1); \
+ q.in.level = lvl2; \
+ TESTCALL(QueryUserInfo, q) \
+ u = *info; \
+ STRING_EQUAL(u.info ## lvl2.field2.string, value, field2); \
+ } while (0)
+
+#define TEST_USERINFO_BINARYSTRING(lvl1, field1, lvl2, field2, value, fpval) do { \
+ torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
+ q.in.level = lvl1; \
+ TESTCALL(QueryUserInfo, q) \
+ s.in.level = lvl1; \
+ s2.in.level = lvl1; \
+ u = *info; \
+ if (lvl1 == 21) { \
+ ZERO_STRUCT(u.info21); \
+ u.info21.fields_present = fpval; \
+ } \
+ init_lsa_BinaryString(&u.info ## lvl1.field1, value, strlen(value)); \
+ TESTCALL(SetUserInfo, s) \
+ TESTCALL(SetUserInfo2, s2) \
+ init_lsa_BinaryString(&u.info ## lvl1.field1, "", 1); \
+ TESTCALL(QueryUserInfo, q); \
+ u = *info; \
+ MEM_EQUAL(u.info ## lvl1.field1.array, value, strlen(value), field1); \
+ q.in.level = lvl2; \
+ TESTCALL(QueryUserInfo, q) \
+ u = *info; \
+ MEM_EQUAL(u.info ## lvl2.field2.array, value, strlen(value), field2); \
+ } while (0)
+
+#define TEST_USERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value, fpval) do { \
+ torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
+ q.in.level = lvl1; \
+ TESTCALL(QueryUserInfo, q) \
+ s.in.level = lvl1; \
+ s2.in.level = lvl1; \
+ u = *info; \
+ if (lvl1 == 21) { \
+ uint8_t *bits = u.info21.logon_hours.bits; \
+ ZERO_STRUCT(u.info21); \
+ if (fpval == SAMR_FIELD_LOGON_HOURS) { \
+ u.info21.logon_hours.units_per_week = 168; \
+ u.info21.logon_hours.bits = bits; \
+ } \
+ u.info21.fields_present = fpval; \
+ } \
+ u.info ## lvl1.field1 = value; \
+ TESTCALL(SetUserInfo, s) \
+ TESTCALL(SetUserInfo2, s2) \
+ u.info ## lvl1.field1 = 0; \
+ TESTCALL(QueryUserInfo, q); \
+ u = *info; \
+ INT_EQUAL(u.info ## lvl1.field1, exp_value, field1); \
+ q.in.level = lvl2; \
+ TESTCALL(QueryUserInfo, q) \
+ u = *info; \
+ INT_EQUAL(u.info ## lvl2.field2, exp_value, field1); \
+ } while (0)
+
+#define TEST_USERINFO_INT(lvl1, field1, lvl2, field2, value, fpval) do { \
+ TEST_USERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value, fpval); \
+ } while (0)
+
+ q0.in.level = 12;
+ do { TESTCALL(QueryUserInfo, q0) } while (0);
+
+ TEST_USERINFO_STRING(2, comment, 1, comment, "xx2-1 comment", 0);
+ TEST_USERINFO_STRING(2, comment, 21, comment, "xx2-21 comment", 0);
+ TEST_USERINFO_STRING(21, comment, 21, comment, "xx21-21 comment",
+ SAMR_FIELD_COMMENT);
+
+ test_account_name = talloc_asprintf(tctx, "%sxx7-1", base_account_name);
+ TEST_USERINFO_STRING(7, account_name, 1, account_name, test_account_name, 0);
+ test_account_name = talloc_asprintf(tctx, "%sxx7-3", base_account_name);
+ TEST_USERINFO_STRING(7, account_name, 3, account_name, test_account_name, 0);
+ test_account_name = talloc_asprintf(tctx, "%sxx7-5", base_account_name);
+ TEST_USERINFO_STRING(7, account_name, 5, account_name, test_account_name, 0);
+ test_account_name = talloc_asprintf(tctx, "%sxx7-6", base_account_name);
+ TEST_USERINFO_STRING(7, account_name, 6, account_name, test_account_name, 0);
+ test_account_name = talloc_asprintf(tctx, "%sxx7-7", base_account_name);
+ TEST_USERINFO_STRING(7, account_name, 7, account_name, test_account_name, 0);
+ test_account_name = talloc_asprintf(tctx, "%sxx7-21", base_account_name);
+ TEST_USERINFO_STRING(7, account_name, 21, account_name, test_account_name, 0);
+ test_account_name = base_account_name;
+ TEST_USERINFO_STRING(21, account_name, 21, account_name, test_account_name,
+ SAMR_FIELD_ACCOUNT_NAME);
+
+ TEST_USERINFO_STRING(6, full_name, 1, full_name, "xx6-1 full_name", 0);
+ TEST_USERINFO_STRING(6, full_name, 3, full_name, "xx6-3 full_name", 0);
+ TEST_USERINFO_STRING(6, full_name, 5, full_name, "xx6-5 full_name", 0);
+ TEST_USERINFO_STRING(6, full_name, 6, full_name, "xx6-6 full_name", 0);
+ TEST_USERINFO_STRING(6, full_name, 8, full_name, "xx6-8 full_name", 0);
+ TEST_USERINFO_STRING(6, full_name, 21, full_name, "xx6-21 full_name", 0);
+ TEST_USERINFO_STRING(8, full_name, 21, full_name, "xx8-21 full_name", 0);
+ TEST_USERINFO_STRING(21, full_name, 21, full_name, "xx21-21 full_name",
+ SAMR_FIELD_FULL_NAME);
+
+ TEST_USERINFO_STRING(6, full_name, 1, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 3, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 5, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 6, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 8, full_name, "", 0);
+ TEST_USERINFO_STRING(6, full_name, 21, full_name, "", 0);
+ TEST_USERINFO_STRING(8, full_name, 21, full_name, "", 0);
+ TEST_USERINFO_STRING(21, full_name, 21, full_name, "",
+ SAMR_FIELD_FULL_NAME);
+
+ TEST_USERINFO_STRING(11, logon_script, 3, logon_script, "xx11-3 logon_script", 0);
+ TEST_USERINFO_STRING(11, logon_script, 5, logon_script, "xx11-5 logon_script", 0);
+ TEST_USERINFO_STRING(11, logon_script, 21, logon_script, "xx11-21 logon_script", 0);
+ TEST_USERINFO_STRING(21, logon_script, 21, logon_script, "xx21-21 logon_script",
+ SAMR_FIELD_LOGON_SCRIPT);
+
+ TEST_USERINFO_STRING(12, profile_path, 3, profile_path, "xx12-3 profile_path", 0);
+ TEST_USERINFO_STRING(12, profile_path, 5, profile_path, "xx12-5 profile_path", 0);
+ TEST_USERINFO_STRING(12, profile_path, 21, profile_path, "xx12-21 profile_path", 0);
+ TEST_USERINFO_STRING(21, profile_path, 21, profile_path, "xx21-21 profile_path",
+ SAMR_FIELD_PROFILE_PATH);
+
+ TEST_USERINFO_STRING(10, home_directory, 3, home_directory, "xx10-3 home_directory", 0);
+ TEST_USERINFO_STRING(10, home_directory, 5, home_directory, "xx10-5 home_directory", 0);
+ TEST_USERINFO_STRING(10, home_directory, 21, home_directory, "xx10-21 home_directory", 0);
+ TEST_USERINFO_STRING(21, home_directory, 21, home_directory, "xx21-21 home_directory",
+ SAMR_FIELD_HOME_DIRECTORY);
+ TEST_USERINFO_STRING(21, home_directory, 10, home_directory, "xx21-10 home_directory",
+ SAMR_FIELD_HOME_DIRECTORY);
+
+ TEST_USERINFO_STRING(10, home_drive, 3, home_drive, "xx10-3 home_drive", 0);
+ TEST_USERINFO_STRING(10, home_drive, 5, home_drive, "xx10-5 home_drive", 0);
+ TEST_USERINFO_STRING(10, home_drive, 21, home_drive, "xx10-21 home_drive", 0);
+ TEST_USERINFO_STRING(21, home_drive, 21, home_drive, "xx21-21 home_drive",
+ SAMR_FIELD_HOME_DRIVE);
+ TEST_USERINFO_STRING(21, home_drive, 10, home_drive, "xx21-10 home_drive",
+ SAMR_FIELD_HOME_DRIVE);
+
+ TEST_USERINFO_STRING(13, description, 1, description, "xx13-1 description", 0);
+ TEST_USERINFO_STRING(13, description, 5, description, "xx13-5 description", 0);
+ TEST_USERINFO_STRING(13, description, 21, description, "xx13-21 description", 0);
+ TEST_USERINFO_STRING(21, description, 21, description, "xx21-21 description",
+ SAMR_FIELD_DESCRIPTION);
+
+ TEST_USERINFO_STRING(14, workstations, 3, workstations, "14workstation3", 0);
+ TEST_USERINFO_STRING(14, workstations, 5, workstations, "14workstation4", 0);
+ TEST_USERINFO_STRING(14, workstations, 21, workstations, "14workstation21", 0);
+ TEST_USERINFO_STRING(21, workstations, 21, workstations, "21workstation21",
+ SAMR_FIELD_WORKSTATIONS);
+ TEST_USERINFO_STRING(21, workstations, 3, workstations, "21workstation3",
+ SAMR_FIELD_WORKSTATIONS);
+ TEST_USERINFO_STRING(21, workstations, 5, workstations, "21workstation5",
+ SAMR_FIELD_WORKSTATIONS);
+ TEST_USERINFO_STRING(21, workstations, 14, workstations, "21workstation14",
+ SAMR_FIELD_WORKSTATIONS);
+
+ TEST_USERINFO_BINARYSTRING(20, parameters, 21, parameters, "xx20-21 parameters", 0);
+ TEST_USERINFO_BINARYSTRING(21, parameters, 21, parameters, "xx21-21 parameters",
+ SAMR_FIELD_PARAMETERS);
+ TEST_USERINFO_BINARYSTRING(21, parameters, 20, parameters, "xx21-20 parameters",
+ SAMR_FIELD_PARAMETERS);
+ /* also empty user parameters are allowed */
+ TEST_USERINFO_BINARYSTRING(20, parameters, 21, parameters, "", 0);
+ TEST_USERINFO_BINARYSTRING(21, parameters, 21, parameters, "",
+ SAMR_FIELD_PARAMETERS);
+ TEST_USERINFO_BINARYSTRING(21, parameters, 20, parameters, "",
+ SAMR_FIELD_PARAMETERS);
+
+ /* Samba 3 cannot store country_code and code_page atm. - gd */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ TEST_USERINFO_INT(2, country_code, 2, country_code, __LINE__, 0);
+ TEST_USERINFO_INT(2, country_code, 21, country_code, __LINE__, 0);
+ TEST_USERINFO_INT(21, country_code, 21, country_code, __LINE__,
+ SAMR_FIELD_COUNTRY_CODE);
+ TEST_USERINFO_INT(21, country_code, 2, country_code, __LINE__,
+ SAMR_FIELD_COUNTRY_CODE);
+
+ TEST_USERINFO_INT(2, code_page, 21, code_page, __LINE__, 0);
+ TEST_USERINFO_INT(21, code_page, 21, code_page, __LINE__,
+ SAMR_FIELD_CODE_PAGE);
+ TEST_USERINFO_INT(21, code_page, 2, code_page, __LINE__,
+ SAMR_FIELD_CODE_PAGE);
+ }
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ TEST_USERINFO_INT(17, acct_expiry, 21, acct_expiry, __LINE__, 0);
+ TEST_USERINFO_INT(17, acct_expiry, 5, acct_expiry, __LINE__, 0);
+ TEST_USERINFO_INT(21, acct_expiry, 21, acct_expiry, __LINE__,
+ SAMR_FIELD_ACCT_EXPIRY);
+ TEST_USERINFO_INT(21, acct_expiry, 5, acct_expiry, __LINE__,
+ SAMR_FIELD_ACCT_EXPIRY);
+ TEST_USERINFO_INT(21, acct_expiry, 17, acct_expiry, __LINE__,
+ SAMR_FIELD_ACCT_EXPIRY);
+ } else {
+ /* Samba 3 can only store seconds / time_t in passdb - gd */
+ NTTIME nt;
+ unix_to_nt_time(&nt, time(NULL) + __LINE__);
+ TEST_USERINFO_INT(17, acct_expiry, 21, acct_expiry, nt, 0);
+ unix_to_nt_time(&nt, time(NULL) + __LINE__);
+ TEST_USERINFO_INT(17, acct_expiry, 5, acct_expiry, nt, 0);
+ unix_to_nt_time(&nt, time(NULL) + __LINE__);
+ TEST_USERINFO_INT(21, acct_expiry, 21, acct_expiry, nt, SAMR_FIELD_ACCT_EXPIRY);
+ unix_to_nt_time(&nt, time(NULL) + __LINE__);
+ TEST_USERINFO_INT(21, acct_expiry, 5, acct_expiry, nt, SAMR_FIELD_ACCT_EXPIRY);
+ unix_to_nt_time(&nt, time(NULL) + __LINE__);
+ TEST_USERINFO_INT(21, acct_expiry, 17, acct_expiry, nt, SAMR_FIELD_ACCT_EXPIRY);
+ }
+
+ TEST_USERINFO_INT(4, logon_hours.bits[3], 3, logon_hours.bits[3], 1, 0);
+ TEST_USERINFO_INT(4, logon_hours.bits[3], 5, logon_hours.bits[3], 2, 0);
+ TEST_USERINFO_INT(4, logon_hours.bits[3], 21, logon_hours.bits[3], 3, 0);
+ TEST_USERINFO_INT(21, logon_hours.bits[3], 21, logon_hours.bits[3], 4,
+ SAMR_FIELD_LOGON_HOURS);
+
+ TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ),
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags),
+ 0);
+ TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags,
+ (base_acct_flags | ACB_DISABLED),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ 0);
+
+ /* Setting PWNOEXP clears the magic ACB_PW_EXPIRED flag */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP),
+ (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP),
+ 0);
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ),
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags),
+ 0);
+
+
+ /* The 'autolock' flag doesn't stick - check this */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_AUTOLOCK),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ 0);
+#if 0
+ /* Removing the 'disabled' flag doesn't stick - check this */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ 0);
+#endif
+
+ /* Samba3 cannot store these atm */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ /* The 'store plaintext' flag does stick */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_ENC_TXT_PWD_ALLOWED),
+ (base_acct_flags | ACB_DISABLED | ACB_ENC_TXT_PWD_ALLOWED | user_extra_flags),
+ 0);
+ /* The 'use DES' flag does stick */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_USE_DES_KEY_ONLY),
+ (base_acct_flags | ACB_DISABLED | ACB_USE_DES_KEY_ONLY | user_extra_flags),
+ 0);
+ /* The 'don't require kerberos pre-authentication flag does stick */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_DONT_REQUIRE_PREAUTH),
+ (base_acct_flags | ACB_DISABLED | ACB_DONT_REQUIRE_PREAUTH | user_extra_flags),
+ 0);
+ /* The 'no kerberos PAC required' flag sticks */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_NO_AUTH_DATA_REQD),
+ (base_acct_flags | ACB_DISABLED | ACB_NO_AUTH_DATA_REQD | user_extra_flags),
+ 0);
+ }
+ TEST_USERINFO_INT_EXP(21, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ SAMR_FIELD_ACCT_FLAGS);
+
+#if 0
+ /* these fail with win2003 - it appears you can't set the primary gid?
+ the set succeeds, but the gid isn't changed. Very weird! */
+ TEST_USERINFO_INT(9, primary_gid, 1, primary_gid, 513);
+ TEST_USERINFO_INT(9, primary_gid, 3, primary_gid, 513);
+ TEST_USERINFO_INT(9, primary_gid, 5, primary_gid, 513);
+ TEST_USERINFO_INT(9, primary_gid, 21, primary_gid, 513);
+#endif
+
+ return ret;
+}
+
+/*
+ generate a random password for password change tests
+*/
+static char *samr_rand_pass_silent(TALLOC_CTX *mem_ctx, int min_len)
+{
+ size_t len = MAX(8, min_len);
+ char *s = generate_random_password(mem_ctx, len, len+6);
+ return s;
+}
+
+static char *samr_rand_pass(TALLOC_CTX *mem_ctx, int min_len)
+{
+ char *s = samr_rand_pass_silent(mem_ctx, min_len);
+ printf("Generated password '%s'\n", s);
+ return s;
+
+}
+
+/*
+ generate a random password for password change tests
+*/
+static DATA_BLOB samr_very_rand_pass(TALLOC_CTX *mem_ctx, int len)
+{
+ int i;
+ DATA_BLOB password = data_blob_talloc(mem_ctx, NULL, len * 2 /* number of unicode chars */);
+ generate_random_buffer(password.data, password.length);
+
+ for (i=0; i < len; i++) {
+ if (((uint16_t *)password.data)[i] == 0) {
+ ((uint16_t *)password.data)[i] = 1;
+ }
+ }
+
+ return password;
+}
+
+/*
+ generate a random password for password change tests (fixed length)
+*/
+static char *samr_rand_pass_fixed_len(TALLOC_CTX *mem_ctx, int len)
+{
+ char *s = generate_random_password(mem_ctx, len, len);
+ printf("Generated password '%s'\n", s);
+ return s;
+}
+
+static bool test_SetUserPass(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 24;
+
+ u.info24.password_expired = 0;
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ status = init_samr_CryptPassword(newpass,
+ &session_key,
+ &u.info24.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+
+ torture_comment(tctx, "Testing SetUserInfo level 24 (set password)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+
+static bool test_SetUserPass_23(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t fields_present,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ char *newpass;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 23;
+
+ ZERO_STRUCT(u);
+
+ u.info23.info.fields_present = fields_present;
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ status = init_samr_CryptPassword(newpass,
+ &session_key,
+ &u.info23.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+
+ torture_comment(tctx, "Testing SetUserInfo level 23 (set password)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ /* This should break the key nicely */
+ session_key.data[0]++;
+
+ status = init_samr_CryptPassword(newpass,
+ &session_key,
+ &u.info23.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+
+ /* Reset the session key */
+ session_key.data[0]--;
+
+ torture_comment(tctx, "Testing SetUserInfo level 23 (set password) with wrong password\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_SetUserPass_32(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t fields_present,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ DATA_BLOB session_key;
+ uint8_t salt_data[16];
+ DATA_BLOB salt = {
+ .data = salt_data,
+ .length = sizeof(salt_data),
+ };
+ char *newpass = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+ bool ret = true;
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 32;
+
+ ZERO_STRUCT(u);
+
+ u.info32.info.fields_present = fields_present;
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ "SetUserInfo level %u - no session key - %s\n",
+ s.in.level,
+ nt_errstr(status));
+ return false;
+ }
+
+ generate_nonce_buffer(salt.data, salt.length);
+
+ status = init_samr_CryptPasswordAES(tctx,
+ newpass,
+ &salt,
+ &session_key,
+ &u.info32.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordAES failed");
+
+ torture_comment(tctx,
+ "Testing SetUserInfo level 32 (set password aes)\n");
+
+ status = dcerpc_samr_SetUserInfo_r(b, tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__,
+ __FUNCTION__,
+ newpass,
+ nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ "SetUserInfo level %u failed - %s\n",
+ s.in.level,
+ nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ /* This should break the key nicely */
+ session_key.data[0]++;
+
+ status = init_samr_CryptPasswordAES(tctx,
+ newpass,
+ &salt,
+ &session_key,
+ &u.info32.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ /* Reset the key */
+ session_key.data[0]--;
+
+ torture_comment(tctx,
+ "Testing SetUserInfo level 32 (set password aes) with "
+ "wrong session key\n");
+
+ status = dcerpc_samr_SetUserInfo_r(b, tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "SetUserInfo failed");
+ torture_comment(tctx,
+ "(%s:%s) new_password[%s] status[%s]\n",
+ __location__,
+ __FUNCTION__,
+ newpass,
+ nt_errstr(s.out.result));
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ "SetUserInfo level %u should have failed with "
+ "WRONG_PASSWORD- %s\n",
+ s.in.level,
+ nt_errstr(s.out.result));
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static bool test_SetUserPass_31(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, bool makeshort,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ uint8_t salt_data[16];
+ DATA_BLOB salt = {
+ .data = salt_data,
+ .length = sizeof(salt_data),
+ };
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ if (makeshort && policy_min_pw_len) {
+ newpass = samr_rand_pass_fixed_len(tctx, policy_min_pw_len - 1);
+ } else {
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+ }
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 31;
+
+ ZERO_STRUCT(u);
+
+ u.info31.password_expired = 0;
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ generate_nonce_buffer(salt.data, salt.length);
+
+ status = init_samr_CryptPasswordAES(tctx,
+ newpass,
+ &salt,
+ &session_key,
+ &u.info31.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ torture_comment(tctx, "Testing SetUserInfo level 31 (set password aes)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ /* This should break the key nicely */
+ session_key.data[0]++;
+
+ status = init_samr_CryptPasswordAES(tctx,
+ newpass,
+ &salt,
+ &session_key,
+ &u.info31.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ /* Reset the key */
+ session_key.data[0]--;
+
+ torture_comment(tctx, "Testing SetUserInfo level 31 (set password aes) with wrong session key\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u should have failed with WRONG_PASSWORD: %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+
+static bool test_SetUserPassEx(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, bool makeshort,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ if (makeshort && policy_min_pw_len) {
+ newpass = samr_rand_pass_fixed_len(tctx, policy_min_pw_len - 1);
+ } else {
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+ }
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 26;
+
+ u.info26.password_expired = 0;
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ status = init_samr_CryptPasswordEx(newpass,
+ &session_key,
+ &u.info26.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ torture_comment(tctx, "Testing SetUserInfo level 26 (set password ex)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ /* This should break the key nicely */
+ session_key.data[0]++;
+
+ status = init_samr_CryptPasswordEx(newpass,
+ &session_key,
+ &u.info26.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ /* Reset the key */
+ session_key.data[0]--;
+
+ torture_comment(tctx, "Testing SetUserInfo level 26 (set password ex) with wrong session key\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u should have failed with WRONG_PASSWORD: %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+static bool test_SetUserPass_25(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t fields_present,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 25;
+
+ ZERO_STRUCT(u);
+
+ u.info25.info.fields_present = fields_present;
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ status = init_samr_CryptPasswordEx(newpass,
+ &session_key,
+ &u.info25.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ torture_comment(tctx, "Testing SetUserInfo level 25 (set password ex)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ /* This should break the key nicely */
+ session_key.data[0]++;
+
+ status = init_samr_CryptPasswordEx(newpass,
+ &session_key,
+ &u.info25.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+
+ /* Reset the key */
+ session_key.data[0]--;
+
+ torture_comment(tctx, "Testing SetUserInfo level 25 (set password ex) with wrong session key\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_SetUserPass_18(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+ uint8_t lm_hash[16], nt_hash[16];
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 18;
+
+ ZERO_STRUCT(u);
+
+ u.info18.nt_pwd_active = true;
+ u.info18.lm_pwd_active = true;
+
+ E_md4hash(newpass, nt_hash);
+ E_deshash(newpass, lm_hash);
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ {
+ DATA_BLOB in,out;
+ in = data_blob_const(nt_hash, 16);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ memcpy(u.info18.nt_pwd.hash, out.data, out.length);
+ }
+ {
+ DATA_BLOB in,out;
+ in = data_blob_const(lm_hash, 16);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ memcpy(u.info18.lm_pwd.hash, out.data, out.length);
+ }
+
+ torture_comment(tctx, "Testing SetUserInfo level 18 (set password hash)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+static bool test_SetUserPass_21(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t fields_present,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+ uint8_t lm_hash[16], nt_hash[16];
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 21;
+
+ E_md4hash(newpass, nt_hash);
+ E_deshash(newpass, lm_hash);
+
+ ZERO_STRUCT(u);
+
+ u.info21.fields_present = fields_present;
+
+ if (fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) {
+ u.info21.lm_owf_password.length = 16;
+ u.info21.lm_owf_password.size = 16;
+ u.info21.lm_owf_password.array = (uint16_t *)lm_hash;
+ u.info21.lm_password_set = true;
+ }
+
+ if (fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) {
+ u.info21.nt_owf_password.length = 16;
+ u.info21.nt_owf_password.size = 16;
+ u.info21.nt_owf_password.array = (uint16_t *)nt_hash;
+ u.info21.nt_password_set = true;
+ }
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ if (fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) {
+ DATA_BLOB in,out;
+ in = data_blob_const(u.info21.lm_owf_password.array,
+ u.info21.lm_owf_password.length);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ u.info21.lm_owf_password.array = (uint16_t *)out.data;
+ }
+
+ if (fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) {
+ DATA_BLOB in,out;
+ in = data_blob_const(u.info21.nt_owf_password.array,
+ u.info21.nt_owf_password.length);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ u.info21.nt_owf_password.array = (uint16_t *)out.data;
+ }
+
+ torture_comment(tctx, "Testing SetUserInfo level 21 (set password hash)\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ /* try invalid length */
+ if (fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) {
+
+ u.info21.nt_owf_password.length++;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u should have failed with NT_STATUS_INVALID_PARAMETER - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ }
+ }
+
+ if (fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) {
+
+ u.info21.lm_owf_password.length++;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ if (!NT_STATUS_EQUAL(s.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u should have failed with NT_STATUS_INVALID_PARAMETER - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_SetUserPass_level_ex(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint16_t level,
+ uint32_t fields_present,
+ char **password, uint8_t password_expired,
+ bool use_setinfo2,
+ bool *matched_expected_error)
+{
+ NTSTATUS status;
+ NTSTATUS expected_error = NT_STATUS_OK;
+ struct samr_SetUserInfo s;
+ struct samr_SetUserInfo2 s2;
+ union samr_UserInfo u;
+ bool ret = true;
+ DATA_BLOB session_key;
+ uint8_t salt_data[16];
+ DATA_BLOB salt = {
+ .data = salt_data,
+ .length = sizeof(salt_data),
+ };
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+ const char *comment = NULL;
+ uint8_t lm_hash[16], nt_hash[16];
+
+ pwp.in.user_handle = handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass_silent(tctx, policy_min_pw_len);
+
+ if (use_setinfo2) {
+ s2.in.user_handle = handle;
+ s2.in.info = &u;
+ s2.in.level = level;
+ } else {
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = level;
+ }
+
+ if (fields_present & SAMR_FIELD_COMMENT) {
+ comment = talloc_asprintf(tctx, "comment: %ld\n", (long int) time(NULL));
+ }
+
+ ZERO_STRUCT(u);
+
+ switch (level) {
+ case 18:
+ E_md4hash(newpass, nt_hash);
+ E_deshash(newpass, lm_hash);
+
+ u.info18.nt_pwd_active = true;
+ u.info18.lm_pwd_active = true;
+ u.info18.password_expired = password_expired;
+
+ memcpy(u.info18.lm_pwd.hash, lm_hash, 16);
+ memcpy(u.info18.nt_pwd.hash, nt_hash, 16);
+
+ break;
+ case 21:
+ E_md4hash(newpass, nt_hash);
+ E_deshash(newpass, lm_hash);
+
+ u.info21.fields_present = fields_present;
+ u.info21.password_expired = password_expired;
+ u.info21.comment.string = comment;
+
+ if (fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) {
+ u.info21.lm_owf_password.length = 16;
+ u.info21.lm_owf_password.size = 16;
+ u.info21.lm_owf_password.array = (uint16_t *)lm_hash;
+ u.info21.lm_password_set = true;
+ }
+
+ if (fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) {
+ u.info21.nt_owf_password.length = 16;
+ u.info21.nt_owf_password.size = 16;
+ u.info21.nt_owf_password.array = (uint16_t *)nt_hash;
+ u.info21.nt_password_set = true;
+ }
+
+ break;
+ case 23:
+ u.info23.info.fields_present = fields_present;
+ u.info23.info.password_expired = password_expired;
+ u.info23.info.comment.string = comment;
+
+ break;
+ case 24:
+ u.info24.password_expired = password_expired;
+
+ break;
+ case 25:
+ u.info25.info.fields_present = fields_present;
+ u.info25.info.password_expired = password_expired;
+ u.info25.info.comment.string = comment;
+
+ break;
+ case 26:
+ u.info26.password_expired = password_expired;
+
+ break;
+ case 31:
+ u.info31.password_expired = password_expired;
+
+ break;
+ case 28:
+ u.info25.info.fields_present = fields_present;
+ u.info25.info.password_expired = password_expired;
+ u.info25.info.comment.string = comment;
+
+ break;
+ }
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ generate_nonce_buffer(salt.data, salt.length);
+
+ switch (level) {
+ case 18:
+ {
+ DATA_BLOB in,out;
+ in = data_blob_const(u.info18.nt_pwd.hash, 16);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ memcpy(u.info18.nt_pwd.hash, out.data, out.length);
+ }
+ {
+ DATA_BLOB in,out;
+ in = data_blob_const(u.info18.lm_pwd.hash, 16);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ memcpy(u.info18.lm_pwd.hash, out.data, out.length);
+ }
+
+ break;
+ case 21:
+ if (fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) {
+ DATA_BLOB in,out;
+ in = data_blob_const(u.info21.lm_owf_password.array,
+ u.info21.lm_owf_password.length);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ u.info21.lm_owf_password.array = (uint16_t *)out.data;
+ }
+ if (fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) {
+ DATA_BLOB in,out;
+ in = data_blob_const(u.info21.nt_owf_password.array,
+ u.info21.nt_owf_password.length);
+ out = data_blob_talloc_zero(tctx, 16);
+ sess_crypt_blob(&out, &in, &session_key, SAMBA_GNUTLS_ENCRYPT);
+ u.info21.nt_owf_password.array = (uint16_t *)out.data;
+ }
+ break;
+ case 23:
+ status = init_samr_CryptPassword(newpass,
+ &session_key,
+ &u.info23.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+ break;
+ case 24:
+ status = init_samr_CryptPassword(newpass,
+ &session_key,
+ &u.info24.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+ break;
+ case 25:
+ status = init_samr_CryptPasswordEx(newpass,
+ &session_key,
+ &u.info25.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+ break;
+ case 26:
+ status = init_samr_CryptPasswordEx(newpass,
+ &session_key,
+ &u.info26.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPasswordEx failed");
+ break;
+ case 31:
+ status = init_samr_CryptPasswordAES(tctx,
+ newpass,
+ &salt,
+ &session_key,
+ &u.info31.password);
+
+ break;
+ case 32:
+ status = init_samr_CryptPasswordAES(tctx,
+ newpass,
+ &salt,
+ &session_key,
+ &u.info32.password);
+
+ break;
+ }
+
+ if (use_setinfo2) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo2_r(b, tctx, &s2),
+ "SetUserInfo2 failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s2.out.result));
+ status = s2.out.result;
+ } else {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ newpass, nt_errstr(s.out.result));
+ status = s.out.result;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ if (fields_present == 0) {
+ expected_error = NT_STATUS_INVALID_PARAMETER;
+ }
+ if (fields_present & SAMR_FIELD_LAST_PWD_CHANGE) {
+ expected_error = NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(expected_error)) {
+ if (use_setinfo2) {
+ torture_assert_ntstatus_equal(tctx,
+ s2.out.result,
+ expected_error, "SetUserInfo2 failed");
+ } else {
+ torture_assert_ntstatus_equal(tctx,
+ s.out.result,
+ expected_error, "SetUserInfo failed");
+ }
+ *matched_expected_error = true;
+ return true;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo%s level %u failed - %s\n",
+ use_setinfo2 ? "2":"", level, nt_errstr(status));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+static bool test_SetAliasInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_SetAliasInfo r;
+ struct samr_QueryAliasInfo q;
+ union samr_AliasInfo *info;
+ uint16_t levels[] = {2, 3};
+ int i;
+ bool ret = true;
+
+ /* Ignoring switch level 1, as that includes the number of members for the alias
+ * and setting this to a wrong value might have negative consequences
+ */
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing SetAliasInfo level %u\n", levels[i]);
+
+ r.in.alias_handle = handle;
+ r.in.level = levels[i];
+ r.in.info = talloc(tctx, union samr_AliasInfo);
+ switch (r.in.level) {
+ case ALIASINFONAME: init_lsa_String(&r.in.info->name,TEST_ALIASNAME); break;
+ case ALIASINFODESCRIPTION: init_lsa_String(&r.in.info->description,
+ "Test Description, should test I18N as well"); break;
+ case ALIASINFOALL: torture_comment(tctx, "ALIASINFOALL ignored\n"); break;
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetAliasInfo_r(b, tctx, &r),
+ "SetAliasInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetAliasInfo level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ q.in.alias_handle = handle;
+ q.in.level = levels[i];
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryAliasInfo_r(b, tctx, &q),
+ "QueryAliasInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryAliasInfo level %u failed - %s\n",
+ levels[i], nt_errstr(q.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_GetGroupsForUser(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle)
+{
+ struct samr_GetGroupsForUser r;
+ struct samr_RidWithAttributeArray *rids = NULL;
+
+ torture_comment(tctx, "Testing GetGroupsForUser\n");
+
+ r.in.user_handle = user_handle;
+ r.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetGroupsForUser_r(b, tctx, &r),
+ "GetGroupsForUser failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetGroupsForUser failed");
+
+ return true;
+
+}
+
+static bool test_GetDomPwInfo(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct lsa_String *domain_name)
+{
+ struct samr_GetDomPwInfo r;
+ struct samr_PwInfo info;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.domain_name = domain_name;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r),
+ "GetDomPwInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed");
+
+ r.in.domain_name->string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r),
+ "GetDomPwInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed");
+
+ r.in.domain_name->string = "\\\\__NONAME__";
+ torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r),
+ "GetDomPwInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed");
+
+ r.in.domain_name->string = "\\\\Builtin";
+ torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r),
+ "GetDomPwInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetDomPwInfo failed");
+
+ return true;
+}
+
+static bool test_GetUserPwInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_GetUserPwInfo r;
+ struct samr_PwInfo info;
+
+ torture_comment(tctx, "Testing GetUserPwInfo\n");
+
+ r.in.user_handle = handle;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &r),
+ "GetUserPwInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetUserPwInfo");
+
+ return true;
+}
+
+static NTSTATUS test_LookupName(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle, const char *name,
+ uint32_t *rid)
+{
+ NTSTATUS status;
+ struct samr_LookupNames n;
+ struct lsa_String sname[2];
+ struct samr_Ids rids, types;
+
+ init_lsa_String(&sname[0], name);
+
+ n.in.domain_handle = domain_handle;
+ n.in.num_names = 1;
+ n.in.names = sname;
+ n.out.rids = &rids;
+ n.out.types = &types;
+ status = dcerpc_samr_LookupNames_r(b, tctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (NT_STATUS_IS_OK(n.out.result)) {
+ *rid = n.out.rids->ids[0];
+ } else {
+ return n.out.result;
+ }
+
+ init_lsa_String(&sname[1], "xxNONAMExx");
+ n.in.num_names = 2;
+ status = dcerpc_samr_LookupNames_r(b, tctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_EQUAL(n.out.result, STATUS_SOME_UNMAPPED)) {
+ torture_result(tctx, TORTURE_FAIL, "LookupNames[2] failed - %s\n", nt_errstr(n.out.result));
+ if (NT_STATUS_IS_OK(n.out.result)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return n.out.result;
+ }
+
+ n.in.num_names = 0;
+ status = dcerpc_samr_LookupNames_r(b, tctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(n.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "LookupNames[0] failed - %s\n", nt_errstr(status));
+ return n.out.result;
+ }
+
+ init_lsa_String(&sname[0], "xxNONAMExx");
+ n.in.num_names = 1;
+ status = dcerpc_samr_LookupNames_r(b, tctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_EQUAL(n.out.result, NT_STATUS_NONE_MAPPED)) {
+ torture_result(tctx, TORTURE_FAIL, "LookupNames[1 bad name] failed - %s\n", nt_errstr(n.out.result));
+ if (NT_STATUS_IS_OK(n.out.result)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return n.out.result;
+ }
+
+ init_lsa_String(&sname[0], "xxNONAMExx");
+ init_lsa_String(&sname[1], "xxNONAME2xx");
+ n.in.num_names = 2;
+ status = dcerpc_samr_LookupNames_r(b, tctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_EQUAL(n.out.result, NT_STATUS_NONE_MAPPED)) {
+ torture_result(tctx, TORTURE_FAIL, "LookupNames[2 bad names] failed - %s\n", nt_errstr(n.out.result));
+ if (NT_STATUS_IS_OK(n.out.result)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return n.out.result;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_OpenUser_byname(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *name, struct policy_handle *user_handle)
+{
+ NTSTATUS status;
+ struct samr_OpenUser r;
+ uint32_t rid;
+
+ status = test_LookupName(b, tctx, domain_handle, name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.user_handle = user_handle;
+ status = dcerpc_samr_OpenUser_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenUser_byname(%s -> %d) failed - %s\n", name, rid, nt_errstr(r.out.result));
+ }
+
+ return r.out.result;
+}
+
+#if 0
+static bool test_ChangePasswordNT3(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct samr_ChangePasswordUser r;
+ bool ret = true;
+ struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
+ struct policy_handle user_handle;
+ char *oldpass = "test";
+ char *newpass = "test2";
+ uint8_t old_nt_hash[16], new_nt_hash[16];
+ uint8_t old_lm_hash[16], new_lm_hash[16];
+
+ status = test_OpenUser_byname(p, tctx, handle, "testuser", &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ torture_comment(tctx, "Testing ChangePasswordUser for user 'testuser'\n");
+
+ torture_comment(tctx, "old password: %s\n", oldpass);
+ torture_comment(tctx, "new password: %s\n", newpass);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ if (!test_samr_handle_Close(p, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+#endif
+
+static bool test_ChangePasswordUser(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ const char *acct_name,
+ struct policy_handle *handle, char **password)
+{
+ NTSTATUS status;
+ struct samr_ChangePasswordUser r;
+ bool ret = true;
+ struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
+ struct policy_handle user_handle;
+ char *oldpass;
+ uint8_t old_nt_hash[16], new_nt_hash[16];
+ uint8_t old_lm_hash[16], new_lm_hash[16];
+ bool changed = true;
+
+ char *newpass;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+
+ status = test_OpenUser_byname(b, tctx, handle, acct_name, &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ pwp.in.user_handle = &user_handle;
+ pwp.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetUserPwInfo_r(b, tctx, &pwp),
+ "GetUserPwInfo failed");
+ if (NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ torture_comment(tctx, "Testing ChangePasswordUser\n");
+
+ torture_assert(tctx, *password != NULL,
+ "Failing ChangePasswordUser as old password was NULL. Previous test failed?");
+
+ oldpass = *password;
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ /* Break the NT hash */
+ hash3.hash[0]++;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ /* Do not proceed if this call has been removed */
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
+ torture_skip(tctx, "ValidatePassword not supported by server\n");
+ }
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_WRONG_PASSWORD,
+ "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM hash");
+ }
+
+ /* Unbreak the NT hash */
+ hash3.hash[0]--;
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ /* Break the LM hash */
+ hash1.hash[0]--;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_WRONG_PASSWORD,
+ "expected NT_STATUS_WRONG_PASSWORD because we broke the NT hash");
+ }
+
+ /* Unbreak the NT hash */
+ hash3.hash[0]--;
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ /* Break the LM cross */
+ hash6.hash[0]++;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD) &&
+ !NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION))
+ {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD or NT_STATUS_PASSWORD_RESTRICTION because we broke the LM cross-hash, got %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ /* Unbreak the LM cross */
+ hash6.hash[0]--;
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ /* Break the NT cross */
+ hash5.hash[0]++;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD) &&
+ !NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION))
+ {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD or NT_STATUS_PASSWORD_RESTRICTION because we broke the NT cross-hash, got %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ /* Unbreak the NT cross */
+ hash5.hash[0]--;
+
+
+ /* Reset the hashes to not broken values */
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 0;
+ r.in.lm_cross = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (NT_STATUS_IS_OK(r.out.result)) {
+ changed = true;
+ *password = newpass;
+ } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed: expected NT_STATUS_OK, or at least NT_STATUS_PASSWORD_RESTRICTION, got %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ oldpass = newpass;
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+
+ /* Reset the hashes to not broken values */
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 0;
+ r.in.nt_cross = NULL;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (NT_STATUS_IS_OK(r.out.result)) {
+ changed = true;
+ *password = newpass;
+ } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed: expected NT_STATUS_OK, or at least NT_STATUS_PASSWORD_RESTRICTION, got %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ oldpass = newpass;
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+
+ /* Reset the hashes to not broken values */
+ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
+ E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
+ E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
+ E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
+ E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
+ E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_comment(tctx, "ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result));
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ } else {
+ changed = true;
+ *password = newpass;
+ }
+
+ r.in.user_handle = &user_handle;
+ r.in.lm_present = 1;
+ r.in.old_lm_crypted = &hash1;
+ r.in.new_lm_crypted = &hash2;
+ r.in.nt_present = 1;
+ r.in.old_nt_crypted = &hash3;
+ r.in.new_nt_crypted = &hash4;
+ r.in.cross1_present = 1;
+ r.in.nt_cross = &hash5;
+ r.in.cross2_present = 1;
+ r.in.lm_cross = &hash6;
+
+ if (changed) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser_r(b, tctx, &r),
+ "ChangePasswordUser failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_comment(tctx, "ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result));
+ } else if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we already changed the password, got %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+
+ if (!test_samr_handle_Close(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static bool test_OemChangePasswordUser2(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *acct_name,
+ struct policy_handle *handle, char **password)
+{
+ struct samr_OemChangePasswordUser2 r;
+ bool ret = true;
+ struct samr_Password lm_verifier;
+ struct samr_CryptPassword lm_pass;
+ struct lsa_AsciiString server, account, account_bad;
+ char *oldpass;
+ char *newpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t old_lm_hash[16], new_lm_hash[16];
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t session_key = {
+ .data = old_lm_hash,
+ .size = 16
+ };
+
+ struct samr_GetDomPwInfo dom_pw_info;
+ struct samr_PwInfo info;
+ int policy_min_pw_len = 0;
+
+ struct lsa_String domain_name;
+
+ domain_name.string = "";
+ dom_pw_info.in.domain_name = &domain_name;
+ dom_pw_info.out.info = &info;
+
+ torture_comment(tctx, "Testing OemChangePasswordUser2\n");
+
+ torture_assert(tctx, *password != NULL,
+ "Failing OemChangePasswordUser2 as old password was NULL. Previous test failed?");
+
+ oldpass = *password;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &dom_pw_info),
+ "GetDomPwInfo failed");
+ if (NT_STATUS_IS_OK(dom_pw_info.out.result)) {
+ policy_min_pw_len = dom_pw_info.out.info->min_password_length;
+ }
+
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ server.string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ account.string = acct_name;
+
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII);
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &session_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd, lm_pass.data, 516);
+ gnutls_cipher_deinit(cipher_hnd);
+ E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &lm_pass;
+ r.in.hash = &lm_verifier;
+
+ /* Break the verification */
+ lm_verifier.hash[0]++;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_assert_ntstatus_equal(tctx,
+ r.out.result,
+ NT_STATUS_NOT_IMPLEMENTED,
+ "Samba4 should refuse LM password change");
+ /*
+ * No point continuing, once we have checked this is not
+ * implemented
+ */
+ return true;
+ }
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)
+ && !NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalid password verifier - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII);
+ /* Break the old password */
+ old_lm_hash[0]++;
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &session_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd, lm_pass.data, 516);
+ gnutls_cipher_deinit(cipher_hnd);
+ /* unbreak it for the next operation */
+ old_lm_hash[0]--;
+ E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &lm_pass;
+ r.in.hash = &lm_verifier;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)
+ && !NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrypted password - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII);
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &session_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd, lm_pass.data, 516);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &lm_pass;
+ r.in.hash = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)
+ && !NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER (or at least 'PASSWORD_RESTRICTON') for no supplied validation hash - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ /* This shouldn't be a valid name */
+ account_bad.string = TEST_ACCOUNT_NAME "XX";
+ r.in.account = &account_bad;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER for no supplied validation hash and invalid user - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ /* This shouldn't be a valid name */
+ account_bad.string = TEST_ACCOUNT_NAME "XX";
+ r.in.account = &account_bad;
+ r.in.password = &lm_pass;
+ r.in.hash = &lm_verifier;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed, should have returned WRONG_PASSWORD for invalid user - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ /* This shouldn't be a valid name */
+ account_bad.string = TEST_ACCOUNT_NAME "XX";
+ r.in.account = &account_bad;
+ r.in.password = NULL;
+ r.in.hash = &lm_verifier;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed, should have returned INVALID_PARAMETER for no supplied password and invalid user - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII);
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &session_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd, lm_pass.data, 516);
+ gnutls_cipher_deinit(cipher_hnd);
+ E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &lm_pass;
+ r.in.hash = &lm_verifier;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OemChangePasswordUser2_r(b, tctx, &r),
+ "OemChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_comment(tctx, "OemChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result));
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OemChangePasswordUser2 failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+
+static bool test_ChangePasswordUser2(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *acct_name,
+ char **password,
+ char *newpass, bool allow_password_restriction)
+{
+ struct samr_ChangePasswordUser2 r;
+ bool ret = true;
+ struct lsa_String server, account;
+ struct samr_CryptPassword nt_pass, lm_pass;
+ struct samr_Password nt_verifier, lm_verifier;
+ char *oldpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t old_nt_hash[16] = { 0 }, new_nt_hash[16];
+ uint8_t old_lm_hash[16], new_lm_hash[16];
+ DATA_BLOB old_nt_hash_blob
+ = data_blob_const(old_nt_hash, sizeof(old_nt_hash));
+ struct samr_GetDomPwInfo dom_pw_info;
+ struct samr_PwInfo info;
+
+ struct lsa_String domain_name;
+ NTSTATUS status;
+
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t old_lm_key = {
+ .data = old_lm_hash,
+ .size = sizeof(old_lm_hash),
+ };
+
+ domain_name.string = "";
+ dom_pw_info.in.domain_name = &domain_name;
+ dom_pw_info.out.info = &info;
+
+ torture_comment(tctx, "Testing ChangePasswordUser2 on %s\n", acct_name);
+
+ torture_assert(tctx, *password != NULL,
+ "Failing ChangePasswordUser2 as old password was NULL. Previous test failed?");
+ oldpass = *password;
+
+ if (!newpass) {
+ int policy_min_pw_len = 0;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &dom_pw_info),
+ "GetDomPwInfo failed");
+ if (NT_STATUS_IS_OK(dom_pw_info.out.result)) {
+ policy_min_pw_len = dom_pw_info.out.info->min_password_length;
+ }
+
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+ }
+
+ server.string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ init_lsa_String(&account, acct_name);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII|STR_TERMINATE);
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &old_lm_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd,
+ lm_pass.data,
+ 516);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash);
+
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &nt_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 1;
+ r.in.lm_password = &lm_pass;
+ r.in.lm_verifier = &lm_verifier;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser2_r(b, tctx, &r),
+ "ChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (allow_password_restriction && NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_comment(tctx, "ChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result));
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser2 failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ } else {
+ *password = newpass;
+ }
+
+ return ret;
+}
+
+
+static bool test_ChangePasswordUser2_ntstatus(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *acct_name,
+ const char *password, NTSTATUS status)
+{
+ struct samr_ChangePasswordUser2 r;
+ struct lsa_String server, account;
+ struct samr_CryptPassword nt_pass, lm_pass;
+ struct samr_Password nt_verifier, lm_verifier;
+ const char *oldpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t old_nt_hash[16] = { 0 }, new_nt_hash[16];
+ uint8_t old_lm_hash[16], new_lm_hash[16];
+ DATA_BLOB old_nt_hash_blob
+ = data_blob_const(old_nt_hash, sizeof(old_nt_hash));
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t old_lm_key = {
+ .data = old_lm_hash,
+ .size = sizeof(old_lm_hash),
+ };
+
+ struct samr_GetDomPwInfo dom_pw_info;
+ struct samr_PwInfo info;
+
+ struct lsa_String domain_name;
+ NTSTATUS crypt_status;
+
+ char *newpass;
+ int policy_min_pw_len = 0;
+
+ domain_name.string = "";
+ dom_pw_info.in.domain_name = &domain_name;
+ dom_pw_info.out.info = &info;
+
+ torture_comment(tctx, "Testing ChangePasswordUser2 on %s\n", acct_name);
+
+ oldpass = password;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &dom_pw_info),
+ "GetDomPwInfo failed");
+ if (NT_STATUS_IS_OK(dom_pw_info.out.result)) {
+ policy_min_pw_len = dom_pw_info.out.info->min_password_length;
+ }
+
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+
+ server.string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ init_lsa_String(&account, acct_name);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ encode_pw_buffer(lm_pass.data, newpass, STR_ASCII|STR_TERMINATE);
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &old_lm_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd,
+ lm_pass.data,
+ 516);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash);
+
+ crypt_status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &nt_pass);
+ torture_assert_ntstatus_ok(tctx,
+ crypt_status,
+ "init_samr_CryptPassword failed");
+
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 1;
+ r.in.lm_password = &lm_pass;
+ r.in.lm_verifier = &lm_verifier;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser2_r(b, tctx, &r),
+ "ChangePasswordUser2 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ torture_comment(tctx, "ChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(r.out.result));
+ } else {
+ torture_assert_ntstatus_equal(tctx, r.out.result, status, "ChangePasswordUser2 returned unexpected value");
+ }
+
+ return true;
+}
+
+
+bool test_ChangePasswordUser3(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *account_string,
+ int policy_min_pw_len,
+ char **password,
+ const char *newpass,
+ NTTIME last_password_change,
+ bool handle_reject_reason)
+{
+ struct samr_ChangePasswordUser3 r;
+ bool ret = true;
+ struct lsa_String server, account, account_bad;
+ struct samr_CryptPassword nt_pass, lm_pass;
+ struct samr_Password nt_verifier, lm_verifier;
+ char *oldpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t old_nt_hash[16] = { 0 }, new_nt_hash[16];
+ uint8_t old_lm_hash[16], new_lm_hash[16];
+ NTTIME t;
+ struct samr_DomInfo1 *dominfo = NULL;
+ struct userPwdChangeFailureInformation *reject = NULL;
+ DATA_BLOB old_nt_hash_blob = data_blob_const(old_nt_hash, 16);
+ NTSTATUS status;
+
+ torture_comment(tctx, "Testing ChangePasswordUser3\n");
+
+ if (newpass == NULL) {
+ do {
+ if (policy_min_pw_len == 0) {
+ newpass = samr_rand_pass(tctx, policy_min_pw_len);
+ } else {
+ newpass = samr_rand_pass_fixed_len(tctx, policy_min_pw_len);
+ }
+ } while (check_password_quality(newpass) == false);
+ } else {
+ torture_comment(tctx, "Using password '%s'\n", newpass);
+ }
+
+ torture_assert(tctx, *password != NULL,
+ "Failing ChangePasswordUser3 as old password was NULL. Previous test failed?");
+
+ oldpass = *password;
+ server.string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ init_lsa_String(&account, account_string);
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ /*
+ * The new plaintext password is encrypted using RC4 with the
+ * old NT password hash (directly, with no confounder). The
+ * password is at the end of the random padded buffer,
+ * offering a little protection.
+ *
+ * This is almost certainly wrong, it should be the old LM
+ * hash, it was switched in an unrelated commit
+ * 579c13da43d5b40ac6d6c1436399fbc1d8dfd054 in 2004.
+ */
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &lm_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword");
+
+ /*
+ * Now we prepare a DES cross-hash of the old LM and new NT
+ * passwords to link the two buffers
+ */
+ E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash);
+
+ /*
+ * The new plaintext password is also encrypted using RC4 with
+ * the old NT password hash (directly, with no confounder).
+ * The password is at the end of the random padded buffer,
+ * offering a little protection.
+ */
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &nt_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword");
+
+ /*
+ * Another DES based cross-hash
+ */
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ /* Break the verification */
+ nt_verifier.hash[0]++;
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 1;
+ r.in.lm_password = &lm_pass;
+ r.in.lm_verifier = &lm_verifier;
+ r.in.password3 = NULL;
+ r.out.dominfo = &dominfo;
+ r.out.reject = &reject;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r),
+ "ChangePasswordUser3 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) &&
+ (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD))) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalid password verifier - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &lm_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword");
+
+ E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash);
+
+ /* Break the NT Hash */
+ old_nt_hash[0]++;
+
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &nt_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword");
+
+ /* Unbreak it again */
+ old_nt_hash[0]--;
+
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 1;
+ r.in.lm_password = &lm_pass;
+ r.in.lm_verifier = &lm_verifier;
+ r.in.password3 = NULL;
+ r.out.dominfo = &dominfo;
+ r.out.reject = &reject;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r),
+ "ChangePasswordUser3 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION) &&
+ (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD))) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrypted password - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ /* This shouldn't be a valid name */
+ init_lsa_String(&account_bad, talloc_asprintf(tctx, "%sXX", account_string));
+
+ r.in.account = &account_bad;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r),
+ "ChangePasswordUser3 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_WRONG_PASSWORD)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser3 failed, should have returned WRONG_PASSWORD for invalid username - %s\n",
+ nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ E_md4hash(oldpass, old_nt_hash);
+ E_md4hash(newpass, new_nt_hash);
+
+ E_deshash(oldpass, old_lm_hash);
+ E_deshash(newpass, new_lm_hash);
+
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &lm_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword");
+
+ E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash);
+
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &nt_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword");
+
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 1;
+ r.in.lm_password = &lm_pass;
+ r.in.lm_verifier = &lm_verifier;
+ r.in.password3 = NULL;
+ r.out.dominfo = &dominfo;
+ r.out.reject = &reject;
+
+ unix_to_nt_time(&t, time(NULL));
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r),
+ "ChangePasswordUser3 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ torture_comment(tctx, "(%s): dominfo[%s], reject[%s], handle_reject_reason[%s], "
+ "last_password_change[%s], dominfo->min_password_age[%lld]\n",
+ __location__,
+ (dominfo == NULL)? "NULL" : "present",
+ reject ? "true" : "false",
+ handle_reject_reason ? "true" : "false",
+ null_nttime(last_password_change) ? "null" : "not null",
+ dominfo ? (long long)dominfo->min_password_age : (long long)0);
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)
+ && dominfo
+ && reject
+ && handle_reject_reason
+ && (!null_nttime(last_password_change) || !dominfo->min_password_age)) {
+ if (dominfo->password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE ) {
+
+ if (reject && (reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR)) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n",
+ SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason);
+ return false;
+ }
+ }
+
+ /* We tested the order of precedence which is as follows:
+
+ * pwd min_age
+ * pwd length
+ * pwd complexity
+ * pwd history
+
+ Guenther */
+
+ if ((dominfo->min_password_age < 0) && !null_nttime(last_password_change) &&
+ (last_password_change - dominfo->min_password_age > t)) {
+
+ if (reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n",
+ SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason);
+ return false;
+ }
+
+ } else if ((dominfo->min_password_length > 0) &&
+ (strlen(newpass) < dominfo->min_password_length)) {
+
+ if (reject->extendedFailureReason != SAM_PWD_CHANGE_PASSWORD_TOO_SHORT) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_PASSWORD_TOO_SHORT (%d), got %d\n",
+ SAM_PWD_CHANGE_PASSWORD_TOO_SHORT, reject->extendedFailureReason);
+ return false;
+ }
+
+ } else if ((dominfo->password_history_length > 0) &&
+ strequal(oldpass, newpass)) {
+
+ if (reject->extendedFailureReason != SAM_PWD_CHANGE_PWD_IN_HISTORY) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_PWD_IN_HISTORY (%d), got %d\n",
+ SAM_PWD_CHANGE_PWD_IN_HISTORY, reject->extendedFailureReason);
+ return false;
+ }
+ } else if (dominfo->password_properties & DOMAIN_PASSWORD_COMPLEX) {
+
+ if (reject->extendedFailureReason != SAM_PWD_CHANGE_NOT_COMPLEX) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_NOT_COMPLEX (%d), got %d\n",
+ SAM_PWD_CHANGE_NOT_COMPLEX, reject->extendedFailureReason);
+ return false;
+ }
+
+ }
+
+ if (reject->extendedFailureReason == SAM_PWD_CHANGE_PASSWORD_TOO_SHORT) {
+ /* retry with adjusted size */
+ return test_ChangePasswordUser3(p, tctx, account_string,
+ dominfo->min_password_length,
+ password, NULL, 0, false);
+
+ }
+
+ } else if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ if (reject && reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n",
+ SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason);
+ return false;
+ }
+ /* Perhaps the server has a 'min password age' set? */
+
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ChangePasswordUser3");
+
+ *password = talloc_strdup(tctx, newpass);
+ }
+
+ return ret;
+}
+
+bool test_ChangePasswordUser4(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *account_string,
+ int policy_min_pw_len,
+ char **password,
+ const char *newpassword)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct samr_ChangePasswordUser4 r;
+ const char *oldpassword = *password;
+ char *srv_str = NULL;
+ struct lsa_String server;
+ struct lsa_String account;
+ uint8_t old_nt_key_data[16] = {0};
+ gnutls_datum_t old_nt_key = {
+ .data = old_nt_key_data,
+ .size = sizeof(old_nt_key),
+ };
+ uint8_t cek_data[16] = {0};
+ DATA_BLOB cek = {
+ .data = cek_data,
+ .length = sizeof(cek_data),
+ };
+ uint8_t pw_data[514] = {0};
+ DATA_BLOB plaintext = {
+ .data = pw_data,
+ .length = sizeof(pw_data),
+ };
+ DATA_BLOB ciphertext = data_blob_null;
+ struct samr_EncryptedPasswordAES pwd_buf = {.cipher_len = 0};
+ DATA_BLOB iv = {
+ .data = pwd_buf.salt,
+ .length = sizeof(pwd_buf.salt),
+ };
+ gnutls_datum_t iv_datum = {
+ .data = iv.data,
+ .size = iv.length,
+ };
+ uint64_t pbkdf2_iterations = generate_random_u64_range(5000, 1000000);
+ NTSTATUS status;
+ bool ok;
+ int rc;
+
+ torture_comment(tctx, "Testing ChangePasswordUser4\n");
+
+ if (newpassword == NULL) {
+ do {
+ if (policy_min_pw_len == 0) {
+ newpassword =
+ samr_rand_pass(tctx, policy_min_pw_len);
+ } else {
+ newpassword = samr_rand_pass_fixed_len(
+ tctx,
+ policy_min_pw_len);
+ }
+ } while (check_password_quality(newpassword) == false);
+ } else {
+ torture_comment(tctx, "Using password '%s'\n", newpassword);
+ }
+
+ torture_assert_not_null(tctx,
+ *password,
+ "Failing ChangePasswordUser4 as old password "
+ "was NULL. Previous test failed?");
+
+ srv_str = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ torture_assert_not_null(tctx, srv_str, "srvstr is NULL");
+ init_lsa_String(&server, srv_str);
+
+ init_lsa_String(&account, account_string);
+
+ E_md4hash(oldpassword, old_nt_key_data);
+
+ generate_nonce_buffer(iv.data, iv.length);
+
+ rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
+ &old_nt_key,
+ &iv_datum,
+ pbkdf2_iterations,
+ cek.data,
+ cek.length);
+ torture_assert_int_equal(tctx, rc, 0, "gnutls_pbkdf2 failed");
+
+ ok = encode_pwd_buffer514_from_str(pw_data, newpassword, STR_UNICODE);
+ torture_assert(tctx, ok, "encode_aes_pw_buffer failed");
+
+ status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(
+ tctx,
+ &plaintext,
+ &cek,
+ &samr_aes256_enc_key_salt,
+ &samr_aes256_mac_key_salt,
+ &iv,
+ &ciphertext,
+ pwd_buf.auth_data);
+ torture_assert_ntstatus_ok(
+ tctx,
+ status,
+ "samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt failed");
+
+ pwd_buf.cipher_len = ciphertext.length;
+ pwd_buf.cipher = ciphertext.data;
+ pwd_buf.PBKDF2Iterations = pbkdf2_iterations;
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.password = &pwd_buf;
+
+ status = dcerpc_samr_ChangePasswordUser4_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "ChangePasswordUser4 failed");
+
+ *password = talloc_strdup(tctx, newpassword);
+ return true;
+}
+
+bool test_ChangePasswordRandomBytes(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *account_string,
+ struct policy_handle *handle,
+ char **password)
+{
+ NTSTATUS status;
+ struct samr_ChangePasswordUser3 r;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ DATA_BLOB session_key;
+
+ bool ret = true;
+ struct lsa_String server, account;
+ struct samr_CryptPassword nt_pass;
+ struct samr_Password nt_verifier;
+ DATA_BLOB new_random_pass;
+ char *newpass;
+ char *oldpass;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint8_t old_nt_hash[16] = { 0 }, new_nt_hash[16];
+ DATA_BLOB old_nt_hash_blob
+ = data_blob_const(old_nt_hash,
+ sizeof(old_nt_hash));
+ NTTIME t;
+ struct samr_DomInfo1 *dominfo = NULL;
+ struct userPwdChangeFailureInformation *reject = NULL;
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ uint8_t _confounder[16] = {0};
+ DATA_BLOB confounder
+ = data_blob_const(_confounder,
+ sizeof(_confounder));
+ DATA_BLOB pw_data;
+ gnutls_datum_t old_nt_key = {
+ .data = old_nt_hash,
+ .size = sizeof(old_nt_hash),
+ };
+
+ new_random_pass = samr_very_rand_pass(tctx, 128);
+
+ torture_assert(tctx, *password != NULL,
+ "Failing ChangePasswordUser3 as old password was NULL. Previous test failed?");
+
+ oldpass = *password;
+ server.string = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ init_lsa_String(&account, account_string);
+
+ s.in.user_handle = handle;
+ s.in.info = &u;
+ s.in.level = 25;
+
+ ZERO_STRUCT(u);
+
+ u.info25.info.fields_present = SAMR_FIELD_NT_PASSWORD_PRESENT;
+
+ set_pw_in_buffer(u.info25.password.data, &new_random_pass);
+
+ pw_data = data_blob_const(u.info25.password.data, 516);
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ return false;
+ }
+
+ generate_random_buffer(_confounder,
+ sizeof(_confounder));
+
+ samba_gnutls_arcfour_confounded_md5(&confounder,
+ &session_key,
+ &pw_data,
+ SAMBA_GNUTLS_ENCRYPT);
+
+ memcpy(&u.info25.password.data[516], _confounder, sizeof(_confounder));
+
+ torture_comment(tctx, "Testing SetUserInfo level 25 (set password ex) with a password made up of only random bytes\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &s),
+ "SetUserInfo failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, "RANDOM", nt_errstr(s.out.result));
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetUserInfo level %u failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ ret = false;
+ }
+
+ torture_comment(tctx, "Testing ChangePasswordUser3 with a password made up of only random bytes\n");
+
+ mdfour(old_nt_hash, new_random_pass.data, new_random_pass.length);
+
+ new_random_pass = samr_very_rand_pass(tctx, 128);
+
+ mdfour(new_nt_hash, new_random_pass.data, new_random_pass.length);
+
+ set_pw_in_buffer(nt_pass.data, &new_random_pass);
+
+ gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &old_nt_key,
+ NULL);
+ gnutls_cipher_encrypt(cipher_hnd,
+ nt_pass.data,
+ 516);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 0;
+ r.in.lm_password = NULL;
+ r.in.lm_verifier = NULL;
+ r.in.password3 = NULL;
+ r.out.dominfo = &dominfo;
+ r.out.reject = &reject;
+
+ unix_to_nt_time(&t, time(NULL));
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r),
+ "ChangePasswordUser3 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, "RANDOM", nt_errstr(r.out.result));
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ if (reject && reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n",
+ SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason);
+ return false;
+ }
+ /* Perhaps the server has a 'min password age' set? */
+
+ } else if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "ChangePasswordUser3 failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ newpass = samr_rand_pass(tctx, 128);
+
+ mdfour(old_nt_hash, new_random_pass.data, new_random_pass.length);
+
+ E_md4hash(newpass, new_nt_hash);
+
+ status = init_samr_CryptPassword(newpass,
+ &old_nt_hash_blob,
+ &nt_pass);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+
+ E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
+
+ r.in.server = &server;
+ r.in.account = &account;
+ r.in.nt_password = &nt_pass;
+ r.in.nt_verifier = &nt_verifier;
+ r.in.lm_change = 0;
+ r.in.lm_password = NULL;
+ r.in.lm_verifier = NULL;
+ r.in.password3 = NULL;
+ r.out.dominfo = &dominfo;
+ r.out.reject = &reject;
+
+ unix_to_nt_time(&t, time(NULL));
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_ChangePasswordUser3_r(b, tctx, &r),
+ "ChangePasswordUser3 failed");
+ torture_comment(tctx, "(%s:%s) old_password[%s] new_password[%s] status[%s]\n",
+ __location__, __FUNCTION__,
+ oldpass, newpass, nt_errstr(r.out.result));
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
+ if (reject && reject->extendedFailureReason != SAM_PWD_CHANGE_NO_ERROR) {
+ torture_result(tctx, TORTURE_FAIL, "expected SAM_PWD_CHANGE_NO_ERROR (%d), got %d\n",
+ SAM_PWD_CHANGE_NO_ERROR, reject->extendedFailureReason);
+ return false;
+ }
+ /* Perhaps the server has a 'min password age' set? */
+
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result, "ChangePasswordUser3 (on second random password)");
+ *password = talloc_strdup(tctx, newpass);
+ }
+
+ return ret;
+}
+
+
+static bool test_GetMembersInAlias(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *alias_handle)
+{
+ struct samr_GetMembersInAlias r;
+ struct lsa_SidArray sids;
+
+ torture_comment(tctx, "Testing GetMembersInAlias\n");
+
+ r.in.alias_handle = alias_handle;
+ r.out.sids = &sids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetMembersInAlias_r(b, tctx, &r),
+ "GetMembersInAlias failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetMembersInAlias failed");
+
+ return true;
+}
+
+static bool test_AddMemberToAlias(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *alias_handle,
+ const struct dom_sid *domain_sid)
+{
+ struct samr_AddAliasMember r;
+ struct samr_DeleteAliasMember d;
+ struct dom_sid *sid;
+
+ sid = dom_sid_add_rid(tctx, domain_sid, 512);
+
+ torture_comment(tctx, "Testing AddAliasMember\n");
+ r.in.alias_handle = alias_handle;
+ r.in.sid = sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddAliasMember_r(b, tctx, &r),
+ "AddAliasMember failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "AddAliasMember failed");
+
+ d.in.alias_handle = alias_handle;
+ d.in.sid = sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteAliasMember_r(b, tctx, &d),
+ "DeleteAliasMember failed");
+ torture_assert_ntstatus_ok(tctx, d.out.result, "DelAliasMember failed");
+
+ return true;
+}
+
+static bool test_AddMultipleMembersToAlias(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *alias_handle)
+{
+ struct samr_AddMultipleMembersToAlias a;
+ struct samr_RemoveMultipleMembersFromAlias r;
+ struct lsa_SidArray sids;
+
+ torture_comment(tctx, "Testing AddMultipleMembersToAlias\n");
+ a.in.alias_handle = alias_handle;
+ a.in.sids = &sids;
+
+ sids.num_sids = 3;
+ sids.sids = talloc_array(tctx, struct lsa_SidPtr, 3);
+
+ sids.sids[0].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-1");
+ sids.sids[1].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-2");
+ sids.sids[2].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-3");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddMultipleMembersToAlias_r(b, tctx, &a),
+ "AddMultipleMembersToAlias failed");
+ torture_assert_ntstatus_ok(tctx, a.out.result, "AddMultipleMembersToAlias");
+
+
+ torture_comment(tctx, "Testing RemoveMultipleMembersFromAlias\n");
+ r.in.alias_handle = alias_handle;
+ r.in.sids = &sids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMultipleMembersFromAlias_r(b, tctx, &r),
+ "RemoveMultipleMembersFromAlias failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "RemoveMultipleMembersFromAlias failed");
+
+ /* strange! removing twice doesn't give any error */
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMultipleMembersFromAlias_r(b, tctx, &r),
+ "RemoveMultipleMembersFromAlias failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "RemoveMultipleMembersFromAlias failed");
+
+ /* but removing an alias that isn't there does */
+ sids.sids[2].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-4");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMultipleMembersFromAlias_r(b, tctx, &r),
+ "RemoveMultipleMembersFromAlias failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND, "RemoveMultipleMembersFromAlias");
+
+ return true;
+}
+
+static bool test_GetAliasMembership(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle)
+{
+ struct samr_GetAliasMembership r;
+ struct lsa_SidArray sids;
+ struct samr_Ids rids;
+
+ torture_comment(tctx, "Testing GetAliasMembership\n");
+
+ r.in.domain_handle = domain_handle;
+ r.in.sids = &sids;
+ r.out.rids = &rids;
+
+ sids.num_sids = 0;
+ sids.sids = talloc_zero_array(tctx, struct lsa_SidPtr, sids.num_sids);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r),
+ "GetAliasMembership failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_GetAliasMembership failed");
+
+ torture_assert_int_equal(tctx, sids.num_sids, rids.count,
+ "protocol misbehaviour");
+
+ sids.num_sids = 1;
+ sids.sids = talloc_zero_array(tctx, struct lsa_SidPtr, sids.num_sids);
+ sids.sids[0].sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1-2-3-1");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r),
+ "samr_GetAliasMembership failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_GetAliasMembership failed");
+
+#if 0
+ /* only true for w2k8 it seems
+ * win7, xp, w2k3 will return a 0 length array pointer */
+
+ if (rids.ids && (rids.count == 0)) {
+ torture_fail(tctx, "samr_GetAliasMembership returned 0 count and a rids array");
+ }
+#endif
+ if (!rids.ids && rids.count) {
+ torture_fail(tctx, "samr_GetAliasMembership returned non-0 count but no rids");
+ }
+
+ return true;
+}
+
+static bool test_TestPrivateFunctionsUser(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle)
+{
+ struct samr_TestPrivateFunctionsUser r;
+
+ torture_comment(tctx, "Testing TestPrivateFunctionsUser\n");
+
+ r.in.user_handle = user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_TestPrivateFunctionsUser_r(b, tctx, &r),
+ "TestPrivateFunctionsUser failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_IMPLEMENTED, "TestPrivateFunctionsUser");
+
+ return true;
+}
+
+static bool test_QueryUserInfo_pwdlastset(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ bool use_info2,
+ NTTIME *pwdlastset)
+{
+ NTSTATUS status;
+ uint16_t levels[] = { /* 3, */ 5, 21 };
+ int i;
+ /* NTTIME pwdlastset3 = 0; */
+ NTTIME pwdlastset5 = 0;
+ NTTIME pwdlastset21 = 0;
+
+ torture_comment(tctx, "Testing QueryUserInfo%s level 5 and 21 call ",
+ use_info2 ? "2":"");
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ struct samr_QueryUserInfo r;
+ struct samr_QueryUserInfo2 r2;
+ union samr_UserInfo *info;
+
+ if (use_info2) {
+ r2.in.user_handle = handle;
+ r2.in.level = levels[i];
+ r2.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo2_r(b, tctx, &r2),
+ "QueryUserInfo2 failed");
+ status = r2.out.result;
+
+ } else {
+ r.in.user_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "QueryUserInfo failed");
+ status = r.out.result;
+ }
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo%s level %u failed - %s\n",
+ use_info2 ? "2":"", levels[i], nt_errstr(status));
+ return false;
+ }
+
+ switch (levels[i]) {
+ case 3:
+ /* pwdlastset3 = info->info3.last_password_change; */
+ break;
+ case 5:
+ pwdlastset5 = info->info5.last_password_change;
+ break;
+ case 21:
+ pwdlastset21 = info->info21.last_password_change;
+ break;
+ default:
+ return false;
+ }
+ }
+ /* torture_assert_int_equal(tctx, pwdlastset3, pwdlastset5,
+ "pwdlastset mixup"); */
+ torture_assert_int_equal(tctx, pwdlastset5, pwdlastset21,
+ "pwdlastset mixup");
+
+ *pwdlastset = pwdlastset21;
+
+ torture_comment(tctx, "(pwdlastset: %llu)\n",
+ (unsigned long long) *pwdlastset);
+
+ return true;
+}
+
+static bool test_SamLogon(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials,
+ struct cli_credentials *test_credentials,
+ NTSTATUS expected_result,
+ bool interactive)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogonEx r;
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative;
+ struct netr_IdentityInfo identity;
+ struct netr_NetworkInfo ninfo;
+ struct netr_PasswordInfo pinfo;
+ DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+ int flags = CLI_CRED_NTLM_AUTH;
+ uint32_t samlogon_flags = 0;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator a;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx, (creds = cli_credentials_get_netlogon_creds(machine_credentials)), "");
+
+ if (lpcfg_client_lanman_auth(tctx->lp_ctx)) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+
+ if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx)) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+ }
+
+ cli_credentials_get_ntlm_username_domain(test_credentials, tctx,
+ &identity.account_name.string,
+ &identity.domain_name.string);
+
+ identity.parameter_control =
+ MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
+ MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
+ identity.logon_id = 0;
+ identity.workstation.string = cli_credentials_get_workstation(test_credentials);
+
+ if (interactive) {
+ netlogon_creds_client_authenticator(creds, &a);
+
+ if (!E_deshash(cli_credentials_get_password(test_credentials), pinfo.lmpassword.hash)) {
+ ZERO_STRUCT(pinfo.lmpassword.hash);
+ }
+ E_md4hash(cli_credentials_get_password(test_credentials), pinfo.ntpassword.hash);
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_encrypt(creds, pinfo.lmpassword.hash, 16);
+ netlogon_creds_aes_encrypt(creds, pinfo.ntpassword.hash, 16);
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ netlogon_creds_arcfour_crypt(creds, pinfo.lmpassword.hash, 16);
+ netlogon_creds_arcfour_crypt(creds, pinfo.ntpassword.hash, 16);
+ } else {
+ netlogon_creds_des_encrypt(creds, &pinfo.lmpassword);
+ netlogon_creds_des_encrypt(creds, &pinfo.ntpassword);
+ }
+
+ pinfo.identity_info = identity;
+ logon.password = &pinfo;
+
+ r.in.logon_level = NetlogonInteractiveInformation;
+ } else {
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ chal = data_blob_const(ninfo.challenge,
+ sizeof(ninfo.challenge));
+
+ names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(test_credentials),
+ cli_credentials_get_domain(test_credentials));
+
+ status = cli_credentials_get_ntlm_response(test_credentials, tctx,
+ &flags,
+ chal,
+ NULL, /* server_timestamp */
+ names_blob,
+ &lm_resp, &nt_resp,
+ NULL, NULL);
+ torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
+
+ ninfo.lm.data = lm_resp.data;
+ ninfo.lm.length = lm_resp.length;
+
+ ninfo.nt.data = nt_resp.data;
+ ninfo.nt.length = nt_resp.length;
+
+ ninfo.identity_info = identity;
+ logon.network = &ninfo;
+
+ r.in.logon_level = NetlogonNetworkInformation;
+ }
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(test_credentials);
+ r.in.logon = &logon;
+ r.in.flags = &samlogon_flags;
+ r.out.flags = &samlogon_flags;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+
+ torture_comment(tctx, "Testing LogonSamLogon with name %s\n", identity.account_name.string);
+
+ r.in.validation_level = 6;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "netr_LogonSamLogonEx failed");
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
+ r.in.validation_level = 3;
+ torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "netr_LogonSamLogonEx failed");
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_assert_ntstatus_equal(tctx, r.out.result, expected_result, "LogonSamLogonEx failed");
+ return true;
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogonEx failed");
+ }
+
+ return true;
+}
+
+static bool test_SamLogon_with_creds(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_creds,
+ const char *acct_name,
+ const char *password,
+ NTSTATUS expected_samlogon_result,
+ bool interactive)
+{
+ bool ret = true;
+ struct cli_credentials *test_credentials;
+
+ test_credentials = cli_credentials_init(tctx);
+
+ cli_credentials_set_workstation(test_credentials,
+ cli_credentials_get_workstation(machine_creds), CRED_SPECIFIED);
+ cli_credentials_set_domain(test_credentials,
+ cli_credentials_get_domain(machine_creds), CRED_SPECIFIED);
+ cli_credentials_set_username(test_credentials,
+ acct_name, CRED_SPECIFIED);
+ cli_credentials_set_password(test_credentials,
+ password, CRED_SPECIFIED);
+
+ torture_comment(tctx, "Testing samlogon (%s) as %s password: %s\n",
+ interactive ? "interactive" : "network", acct_name, password);
+
+ if (!test_SamLogon(tctx, p, machine_creds, test_credentials,
+ expected_samlogon_result, interactive)) {
+ torture_result(tctx, TORTURE_FAIL, "new password did not work\n");
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_SetPassword_level(struct dcerpc_pipe *p,
+ struct dcerpc_pipe *np,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint16_t level,
+ uint32_t fields_present,
+ uint8_t password_expired,
+ bool *matched_expected_error,
+ bool use_setinfo2,
+ const char *acct_name,
+ char **password,
+ struct cli_credentials *machine_creds,
+ bool use_queryinfo2,
+ NTTIME *pwdlastset,
+ NTSTATUS expected_samlogon_result)
+{
+ const char *fields = NULL;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ switch (level) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ fields = talloc_asprintf(tctx, "(fields_present: 0x%08x)",
+ fields_present);
+ break;
+ default:
+ break;
+ }
+
+ torture_comment(tctx, "Testing SetUserInfo%s level %d call "
+ "(password_expired: %d) %s\n",
+ use_setinfo2 ? "2":"", level, password_expired,
+ fields ? fields : "");
+
+ if (!test_SetUserPass_level_ex(p, tctx, handle, level,
+ fields_present,
+ password,
+ password_expired,
+ use_setinfo2,
+ matched_expected_error)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo_pwdlastset(b, tctx, handle,
+ use_queryinfo2,
+ pwdlastset)) {
+ ret = false;
+ }
+
+ if (*matched_expected_error == true) {
+ return ret;
+ }
+
+ if (!test_SamLogon_with_creds(tctx, np,
+ machine_creds,
+ acct_name,
+ *password,
+ expected_samlogon_result,
+ false)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool setup_schannel_netlogon_pipe(struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct dcerpc_pipe **p)
+{
+ struct dcerpc_binding *b;
+ NTSTATUS status;
+
+ torture_assert_ntstatus_ok(tctx, torture_rpc_binding(tctx, &b),
+ "failed to get rpc binding");
+
+ /* We have to use schannel, otherwise the SamLogonEx fails
+ * with INTERNAL_ERROR */
+
+ status = dcerpc_binding_set_flags(b,
+ DCERPC_SCHANNEL |
+ DCERPC_SIGN | DCERPC_SEAL |
+ DCERPC_SCHANNEL_AUTO,
+ DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, p, b, &ndr_table_netlogon,
+ credentials, tctx->ev, tctx->lp_ctx),
+ "failed to bind to netlogon");
+
+ return true;
+}
+
+static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ uint32_t acct_flags,
+ const char *acct_name,
+ struct policy_handle *handle,
+ char **password,
+ struct cli_credentials *machine_credentials)
+{
+ int s = 0, q = 0, f = 0, l = 0, z = 0;
+ bool ret = true;
+ int delay = 50000;
+ bool set_levels[] = { false, true };
+ bool query_levels[] = { false, true };
+ uint32_t levels[] = { 18, 21, 26, 23, 24, 25, 31 }; /* Second half only used when TEST_ALL_LEVELS defined */
+ uint32_t nonzeros[] = { 1, 24 };
+ uint32_t fields_present[] = {
+ 0,
+ SAMR_FIELD_EXPIRED_FLAG,
+ SAMR_FIELD_LAST_PWD_CHANGE,
+ SAMR_FIELD_EXPIRED_FLAG | SAMR_FIELD_LAST_PWD_CHANGE,
+ SAMR_FIELD_COMMENT,
+ SAMR_FIELD_NT_PASSWORD_PRESENT,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LAST_PWD_CHANGE,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT | SAMR_FIELD_LAST_PWD_CHANGE,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_EXPIRED_FLAG,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT | SAMR_FIELD_EXPIRED_FLAG,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT | SAMR_FIELD_LAST_PWD_CHANGE | SAMR_FIELD_EXPIRED_FLAG
+ };
+ struct dcerpc_pipe *np = NULL;
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ delay = 999999;
+ torture_comment(tctx, "Samba3 has second granularity, setting delay to: %d\n",
+ delay);
+ }
+
+ torture_assert(tctx, setup_schannel_netlogon_pipe(tctx, machine_credentials, &np), "");
+
+ /* set to 1 to enable testing for all possible opcode
+ (SetUserInfo, SetUserInfo2, QueryUserInfo, QueryUserInfo2)
+ combinations */
+#if 0
+#define TEST_ALL_LEVELS 1
+#define TEST_SET_LEVELS 1
+#define TEST_QUERY_LEVELS 1
+#endif
+#ifdef TEST_ALL_LEVELS
+ for (l=0; l<ARRAY_SIZE(levels); l++) {
+#else
+ for (l=0; l<(ARRAY_SIZE(levels))/2; l++) {
+#endif
+ for (z=0; z<ARRAY_SIZE(nonzeros); z++) {
+ for (f=0; f<ARRAY_SIZE(fields_present); f++) {
+#ifdef TEST_SET_LEVELS
+ for (s=0; s<ARRAY_SIZE(set_levels); s++) {
+#endif
+#ifdef TEST_QUERY_LEVELS
+ for (q=0; q<ARRAY_SIZE(query_levels); q++) {
+#endif
+ NTTIME pwdlastset_old = 0;
+ NTTIME pwdlastset_new = 0;
+ bool matched_expected_error = false;
+ NTSTATUS expected_samlogon_result = NT_STATUS_ACCOUNT_DISABLED;
+
+ torture_comment(tctx, "------------------------------\n"
+ "Testing pwdLastSet attribute for flags: 0x%08x "
+ "(s: %d (l: %d), q: %d)\n",
+ acct_flags, s, levels[l], q);
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if (!((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT))) {
+ expected_samlogon_result = NT_STATUS_WRONG_PASSWORD;
+ }
+ break;
+ }
+
+
+ /* set #1 */
+
+ /* set a password and force password change (pwdlastset 0) by
+ * setting the password expired flag to a non-0 value */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ nonzeros[z],
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ if (matched_expected_error == true) {
+ /* skipping on expected failure */
+ continue;
+ }
+
+ /* pwdlastset must be 0 afterwards, except for a level 21, 23 and 25
+ * set without the SAMR_FIELD_EXPIRED_FLAG */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if ((pwdlastset_new != 0) &&
+ !(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG)) {
+ torture_comment(tctx, "not considering a non-0 "
+ "pwdLastSet as a an error as the "
+ "SAMR_FIELD_EXPIRED_FLAG has not "
+ "been set\n");
+ break;
+ }
+ break;
+ default:
+ if (pwdlastset_new != 0) {
+ torture_result(tctx, TORTURE_FAIL, "pwdLastSet test failed: "
+ "expected pwdLastSet 0 but got %llu\n",
+ (unsigned long long) pwdlastset_old);
+ ret = false;
+ }
+ break;
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_result(tctx, TORTURE_FAIL, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ pwdlastset_old = pwdlastset_new;
+
+ usleep(delay);
+
+ /* set #2 */
+
+ /* set a password, pwdlastset needs to get updated (increased
+ * value), password_expired value used here is 0 */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ 0,
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ /* when a password has been changed, pwdlastset must not be 0 afterwards
+ * and must be larger then the old value */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ /* SAMR_FIELD_EXPIRED_FLAG has not been set and no
+ * password has been changed, old and new pwdlastset
+ * need to be the same value */
+
+ if (!(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG) &&
+ !((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)))
+ {
+ torture_assert_int_equal(tctx, pwdlastset_old,
+ pwdlastset_new, "pwdlastset must be equal");
+ break;
+ }
+ break;
+ default:
+ if (pwdlastset_old >= pwdlastset_new) {
+ torture_result(tctx, TORTURE_FAIL, "pwdLastSet test failed: "
+ "expected last pwdlastset (%llu) < new pwdlastset (%llu)\n",
+ (unsigned long long) pwdlastset_old,
+ (unsigned long long) pwdlastset_new);
+ ret = false;
+ }
+ if (pwdlastset_new == 0) {
+ torture_result(tctx, TORTURE_FAIL, "pwdLastSet test failed: "
+ "expected non-0 pwdlastset, got: %llu\n",
+ (unsigned long long) pwdlastset_new);
+ ret = false;
+ }
+ break;
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_result(tctx, TORTURE_FAIL, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ pwdlastset_old = pwdlastset_new;
+
+ usleep(delay);
+
+ /* set #2b */
+
+ /* set a password, pwdlastset needs to get updated (increased
+ * value), password_expired value used here is 0 */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ 0,
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ /* when a password has been changed, pwdlastset must not be 0 afterwards
+ * and must be larger then the old value */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ /* SAMR_FIELD_EXPIRED_FLAG has not been set and no
+ * password has been changed, old and new pwdlastset
+ * need to be the same value */
+
+ if (!(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG) &&
+ !((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)))
+ {
+ torture_assert_int_equal(tctx, pwdlastset_old,
+ pwdlastset_new, "pwdlastset must be equal");
+ break;
+ }
+ break;
+ default:
+ if (pwdlastset_old >= pwdlastset_new) {
+ torture_result(tctx, TORTURE_FAIL, "pwdLastSet test failed: "
+ "expected last pwdlastset (%llu) < new pwdlastset (%llu)\n",
+ (unsigned long long) pwdlastset_old,
+ (unsigned long long) pwdlastset_new);
+ ret = false;
+ }
+ if (pwdlastset_new == 0) {
+ torture_result(tctx, TORTURE_FAIL, "pwdLastSet test failed: "
+ "expected non-0 pwdlastset, got: %llu\n",
+ (unsigned long long) pwdlastset_new);
+ ret = false;
+ }
+ break;
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_result(tctx, TORTURE_FAIL, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ pwdlastset_old = pwdlastset_new;
+
+ usleep(delay);
+
+ /* set #3 */
+
+ /* set a password and force password change (pwdlastset 0) by
+ * setting the password expired flag to a non-0 value */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ nonzeros[z],
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ /* pwdlastset must be 0 afterwards, except for a level 21, 23 and 25
+ * set without the SAMR_FIELD_EXPIRED_FLAG */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if ((pwdlastset_new != 0) &&
+ !(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG)) {
+ torture_comment(tctx, "not considering a non-0 "
+ "pwdLastSet as a an error as the "
+ "SAMR_FIELD_EXPIRED_FLAG has not "
+ "been set\n");
+ break;
+ }
+
+ /* SAMR_FIELD_EXPIRED_FLAG has not been set and no
+ * password has been changed, old and new pwdlastset
+ * need to be the same value */
+
+ if (!(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG) &&
+ !((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)))
+ {
+ torture_assert_int_equal(tctx, pwdlastset_old,
+ pwdlastset_new, "pwdlastset must be equal");
+ break;
+ }
+ break;
+ default:
+ if (pwdlastset_new != 0) {
+ torture_result(tctx, TORTURE_FAIL, "pwdLastSet test failed: "
+ "expected pwdLastSet 0, got %llu\n",
+ (unsigned long long) pwdlastset_old);
+ ret = false;
+ }
+ break;
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ case 32:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_result(tctx, TORTURE_FAIL, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ /* if the level we are testing does not have a fields_present
+ * field, skip all fields present tests by setting f to to
+ * arraysize */
+ switch (levels[l]) {
+ case 18:
+ case 24:
+ case 26:
+ case 31:
+ f = ARRAY_SIZE(fields_present);
+ break;
+ }
+
+#ifdef TEST_QUERY_LEVELS
+ }
+#endif
+#ifdef TEST_SET_LEVELS
+ }
+#endif
+ } /* fields present */
+ } /* nonzeros */
+ } /* levels */
+
+#undef TEST_SET_LEVELS
+#undef TEST_QUERY_LEVELS
+
+ talloc_free(np);
+
+ return ret;
+}
+
+static bool test_QueryUserInfo_badpwdcount(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t *badpwdcount)
+{
+ union samr_UserInfo *info;
+ struct samr_QueryUserInfo r;
+
+ r.in.user_handle = handle;
+ r.in.level = 3;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "failed to query userinfo");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query userinfo");
+
+ *badpwdcount = info->info3.bad_password_count;
+
+ torture_comment(tctx, " (bad password count: %d)\n", *badpwdcount);
+
+ return true;
+}
+
+static bool test_SetUserInfo_acct_flags(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle,
+ uint32_t acct_flags)
+{
+ struct samr_SetUserInfo r;
+ union samr_UserInfo user_info;
+
+ torture_comment(tctx, "Testing SetUserInfo level 16\n");
+
+ user_info.info16.acct_flags = acct_flags;
+
+ r.in.user_handle = user_handle;
+ r.in.level = 16;
+ r.in.info = &user_info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo_r(b, tctx, &r),
+ "failed to set account flags");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to set account flags");
+
+ return true;
+}
+
+static bool test_reset_badpwdcount(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle,
+ uint32_t acct_flags,
+ char **password)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password),
+ "failed to set password");
+
+ torture_comment(tctx, "Testing SetUserInfo level 16 (enable account)\n");
+
+ torture_assert(tctx,
+ test_SetUserInfo_acct_flags(b, tctx, user_handle,
+ acct_flags & ~ACB_DISABLED),
+ "failed to enable user");
+
+ torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password),
+ "failed to set password");
+
+ return true;
+}
+
+static bool test_SetDomainInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ enum samr_DomainInfoClass level,
+ union samr_DomainInfo *info)
+{
+ struct samr_SetDomainInfo r;
+
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_SetDomainInfo_r(b, tctx, &r),
+ "failed to set domain info");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to set domain info");
+
+ return true;
+}
+
+static bool test_SetDomainInfo_ntstatus(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ enum samr_DomainInfoClass level,
+ union samr_DomainInfo *info,
+ NTSTATUS expected)
+{
+ struct samr_SetDomainInfo r;
+
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.in.info = info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &r),
+ "SetDomainInfo failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, expected, "");
+
+ return true;
+}
+
+static bool test_QueryDomainInfo2_level(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ enum samr_DomainInfoClass level,
+ union samr_DomainInfo **q_info)
+{
+ struct samr_QueryDomainInfo2 r;
+
+ r.in.domain_handle = domain_handle;
+ r.in.level = level;
+ r.out.info = q_info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo2_r(b, tctx, &r),
+ "failed to query domain info");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query domain info");
+
+ return true;
+}
+
+static bool test_Password_badpwdcount(struct dcerpc_pipe *p,
+ struct dcerpc_pipe *np,
+ struct torture_context *tctx,
+ uint32_t acct_flags,
+ const char *acct_name,
+ struct policy_handle *domain_handle,
+ struct policy_handle *user_handle,
+ char **password,
+ struct cli_credentials *machine_credentials,
+ const char *comment,
+ bool disable,
+ bool interactive,
+ NTSTATUS expected_success_status,
+ struct samr_DomInfo1 *info1,
+ struct samr_DomInfo12 *info12)
+{
+ union samr_DomainInfo info;
+ char **passwords;
+ int i;
+ uint32_t badpwdcount, tmp;
+ uint32_t password_history_length = 12;
+ uint32_t lockout_threshold = 15;
+ uint32_t lockout_seconds = 5;
+ uint64_t delta_time_factor = 10 * 1000 * 1000;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ lockout_seconds = 60;
+ }
+
+ torture_comment(tctx, "\nTesting bad pwd count with: %s\n", comment);
+
+ torture_assert(tctx, password_history_length < lockout_threshold,
+ "password history length needs to be smaller than account lockout threshold for this test");
+
+
+ /* set policies */
+
+ info.info1 = *info1;
+ info.info1.password_history_length = password_history_length;
+ info.info1.min_password_age = 0;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainPasswordInformation, &info),
+ "failed to set password history length and min passwd age");
+
+ info.info12 = *info12;
+ info.info12.lockout_threshold = lockout_threshold;
+
+ /* set lockout duration of 5 seconds */
+ info.info12.lockout_duration = ~(lockout_seconds * delta_time_factor);
+ info.info12.lockout_window = ~(lockout_seconds * delta_time_factor);
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainLockoutInformation, &info),
+ "failed to set lockout threshold");
+
+ /* reset bad pwd count */
+
+ torture_assert(tctx,
+ test_reset_badpwdcount(p, tctx, user_handle, acct_flags, password), "");
+
+
+ /* enable or disable account */
+ if (disable) {
+ torture_assert(tctx,
+ test_SetUserInfo_acct_flags(b, tctx, user_handle,
+ acct_flags | ACB_DISABLED),
+ "failed to disable user");
+ } else {
+ torture_assert(tctx,
+ test_SetUserInfo_acct_flags(b, tctx, user_handle,
+ acct_flags & ~ACB_DISABLED),
+ "failed to enable user");
+ }
+
+
+ /* setup password history */
+
+ passwords = talloc_array(tctx, char *, password_history_length);
+
+ for (i=0; i < password_history_length; i++) {
+
+ torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password),
+ "failed to set password");
+ passwords[i] = talloc_strdup(tctx, *password);
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, passwords[i],
+ expected_success_status, interactive)) {
+ torture_fail(tctx, "failed to auth with latest password");
+ }
+
+ torture_assert(tctx,
+ test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), "");
+
+ torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0");
+ }
+
+
+ /* test with wrong password */
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, "random_crap",
+ NT_STATUS_WRONG_PASSWORD, interactive)) {
+ torture_fail(tctx, "succeeded to authenticate with wrong password");
+ }
+
+ torture_assert(tctx,
+ test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), "");
+
+ torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1");
+
+
+ /* test with latest good password */
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name,
+ passwords[password_history_length-1],
+ expected_success_status, interactive)) {
+ torture_fail(tctx, "succeeded to authenticate with wrong password");
+ }
+
+ torture_assert(tctx,
+ test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), "");
+
+ if (disable) {
+ torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1");
+ } else {
+ /* only enabled accounts get the bad pwd count reset upon
+ * successful logon */
+ torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0");
+ }
+
+ tmp = badpwdcount;
+
+
+ /* test password history */
+
+ for (i=0; i < password_history_length; i++) {
+
+ torture_comment(tctx, "Testing bad password count behavior with "
+ "password #%d of #%d\n", i, password_history_length);
+
+ /* - network samlogon will succeed auth and not
+ * increase badpwdcount for 2 last entries
+ * - interactive samlogon only for the last one */
+
+ if (i == password_history_length - 1 ||
+ (i == password_history_length - 2 && !interactive)) {
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, passwords[i],
+ expected_success_status, interactive)) {
+ torture_fail(tctx, talloc_asprintf(tctx, "did not successfully to obtain %s for %s login with old password (#%d of #%d in history)",
+ nt_errstr(expected_success_status),
+ interactive ? "interactive" : "network", i, password_history_length));
+ }
+
+ torture_assert(tctx,
+ test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), "");
+
+ if (disable) {
+ /* torture_comment(tctx, "expecting bad pwd count to *NOT INCREASE* for pwd history entry %d\n", i); */
+ torture_assert_int_equal(tctx, badpwdcount, tmp, "unexpected badpwdcount");
+ } else {
+ /* torture_comment(tctx, "expecting bad pwd count to be 0 for pwd history entry %d\n", i); */
+ torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0");
+ }
+
+ tmp = badpwdcount;
+
+ continue;
+ }
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, passwords[i],
+ NT_STATUS_WRONG_PASSWORD, interactive)) {
+ torture_fail(tctx, talloc_asprintf(tctx, "succeeded to authenticate with old password (#%d of #%d in history)", i, password_history_length));
+ }
+
+ torture_assert(tctx,
+ test_QueryUserInfo_badpwdcount(b, tctx, user_handle, &badpwdcount), "");
+
+ /* - network samlogon will fail auth but not increase
+ * badpwdcount for 3rd last entry
+ * - interactive samlogon for 3rd and 2nd last entry */
+
+ if (i == password_history_length - 3 ||
+ (i == password_history_length - 2 && interactive)) {
+ /* torture_comment(tctx, "expecting bad pwd count to *NOT INCREASE * by one for pwd history entry %d\n", i); */
+ torture_assert_int_equal(tctx, badpwdcount, tmp, "unexpected badpwdcount");
+ } else {
+ /* torture_comment(tctx, "expecting bad pwd count to increase by one for pwd history entry %d\n", i); */
+ torture_assert_int_equal(tctx, badpwdcount, tmp + 1, "unexpected badpwdcount");
+ }
+
+ tmp = badpwdcount;
+ }
+
+ return true;
+}
+
+static bool test_Password_badpwdcount_wrap(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ uint32_t acct_flags,
+ const char *acct_name,
+ struct policy_handle *domain_handle,
+ struct policy_handle *user_handle,
+ char **password,
+ struct cli_credentials *machine_credentials)
+{
+ union samr_DomainInfo *q_info, s_info;
+ struct samr_DomInfo1 info1, _info1;
+ struct samr_DomInfo12 info12, _info12;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *np;
+ int i;
+
+ struct {
+ const char *comment;
+ bool disabled;
+ bool interactive;
+ NTSTATUS expected_success_status;
+ } creds[] = {
+ {
+ .comment = "network logon (disabled account)",
+ .disabled = true,
+ .interactive = false,
+ .expected_success_status= NT_STATUS_ACCOUNT_DISABLED
+ },
+ {
+ .comment = "network logon (enabled account)",
+ .disabled = false,
+ .interactive = false,
+ .expected_success_status= NT_STATUS_OK
+ },
+ {
+ .comment = "interactive logon (disabled account)",
+ .disabled = true,
+ .interactive = true,
+ .expected_success_status= NT_STATUS_ACCOUNT_DISABLED
+ },
+ {
+ .comment = "interactive logon (enabled account)",
+ .disabled = false,
+ .interactive = true,
+ .expected_success_status= NT_STATUS_OK
+ },
+ };
+
+ torture_assert(tctx, setup_schannel_netlogon_pipe(tctx, machine_credentials, &np), "");
+
+ /* backup old policies */
+
+ torture_assert(tctx,
+ test_QueryDomainInfo2_level(b, tctx, domain_handle,
+ DomainPasswordInformation, &q_info),
+ "failed to query domain info level 1");
+
+ info1 = q_info->info1;
+ _info1 = info1;
+
+ torture_assert(tctx,
+ test_QueryDomainInfo2_level(b, tctx, domain_handle,
+ DomainLockoutInformation, &q_info),
+ "failed to query domain info level 12");
+
+ info12 = q_info->info12;
+ _info12 = info12;
+
+ /* run tests */
+
+ for (i=0; i < ARRAY_SIZE(creds); i++) {
+
+ /* skip trust tests for now */
+ if (acct_flags & ACB_WSTRUST ||
+ acct_flags & ACB_SVRTRUST ||
+ acct_flags & ACB_DOMTRUST) {
+ continue;
+ }
+
+ if (!test_Password_badpwdcount(p, np, tctx, acct_flags, acct_name,
+ domain_handle, user_handle, password,
+ machine_credentials,
+ creds[i].comment,
+ creds[i].disabled,
+ creds[i].interactive,
+ creds[i].expected_success_status,
+ &_info1, &_info12)) {
+ torture_result(tctx, TORTURE_FAIL, "TEST #%d (%s) failed\n", i, creds[i].comment);
+ ret = false;
+ } else {
+ torture_comment(tctx, "TEST #%d (%s) succeeded\n", i, creds[i].comment);
+ }
+ }
+
+ /* restore policies */
+
+ s_info.info1 = info1;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainPasswordInformation, &s_info),
+ "failed to set password information");
+
+ s_info.info12 = info12;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainLockoutInformation, &s_info),
+ "failed to set lockout information");
+
+ return ret;
+}
+
+static bool test_QueryUserInfo_lockout(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *acct_name,
+ uint16_t raw_bad_password_count,
+ uint16_t effective_bad_password_count,
+ uint32_t effective_acb_lockout)
+{
+ struct policy_handle user_handle;
+ union samr_UserInfo *i;
+ struct samr_QueryUserInfo r;
+
+ NTSTATUS status = test_OpenUser_byname(b, tctx, domain_handle, acct_name, &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ r.in.user_handle = &user_handle;
+ r.in.level = 3;
+ r.out.info = &i;
+ torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level);
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "failed to query userinfo");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query userinfo");
+ torture_comment(tctx, " (acct_flags: 0x%08x) (raw_bad_pwd_count: %u)\n",
+ i->info3.acct_flags, i->info3.bad_password_count);
+ torture_assert_int_equal(tctx, i->info3.bad_password_count,
+ raw_bad_password_count,
+ "raw badpwdcount");
+ torture_assert_int_equal(tctx, i->info3.acct_flags & ACB_AUTOLOCK,
+ effective_acb_lockout,
+ "effective acb_lockout");
+ TALLOC_FREE(i);
+
+ r.in.user_handle = &user_handle;
+ r.in.level = 5;
+ r.out.info = &i;
+ torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level);
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "failed to query userinfo");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query userinfo");
+ torture_comment(tctx, " (acct_flags: 0x%08x) (effective_bad_pwd_count: %u)\n",
+ i->info5.acct_flags, i->info5.bad_password_count);
+ torture_assert_int_equal(tctx, i->info5.bad_password_count,
+ effective_bad_password_count,
+ "effective badpwdcount");
+ torture_assert_int_equal(tctx, i->info5.acct_flags & ACB_AUTOLOCK,
+ effective_acb_lockout,
+ "effective acb_lockout");
+ TALLOC_FREE(i);
+
+ r.in.user_handle = &user_handle;
+ r.in.level = 16;
+ r.out.info = &i;
+ torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level);
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "failed to query userinfo");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query userinfo");
+ torture_comment(tctx, " (acct_flags: 0x%08x)\n",
+ i->info16.acct_flags);
+ torture_assert_int_equal(tctx, i->info16.acct_flags & ACB_AUTOLOCK,
+ effective_acb_lockout,
+ "effective acb_lockout");
+ TALLOC_FREE(i);
+
+ r.in.user_handle = &user_handle;
+ r.in.level = 21;
+ r.out.info = &i;
+ torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level);
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "failed to query userinfo");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query userinfo");
+ torture_comment(tctx, " (acct_flags: 0x%08x) (effective_bad_pwd_count: %u)\n",
+ i->info21.acct_flags, i->info21.bad_password_count);
+ torture_assert_int_equal(tctx, i->info21.bad_password_count,
+ effective_bad_password_count,
+ "effective badpwdcount");
+ torture_assert_int_equal(tctx, i->info21.acct_flags & ACB_AUTOLOCK,
+ effective_acb_lockout,
+ "effective acb_lockout");
+ TALLOC_FREE(i);
+
+ if (!test_samr_handle_Close(b, tctx, &user_handle)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_Password_lockout(struct dcerpc_pipe *p,
+ struct dcerpc_pipe *np,
+ struct torture_context *tctx,
+ uint32_t acct_flags,
+ const char *acct_name,
+ struct policy_handle *domain_handle,
+ struct policy_handle *user_handle,
+ char **password,
+ struct cli_credentials *machine_credentials,
+ const char *comment,
+ bool disable,
+ bool interactive,
+ uint32_t password_history_length,
+ NTSTATUS expected_success_status,
+ struct samr_DomInfo1 *info1,
+ struct samr_DomInfo12 *info12)
+{
+ union samr_DomainInfo info;
+ uint64_t lockout_threshold = 1;
+ uint32_t lockout_seconds = 5;
+ uint64_t delta_time_factor = 10 * 1000 * 1000;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ lockout_seconds = 60;
+ }
+
+ torture_comment(tctx, "\nTesting account lockout: %s\n", comment);
+
+ /* set policies */
+
+ info.info1 = *info1;
+
+ torture_comment(tctx, "setting password history length to %d.\n", password_history_length);
+ info.info1.password_history_length = password_history_length;
+
+ torture_comment(tctx, "setting min password again.\n");
+ info.info1.min_password_age = 0;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainPasswordInformation, &info),
+ "failed to set password history length");
+
+ info.info12 = *info12;
+ info.info12.lockout_threshold = lockout_threshold;
+
+ /* set lockout duration < lockout window: should fail */
+ info.info12.lockout_duration = ~(lockout_seconds * delta_time_factor);
+ info.info12.lockout_window = ~((lockout_seconds + 1) * delta_time_factor);
+
+ torture_assert(tctx,
+ test_SetDomainInfo_ntstatus(b, tctx, domain_handle,
+ DomainLockoutInformation, &info,
+ NT_STATUS_INVALID_PARAMETER),
+ "setting lockout duration < lockout window gave unexpected result");
+
+ info.info12.lockout_duration = 0;
+ info.info12.lockout_window = 0;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainLockoutInformation, &info),
+ "failed to set lockout window and duration to 0");
+
+
+ /* set lockout duration of 5 seconds */
+ info.info12.lockout_duration = ~(lockout_seconds * delta_time_factor);
+ info.info12.lockout_window = ~(lockout_seconds * delta_time_factor);
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainLockoutInformation, &info),
+ "failed to set lockout window and duration to 5 seconds");
+
+ /* reset bad pwd count */
+
+ torture_assert(tctx,
+ test_reset_badpwdcount(p, tctx, user_handle, acct_flags, password), "");
+
+
+ /* enable or disable account */
+
+ if (disable) {
+ torture_assert(tctx,
+ test_SetUserInfo_acct_flags(b, tctx, user_handle,
+ acct_flags | ACB_DISABLED),
+ "failed to disable user");
+ } else {
+ torture_assert(tctx,
+ test_SetUserInfo_acct_flags(b, tctx, user_handle,
+ acct_flags & ~ACB_DISABLED),
+ "failed to enable user");
+ }
+
+
+ /* test logon with right password */
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, *password,
+ expected_success_status, interactive)) {
+ torture_fail(tctx, "failed to auth with latest password");
+ }
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 0, 0, 0),
+ "expected account to not be locked");
+
+ /* test with wrong password ==> lockout */
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, "random_crap",
+ NT_STATUS_WRONG_PASSWORD, interactive)) {
+ torture_fail(tctx, "succeeded to authenticate with wrong password");
+ }
+
+ /*
+ * curiously, windows does _not_ return fresh values of
+ * effective bad_password_count and ACB_AUTOLOCK.
+ */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to not be locked");
+
+ /* test with good password */
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name,
+ *password,
+ NT_STATUS_ACCOUNT_LOCKED_OUT, interactive))
+ {
+ torture_fail(tctx, "authenticate did not return NT_STATUS_ACCOUNT_LOCKED_OUT");
+ }
+
+ /* bad pwd count should not get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, *password,
+ NT_STATUS_ACCOUNT_LOCKED_OUT),
+ "got wrong status from ChangePasswordUser2");
+
+ /* bad pwd count should not get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, "random_crap", NT_STATUS_ACCOUNT_LOCKED_OUT),
+ "got wrong status from ChangePasswordUser2");
+
+ /* bad pwd count should not get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ /* with bad password */
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+ acct_name, "random_crap2",
+ NT_STATUS_ACCOUNT_LOCKED_OUT, interactive))
+ {
+ torture_fail(tctx, "authenticate did not return NT_STATUS_ACCOUNT_LOCKED_OUT");
+ }
+
+ /* bad pwd count should not get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ /* let lockout duration expire ==> unlock */
+
+ torture_comment(tctx, "let lockout duration expire...\n");
+ sleep(lockout_seconds + 1);
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 0, 0),
+ "expected account to not be locked");
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name,
+ *password,
+ expected_success_status, interactive))
+ {
+ torture_fail(tctx, "failed to authenticate after lockout expired");
+ }
+
+ if (NT_STATUS_IS_OK(expected_success_status)) {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 0, 0, 0),
+ "expected account to not be locked");
+ } else {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 0, 0),
+ "expected account to not be locked");
+ }
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, "random_crap", NT_STATUS_WRONG_PASSWORD),
+ "got wrong status from ChangePasswordUser2");
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, *password, NT_STATUS_ACCOUNT_LOCKED_OUT),
+ "got wrong status from ChangePasswordUser2");
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, "random_crap", NT_STATUS_ACCOUNT_LOCKED_OUT),
+ "got wrong status from ChangePasswordUser2");
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ /* let lockout duration expire ==> unlock */
+
+ torture_comment(tctx, "let lockout duration expire...\n");
+ sleep(lockout_seconds + 1);
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 0, 0),
+ "expected account to not be locked");
+
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name,
+ *password,
+ expected_success_status, interactive))
+ {
+ torture_fail(tctx, "failed to authenticate after lockout expired");
+ }
+
+ if (NT_STATUS_IS_OK(expected_success_status)) {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 0, 0, 0),
+ "expected account to not be locked");
+ } else {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 0, 0),
+ "expected account to not be locked");
+ }
+
+ /* Testing ChangePasswordUser behaviour with 3 attempts */
+ info.info12.lockout_threshold = 3;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainLockoutInformation, &info),
+ "failed to set lockout threshold to 3");
+
+ if (NT_STATUS_IS_OK(expected_success_status)) {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 0, 0, 0),
+ "expected account to not be locked");
+ } else {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 0, 0),
+ "expected account to not be locked");
+ }
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, "random_crap", NT_STATUS_WRONG_PASSWORD),
+ "got wrong status from ChangePasswordUser2");
+
+ /* bad pwd count will get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 1, 1, 0),
+ "expected account to not be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, "random_crap", NT_STATUS_WRONG_PASSWORD),
+ "got wrong status from ChangePasswordUser2");
+
+ /* bad pwd count will get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 2, 2, 0),
+ "expected account to not be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, "random_crap", NT_STATUS_WRONG_PASSWORD),
+ "got wrong status from ChangePasswordUser2");
+
+ /* bad pwd count should get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 3, 3, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2_ntstatus(p, tctx, acct_name, *password, NT_STATUS_ACCOUNT_LOCKED_OUT),
+ "got wrong status from ChangePasswordUser2");
+
+ /* bad pwd count should not get updated */
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 3, 3, ACB_AUTOLOCK),
+ "expected account to be locked");
+
+ /* let lockout duration expire ==> unlock */
+
+ torture_comment(tctx, "let lockout duration expire...\n");
+ sleep(lockout_seconds + 1);
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 3, 0, 0),
+ "expected account to not be locked");
+
+ torture_assert(tctx,
+ test_ChangePasswordUser2(p, tctx, acct_name, password, NULL, false),
+ "got wrong status from ChangePasswordUser2");
+
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 3, 0, 0),
+ "expected account to not be locked");
+
+ /* Used to reset the badPwdCount for the other tests */
+ if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name,
+ *password,
+ expected_success_status, interactive))
+ {
+ torture_fail(tctx, "failed to authenticate after lockout expired");
+ }
+
+ if (NT_STATUS_IS_OK(expected_success_status)) {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 0, 0, 0),
+ "expected account to not be locked");
+ } else {
+ torture_assert(tctx,
+ test_QueryUserInfo_lockout(b, tctx, domain_handle, acct_name,
+ 3, 0, 0),
+ "expected account to not be locked");
+ }
+
+ return true;
+}
+
+static bool test_Password_lockout_wrap(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ uint32_t acct_flags,
+ const char *acct_name,
+ struct policy_handle *domain_handle,
+ struct policy_handle *user_handle,
+ char **password,
+ struct cli_credentials *machine_credentials)
+{
+ union samr_DomainInfo *q_info, s_info;
+ struct samr_DomInfo1 info1, _info1;
+ struct samr_DomInfo12 info12, _info12;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *np;
+ int i;
+
+ struct {
+ const char *comment;
+ bool disabled;
+ bool interactive;
+ uint32_t password_history_length;
+ NTSTATUS expected_success_status;
+ } creds[] = {
+ {
+ .comment = "network logon (disabled account)",
+ .disabled = true,
+ .interactive = false,
+ .expected_success_status= NT_STATUS_ACCOUNT_DISABLED
+ },
+ {
+ .comment = "network logon (enabled account)",
+ .disabled = false,
+ .interactive = false,
+ .expected_success_status= NT_STATUS_OK
+ },
+ {
+ .comment = "network logon (enabled account, history len = 1)",
+ .disabled = false,
+ .interactive = false,
+ .expected_success_status= NT_STATUS_OK,
+ .password_history_length = 1
+ },
+ {
+ .comment = "interactive logon (disabled account)",
+ .disabled = true,
+ .interactive = true,
+ .expected_success_status= NT_STATUS_ACCOUNT_DISABLED
+ },
+ {
+ .comment = "interactive logon (enabled account)",
+ .disabled = false,
+ .interactive = true,
+ .expected_success_status= NT_STATUS_OK
+ },
+ {
+ .comment = "interactive logon (enabled account, history len = 1)",
+ .disabled = false,
+ .interactive = true,
+ .expected_success_status= NT_STATUS_OK,
+ .password_history_length = 1
+ },
+ };
+
+ torture_assert(tctx, setup_schannel_netlogon_pipe(tctx, machine_credentials, &np), "");
+
+ /* backup old policies */
+
+ torture_assert(tctx,
+ test_QueryDomainInfo2_level(b, tctx, domain_handle,
+ DomainPasswordInformation, &q_info),
+ "failed to query domain info level 1");
+
+ info1 = q_info->info1;
+ _info1 = info1;
+
+ torture_assert(tctx,
+ test_QueryDomainInfo2_level(b, tctx, domain_handle,
+ DomainLockoutInformation, &q_info),
+ "failed to query domain info level 12");
+
+ info12 = q_info->info12;
+ _info12 = info12;
+
+ /* run tests */
+
+ for (i=0; i < ARRAY_SIZE(creds); i++) {
+ bool test_passed;
+ /* skip trust tests for now */
+ if (acct_flags & ACB_WSTRUST ||
+ acct_flags & ACB_SVRTRUST ||
+ acct_flags & ACB_DOMTRUST) {
+ continue;
+ }
+
+ test_passed = test_Password_lockout(p, np, tctx, acct_flags, acct_name,
+ domain_handle, user_handle, password,
+ machine_credentials,
+ creds[i].comment,
+ creds[i].disabled,
+ creds[i].interactive,
+ creds[i].password_history_length,
+ creds[i].expected_success_status,
+ &_info1, &_info12);
+ ret &= test_passed;
+ if (!test_passed) {
+ torture_result(tctx, TORTURE_FAIL, "TEST #%d (%s) failed\n", i, creds[i].comment);
+ break;
+ } else {
+ torture_comment(tctx, "TEST #%d (%s) succeeded\n", i, creds[i].comment);
+ }
+ }
+
+ /* restore policies */
+
+ s_info.info1 = info1;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainPasswordInformation, &s_info),
+ "failed to set password information");
+
+ s_info.info12 = info12;
+
+ torture_assert(tctx,
+ test_SetDomainInfo(b, tctx, domain_handle,
+ DomainLockoutInformation, &s_info),
+ "failed to set lockout information");
+
+ return ret;
+}
+
+static bool test_DeleteUser_with_privs(struct dcerpc_pipe *p,
+ struct dcerpc_pipe *lp,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ struct policy_handle *lsa_handle,
+ struct policy_handle *user_handle,
+ const struct dom_sid *domain_sid,
+ uint32_t rid,
+ struct cli_credentials *machine_credentials)
+{
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_binding_handle *lb = lp->binding_handle;
+
+ struct policy_handle lsa_acct_handle;
+ struct dom_sid *user_sid;
+
+ user_sid = dom_sid_add_rid(tctx, domain_sid, rid);
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r),
+ "lsa_EnumAccountRights failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "Expected enum rights for account to fail");
+ }
+
+ {
+ struct lsa_RightSet rights;
+ struct lsa_StringLarge names[2];
+ struct lsa_AddAccountRights r;
+
+ torture_comment(tctx, "Testing LSA AddAccountRights\n");
+
+ init_lsa_StringLarge(&names[0], "SeMachineAccountPrivilege");
+ init_lsa_StringLarge(&names[1], NULL);
+
+ rights.count = 1;
+ rights.names = names;
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.rights = &rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_AddAccountRights_r(lb, tctx, &r),
+ "lsa_AddAccountRights failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to add privileges");
+ }
+
+ {
+ struct lsa_RightSet rights;
+ struct lsa_StringLarge names[2];
+ struct lsa_AddAccountRights r;
+
+ torture_comment(tctx, "Testing LSA AddAccountRights 1\n");
+
+ init_lsa_StringLarge(&names[0], "SeInteractiveLogonRight");
+ init_lsa_StringLarge(&names[1], NULL);
+
+ rights.count = 1;
+ rights.names = names;
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.rights = &rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_AddAccountRights_r(lb, tctx, &r),
+ "lsa_AddAccountRights 1 failed");
+
+ if (torture_setting_bool(tctx, "nt4_dc", false)) {
+ /*
+ * The NT4 DC doesn't implement Rights.
+ */
+ torture_assert_ntstatus_equal(tctx, r.out.result,
+ NT_STATUS_NO_SUCH_PRIVILEGE,
+ "Add rights failed with incorrect error");
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to add rights");
+
+ }
+ }
+
+
+ {
+ struct lsa_EnumAccounts r;
+ uint32_t resume_handle = 0;
+ struct lsa_SidArray lsa_sid_array;
+ int i;
+ bool found_sid = false;
+
+ torture_comment(tctx, "Testing LSA EnumAccounts\n");
+
+ r.in.handle = lsa_handle;
+ r.in.num_entries = 0x1000;
+ r.in.resume_handle = &resume_handle;
+ r.out.sids = &lsa_sid_array;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(lb, tctx, &r),
+ "lsa_EnumAccounts failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to enum accounts");
+
+ for (i=0; i < lsa_sid_array.num_sids; i++) {
+ if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) {
+ found_sid = true;
+ }
+ }
+
+ torture_assert(tctx, found_sid,
+ "failed to list privileged account");
+ }
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet user_rights;
+ uint32_t expected_count = 2;
+
+ if (torture_setting_bool(tctx, "nt4_dc", false)) {
+ /*
+ * NT4 DC doesn't store rights.
+ */
+ expected_count = 1;
+ }
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &user_rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r),
+ "lsa_EnumAccountRights failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to enum rights for account");
+
+ if (user_rights.count < expected_count) {
+ torture_result(tctx, TORTURE_FAIL, "failed to find newly added rights");
+ return false;
+ }
+ }
+
+ {
+ struct lsa_OpenAccount r;
+
+ torture_comment(tctx, "Testing LSA OpenAccount\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.acct_handle = &lsa_acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenAccount_r(lb, tctx, &r),
+ "lsa_OpenAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to open lsa account");
+ }
+
+ {
+ struct lsa_GetSystemAccessAccount r;
+ uint32_t access_mask;
+
+ torture_comment(tctx, "Testing LSA GetSystemAccessAccount\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.access_mask = &access_mask;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetSystemAccessAccount_r(lb, tctx, &r),
+ "lsa_GetSystemAccessAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to get lsa system access account");
+ }
+
+ {
+ struct lsa_Close r;
+
+ torture_comment(tctx, "Testing LSA Close\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.handle = &lsa_acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_Close_r(lb, tctx, &r),
+ "lsa_Close failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to close lsa");
+ }
+
+ {
+ struct samr_DeleteUser r;
+
+ torture_comment(tctx, "Testing SAMR DeleteUser\n");
+
+ r.in.user_handle = user_handle;
+ r.out.user_handle = user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, tctx, &r),
+ "DeleteUser failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "DeleteUser failed");
+ }
+
+ {
+ struct lsa_EnumAccounts r;
+ uint32_t resume_handle = 0;
+ struct lsa_SidArray lsa_sid_array;
+ int i;
+ bool found_sid = false;
+
+ torture_comment(tctx, "Testing LSA EnumAccounts\n");
+
+ r.in.handle = lsa_handle;
+ r.in.num_entries = 0x1000;
+ r.in.resume_handle = &resume_handle;
+ r.out.sids = &lsa_sid_array;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(lb, tctx, &r),
+ "lsa_EnumAccounts failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to enum accounts");
+
+ for (i=0; i < lsa_sid_array.num_sids; i++) {
+ if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) {
+ found_sid = true;
+ }
+ }
+
+ torture_assert(tctx, found_sid,
+ "failed to list privileged account");
+ }
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet user_rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &user_rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r),
+ "lsa_EnumAccountRights failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to enum rights for account");
+
+ if (user_rights.count < 1) {
+ torture_result(tctx, TORTURE_FAIL, "failed to find newly added rights");
+ return false;
+ }
+ }
+
+ {
+ struct lsa_OpenAccount r;
+
+ torture_comment(tctx, "Testing LSA OpenAccount\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.acct_handle = &lsa_acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenAccount_r(lb, tctx, &r),
+ "lsa_OpenAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to open lsa account");
+ }
+
+ {
+ struct lsa_GetSystemAccessAccount r;
+ uint32_t access_mask;
+
+ torture_comment(tctx, "Testing LSA GetSystemAccessAccount\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.access_mask = &access_mask;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetSystemAccessAccount_r(lb, tctx, &r),
+ "lsa_GetSystemAccessAccount failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to get lsa system access account");
+ }
+
+ {
+ struct lsa_DeleteObject r;
+
+ torture_comment(tctx, "Testing LSA DeleteObject\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.handle = &lsa_acct_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_DeleteObject_r(lb, tctx, &r),
+ "lsa_DeleteObject failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to delete object");
+ }
+
+ {
+ struct lsa_EnumAccounts r;
+ uint32_t resume_handle = 0;
+ struct lsa_SidArray lsa_sid_array;
+ int i;
+ bool found_sid = false;
+
+ torture_comment(tctx, "Testing LSA EnumAccounts\n");
+
+ r.in.handle = lsa_handle;
+ r.in.num_entries = 0x1000;
+ r.in.resume_handle = &resume_handle;
+ r.out.sids = &lsa_sid_array;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccounts_r(lb, tctx, &r),
+ "lsa_EnumAccounts failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "Failed to enum accounts");
+
+ for (i=0; i < lsa_sid_array.num_sids; i++) {
+ if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) {
+ found_sid = true;
+ }
+ }
+
+ torture_assert(tctx, !found_sid,
+ "should not have listed privileged account");
+ }
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet user_rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &user_rights;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_EnumAccountRights_r(lb, tctx, &r),
+ "lsa_EnumAccountRights failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "Failed to enum rights for account");
+ }
+
+ return ret;
+}
+
+static bool test_user_ops(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle,
+ struct policy_handle *domain_handle,
+ const struct dom_sid *domain_sid,
+ uint32_t base_acct_flags,
+ const char *base_acct_name, enum torture_samr_choice which_ops,
+ struct cli_credentials *machine_credentials)
+{
+ char *password = NULL;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ bool ret = true;
+ int i;
+ uint32_t rid;
+ const uint32_t password_fields[] = {
+ SAMR_FIELD_NT_PASSWORD_PRESENT,
+ SAMR_FIELD_LM_PASSWORD_PRESENT,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT,
+ 0
+ };
+
+ status = test_LookupName(b, tctx, domain_handle, base_acct_name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ }
+
+ switch (which_ops) {
+ case TORTURE_SAMR_USER_ATTRIBUTES:
+ if (!test_QuerySecurity(b, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo(b, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo2(b, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_SetUserInfo(b, tctx, user_handle, base_acct_flags,
+ base_acct_name)) {
+ ret = false;
+ }
+
+ if (!test_GetUserPwInfo(b, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_TestPrivateFunctionsUser(b, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_SetUserPass(p, tctx, user_handle, &password)) {
+ ret = false;
+ }
+ break;
+ case TORTURE_SAMR_PASSWORDS:
+ if (base_acct_flags & (ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST)) {
+ char simple_pass[9];
+ char *v = generate_random_str(tctx, 1);
+
+ ZERO_STRUCT(simple_pass);
+ memset(simple_pass, *v, sizeof(simple_pass) - 1);
+
+ torture_comment(tctx, "Testing machine account password policy rules\n");
+
+ /* Workstation trust accounts don't seem to need to honour password quality policy */
+ if (!test_SetUserPassEx(p, tctx, user_handle, true, &password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser2(p, tctx, base_acct_name, &password, simple_pass, false)) {
+ ret = false;
+ }
+
+ /* reset again, to allow another 'user' password change */
+ if (!test_SetUserPassEx(p, tctx, user_handle, true, &password)) {
+ ret = false;
+ }
+
+ /* Try a 'short' password */
+ if (!test_ChangePasswordUser2(p, tctx, base_acct_name, &password, samr_rand_pass(tctx, 4), false)) {
+ ret = false;
+ }
+
+ /* Try a completely random password */
+ if (!test_ChangePasswordRandomBytes(p, tctx, base_acct_name, user_handle, &password)) {
+ ret = false;
+ }
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_23(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_25(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+
+ if (!test_SetUserPass_31(p, tctx, user_handle, false, &password)) {
+ ret = false;
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_32(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+
+ if (!test_ChangePassword(p, tctx, base_acct_name, domain_handle, &password)) {
+ ret = false;
+ }
+
+ if (!test_SetUserPassEx(p, tctx, user_handle, false, &password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePassword(p, tctx, base_acct_name, domain_handle, &password)) {
+ ret = false;
+ }
+
+ if (!test_SetUserPass_18(p, tctx, user_handle, &password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+
+ if (password_fields[i] == SAMR_FIELD_LM_PASSWORD_PRESENT) {
+ /* we need to skip as that would break
+ * the ChangePasswordUser3 verify */
+ continue;
+ }
+
+ if (!test_SetUserPass_21(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+
+ q.in.user_handle = user_handle;
+ q.in.level = 5;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level %u failed - %s\n",
+ q.in.level, nt_errstr(q.out.result));
+ ret = false;
+ } else {
+ uint32_t expected_flags = (base_acct_flags | ACB_PWNOTREQ | ACB_DISABLED);
+ if ((info->info5.acct_flags) != expected_flags) {
+ /* FIXME: GD */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n",
+ info->info5.acct_flags,
+ expected_flags);
+ ret = false;
+ }
+ }
+ if (info->info5.rid != rid) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 5 failed, it returned %u when we expected rid of %u\n",
+ info->info5.rid, rid);
+
+ }
+ }
+
+ break;
+
+ case TORTURE_SAMR_PASSWORDS_PWDLASTSET:
+
+ /* test last password change timestamp behaviour */
+ torture_assert(tctx, test_SetPassword_pwdlastset(p, tctx, base_acct_flags,
+ base_acct_name,
+ user_handle, &password,
+ machine_credentials),
+ "pwdLastSet test failed\n");
+ break;
+
+ case TORTURE_SAMR_PASSWORDS_BADPWDCOUNT:
+
+ /* test bad pwd count change behaviour */
+ torture_assert(tctx, test_Password_badpwdcount_wrap(p, tctx, base_acct_flags,
+ base_acct_name,
+ domain_handle,
+ user_handle, &password,
+ machine_credentials),
+ "badPwdCount test failed\n");
+ break;
+
+ case TORTURE_SAMR_PASSWORDS_LOCKOUT:
+
+ torture_assert(tctx, test_Password_lockout_wrap(p, tctx, base_acct_flags,
+ base_acct_name,
+ domain_handle,
+ user_handle, &password,
+ machine_credentials),
+ "Lockout test failed");
+ break;
+
+
+ case TORTURE_SAMR_USER_PRIVILEGES: {
+
+ struct dcerpc_pipe *lp;
+ struct policy_handle *lsa_handle;
+ struct dcerpc_binding_handle *lb;
+
+ status = torture_rpc_connection(tctx, &lp, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to open LSA pipe");
+ lb = lp->binding_handle;
+
+ if (!test_lsa_OpenPolicy2(lb, tctx, &lsa_handle)) {
+ ret = false;
+ }
+
+ if (!test_DeleteUser_with_privs(p, lp, tctx,
+ domain_handle, lsa_handle, user_handle,
+ domain_sid, rid,
+ machine_credentials)) {
+ ret = false;
+ }
+
+ if (!test_lsa_Close(lb, tctx, lsa_handle)) {
+ ret = false;
+ }
+
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "privileged user delete test failed\n");
+ }
+
+ break;
+ }
+ case TORTURE_SAMR_OTHER:
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ case TORTURE_SAMR_MANY_GROUPS:
+ case TORTURE_SAMR_MANY_ALIASES:
+ /* We just need the account to exist */
+ break;
+ }
+ return ret;
+}
+
+static bool test_alias_ops(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *alias_handle,
+ const struct dom_sid *domain_sid)
+{
+ bool ret = true;
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (!test_QuerySecurity(b, tctx, alias_handle)) {
+ ret = false;
+ }
+ }
+
+ if (!test_QueryAliasInfo(b, tctx, alias_handle)) {
+ ret = false;
+ }
+
+ if (!test_SetAliasInfo(b, tctx, alias_handle)) {
+ ret = false;
+ }
+
+ if (!test_AddMemberToAlias(b, tctx, alias_handle, domain_sid)) {
+ ret = false;
+ }
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping MultipleMembers Alias tests against Samba\n");
+ return ret;
+ }
+
+ if (!test_AddMultipleMembersToAlias(b, tctx, alias_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static bool test_DeleteUser(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle)
+{
+ struct samr_DeleteUser d;
+ torture_comment(tctx, "Testing DeleteUser\n");
+
+ d.in.user_handle = user_handle;
+ d.out.user_handle = user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, tctx, &d),
+ "DeleteUser failed");
+ torture_assert_ntstatus_ok(tctx, d.out.result, "DeleteUser");
+
+ return true;
+}
+
+bool test_DeleteUser_byname(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *name)
+{
+ NTSTATUS status;
+ struct samr_DeleteUser d;
+ struct policy_handle user_handle;
+ uint32_t rid;
+
+ status = test_LookupName(b, tctx, handle, name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ status = test_OpenUser_byname(b, tctx, handle, name, &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ d.in.user_handle = &user_handle;
+ d.out.user_handle = &user_handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, tctx, &d),
+ "DeleteUser failed");
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ status = d.out.result;
+ goto failed;
+ }
+
+ return true;
+
+failed:
+ torture_result(tctx, TORTURE_FAIL, "DeleteUser_byname(%s) failed - %s\n", name, nt_errstr(status));
+ return false;
+}
+
+
+static bool test_DeleteGroup_byname(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *name)
+{
+ NTSTATUS status;
+ struct samr_OpenGroup r;
+ struct samr_DeleteDomainGroup d;
+ struct policy_handle group_handle;
+ uint32_t rid;
+
+ status = test_LookupName(b, tctx, handle, name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.group_handle = &group_handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenGroup_r(b, tctx, &r),
+ "OpenGroup failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ status = r.out.result;
+ goto failed;
+ }
+
+ d.in.group_handle = &group_handle;
+ d.out.group_handle = &group_handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomainGroup_r(b, tctx, &d),
+ "DeleteDomainGroup failed");
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ status = d.out.result;
+ goto failed;
+ }
+
+ return true;
+
+failed:
+ torture_result(tctx, TORTURE_FAIL, "DeleteGroup_byname(%s) failed - %s\n", name, nt_errstr(status));
+ return false;
+}
+
+
+static bool test_DeleteAlias_byname(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ struct samr_OpenAlias r;
+ struct samr_DeleteDomAlias d;
+ struct policy_handle alias_handle;
+ uint32_t rid;
+
+ torture_comment(tctx, "Testing DeleteAlias_byname\n");
+
+ status = test_LookupName(b, tctx, domain_handle, name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.alias_handle = &alias_handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenAlias_r(b, tctx, &r),
+ "OpenAlias failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ status = r.out.result;
+ goto failed;
+ }
+
+ d.in.alias_handle = &alias_handle;
+ d.out.alias_handle = &alias_handle;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomAlias_r(b, tctx, &d),
+ "DeleteDomAlias failed");
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ status = d.out.result;
+ goto failed;
+ }
+
+ return true;
+
+failed:
+ torture_result(tctx, TORTURE_FAIL, "DeleteAlias_byname(%s) failed - %s\n", name, nt_errstr(status));
+ return false;
+}
+
+static bool test_DeleteAlias(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *alias_handle)
+{
+ struct samr_DeleteDomAlias d;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing DeleteAlias\n");
+
+ d.in.alias_handle = alias_handle;
+ d.out.alias_handle = alias_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomAlias_r(b, tctx, &d),
+ "DeleteDomAlias failed");
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "DeleteAlias failed - %s\n", nt_errstr(d.out.result));
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_CreateAlias(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *alias_name,
+ struct policy_handle *alias_handle,
+ const struct dom_sid *domain_sid,
+ bool test_alias)
+{
+ struct samr_CreateDomAlias r;
+ struct lsa_String name;
+ uint32_t rid;
+ bool ret = true;
+
+ init_lsa_String(&name, alias_name);
+ r.in.domain_handle = domain_handle;
+ r.in.alias_name = &name;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.alias_handle = alias_handle;
+ r.out.rid = &rid;
+
+ torture_comment(tctx, "Testing CreateAlias (%s)\n", r.in.alias_name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomAlias_r(b, tctx, &r),
+ "CreateDomAlias failed");
+
+ if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.alias_name->string);
+ return true;
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "Server should have refused create of '%s', got %s instead\n", r.in.alias_name->string,
+ nt_errstr(r.out.result));
+ return false;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ALIAS_EXISTS)) {
+ if (!test_DeleteAlias_byname(b, tctx, domain_handle, r.in.alias_name->string)) {
+ return false;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomAlias_r(b, tctx, &r),
+ "CreateDomAlias failed");
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "CreateAlias failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!test_alias) {
+ return ret;
+ }
+
+ if (!test_alias_ops(b, tctx, alias_handle, domain_sid)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_ChangePassword(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ const char *acct_name,
+ struct policy_handle *domain_handle, char **password)
+{
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!*password) {
+ return false;
+ }
+
+ if (!test_ChangePasswordUser(b, tctx, acct_name, domain_handle, password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser2(p, tctx, acct_name, password, 0, true)) {
+ ret = false;
+ }
+
+ if (!test_OemChangePasswordUser2(p, tctx, acct_name, domain_handle, password)) {
+ ret = false;
+ }
+
+ /* test what happens when setting the old password again */
+ if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, *password, 0, true)) {
+ ret = false;
+ }
+
+ {
+ char simple_pass[9];
+ char *v = generate_random_str(tctx, 1);
+
+ ZERO_STRUCT(simple_pass);
+ memset(simple_pass, *v, sizeof(simple_pass) - 1);
+
+ /* test what happens when picking a simple password */
+ if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, simple_pass, 0, true)) {
+ ret = false;
+ }
+ }
+
+ /* set samr_SetDomainInfo level 1 with min_length 5 */
+ {
+ struct samr_QueryDomainInfo r;
+ union samr_DomainInfo *info = NULL;
+ struct samr_SetDomainInfo s;
+ uint16_t len_old, len;
+ uint32_t pwd_prop_old;
+ int64_t min_pwd_age_old;
+
+ len = 5;
+
+ r.in.domain_handle = domain_handle;
+ r.in.level = 1;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing samr_QueryDomainInfo level 1\n");
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r),
+ "QueryDomainInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ return false;
+ }
+
+ s.in.domain_handle = domain_handle;
+ s.in.level = 1;
+ s.in.info = info;
+
+ /* remember the old min length, so we can reset it */
+ len_old = s.in.info->info1.min_password_length;
+ s.in.info->info1.min_password_length = len;
+ pwd_prop_old = s.in.info->info1.password_properties;
+ /* turn off password complexity checks for this test */
+ s.in.info->info1.password_properties &= ~DOMAIN_PASSWORD_COMPLEX;
+
+ min_pwd_age_old = s.in.info->info1.min_password_age;
+ s.in.info->info1.min_password_age = 0;
+
+ torture_comment(tctx, "Testing samr_SetDomainInfo level 1\n");
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s),
+ "SetDomainInfo failed");
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ return false;
+ }
+
+ torture_comment(tctx, "calling test_ChangePasswordUser3 with too short password\n");
+
+ if (!test_ChangePasswordUser3(p, tctx, acct_name, len - 1, password, NULL, 0, true)) {
+ ret = false;
+ }
+
+ s.in.info->info1.min_password_length = len_old;
+ s.in.info->info1.password_properties = pwd_prop_old;
+ s.in.info->info1.min_password_age = min_pwd_age_old;
+
+ torture_comment(tctx, "Testing samr_SetDomainInfo level 1\n");
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s),
+ "SetDomainInfo failed");
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ return false;
+ }
+
+ }
+
+ {
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ struct samr_LookupNames n;
+ struct policy_handle user_handle;
+ struct samr_Ids rids, types;
+
+ n.in.domain_handle = domain_handle;
+ n.in.num_names = 1;
+ n.in.names = talloc_array(tctx, struct lsa_String, 1);
+ n.in.names[0].string = acct_name;
+ n.out.rids = &rids;
+ n.out.types = &types;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupNames_r(b, tctx, &n),
+ "LookupNames failed");
+ if (!NT_STATUS_IS_OK(n.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "LookupNames failed - %s\n", nt_errstr(n.out.result));
+ return false;
+ }
+
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = n.out.rids->ids[0];
+ r.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
+ "OpenUser failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenUser(%u) failed - %s\n", n.out.rids->ids[0], nt_errstr(r.out.result));
+ return false;
+ }
+
+ q.in.user_handle = &user_handle;
+ q.in.level = 5;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo failed - %s\n", nt_errstr(q.out.result));
+ return false;
+ }
+
+ torture_comment(tctx, "calling test_ChangePasswordUser3 with too early password change\n");
+
+ if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, NULL,
+ info->info5.last_password_change, true)) {
+ ret = false;
+ }
+ }
+
+ /* we change passwords twice - this has the effect of verifying
+ they were changed correctly for the final call */
+ if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, NULL, 0, true)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser3(p, tctx, acct_name, 0, password, NULL, 0, true)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser4(p, tctx, acct_name, 0, password, NULL)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_CreateUser(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *user_name,
+ struct policy_handle *user_handle_out,
+ struct dom_sid *domain_sid,
+ enum torture_samr_choice which_ops,
+ struct cli_credentials *machine_credentials,
+ bool test_user)
+{
+
+ TALLOC_CTX *user_ctx;
+
+ struct samr_CreateUser r;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ struct samr_DeleteUser d;
+ uint32_t rid;
+
+ /* This call creates a 'normal' account - check that it really does */
+ const uint32_t acct_flags = ACB_NORMAL;
+ struct lsa_String name;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct policy_handle user_handle;
+ user_ctx = talloc_named(tctx, 0, "test_CreateUser2 per-user context");
+ init_lsa_String(&name, user_name);
+
+ r.in.domain_handle = domain_handle;
+ r.in.account_name = &name;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.user_handle = &user_handle;
+ r.out.rid = &rid;
+
+ torture_comment(tctx, "Testing CreateUser(%s)\n", r.in.account_name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser_r(b, user_ctx, &r),
+ "CreateUser failed");
+
+ if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.account_name->string);
+ return true;
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "Server should have refused create of '%s', got %s instead\n", r.in.account_name->string,
+ nt_errstr(r.out.result));
+ return false;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) {
+ if (!test_DeleteUser_byname(b, tctx, domain_handle, r.in.account_name->string)) {
+ talloc_free(user_ctx);
+ return false;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser_r(b, user_ctx, &r),
+ "CreateUser failed");
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ talloc_free(user_ctx);
+ torture_result(tctx, TORTURE_FAIL, "CreateUser failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!test_user) {
+ if (user_handle_out) {
+ *user_handle_out = user_handle;
+ }
+ return ret;
+ }
+
+ {
+ q.in.user_handle = &user_handle;
+ q.in.level = 16;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, user_ctx, &q),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level %u failed - %s\n",
+ q.in.level, nt_errstr(q.out.result));
+ ret = false;
+ } else {
+ if ((info->info16.acct_flags & acct_flags) != acct_flags) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 16 failed, it returned 0x%08x when we expected flags of 0x%08x\n",
+ info->info16.acct_flags,
+ acct_flags);
+ ret = false;
+ }
+ }
+
+ if (!test_user_ops(p, tctx, &user_handle, domain_handle,
+ domain_sid, acct_flags, name.string, which_ops,
+ machine_credentials)) {
+ ret = false;
+ }
+
+ if (user_handle_out) {
+ *user_handle_out = user_handle;
+ } else {
+ torture_comment(tctx, "Testing DeleteUser (createuser test)\n");
+
+ d.in.user_handle = &user_handle;
+ d.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, user_ctx, &d),
+ "DeleteUser failed");
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "DeleteUser failed - %s\n", nt_errstr(d.out.result));
+ ret = false;
+ }
+ }
+
+ }
+
+ talloc_free(user_ctx);
+
+ return ret;
+}
+
+
+static bool test_CreateUser2(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid *domain_sid,
+ enum torture_samr_choice which_ops,
+ struct cli_credentials *machine_credentials)
+{
+ struct samr_CreateUser2 r;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ struct samr_DeleteUser d;
+ struct policy_handle user_handle;
+ uint32_t rid;
+ struct lsa_String name;
+ bool ret = true;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct {
+ uint32_t acct_flags;
+ const char *account_name;
+ NTSTATUS nt_status;
+ } account_types[] = {
+ { ACB_NORMAL, TEST_ACCOUNT_NAME, NT_STATUS_OK },
+ { ACB_NORMAL | ACB_DISABLED, TEST_ACCOUNT_NAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_NORMAL | ACB_PWNOEXP, TEST_ACCOUNT_NAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_WSTRUST, TEST_MACHINENAME, NT_STATUS_OK },
+ { ACB_WSTRUST | ACB_DISABLED, TEST_MACHINENAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_WSTRUST | ACB_PWNOEXP, TEST_MACHINENAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_SVRTRUST, TEST_MACHINENAME, NT_STATUS_OK },
+ { ACB_SVRTRUST | ACB_DISABLED, TEST_MACHINENAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_SVRTRUST | ACB_PWNOEXP, TEST_MACHINENAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_DOMTRUST, TEST_DOMAINNAME, NT_STATUS_ACCESS_DENIED },
+ { ACB_DOMTRUST | ACB_DISABLED, TEST_DOMAINNAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_DOMTRUST | ACB_PWNOEXP, TEST_DOMAINNAME, NT_STATUS_INVALID_PARAMETER },
+ { 0, TEST_ACCOUNT_NAME, NT_STATUS_INVALID_PARAMETER },
+ { ACB_DISABLED, TEST_ACCOUNT_NAME, NT_STATUS_INVALID_PARAMETER },
+ { 0, NULL, NT_STATUS_INVALID_PARAMETER }
+ };
+
+ for (i = 0; account_types[i].account_name; i++) {
+ TALLOC_CTX *user_ctx;
+ uint32_t acct_flags = account_types[i].acct_flags;
+ uint32_t access_granted;
+ user_ctx = talloc_named(tctx, 0, "test_CreateUser2 per-user context");
+ init_lsa_String(&name, account_types[i].account_name);
+
+ r.in.domain_handle = domain_handle;
+ r.in.account_name = &name;
+ r.in.acct_flags = acct_flags;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.user_handle = &user_handle;
+ r.out.access_granted = &access_granted;
+ r.out.rid = &rid;
+
+ torture_comment(tctx, "Testing CreateUser2(%s, 0x%x)\n", r.in.account_name->string, acct_flags);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser2_r(b, user_ctx, &r),
+ "CreateUser2 failed");
+
+ if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.account_name->string);
+ continue;
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "Server should have refused create of '%s', got %s instead\n", r.in.account_name->string,
+ nt_errstr(r.out.result));
+ ret = false;
+ continue;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) {
+ if (!test_DeleteUser_byname(b, tctx, domain_handle, r.in.account_name->string)) {
+ talloc_free(user_ctx);
+ ret = false;
+ continue;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateUser2_r(b, user_ctx, &r),
+ "CreateUser2 failed");
+
+ }
+ if (!NT_STATUS_EQUAL(r.out.result, account_types[i].nt_status)) {
+ torture_result(tctx, TORTURE_FAIL, "CreateUser2 failed gave incorrect error return - %s (should be %s)\n",
+ nt_errstr(r.out.result), nt_errstr(account_types[i].nt_status));
+ ret = false;
+ }
+
+ if (NT_STATUS_IS_OK(r.out.result)) {
+ q.in.user_handle = &user_handle;
+ q.in.level = 5;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, user_ctx, &q),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level %u failed - %s\n",
+ q.in.level, nt_errstr(q.out.result));
+ ret = false;
+ } else {
+ uint32_t expected_flags = (acct_flags | ACB_PWNOTREQ | ACB_DISABLED);
+ if (acct_flags == ACB_NORMAL) {
+ expected_flags |= ACB_PW_EXPIRED;
+ }
+ if ((info->info5.acct_flags) != expected_flags) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n",
+ info->info5.acct_flags,
+ expected_flags);
+ ret = false;
+ }
+ switch (acct_flags) {
+ case ACB_SVRTRUST:
+ if (info->info5.primary_gid != DOMAIN_RID_DCS) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 5: DC should have had Primary Group %d, got %d\n",
+ DOMAIN_RID_DCS, info->info5.primary_gid);
+ ret = false;
+ }
+ break;
+ case ACB_WSTRUST:
+ if (info->info5.primary_gid != DOMAIN_RID_DOMAIN_MEMBERS) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 5: Domain Member should have had Primary Group %d, got %d\n",
+ DOMAIN_RID_DOMAIN_MEMBERS, info->info5.primary_gid);
+ ret = false;
+ }
+ break;
+ case ACB_NORMAL:
+ if (info->info5.primary_gid != DOMAIN_RID_USERS) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 5: Users should have had Primary Group %d, got %d\n",
+ DOMAIN_RID_USERS, info->info5.primary_gid);
+ ret = false;
+ }
+ break;
+ }
+ }
+
+ if (!test_user_ops(p, tctx, &user_handle, domain_handle,
+ domain_sid, acct_flags, name.string, which_ops,
+ machine_credentials)) {
+ ret = false;
+ }
+
+ if (!ndr_policy_handle_empty(&user_handle)) {
+ torture_comment(tctx, "Testing DeleteUser (createuser2 test)\n");
+
+ d.in.user_handle = &user_handle;
+ d.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteUser_r(b, user_ctx, &d),
+ "DeleteUser failed");
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "DeleteUser failed - %s\n", nt_errstr(d.out.result));
+ ret = false;
+ }
+ }
+ }
+ talloc_free(user_ctx);
+ }
+
+ return ret;
+}
+
+static bool test_QueryAliasInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryAliasInfo r;
+ union samr_AliasInfo *info;
+ uint16_t levels[] = {1, 2, 3};
+ int i;
+ bool ret = true;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryAliasInfo level %u\n", levels[i]);
+
+ r.in.alias_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryAliasInfo_r(b, tctx, &r),
+ "QueryAliasInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryAliasInfo level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryGroupInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryGroupInfo r;
+ union samr_GroupInfo *info;
+ uint16_t levels[] = {1, 2, 3, 4, 5};
+ int i;
+ bool ret = true;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryGroupInfo level %u\n", levels[i]);
+
+ r.in.group_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupInfo_r(b, tctx, &r),
+ "QueryGroupInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryGroupInfo level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryGroupMember(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryGroupMember r;
+ struct samr_RidAttrArray *rids = NULL;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing QueryGroupMember\n");
+
+ r.in.group_handle = handle;
+ r.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &r),
+ "QueryGroupMember failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryGroupMember failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static bool test_SetGroupInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryGroupInfo r;
+ union samr_GroupInfo *info;
+ struct samr_SetGroupInfo s;
+ uint16_t levels[] = {1, 2, 3, 4};
+ uint16_t set_ok[] = {0, 1, 1, 1};
+ int i;
+ bool ret = true;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryGroupInfo level %u\n", levels[i]);
+
+ r.in.group_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupInfo_r(b, tctx, &r),
+ "QueryGroupInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryGroupInfo level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ torture_comment(tctx, "Testing SetGroupInfo level %u\n", levels[i]);
+
+ s.in.group_handle = handle;
+ s.in.level = levels[i];
+ s.in.info = *r.out.info;
+
+#if 0
+ /* disabled this, as it changes the name only from the point of view of samr,
+ but leaves the name from the point of view of w2k3 internals (and ldap). This means
+ the name is still reserved, so creating the old name fails, but deleting by the old name
+ also fails */
+ if (s.in.level == 2) {
+ init_lsa_String(&s.in.info->string, "NewName");
+ }
+#endif
+
+ if (s.in.level == 4) {
+ init_lsa_String(&s.in.info->description, "test description");
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetGroupInfo_r(b, tctx, &s),
+ "SetGroupInfo failed");
+ if (set_ok[i]) {
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetGroupInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(s.out.result));
+ ret = false;
+ continue;
+ }
+ } else {
+ if (!NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetGroupInfo level %u gave %s - should have been NT_STATUS_INVALID_INFO_CLASS\n",
+ r.in.level, nt_errstr(s.out.result));
+ ret = false;
+ continue;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryUserInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryUserInfo r;
+ union samr_UserInfo *info;
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 16, 17, 20, 21};
+ int i;
+ bool ret = true;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryUserInfo level %u\n", levels[i]);
+
+ r.in.user_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryUserInfo2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryUserInfo2 r;
+ union samr_UserInfo *info;
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 16, 17, 20, 21};
+ int i;
+ bool ret = true;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryUserInfo2 level %u\n", levels[i]);
+
+ r.in.user_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo2_r(b, tctx, &r),
+ "QueryUserInfo2 failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo2 level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_OpenUser(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t rid)
+{
+ struct samr_OpenUser r;
+ struct policy_handle user_handle;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing OpenUser(%u)\n", rid);
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
+ "OpenUser failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenUser(%u) failed - %s\n", rid, nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!test_QuerySecurity(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo2(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ if (!test_GetUserPwInfo(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ if (!test_GetGroupsForUser(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ if (!test_samr_handle_Close(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_OpenGroup(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t rid)
+{
+ struct samr_OpenGroup r;
+ struct policy_handle group_handle;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing OpenGroup(%u)\n", rid);
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.group_handle = &group_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenGroup_r(b, tctx, &r),
+ "OpenGroup failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenGroup(%u) failed - %s\n", rid, nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (!test_QuerySecurity(b, tctx, &group_handle)) {
+ ret = false;
+ }
+ }
+
+ if (!test_QueryGroupInfo(b, tctx, &group_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryGroupMember(b, tctx, &group_handle)) {
+ ret = false;
+ }
+
+ if (!test_samr_handle_Close(b, tctx, &group_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_OpenAlias(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t rid)
+{
+ struct samr_OpenAlias r;
+ struct policy_handle alias_handle;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing OpenAlias(%u)\n", rid);
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.alias_handle = &alias_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenAlias_r(b, tctx, &r),
+ "OpenAlias failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenAlias(%u) failed - %s\n", rid, nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (!test_QuerySecurity(b, tctx, &alias_handle)) {
+ ret = false;
+ }
+ }
+
+ if (!test_QueryAliasInfo(b, tctx, &alias_handle)) {
+ ret = false;
+ }
+
+ if (!test_GetMembersInAlias(b, tctx, &alias_handle)) {
+ ret = false;
+ }
+
+ if (!test_samr_handle_Close(b, tctx, &alias_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool check_mask(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, uint32_t rid,
+ uint32_t acct_flag_mask)
+{
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ struct policy_handle user_handle;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing OpenUser(%u)\n", rid);
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
+ "OpenUser failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenUser(%u) failed - %s\n", rid, nt_errstr(r.out.result));
+ return false;
+ }
+
+ q.in.user_handle = &user_handle;
+ q.in.level = 16;
+ q.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo level 16 failed - %s\n",
+ nt_errstr(q.out.result));
+ ret = false;
+ } else {
+ if ((acct_flag_mask & info->info16.acct_flags) == 0) {
+ torture_result(tctx, TORTURE_FAIL, "Server failed to filter for 0x%x, allowed 0x%x (%d) on EnumDomainUsers\n",
+ acct_flag_mask, info->info16.acct_flags, rid);
+ ret = false;
+ }
+ }
+
+ if (!test_samr_handle_Close(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_EnumDomainUsers_all(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_EnumDomainUsers r;
+ uint32_t mask, resume_handle=0;
+ int i, mask_idx;
+ bool ret = true;
+ struct samr_LookupNames n;
+ struct samr_LookupRids lr ;
+ struct lsa_Strings names;
+ struct samr_Ids rids, types;
+ struct samr_SamArray *sam = NULL;
+ uint32_t num_entries = 0;
+
+ uint32_t masks[] = {ACB_NORMAL, ACB_DOMTRUST, ACB_WSTRUST,
+ ACB_DISABLED, ACB_NORMAL | ACB_DISABLED,
+ ACB_SVRTRUST | ACB_DOMTRUST | ACB_WSTRUST,
+ ACB_PWNOEXP, 0};
+
+ torture_comment(tctx, "Testing EnumDomainUsers\n");
+
+ for (mask_idx=0;mask_idx<ARRAY_SIZE(masks);mask_idx++) {
+ r.in.domain_handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.acct_flags = mask = masks[mask_idx];
+ r.in.max_size = (uint32_t)-1;
+ r.out.resume_handle = &resume_handle;
+ r.out.num_entries = &num_entries;
+ r.out.sam = &sam;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainUsers_r(b, tctx, &r),
+ "EnumDomainUsers failed");
+ if (!NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) &&
+ !NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "EnumDomainUsers failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ torture_assert(tctx, sam, "EnumDomainUsers failed: r.out.sam unexpectedly NULL");
+
+ if (sam->count == 0) {
+ continue;
+ }
+
+ for (i=0;i<sam->count;i++) {
+ if (mask) {
+ if (!check_mask(b, tctx, handle, sam->entries[i].idx, mask)) {
+ ret = false;
+ }
+ } else if (!test_OpenUser(b, tctx, handle, sam->entries[i].idx)) {
+ ret = false;
+ }
+ }
+ }
+
+ torture_comment(tctx, "Testing LookupNames\n");
+ n.in.domain_handle = handle;
+ n.in.num_names = sam->count;
+ n.in.names = talloc_array(tctx, struct lsa_String, sam->count);
+ n.out.rids = &rids;
+ n.out.types = &types;
+ for (i=0;i<sam->count;i++) {
+ n.in.names[i].string = sam->entries[i].name.string;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupNames_r(b, tctx, &n),
+ "LookupNames failed");
+ if (!NT_STATUS_IS_OK(n.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "LookupNames failed - %s\n", nt_errstr(n.out.result));
+ ret = false;
+ }
+
+
+ torture_comment(tctx, "Testing LookupRids\n");
+ lr.in.domain_handle = handle;
+ lr.in.num_rids = sam->count;
+ lr.in.rids = talloc_array(tctx, uint32_t, sam->count);
+ lr.out.names = &names;
+ lr.out.types = &types;
+ for (i=0;i<sam->count;i++) {
+ lr.in.rids[i] = sam->entries[i].idx;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupRids_r(b, tctx, &lr),
+ "LookupRids failed");
+ torture_assert_ntstatus_ok(tctx, lr.out.result, "LookupRids");
+
+ return ret;
+}
+
+/*
+ try blasting the server with a bunch of sync requests
+*/
+static bool test_EnumDomainUsers_async(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_EnumDomainUsers r;
+ uint32_t resume_handle=0;
+ int i;
+#define ASYNC_COUNT 100
+ struct tevent_req *req[ASYNC_COUNT];
+
+ if (!torture_setting_bool(tctx, "dangerous", false)) {
+ torture_skip(tctx, "samr async test disabled - enable dangerous tests to use\n");
+ }
+
+ torture_comment(tctx, "Testing EnumDomainUsers_async\n");
+
+ r.in.domain_handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.acct_flags = 0;
+ r.in.max_size = (uint32_t)-1;
+ r.out.resume_handle = &resume_handle;
+
+ for (i=0;i<ASYNC_COUNT;i++) {
+ req[i] = dcerpc_samr_EnumDomainUsers_r_send(tctx, tctx->ev, p->binding_handle, &r);
+ }
+
+ for (i=0;i<ASYNC_COUNT;i++) {
+ tevent_req_poll(req[i], tctx->ev);
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainUsers_r_recv(req[i], tctx),
+ talloc_asprintf(tctx, "EnumDomainUsers[%d] failed - %s\n",
+ i, nt_errstr(r.out.result)));
+ }
+
+ torture_comment(tctx, "%d async requests OK\n", i);
+
+ return true;
+}
+
+static bool test_EnumDomainGroups_all(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_EnumDomainGroups r;
+ uint32_t resume_handle=0;
+ struct samr_SamArray *sam = NULL;
+ uint32_t num_entries = 0;
+ int i;
+ bool ret = true;
+ bool universal_group_found = false;
+
+ torture_comment(tctx, "Testing EnumDomainGroups\n");
+
+ r.in.domain_handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.max_size = (uint32_t)-1;
+ r.out.resume_handle = &resume_handle;
+ r.out.num_entries = &num_entries;
+ r.out.sam = &sam;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r),
+ "EnumDomainGroups failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "EnumDomainGroups failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!sam) {
+ return false;
+ }
+
+ for (i=0;i<sam->count;i++) {
+ if (!test_OpenGroup(b, tctx, handle, sam->entries[i].idx)) {
+ ret = false;
+ }
+ if ((ret == true) && (strcasecmp(sam->entries[i].name.string,
+ "Enterprise Admins") == 0)) {
+ universal_group_found = true;
+ }
+ }
+
+ /* when we are running this on s4 we should get back at least the
+ * "Enterprise Admins" universal group. If we don't get a group entry
+ * at all we probably are performing the test on the builtin domain.
+ * So ignore this case. */
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ if ((sam->count > 0) && (!universal_group_found)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_EnumDomainAliases_all(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_EnumDomainAliases r;
+ uint32_t resume_handle=0;
+ struct samr_SamArray *sam = NULL;
+ uint32_t num_entries = 0;
+ int i;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing EnumDomainAliases\n");
+
+ r.in.domain_handle = handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.max_size = (uint32_t)-1;
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r),
+ "EnumDomainAliases failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "EnumDomainAliases failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ }
+
+ if (!sam) {
+ return false;
+ }
+
+ for (i=0;i<sam->count;i++) {
+ if (!test_OpenAlias(b, tctx, handle, sam->entries[i].idx)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_GetDisplayEnumerationIndex(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_GetDisplayEnumerationIndex r;
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5};
+ uint16_t ok_lvl[] = {1, 1, 1, 0, 0};
+ struct lsa_String name;
+ uint32_t idx = 0;
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing GetDisplayEnumerationIndex level %u\n", levels[i]);
+
+ init_lsa_String(&name, TEST_ACCOUNT_NAME);
+
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.in.name = &name;
+ r.out.idx = &idx;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDisplayEnumerationIndex_r(b, tctx, &r),
+ "GetDisplayEnumerationIndex failed");
+
+ if (ok_lvl[i] &&
+ !NT_STATUS_IS_OK(r.out.result) &&
+ !NT_STATUS_EQUAL(NT_STATUS_NO_MORE_ENTRIES, r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "GetDisplayEnumerationIndex level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ init_lsa_String(&name, "zzzzzzzz");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDisplayEnumerationIndex_r(b, tctx, &r),
+ "GetDisplayEnumerationIndex failed");
+
+ if (ok_lvl[i] && !NT_STATUS_EQUAL(NT_STATUS_NO_MORE_ENTRIES, r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "GetDisplayEnumerationIndex level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_GetDisplayEnumerationIndex2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_GetDisplayEnumerationIndex2 r;
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5};
+ uint16_t ok_lvl[] = {1, 1, 1, 0, 0};
+ struct lsa_String name;
+ uint32_t idx = 0;
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing GetDisplayEnumerationIndex2 level %u\n", levels[i]);
+
+ init_lsa_String(&name, TEST_ACCOUNT_NAME);
+
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.in.name = &name;
+ r.out.idx = &idx;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDisplayEnumerationIndex2_r(b, tctx, &r),
+ "GetDisplayEnumerationIndex2 failed");
+ if (ok_lvl[i] &&
+ !NT_STATUS_IS_OK(r.out.result) &&
+ !NT_STATUS_EQUAL(NT_STATUS_NO_MORE_ENTRIES, r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "GetDisplayEnumerationIndex2 level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ init_lsa_String(&name, "zzzzzzzz");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDisplayEnumerationIndex2_r(b, tctx, &r),
+ "GetDisplayEnumerationIndex2 failed");
+ if (ok_lvl[i] && !NT_STATUS_EQUAL(NT_STATUS_NO_MORE_ENTRIES, r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "GetDisplayEnumerationIndex2 level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+#define STRING_EQUAL_QUERY(s1, s2, user) \
+ if (s1.string == NULL && s2.string != NULL && s2.string[0] == '\0') { \
+ /* odd, but valid */ \
+ } else if ((s1.string && !s2.string) || (s2.string && !s1.string) || strcmp(s1.string, s2.string)) { \
+ torture_result(tctx, TORTURE_FAIL, "%s mismatch for %s: %s != %s (%s)\n", \
+ #s1, user.string, s1.string, s2.string, __location__); \
+ ret = false; \
+ }
+#define INT_EQUAL_QUERY(s1, s2, user) \
+ if (s1 != s2) { \
+ torture_result(tctx, TORTURE_FAIL, "%s mismatch for %s: 0x%llx != 0x%llx (%s)\n", \
+ #s1, user.string, (unsigned long long)s1, (unsigned long long)s2, __location__); \
+ ret = false; \
+ }
+
+static bool test_each_DisplayInfo_user(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct samr_QueryDisplayInfo *querydisplayinfo,
+ bool *seen_testuser)
+{
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ struct policy_handle user_handle;
+ int i, ret = true;
+ r.in.domain_handle = querydisplayinfo->in.domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ for (i = 0; ; i++) {
+ switch (querydisplayinfo->in.level) {
+ case 1:
+ if (i >= querydisplayinfo->out.info->info1.count) {
+ return ret;
+ }
+ r.in.rid = querydisplayinfo->out.info->info1.entries[i].rid;
+ break;
+ case 2:
+ if (i >= querydisplayinfo->out.info->info2.count) {
+ return ret;
+ }
+ r.in.rid = querydisplayinfo->out.info->info2.entries[i].rid;
+ break;
+ case 3:
+ /* Groups */
+ case 4:
+ case 5:
+ /* Not interested in validating just the account name */
+ return true;
+ }
+
+ r.out.user_handle = &user_handle;
+
+ switch (querydisplayinfo->in.level) {
+ case 1:
+ case 2:
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
+ "OpenUser failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "OpenUser(%u) failed - %s\n", r.in.rid, nt_errstr(r.out.result));
+ return false;
+ }
+ }
+
+ q.in.user_handle = &user_handle;
+ q.in.level = 21;
+ q.out.info = &info;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &q),
+ "QueryUserInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryUserInfo(%u) failed - %s\n", r.in.rid, nt_errstr(r.out.result));
+ return false;
+ }
+
+ switch (querydisplayinfo->in.level) {
+ case 1:
+ if (seen_testuser && strcmp(info->info21.account_name.string, TEST_ACCOUNT_NAME) == 0) {
+ *seen_testuser = true;
+ }
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info->info1.entries[i].full_name,
+ info->info21.full_name, info->info21.account_name);
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info->info1.entries[i].account_name,
+ info->info21.account_name, info->info21.account_name);
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info->info1.entries[i].description,
+ info->info21.description, info->info21.account_name);
+ INT_EQUAL_QUERY(querydisplayinfo->out.info->info1.entries[i].rid,
+ info->info21.rid, info->info21.account_name);
+ INT_EQUAL_QUERY(querydisplayinfo->out.info->info1.entries[i].acct_flags,
+ info->info21.acct_flags, info->info21.account_name);
+
+ break;
+ case 2:
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info->info2.entries[i].account_name,
+ info->info21.account_name, info->info21.account_name);
+ STRING_EQUAL_QUERY(querydisplayinfo->out.info->info2.entries[i].description,
+ info->info21.description, info->info21.account_name);
+ INT_EQUAL_QUERY(querydisplayinfo->out.info->info2.entries[i].rid,
+ info->info21.rid, info->info21.account_name);
+ INT_EQUAL_QUERY((querydisplayinfo->out.info->info2.entries[i].acct_flags & ~ACB_NORMAL),
+ info->info21.acct_flags, info->info21.account_name);
+
+ if (!(querydisplayinfo->out.info->info2.entries[i].acct_flags & ACB_NORMAL)) {
+ torture_result(tctx, TORTURE_FAIL, "Missing ACB_NORMAL in querydisplayinfo->out.info.info2.entries[i].acct_flags on %s\n",
+ info->info21.account_name.string);
+ }
+
+ if (!(info->info21.acct_flags & (ACB_WSTRUST | ACB_SVRTRUST))) {
+ torture_result(tctx, TORTURE_FAIL, "Found non-trust account %s in trust account listing: 0x%x 0x%x\n",
+ info->info21.account_name.string,
+ querydisplayinfo->out.info->info2.entries[i].acct_flags,
+ info->info21.acct_flags);
+ return false;
+ }
+
+ break;
+ }
+
+ if (!test_samr_handle_Close(b, tctx, &user_handle)) {
+ return false;
+ }
+ }
+ return ret;
+}
+
+static bool test_QueryDisplayInfo(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryDisplayInfo r;
+ struct samr_QueryDomainInfo dom_info;
+ union samr_DomainInfo *info = NULL;
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5};
+ int i;
+ bool seen_testuser = false;
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo disp_info;
+
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryDisplayInfo level %u\n", levels[i]);
+
+ r.in.start_idx = 0;
+ r.out.result = STATUS_MORE_ENTRIES;
+ while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES)) {
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.in.max_entries = 2;
+ r.in.buf_size = (uint32_t)-1;
+ r.out.total_size = &total_size;
+ r.out.returned_size = &returned_size;
+ r.out.info = &disp_info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r),
+ "QueryDisplayInfo failed");
+ if (!NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) && !NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDisplayInfo level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ switch (r.in.level) {
+ case 1:
+ if (!test_each_DisplayInfo_user(b, tctx, &r, &seen_testuser)) {
+ ret = false;
+ }
+ r.in.start_idx += r.out.info->info1.count;
+ break;
+ case 2:
+ if (!test_each_DisplayInfo_user(b, tctx, &r, NULL)) {
+ ret = false;
+ }
+ r.in.start_idx += r.out.info->info2.count;
+ break;
+ case 3:
+ r.in.start_idx += r.out.info->info3.count;
+ break;
+ case 4:
+ r.in.start_idx += r.out.info->info4.count;
+ break;
+ case 5:
+ r.in.start_idx += r.out.info->info5.count;
+ break;
+ }
+ }
+ dom_info.in.domain_handle = handle;
+ dom_info.in.level = 2;
+ dom_info.out.info = &info;
+
+ /* Check number of users returned is correct */
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &dom_info),
+ "QueryDomainInfo failed");
+ if (!NT_STATUS_IS_OK(dom_info.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(dom_info.out.result));
+ ret = false;
+ break;
+ }
+ switch (r.in.level) {
+ case 1:
+ case 4:
+ if (info->general.num_users < r.in.start_idx) {
+ /* On AD deployments this numbers don't match
+ * since QueryDisplayInfo returns universal and
+ * global groups, QueryDomainInfo only global
+ * ones. */
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo indicates that QueryDisplayInfo returned more users (%d/%d) than the domain %s is said to contain!\n",
+ r.in.start_idx, info->general.num_groups,
+ info->general.domain_name.string);
+ ret = false;
+ }
+ }
+ if (!seen_testuser) {
+ struct policy_handle user_handle;
+ if (NT_STATUS_IS_OK(test_OpenUser_byname(b, tctx, handle, TEST_ACCOUNT_NAME, &user_handle))) {
+ torture_result(tctx, TORTURE_FAIL, "Didn't find test user " TEST_ACCOUNT_NAME " in enumeration of %s\n",
+ info->general.domain_name.string);
+ ret = false;
+ test_samr_handle_Close(b, tctx, &user_handle);
+ }
+ }
+ break;
+ case 3:
+ case 5:
+ if (info->general.num_groups != r.in.start_idx) {
+ /* On AD deployments this numbers don't match
+ * since QueryDisplayInfo returns universal and
+ * global groups, QueryDomainInfo only global
+ * ones. */
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo indicates that QueryDisplayInfo didn't return all (%d/%d) the groups in %s\n",
+ r.in.start_idx, info->general.num_groups,
+ info->general.domain_name.string);
+ ret = false;
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ return ret;
+}
+
+static bool test_QueryDisplayInfo2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryDisplayInfo2 r;
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5};
+ int i;
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryDisplayInfo2 level %u\n", levels[i]);
+
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.in.start_idx = 0;
+ r.in.max_entries = 1000;
+ r.in.buf_size = (uint32_t)-1;
+ r.out.total_size = &total_size;
+ r.out.returned_size = &returned_size;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo2_r(b, tctx, &r),
+ "QueryDisplayInfo2 failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDisplayInfo2 level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_QueryDisplayInfo3(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryDisplayInfo3 r;
+ bool ret = true;
+ uint16_t levels[] = {1, 2, 3, 4, 5};
+ int i;
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryDisplayInfo3 level %u\n", levels[i]);
+
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.in.start_idx = 0;
+ r.in.max_entries = 1000;
+ r.in.buf_size = (uint32_t)-1;
+ r.out.total_size = &total_size;
+ r.out.returned_size = &returned_size;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo3_r(b, tctx, &r),
+ "QueryDisplayInfo3 failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDisplayInfo3 level %u failed - %s\n",
+ levels[i], nt_errstr(r.out.result));
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+
+static bool test_QueryDisplayInfo_continue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryDisplayInfo r;
+ bool ret = true;
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo info;
+
+ torture_comment(tctx, "Testing QueryDisplayInfo continuation\n");
+
+ r.in.domain_handle = handle;
+ r.in.level = 1;
+ r.in.start_idx = 0;
+ r.in.max_entries = 1;
+ r.in.buf_size = (uint32_t)-1;
+ r.out.total_size = &total_size;
+ r.out.returned_size = &returned_size;
+ r.out.info = &info;
+
+ do {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r),
+ "QueryDisplayInfo failed");
+ if (NT_STATUS_IS_OK(r.out.result) && *r.out.returned_size != 0) {
+ if (r.out.info->info1.entries[0].idx != r.in.start_idx + 1) {
+ torture_result(tctx, TORTURE_FAIL, "expected idx %d but got %d\n",
+ r.in.start_idx + 1,
+ r.out.info->info1.entries[0].idx);
+ break;
+ }
+ }
+ if (!NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) &&
+ !NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDisplayInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(r.out.result));
+ ret = false;
+ break;
+ }
+ r.in.start_idx++;
+ } while ((NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) ||
+ NT_STATUS_IS_OK(r.out.result)) &&
+ *r.out.returned_size != 0);
+
+ return ret;
+}
+
+static bool test_QueryDomainInfo(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryDomainInfo r;
+ union samr_DomainInfo *info = NULL;
+ struct samr_SetDomainInfo s;
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13};
+ uint16_t set_ok[] = {1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0};
+ int i;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *domain_comment = talloc_asprintf(tctx,
+ "Tortured by Samba4 RPC-SAMR: %s",
+ timestring(tctx, time(NULL)));
+
+ s.in.domain_handle = handle;
+ s.in.level = 4;
+ s.in.info = talloc(tctx, union samr_DomainInfo);
+
+ s.in.info->oem.oem_information.string = domain_comment;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s),
+ "SetDomainInfo failed");
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetDomainInfo level %u (set comment) failed - %s\n",
+ s.in.level, nt_errstr(s.out.result));
+ return false;
+ }
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryDomainInfo level %u\n", levels[i]);
+
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r),
+ "QueryDomainInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(r.out.result));
+ ret = false;
+ continue;
+ }
+
+ switch (levels[i]) {
+ case 2:
+ if (strcmp(info->general.oem_information.string, domain_comment) != 0) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n",
+ levels[i], info->general.oem_information.string, domain_comment);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret = false;
+ }
+ }
+ if (!info->general.primary.string) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u returned no PDC name\n",
+ levels[i]);
+ ret = false;
+ } else if (info->general.role == SAMR_ROLE_DOMAIN_PDC) {
+ if (dcerpc_server_name(p) && strcasecmp_m(dcerpc_server_name(p), info->general.primary.string) != 0) {
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u returned different PDC name (%s) compared to server name (%s), despite claiming to be the PDC\n",
+ levels[i], info->general.primary.string, dcerpc_server_name(p));
+ }
+ }
+ }
+ break;
+ case 4:
+ if (strcmp(info->oem.oem_information.string, domain_comment) != 0) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u returned different oem_information (comment) (%s, expected %s)\n",
+ levels[i], info->oem.oem_information.string, domain_comment);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret = false;
+ }
+ }
+ break;
+ case 6:
+ if (!info->info6.primary.string) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u returned no PDC name\n",
+ levels[i]);
+ ret = false;
+ }
+ break;
+ case 11:
+ if (strcmp(info->general2.general.oem_information.string, domain_comment) != 0) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u returned different comment (%s, expected %s)\n",
+ levels[i], info->general2.general.oem_information.string, domain_comment);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret = false;
+ }
+ }
+ break;
+ }
+
+ torture_comment(tctx, "Testing SetDomainInfo level %u\n", levels[i]);
+
+ s.in.domain_handle = handle;
+ s.in.level = levels[i];
+ s.in.info = info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetDomainInfo_r(b, tctx, &s),
+ "SetDomainInfo failed");
+ if (set_ok[i]) {
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetDomainInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(s.out.result));
+ ret = false;
+ continue;
+ }
+ } else {
+ if (!NT_STATUS_EQUAL(NT_STATUS_INVALID_INFO_CLASS, s.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "SetDomainInfo level %u gave %s - should have been NT_STATUS_INVALID_INFO_CLASS\n",
+ r.in.level, nt_errstr(s.out.result));
+ ret = false;
+ continue;
+ }
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r),
+ "QueryDomainInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo level %u failed - %s\n",
+ r.in.level, nt_errstr(r.out.result));
+ ret = false;
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+
+static bool test_QueryDomainInfo2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_QueryDomainInfo2 r;
+ union samr_DomainInfo *info = NULL;
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13};
+ int i;
+ bool ret = true;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing QueryDomainInfo2 level %u\n", levels[i]);
+
+ r.in.domain_handle = handle;
+ r.in.level = levels[i];
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo2_r(b, tctx, &r),
+ "QueryDomainInfo2 failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDomainInfo2 level %u failed - %s\n",
+ r.in.level, nt_errstr(r.out.result));
+ ret = false;
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+/* Test whether querydispinfo level 5 and enumdomgroups return the same
+ set of group names. */
+static bool test_GroupList(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct dom_sid *domain_sid,
+ struct policy_handle *handle)
+{
+ struct samr_EnumDomainGroups q1;
+ struct samr_QueryDisplayInfo q2;
+ NTSTATUS status;
+ uint32_t resume_handle=0;
+ struct samr_SamArray *sam = NULL;
+ uint32_t num_entries = 0;
+ int i;
+ bool ret = true;
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo info;
+
+ size_t num_names = 0;
+ const char **names = NULL;
+
+ bool builtin_domain = dom_sid_compare(domain_sid,
+ &global_sid_Builtin) == 0;
+
+ torture_comment(tctx, "Testing coherency of querydispinfo vs enumdomgroups\n");
+
+ q1.in.domain_handle = handle;
+ q1.in.resume_handle = &resume_handle;
+ q1.in.max_size = 5;
+ q1.out.resume_handle = &resume_handle;
+ q1.out.num_entries = &num_entries;
+ q1.out.sam = &sam;
+
+ status = STATUS_MORE_ENTRIES;
+ while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &q1),
+ "EnumDomainGroups failed");
+ status = q1.out.result;
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES))
+ break;
+
+ for (i=0; i<*q1.out.num_entries; i++) {
+ add_string_to_array(tctx,
+ sam->entries[i].name.string,
+ &names, &num_names);
+ }
+ }
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumDomainGroups");
+
+ torture_assert(tctx, sam, "EnumDomainGroups failed to return sam");
+
+ if (builtin_domain) {
+ torture_assert(tctx, num_names == 0,
+ "EnumDomainGroups shouldn't return any group in the builtin domain!");
+ }
+
+ q2.in.domain_handle = handle;
+ q2.in.level = 5;
+ q2.in.start_idx = 0;
+ q2.in.max_entries = 5;
+ q2.in.buf_size = (uint32_t)-1;
+ q2.out.total_size = &total_size;
+ q2.out.returned_size = &returned_size;
+ q2.out.info = &info;
+
+ status = STATUS_MORE_ENTRIES;
+ while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &q2),
+ "QueryDisplayInfo failed");
+ status = q2.out.result;
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES))
+ break;
+
+ for (i=0; i<q2.out.info->info5.count; i++) {
+ int j;
+ const char *name = q2.out.info->info5.entries[i].account_name.string;
+ bool found = false;
+ for (j=0; j<num_names; j++) {
+ if (names[j] == NULL)
+ continue;
+ if (strequal(names[j], name)) {
+ names[j] = NULL;
+ found = true;
+ break;
+ }
+ }
+
+ if ((!found) && (!builtin_domain)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDisplayInfo gave name [%s] that EnumDomainGroups did not\n",
+ name);
+ ret = false;
+ }
+ }
+ q2.in.start_idx += q2.out.info->info5.count;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "QueryDisplayInfo level 5 failed - %s\n",
+ nt_errstr(status));
+ ret = false;
+ }
+
+ if (builtin_domain) {
+ torture_assert(tctx, q2.in.start_idx != 0,
+ "QueryDisplayInfo should return all domain groups also on the builtin domain handle!");
+ }
+
+ for (i=0; i<num_names; i++) {
+ if (names[i] != NULL) {
+ torture_result(tctx, TORTURE_FAIL, "EnumDomainGroups gave name [%s] that QueryDisplayInfo did not\n",
+ names[i]);
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool test_DeleteDomainGroup(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *group_handle)
+{
+ struct samr_DeleteDomainGroup d;
+
+ torture_comment(tctx, "Testing DeleteDomainGroup\n");
+
+ d.in.group_handle = group_handle;
+ d.out.group_handle = group_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteDomainGroup_r(b, tctx, &d),
+ "DeleteDomainGroup failed");
+ torture_assert_ntstatus_ok(tctx, d.out.result, "DeleteDomainGroup");
+
+ return true;
+}
+
+static bool test_TestPrivateFunctionsDomain(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle)
+{
+ struct samr_TestPrivateFunctionsDomain r;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing TestPrivateFunctionsDomain\n");
+
+ r.in.domain_handle = domain_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_TestPrivateFunctionsDomain_r(b, tctx, &r),
+ "TestPrivateFunctionsDomain failed");
+ torture_assert_ntstatus_equal(tctx, r.out.result, NT_STATUS_NOT_IMPLEMENTED, "TestPrivateFunctionsDomain");
+
+ return ret;
+}
+
+static bool test_RidToSid(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct dom_sid *domain_sid,
+ struct policy_handle *domain_handle)
+{
+ struct samr_RidToSid r;
+ bool ret = true;
+ struct dom_sid *calc_sid, *out_sid;
+ int rids[] = { 0, 42, 512, 10200 };
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(rids);i++) {
+ torture_comment(tctx, "Testing RidToSid\n");
+
+ calc_sid = dom_sid_dup(tctx, domain_sid);
+ r.in.domain_handle = domain_handle;
+ r.in.rid = rids[i];
+ r.out.sid = &out_sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_RidToSid_r(b, tctx, &r),
+ "RidToSid failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "RidToSid for %d failed - %s\n", rids[i], nt_errstr(r.out.result));
+ ret = false;
+ } else {
+ calc_sid = dom_sid_add_rid(calc_sid, calc_sid, rids[i]);
+
+ if (!dom_sid_equal(calc_sid, out_sid)) {
+ torture_result(tctx, TORTURE_FAIL, "RidToSid for %d failed - got %s, expected %s\n", rids[i],
+ dom_sid_string(tctx, out_sid),
+ dom_sid_string(tctx, calc_sid));
+ ret = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool test_GetBootKeyInformation(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle)
+{
+ struct samr_GetBootKeyInformation r;
+ bool ret = true;
+ uint32_t unknown = 0;
+ NTSTATUS status;
+
+ torture_comment(tctx, "Testing GetBootKeyInformation\n");
+
+ r.in.domain_handle = domain_handle;
+ r.out.unknown = &unknown;
+
+ status = dcerpc_samr_GetBootKeyInformation_r(b, tctx, &r);
+ if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(r.out.result)) {
+ status = r.out.result;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ /* w2k3 seems to fail this sometimes and pass it sometimes */
+ torture_comment(tctx, "GetBootKeyInformation (ignored) - %s\n", nt_errstr(status));
+ }
+
+ return ret;
+}
+
+static bool test_AddGroupMember(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ struct policy_handle *group_handle)
+{
+ NTSTATUS status;
+ struct samr_AddGroupMember r;
+ struct samr_DeleteGroupMember d;
+ struct samr_QueryGroupMember q;
+ struct samr_RidAttrArray *rids = NULL;
+ struct samr_SetMemberAttributesOfGroup s;
+ uint32_t rid;
+ bool found_member = false;
+ int i;
+
+ status = test_LookupName(b, tctx, domain_handle, TEST_ACCOUNT_NAME, &rid);
+ torture_assert_ntstatus_ok(tctx, status, "test_AddGroupMember looking up name " TEST_ACCOUNT_NAME);
+
+ r.in.group_handle = group_handle;
+ r.in.rid = rid;
+ r.in.flags = 0; /* ??? */
+
+ torture_comment(tctx, "Testing AddGroupMember, QueryGroupMember and DeleteGroupMember\n");
+
+ d.in.group_handle = group_handle;
+ d.in.rid = rid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteGroupMember_r(b, tctx, &d),
+ "DeleteGroupMember failed");
+ torture_assert_ntstatus_equal(tctx, NT_STATUS_MEMBER_NOT_IN_GROUP, d.out.result, "DeleteGroupMember");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddGroupMember_r(b, tctx, &r),
+ "AddGroupMember failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "AddGroupMember");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddGroupMember_r(b, tctx, &r),
+ "AddGroupMember failed");
+ torture_assert_ntstatus_equal(tctx, NT_STATUS_MEMBER_IN_GROUP, r.out.result, "AddGroupMember");
+
+ if (torture_setting_bool(tctx, "samba4", false) ||
+ torture_setting_bool(tctx, "samba3", false)) {
+ torture_comment(tctx, "skipping SetMemberAttributesOfGroup test against Samba\n");
+ } else {
+ /* this one is quite strange. I am using random inputs in the
+ hope of triggering an error that might give us a clue */
+
+ s.in.group_handle = group_handle;
+ s.in.unknown1 = random();
+ s.in.unknown2 = random();
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetMemberAttributesOfGroup_r(b, tctx, &s),
+ "SetMemberAttributesOfGroup failed");
+ torture_assert_ntstatus_ok(tctx, s.out.result, "SetMemberAttributesOfGroup");
+ }
+
+ q.in.group_handle = group_handle;
+ q.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &q),
+ "QueryGroupMember failed");
+ torture_assert_ntstatus_ok(tctx, q.out.result, "QueryGroupMember");
+ torture_assert(tctx, rids, "QueryGroupMember did not fill in rids structure");
+
+ for (i=0; i < rids->count; i++) {
+ if (rids->rids[i] == rid) {
+ found_member = true;
+ }
+ }
+
+ torture_assert(tctx, found_member, "QueryGroupMember did not list newly added member");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_DeleteGroupMember_r(b, tctx, &d),
+ "DeleteGroupMember failed");
+ torture_assert_ntstatus_ok(tctx, d.out.result, "DeleteGroupMember");
+
+ rids = NULL;
+ found_member = false;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &q),
+ "QueryGroupMember failed");
+ torture_assert_ntstatus_ok(tctx, q.out.result, "QueryGroupMember");
+ torture_assert(tctx, rids, "QueryGroupMember did not fill in rids structure");
+
+ for (i=0; i < rids->count; i++) {
+ if (rids->rids[i] == rid) {
+ found_member = true;
+ }
+ }
+
+ torture_assert(tctx, !found_member, "QueryGroupMember does still list removed member");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_AddGroupMember_r(b, tctx, &r),
+ "AddGroupMember failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "AddGroupMember");
+
+ return true;
+}
+
+
+static bool test_CreateDomainGroup(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *group_name,
+ struct policy_handle *group_handle,
+ struct dom_sid *domain_sid,
+ bool test_group)
+{
+ struct samr_CreateDomainGroup r;
+ uint32_t rid;
+ struct lsa_String name;
+ bool ret = true;
+
+ init_lsa_String(&name, group_name);
+
+ r.in.domain_handle = domain_handle;
+ r.in.name = &name;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.group_handle = group_handle;
+ r.out.rid = &rid;
+
+ torture_comment(tctx, "Testing CreateDomainGroup(%s)\n", r.in.name->string);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomainGroup_r(b, tctx, &r),
+ "CreateDomainGroup failed");
+
+ if (dom_sid_equal(domain_sid, dom_sid_parse_talloc(tctx, SID_BUILTIN))) {
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "Server correctly refused create of '%s'\n", r.in.name->string);
+ return true;
+ } else {
+ torture_result(tctx, TORTURE_FAIL, "Server should have refused create of '%s', got %s instead\n", r.in.name->string,
+ nt_errstr(r.out.result));
+ return false;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_GROUP_EXISTS)) {
+ if (!test_DeleteGroup_byname(b, tctx, domain_handle, r.in.name->string)) {
+ torture_result(tctx, TORTURE_FAIL, "CreateDomainGroup failed: Could not delete domain group %s - %s\n", r.in.name->string,
+ nt_errstr(r.out.result));
+ return false;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomainGroup_r(b, tctx, &r),
+ "CreateDomainGroup failed");
+ }
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) {
+ if (!test_DeleteUser_byname(b, tctx, domain_handle, r.in.name->string)) {
+
+ torture_result(tctx, TORTURE_FAIL, "CreateDomainGroup failed: Could not delete user %s - %s\n", r.in.name->string,
+ nt_errstr(r.out.result));
+ return false;
+ }
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_CreateDomainGroup_r(b, tctx, &r),
+ "CreateDomainGroup failed");
+ }
+ torture_assert_ntstatus_ok(tctx, r.out.result, "CreateDomainGroup");
+
+ if (!test_group) {
+ return ret;
+ }
+
+ if (!test_AddGroupMember(b, tctx, domain_handle, group_handle)) {
+ torture_result(tctx, TORTURE_FAIL, "CreateDomainGroup failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ if (!test_SetGroupInfo(b, tctx, group_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+/*
+ its not totally clear what this does. It seems to accept any sid you like.
+*/
+static bool test_RemoveMemberFromForeignDomain(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle)
+{
+ struct samr_RemoveMemberFromForeignDomain r;
+
+ r.in.domain_handle = domain_handle;
+ r.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32-12-34-56-78");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_RemoveMemberFromForeignDomain_r(b, tctx, &r),
+ "RemoveMemberFromForeignDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "RemoveMemberFromForeignDomain");
+
+ return true;
+}
+
+static bool test_EnumDomainUsers(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ uint32_t *total_num_entries_p)
+{
+ NTSTATUS status;
+ struct samr_EnumDomainUsers r;
+ uint32_t resume_handle = 0;
+ uint32_t num_entries = 0;
+ uint32_t total_num_entries = 0;
+ struct samr_SamArray *sam;
+
+ r.in.domain_handle = domain_handle;
+ r.in.acct_flags = 0;
+ r.in.max_size = (uint32_t)-1;
+ r.in.resume_handle = &resume_handle;
+
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ torture_comment(tctx, "Testing EnumDomainUsers\n");
+
+ do {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainUsers_r(b, tctx, &r),
+ "EnumDomainUsers failed");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to enumerate users");
+ }
+ status = r.out.result;
+
+ total_num_entries += num_entries;
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (total_num_entries_p) {
+ *total_num_entries_p = total_num_entries;
+ }
+
+ return true;
+}
+
+static bool test_EnumDomainGroups(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ uint32_t *total_num_entries_p)
+{
+ NTSTATUS status;
+ struct samr_EnumDomainGroups r;
+ uint32_t resume_handle = 0;
+ uint32_t num_entries = 0;
+ uint32_t total_num_entries = 0;
+ struct samr_SamArray *sam;
+
+ r.in.domain_handle = domain_handle;
+ r.in.max_size = (uint32_t)-1;
+ r.in.resume_handle = &resume_handle;
+
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ torture_comment(tctx, "Testing EnumDomainGroups\n");
+
+ do {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r),
+ "EnumDomainGroups failed");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to enumerate groups");
+ }
+ status = r.out.result;
+
+ total_num_entries += num_entries;
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (total_num_entries_p) {
+ *total_num_entries_p = total_num_entries;
+ }
+
+ return true;
+}
+
+static bool test_EnumDomainAliases(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ uint32_t *total_num_entries_p)
+{
+ NTSTATUS status;
+ struct samr_EnumDomainAliases r;
+ uint32_t resume_handle = 0;
+ uint32_t num_entries = 0;
+ uint32_t total_num_entries = 0;
+ struct samr_SamArray *sam;
+
+ r.in.domain_handle = domain_handle;
+ r.in.max_size = (uint32_t)-1;
+ r.in.resume_handle = &resume_handle;
+
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ torture_comment(tctx, "Testing EnumDomainAliases\n");
+
+ do {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r),
+ "EnumDomainAliases failed");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to enumerate aliases");
+ }
+ status = r.out.result;
+
+ total_num_entries += num_entries;
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (total_num_entries_p) {
+ *total_num_entries_p = total_num_entries;
+ }
+
+ return true;
+}
+
+static bool test_QueryDisplayInfo_level(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint16_t level,
+ uint32_t *total_num_entries_p)
+{
+ NTSTATUS status;
+ struct samr_QueryDisplayInfo r;
+ uint32_t total_num_entries = 0;
+
+ r.in.domain_handle = handle;
+ r.in.level = level;
+ r.in.start_idx = 0;
+ r.in.max_entries = (uint32_t)-1;
+ r.in.buf_size = (uint32_t)-1;
+
+ torture_comment(tctx, "Testing QueryDisplayInfo\n");
+
+ do {
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo info;
+
+ r.out.total_size = &total_size;
+ r.out.returned_size = &returned_size;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r),
+ "failed to query displayinfo");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query displayinfo");
+ }
+ status = r.out.result;
+
+ if (*r.out.returned_size == 0) {
+ break;
+ }
+
+ switch (r.in.level) {
+ case 1:
+ total_num_entries += info.info1.count;
+ r.in.start_idx += info.info1.entries[info.info1.count - 1].idx + 1;
+ break;
+ case 2:
+ total_num_entries += info.info2.count;
+ r.in.start_idx += info.info2.entries[info.info2.count - 1].idx + 1;
+ break;
+ case 3:
+ total_num_entries += info.info3.count;
+ r.in.start_idx += info.info3.entries[info.info3.count - 1].idx + 1;
+ break;
+ case 4:
+ total_num_entries += info.info4.count;
+ r.in.start_idx += info.info4.entries[info.info4.count - 1].idx + 1;
+ break;
+ case 5:
+ total_num_entries += info.info5.count;
+ r.in.start_idx += info.info5.entries[info.info5.count - 1].idx + 1;
+ break;
+ default:
+ return false;
+ }
+
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (total_num_entries_p) {
+ *total_num_entries_p = total_num_entries;
+ }
+
+ return true;
+}
+
+static bool test_ManyObjects(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid *domain_sid,
+ struct torture_samr_context *ctx)
+{
+ uint32_t num_total = ctx->num_objects_large_dc;
+ uint32_t num_enum = 0;
+ uint32_t num_disp = 0;
+ uint32_t num_created = 0;
+ uint32_t num_anounced = 0;
+ uint32_t i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct policy_handle *handles = talloc_zero_array(tctx, struct policy_handle, num_total);
+
+ /* query */
+
+ {
+ struct samr_QueryDomainInfo2 r;
+ union samr_DomainInfo *info;
+ r.in.domain_handle = domain_handle;
+ r.in.level = 2;
+ r.out.info = &info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo2_r(b, tctx, &r),
+ "QueryDomainInfo2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query domain info");
+
+ switch (ctx->choice) {
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ num_anounced = info->general.num_users;
+ break;
+ case TORTURE_SAMR_MANY_GROUPS:
+ num_anounced = info->general.num_groups;
+ break;
+ case TORTURE_SAMR_MANY_ALIASES:
+ num_anounced = info->general.num_aliases;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ /* create */
+
+ for (i=0; i < num_total; i++) {
+
+ const char *name = NULL;
+
+ switch (ctx->choice) {
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ name = talloc_asprintf(tctx, "%s%04d", TEST_ACCOUNT_NAME, i);
+ torture_assert(tctx,
+ test_CreateUser(p, tctx, domain_handle, name, &handles[i], domain_sid, 0, NULL, false),
+ "failed to create user");
+ break;
+ case TORTURE_SAMR_MANY_GROUPS:
+ name = talloc_asprintf(tctx, "%s%04d", TEST_GROUPNAME, i);
+ torture_assert(tctx,
+ test_CreateDomainGroup(b, tctx, domain_handle, name, &handles[i], domain_sid, false),
+ "failed to create group");
+ break;
+ case TORTURE_SAMR_MANY_ALIASES:
+ name = talloc_asprintf(tctx, "%s%04d", TEST_ALIASNAME, i);
+ torture_assert(tctx,
+ test_CreateAlias(b, tctx, domain_handle, name, &handles[i], domain_sid, false),
+ "failed to create alias");
+ break;
+ default:
+ return false;
+ }
+ if (!ndr_policy_handle_empty(&handles[i])) {
+ num_created++;
+ }
+ }
+
+ /* enum */
+
+ switch (ctx->choice) {
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ torture_assert(tctx,
+ test_EnumDomainUsers(b, tctx, domain_handle, &num_enum),
+ "failed to enum users");
+ break;
+ case TORTURE_SAMR_MANY_GROUPS:
+ torture_assert(tctx,
+ test_EnumDomainGroups(b, tctx, domain_handle, &num_enum),
+ "failed to enum groups");
+ break;
+ case TORTURE_SAMR_MANY_ALIASES:
+ torture_assert(tctx,
+ test_EnumDomainAliases(b, tctx, domain_handle, &num_enum),
+ "failed to enum aliases");
+ break;
+ default:
+ return false;
+ }
+
+ /* dispinfo */
+
+ switch (ctx->choice) {
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ torture_assert(tctx,
+ test_QueryDisplayInfo_level(b, tctx, domain_handle, 1, &num_disp),
+ "failed to query display info");
+ break;
+ case TORTURE_SAMR_MANY_GROUPS:
+ torture_assert(tctx,
+ test_QueryDisplayInfo_level(b, tctx, domain_handle, 3, &num_disp),
+ "failed to query display info");
+ break;
+ case TORTURE_SAMR_MANY_ALIASES:
+ /* no aliases in dispinfo */
+ break;
+ default:
+ return false;
+ }
+
+ /* close or delete */
+
+ for (i=0; i < num_total; i++) {
+
+ if (ndr_policy_handle_empty(&handles[i])) {
+ continue;
+ }
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_assert(tctx,
+ test_samr_handle_Close(b, tctx, &handles[i]),
+ "failed to close handle");
+ } else {
+ switch (ctx->choice) {
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ torture_assert(tctx,
+ test_DeleteUser(b, tctx, &handles[i]),
+ "failed to delete user");
+ break;
+ case TORTURE_SAMR_MANY_GROUPS:
+ torture_assert(tctx,
+ test_DeleteDomainGroup(b, tctx, &handles[i]),
+ "failed to delete group");
+ break;
+ case TORTURE_SAMR_MANY_ALIASES:
+ torture_assert(tctx,
+ test_DeleteAlias(b, tctx, &handles[i]),
+ "failed to delete alias");
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+
+ talloc_free(handles);
+
+ if (ctx->choice == TORTURE_SAMR_MANY_ACCOUNTS && num_enum != num_anounced + num_created) {
+ torture_comment(tctx,
+ "unexpected number of results (%u) returned in enum call, expected %u\n",
+ num_enum, num_anounced + num_created);
+
+ torture_comment(tctx,
+ "unexpected number of results (%u) returned in dispinfo, call, expected %u\n",
+ num_disp, num_anounced + num_created);
+ }
+
+ return true;
+}
+
+static bool test_Connect(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle);
+
+static bool test_OpenDomain(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct torture_samr_context *ctx, struct dom_sid *sid)
+{
+ struct samr_OpenDomain r;
+ struct policy_handle domain_handle;
+ struct policy_handle alias_handle;
+ struct policy_handle user_handle;
+ struct policy_handle group_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(alias_handle);
+ ZERO_STRUCT(user_handle);
+ ZERO_STRUCT(group_handle);
+ ZERO_STRUCT(domain_handle);
+
+ torture_comment(tctx, "Testing OpenDomain of %s\n", dom_sid_string(tctx, sid));
+
+ r.in.connect_handle = &ctx->handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.sid = sid;
+ r.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &r),
+ "OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "OpenDomain failed");
+
+ /* run the domain tests with the main handle closed - this tests
+ the servers reference counting */
+ torture_assert(tctx, test_samr_handle_Close(b, tctx, &ctx->handle), "Failed to close SAMR handle");
+
+ switch (ctx->choice) {
+ case TORTURE_SAMR_PASSWORDS:
+ case TORTURE_SAMR_USER_PRIVILEGES:
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret &= test_CreateUser2(p, tctx, &domain_handle, sid, ctx->choice, NULL);
+ }
+ ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, NULL, true);
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "Testing PASSWORDS or PRIVILEGES on domain %s failed!\n", dom_sid_string(tctx, sid));
+ }
+ break;
+ case TORTURE_SAMR_USER_ATTRIBUTES:
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret &= test_CreateUser2(p, tctx, &domain_handle, sid, ctx->choice, NULL);
+ }
+ ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, NULL, true);
+ /* This test needs 'complex' users to validate */
+ ret &= test_QueryDisplayInfo(b, tctx, &domain_handle);
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "Testing ATTRIBUTES on domain %s failed!\n", dom_sid_string(tctx, sid));
+ }
+ break;
+ case TORTURE_SAMR_PASSWORDS_PWDLASTSET:
+ case TORTURE_SAMR_PASSWORDS_BADPWDCOUNT:
+ case TORTURE_SAMR_PASSWORDS_LOCKOUT:
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret &= test_CreateUser2(p, tctx, &domain_handle, sid, ctx->choice, ctx->machine_credentials);
+ }
+ ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, ctx->machine_credentials, true);
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "Testing PASSWORDS PWDLASTSET or BADPWDCOUNT on domain %s failed!\n", dom_sid_string(tctx, sid));
+ }
+ break;
+ case TORTURE_SAMR_MANY_ACCOUNTS:
+ case TORTURE_SAMR_MANY_GROUPS:
+ case TORTURE_SAMR_MANY_ALIASES:
+ ret &= test_ManyObjects(p, tctx, &domain_handle, sid, ctx);
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "Testing MANY-{ACCOUNTS,GROUPS,ALIASES} on domain %s failed!\n", dom_sid_string(tctx, sid));
+ }
+ break;
+ case TORTURE_SAMR_OTHER:
+ ret &= test_CreateUser(p, tctx, &domain_handle, TEST_ACCOUNT_NAME, &user_handle, sid, ctx->choice, NULL, true);
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "Failed to CreateUser in SAMR-OTHER on domain %s!\n", dom_sid_string(tctx, sid));
+ }
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret &= test_QuerySecurity(b, tctx, &domain_handle);
+ }
+ ret &= test_RemoveMemberFromForeignDomain(b, tctx, &domain_handle);
+ ret &= test_CreateAlias(b, tctx, &domain_handle, TEST_ALIASNAME, &alias_handle, sid, true);
+ ret &= test_CreateDomainGroup(b, tctx, &domain_handle, TEST_GROUPNAME, &group_handle, sid, true);
+ ret &= test_GetAliasMembership(b, tctx, &domain_handle);
+ ret &= test_QueryDomainInfo(p, tctx, &domain_handle);
+ ret &= test_QueryDomainInfo2(b, tctx, &domain_handle);
+ ret &= test_EnumDomainUsers_all(b, tctx, &domain_handle);
+ ret &= test_EnumDomainUsers_async(p, tctx, &domain_handle);
+ ret &= test_EnumDomainGroups_all(b, tctx, &domain_handle);
+ ret &= test_EnumDomainAliases_all(b, tctx, &domain_handle);
+ ret &= test_QueryDisplayInfo2(b, tctx, &domain_handle);
+ ret &= test_QueryDisplayInfo3(b, tctx, &domain_handle);
+ ret &= test_QueryDisplayInfo_continue(b, tctx, &domain_handle);
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping GetDisplayEnumerationIndex test against Samba4\n");
+ } else {
+ ret &= test_GetDisplayEnumerationIndex(b, tctx, &domain_handle);
+ ret &= test_GetDisplayEnumerationIndex2(b, tctx, &domain_handle);
+ }
+ ret &= test_GroupList(b, tctx, sid, &domain_handle);
+ ret &= test_TestPrivateFunctionsDomain(b, tctx, &domain_handle);
+ ret &= test_RidToSid(b, tctx, sid, &domain_handle);
+ ret &= test_GetBootKeyInformation(b, tctx, &domain_handle);
+ if (!ret) {
+ torture_comment(tctx, "Testing SAMR-OTHER on domain %s failed!\n", dom_sid_string(tctx, sid));
+ }
+ break;
+ }
+
+ if (!ndr_policy_handle_empty(&user_handle) &&
+ !test_DeleteUser(b, tctx, &user_handle)) {
+ ret = false;
+ }
+
+ if (!ndr_policy_handle_empty(&alias_handle) &&
+ !test_DeleteAlias(b, tctx, &alias_handle)) {
+ ret = false;
+ }
+
+ if (!ndr_policy_handle_empty(&group_handle) &&
+ !test_DeleteDomainGroup(b, tctx, &group_handle)) {
+ ret = false;
+ }
+
+ torture_assert(tctx, test_samr_handle_Close(b, tctx, &domain_handle), "Failed to close SAMR domain handle");
+
+ torture_assert(tctx, test_Connect(b, tctx, &ctx->handle), "Failed to re-connect SAMR handle");
+ /* reconnect the main handle */
+
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL, "Testing domain %s failed!\n", dom_sid_string(tctx, sid));
+ }
+
+ return ret;
+}
+
+static bool test_LookupDomain(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct torture_samr_context *ctx, const char *domain)
+{
+ struct samr_LookupDomain r;
+ struct dom_sid2 *sid = NULL;
+ struct lsa_String n1;
+ struct lsa_String n2;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing LookupDomain(%s)\n", domain);
+
+ /* check for correct error codes */
+ r.in.connect_handle = &ctx->handle;
+ r.in.domain_name = &n2;
+ r.out.sid = &sid;
+ n2.string = NULL;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r),
+ "LookupDomain failed");
+ torture_assert_ntstatus_equal(tctx, NT_STATUS_INVALID_PARAMETER, r.out.result, "LookupDomain expected NT_STATUS_INVALID_PARAMETER");
+
+ init_lsa_String(&n2, "xxNODOMAINxx");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r),
+ "LookupDomain failed");
+ torture_assert_ntstatus_equal(tctx, NT_STATUS_NO_SUCH_DOMAIN, r.out.result, "LookupDomain expected NT_STATUS_NO_SUCH_DOMAIN");
+
+ r.in.connect_handle = &ctx->handle;
+
+ init_lsa_String(&n1, domain);
+ r.in.domain_name = &n1;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r),
+ "LookupDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LookupDomain");
+
+ if (!test_GetDomPwInfo(p, tctx, &n1)) {
+ ret = false;
+ }
+
+ if (!test_OpenDomain(p, tctx, ctx, *r.out.sid)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static bool test_EnumDomains(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct torture_samr_context *ctx)
+{
+ struct samr_EnumDomains r;
+ uint32_t resume_handle = 0;
+ uint32_t num_entries = 0;
+ struct samr_SamArray *sam = NULL;
+ int i;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.connect_handle = &ctx->handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.buf_size = (uint32_t)-1;
+ r.out.resume_handle = &resume_handle;
+ r.out.num_entries = &num_entries;
+ r.out.sam = &sam;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r),
+ "EnumDomains failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "EnumDomains failed");
+
+ if (!*r.out.sam) {
+ return false;
+ }
+
+ for (i=0;i<sam->count;i++) {
+ if (!test_LookupDomain(p, tctx, ctx,
+ sam->entries[i].name.string)) {
+ ret = false;
+ }
+ }
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r),
+ "EnumDomains failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "EnumDomains failed");
+
+ return ret;
+}
+
+
+static bool test_Connect(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct samr_Connect r;
+ struct samr_Connect2 r2;
+ struct samr_Connect3 r3;
+ struct samr_Connect4 r4;
+ struct samr_Connect5 r5;
+ union samr_ConnectInfo info;
+ struct policy_handle h;
+ uint32_t level_out = 0;
+ bool ret = true, got_handle = false;
+
+ torture_comment(tctx, "Testing samr_Connect\n");
+
+ r.in.system_name = NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.connect_handle = &h;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect_r(b, tctx, &r),
+ "Connect failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "Connect failed - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ } else {
+ got_handle = true;
+ *handle = h;
+ }
+
+ torture_comment(tctx, "Testing samr_Connect2\n");
+
+ r2.in.system_name = NULL;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.out.connect_handle = &h;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect2_r(b, tctx, &r2),
+ "Connect2 failed");
+ if (!NT_STATUS_IS_OK(r2.out.result)) {
+ torture_comment(tctx, "Connect2 failed - %s\n", nt_errstr(r2.out.result));
+ ret = false;
+ } else {
+ if (got_handle) {
+ test_samr_handle_Close(b, tctx, handle);
+ }
+ got_handle = true;
+ *handle = h;
+ }
+
+ torture_comment(tctx, "Testing samr_Connect3\n");
+
+ r3.in.system_name = NULL;
+ r3.in.unknown = 0;
+ r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r3.out.connect_handle = &h;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect3_r(b, tctx, &r3),
+ "Connect3 failed");
+ if (!NT_STATUS_IS_OK(r3.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "Connect3 failed - %s\n", nt_errstr(r3.out.result));
+ ret = false;
+ } else {
+ if (got_handle) {
+ test_samr_handle_Close(b, tctx, handle);
+ }
+ got_handle = true;
+ *handle = h;
+ }
+
+ torture_comment(tctx, "Testing samr_Connect4\n");
+
+ r4.in.system_name = "";
+ r4.in.client_version = 0;
+ r4.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r4.out.connect_handle = &h;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect4_r(b, tctx, &r4),
+ "Connect4 failed");
+ if (!NT_STATUS_IS_OK(r4.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "Connect4 failed - %s\n", nt_errstr(r4.out.result));
+ ret = false;
+ } else {
+ if (got_handle) {
+ test_samr_handle_Close(b, tctx, handle);
+ }
+ got_handle = true;
+ *handle = h;
+ }
+
+ torture_comment(tctx, "Testing samr_Connect5\n");
+
+ info.info1.client_version = 0;
+ info.info1.supported_features = 0;
+
+ r5.in.system_name = "";
+ r5.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r5.in.level_in = 1;
+ r5.out.level_out = &level_out;
+ r5.in.info_in = &info;
+ r5.out.info_out = &info;
+ r5.out.connect_handle = &h;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect5_r(b, tctx, &r5),
+ "Connect5 failed");
+ if (!NT_STATUS_IS_OK(r5.out.result)) {
+ torture_result(tctx, TORTURE_FAIL, "Connect5 failed - %s\n", nt_errstr(r5.out.result));
+ ret = false;
+ } else {
+ if (got_handle) {
+ test_samr_handle_Close(b, tctx, handle);
+ }
+ got_handle = true;
+ *handle = h;
+ }
+
+ return ret;
+}
+
+
+static bool test_samr_ValidatePassword(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct samr_ValidatePassword r;
+ union samr_ValidatePasswordReq req;
+ union samr_ValidatePasswordRep *repp = NULL;
+ NTSTATUS status;
+ const char *passwords[] = { "penguin", "p@ssw0rd", "p@ssw0rd123$", NULL };
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing samr_ValidatePassword\n");
+
+ if (p->conn->transport.transport != NCACN_IP_TCP) {
+ torture_comment(tctx, "samr_ValidatePassword only should succeed over NCACN_IP_TCP!\n");
+ }
+
+ ZERO_STRUCT(r);
+ r.in.level = NetValidatePasswordReset;
+ r.in.req = &req;
+ r.out.rep = &repp;
+
+ ZERO_STRUCT(req);
+ req.req3.account.string = "non-existent-account-aklsdji";
+
+ for (i=0; passwords[i]; i++) {
+ req.req3.password.string = passwords[i];
+
+ status = dcerpc_samr_ValidatePassword_r(b, tctx, &r);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ torture_skip(tctx, "ValidatePassword not supported by server\n");
+ }
+ torture_assert_ntstatus_ok(tctx, status,
+ "samr_ValidatePassword failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_ValidatePassword failed");
+ torture_comment(tctx, "Server %s password '%s' with code %i\n",
+ repp->ctr3.status==SAMR_VALIDATION_STATUS_SUCCESS?"allowed":"refused",
+ req.req3.password.string, repp->ctr3.status);
+ }
+
+ return true;
+}
+
+bool torture_rpc_samr(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_OTHER;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ if (!torture_setting_bool(torture, "samba3", false)) {
+ ret &= test_QuerySecurity(b, torture, &ctx->handle);
+ }
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_SetDsrmPassword(b, torture, &ctx->handle);
+
+ ret &= test_Shutdown(b, torture, &ctx->handle);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+
+bool torture_rpc_samr_users(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_USER_ATTRIBUTES;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ if (!torture_setting_bool(torture, "samba3", false)) {
+ ret &= test_QuerySecurity(b, torture, &ctx->handle);
+ }
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_SetDsrmPassword(b, torture, &ctx->handle);
+
+ ret &= test_Shutdown(b, torture, &ctx->handle);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+
+bool torture_rpc_samr_passwords(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_PASSWORDS;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+static bool torture_rpc_samr_pwdlastset(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ struct cli_credentials *machine_credentials)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_PASSWORDS_PWDLASTSET;
+ ctx->machine_credentials = machine_credentials;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samr_passwords_pwdlastset(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.pwdlastset");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr,
+ TEST_ACCOUNT_NAME_PWD);
+
+ torture_rpc_tcase_add_test_creds(tcase, "pwdLastSet",
+ torture_rpc_samr_pwdlastset);
+
+ return suite;
+}
+
+static bool torture_rpc_samr_users_privileges_delete_user(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ struct cli_credentials *machine_credentials)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_USER_PRIVILEGES;
+ ctx->machine_credentials = machine_credentials;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samr_user_privileges(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.users.privileges");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr,
+ TEST_ACCOUNT_NAME_PWD);
+
+ torture_rpc_tcase_add_test_creds(tcase, "delete_privileged_user",
+ torture_rpc_samr_users_privileges_delete_user);
+
+ return suite;
+}
+
+static bool torture_rpc_samr_many_accounts(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ void *data)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx =
+ talloc_get_type_abort(data, struct torture_samr_context);
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx->choice = TORTURE_SAMR_MANY_ACCOUNTS;
+ ctx->num_objects_large_dc = torture_setting_int(torture, "large_dc",
+ ctx->num_objects_large_dc);
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+static bool torture_rpc_samr_many_groups(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ void *data)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx =
+ talloc_get_type_abort(data, struct torture_samr_context);
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx->choice = TORTURE_SAMR_MANY_GROUPS;
+ ctx->num_objects_large_dc = torture_setting_int(torture, "large_dc",
+ ctx->num_objects_large_dc);
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+static bool torture_rpc_samr_many_aliases(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ void *data)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx =
+ talloc_get_type_abort(data, struct torture_samr_context);
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx->choice = TORTURE_SAMR_MANY_ALIASES;
+ ctx->num_objects_large_dc = torture_setting_int(torture, "large_dc",
+ ctx->num_objects_large_dc);
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samr_large_dc(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.large-dc");
+ struct torture_rpc_tcase *tcase;
+ struct torture_samr_context *ctx;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "samr", &ndr_table_samr);
+
+ ctx = talloc_zero(suite, struct torture_samr_context);
+ ctx->num_objects_large_dc = 150;
+
+ torture_rpc_tcase_add_test_ex(tcase, "many_aliases",
+ torture_rpc_samr_many_aliases, ctx);
+ torture_rpc_tcase_add_test_ex(tcase, "many_groups",
+ torture_rpc_samr_many_groups, ctx);
+ torture_rpc_tcase_add_test_ex(tcase, "many_accounts",
+ torture_rpc_samr_many_accounts, ctx);
+
+ return suite;
+}
+
+static bool torture_rpc_samr_badpwdcount(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ struct cli_credentials *machine_credentials)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_PASSWORDS_BADPWDCOUNT;
+ ctx->machine_credentials = machine_credentials;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samr_passwords_badpwdcount(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.badpwdcount");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr,
+ TEST_ACCOUNT_NAME_PWD);
+
+ torture_rpc_tcase_add_test_creds(tcase, "badPwdCount",
+ torture_rpc_samr_badpwdcount);
+
+ return suite;
+}
+
+static bool torture_rpc_samr_lockout(struct torture_context *torture,
+ struct dcerpc_pipe *p2,
+ struct cli_credentials *machine_credentials)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct torture_samr_context *ctx;
+ struct dcerpc_binding_handle *b;
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ b = p->binding_handle;
+
+ ctx = talloc_zero(torture, struct torture_samr_context);
+
+ ctx->choice = TORTURE_SAMR_PASSWORDS_LOCKOUT;
+ ctx->machine_credentials = machine_credentials;
+
+ ret &= test_Connect(b, torture, &ctx->handle);
+
+ ret &= test_EnumDomains(p, torture, ctx);
+
+ ret &= test_samr_handle_Close(b, torture, &ctx->handle);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samr_passwords_lockout(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.lockout");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr,
+ TEST_ACCOUNT_NAME_PWD);
+
+ torture_rpc_tcase_add_test_creds(tcase, "lockout",
+ torture_rpc_samr_lockout);
+
+ return suite;
+}
+
+struct torture_suite *torture_rpc_samr_passwords_validate(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.passwords.validate");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr);
+ torture_rpc_tcase_add_test(tcase, "validate",
+ test_samr_ValidatePassword);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/samr_accessmask.c b/source4/torture/rpc/samr_accessmask.c
new file mode 100644
index 0000000..1ed0d67
--- /dev/null
+++ b/source4/torture/rpc/samr_accessmask.c
@@ -0,0 +1,1197 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for accessmasks on the SAMR pipe
+
+ Copyright (C) Ronnie Sahlberg 2007
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "libcli/security/security.h"
+
+
+/* test user created to test the ACLs associated to SAMR objects */
+#define TEST_USER_NAME "samr_testuser"
+#define TEST_MACHINENAME "samrtestmach"
+
+static NTSTATUS torture_samr_Close(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *h)
+{
+ NTSTATUS status;
+ struct samr_Close cl;
+
+ cl.in.handle = h;
+ cl.out.handle = h;
+ status = dcerpc_samr_Close_r(b, tctx, &cl);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return cl.out.result;
+}
+
+static NTSTATUS torture_samr_Connect5(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t mask, struct policy_handle *h)
+{
+ NTSTATUS status;
+ struct samr_Connect5 r5;
+ union samr_ConnectInfo info;
+ uint32_t level_out = 0;
+
+ info.info1.client_version = 0;
+ info.info1.supported_features = 0;
+ r5.in.system_name = "";
+ r5.in.level_in = 1;
+ r5.in.info_in = &info;
+ r5.out.info_out = &info;
+ r5.out.level_out = &level_out;
+ r5.out.connect_handle = h;
+ r5.in.access_mask = mask;
+
+ status = dcerpc_samr_Connect5_r(b, tctx, &r5);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return r5.out.result;
+}
+
+/* check which bits in accessmask allows us to connect to the server */
+static bool test_samr_accessmask_Connect5(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct policy_handle h;
+ int i;
+ uint32_t mask;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ printf("Testing which bits in accessmask allows us to connect\n");
+ mask = 1;
+ for (i=0;i<33;i++) {
+ printf("Testing Connect5 with access mask 0x%08x", mask);
+ status = torture_samr_Connect5(tctx, b, mask, &h);
+ mask <<= 1;
+
+ switch (i) {
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 26:
+ case 27:
+ printf(" expecting to fail");
+ /* of only one of these bits are set we expect to
+ fail by default
+ */
+ if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ default:
+ /* these bits set are expected to succeed by default */
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &h);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ }
+ printf(" OK\n");
+ }
+
+ return true;
+}
+
+/* check which bits in accessmask allows us to EnumDomains()
+ by default we must specify at least one of :
+ SAMR/EnumDomains
+ Maximum
+ GenericAll
+ GenericRead
+ in the access mask to Connect5() in order to be allowed to perform
+ EnumDomains() on the policy handle returned from Connect5()
+*/
+static bool test_samr_accessmask_EnumDomains(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct samr_EnumDomains ed;
+ struct policy_handle ch;
+ int i;
+ uint32_t mask;
+ uint32_t resume_handle = 0;
+ struct samr_SamArray *sam = NULL;
+ uint32_t num_entries = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ printf("Testing which bits in Connect5 accessmask allows us to EnumDomains\n");
+ mask = 1;
+ for (i=0;i<33;i++) {
+ printf("Testing Connect5/EnumDomains with access mask 0x%08x", mask);
+ status = torture_samr_Connect5(tctx, b, mask, &ch);
+ mask <<= 1;
+
+ switch (i) {
+ case 4: /* SAMR/EnumDomains */
+ case 25: /* Maximum */
+ case 28: /* GenericAll */
+ case 31: /* GenericRead */
+ /* these bits set are expected to succeed by default */
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ed.in.connect_handle = &ch;
+ ed.in.resume_handle = &resume_handle;
+ ed.in.buf_size = (uint32_t)-1;
+ ed.out.resume_handle = &resume_handle;
+ ed.out.num_entries = &num_entries;
+ ed.out.sam = &sam;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &ed),
+ "EnumDomains failed");
+ if (!NT_STATUS_IS_OK(ed.out.result)) {
+ printf("EnumDomains failed - %s\n", nt_errstr(ed.out.result));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ default:
+ printf(" expecting to fail");
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf(" OK\n");
+ continue;
+ }
+
+ ed.in.connect_handle = &ch;
+ ed.in.resume_handle = &resume_handle;
+ ed.in.buf_size = (uint32_t)-1;
+ ed.out.resume_handle = &resume_handle;
+ ed.out.num_entries = &num_entries;
+ ed.out.sam = &sam;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &ed),
+ "EnumDomains failed");
+ if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, ed.out.result)) {
+ printf("EnumDomains failed - %s\n", nt_errstr(ed.out.result));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ }
+ printf(" OK\n");
+ }
+
+ return true;
+}
+
+
+/*
+ * test how ACLs affect how/if a user can connect to the SAMR service
+ *
+ * samr_SetSecurity() returns SUCCESS when changing the ACL for
+ * a policy handle got from Connect5() but the ACL is not changed on
+ * the server
+ */
+static bool test_samr_connect_user_acl(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct cli_credentials *test_credentials,
+ const struct dom_sid *test_sid)
+
+{
+ NTSTATUS status;
+ struct policy_handle ch;
+ struct policy_handle uch;
+ struct samr_QuerySecurity qs;
+ struct samr_SetSecurity ss;
+ struct security_ace ace = {};
+ struct security_descriptor *sd;
+ struct sec_desc_buf sdb, *sdbuf = NULL;
+ bool ret = true;
+ int sd_size;
+ struct dcerpc_pipe *test_p;
+ struct dcerpc_binding_handle *test_b;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+
+ printf("Testing ACLs to allow/prevent users to connect to SAMR");
+
+ /* connect to SAMR */
+ status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+
+ /* get the current ACL for the SAMR policy handle */
+ qs.in.handle = &ch;
+ qs.in.sec_info = SECINFO_DACL;
+ qs.out.sdbuf = &sdbuf;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &qs),
+ "QuerySecurity failed");
+ if (!NT_STATUS_IS_OK(qs.out.result)) {
+ printf("QuerySecurity failed - %s\n", nt_errstr(qs.out.result));
+ ret = false;
+ }
+
+ /* how big is the security descriptor? */
+ sd_size = sdbuf->sd_size;
+
+
+ /* add an ACE to the security descriptor to deny the user the
+ * 'connect to server' right
+ */
+ sd = sdbuf->sd;
+ ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
+ ace.flags = 0;
+ ace.access_mask = SAMR_ACCESS_CONNECT_TO_SERVER;
+ ace.trustee = *test_sid;
+ status = security_descriptor_dacl_add(sd, &ace);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to add ACE to security descriptor\n");
+ ret = false;
+ }
+ ss.in.handle = &ch;
+ ss.in.sec_info = SECINFO_DACL;
+ ss.in.sdbuf = &sdb;
+ sdb.sd = sd;
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetSecurity_r(b, tctx, &ss),
+ "SetSecurity failed");
+ if (!NT_STATUS_IS_OK(ss.out.result)) {
+ printf("SetSecurity failed - %s\n", nt_errstr(ss.out.result));
+ ret = false;
+ }
+
+
+ /* Try to connect as the test user */
+ status = dcerpc_pipe_connect(tctx,
+ &test_p, binding, &ndr_table_samr,
+ test_credentials, tctx->ev, tctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status));
+ return false;
+ }
+ test_b = test_p->binding_handle;
+
+ /* connect to SAMR as the user */
+ status = torture_samr_Connect5(tctx, test_b, SEC_FLAG_MAXIMUM_ALLOWED, &uch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ /* disconnect the user */
+ talloc_free(test_p);
+
+
+ /* read the sequrity descriptor back. it should not have changed
+ * even though samr_SetSecurity returned SUCCESS
+ */
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &qs),
+ "QuerySecurity failed");
+ if (!NT_STATUS_IS_OK(qs.out.result)) {
+ printf("QuerySecurity failed - %s\n", nt_errstr(qs.out.result));
+ ret = false;
+ }
+ if (sd_size != sdbuf->sd_size) {
+ printf("security descriptor changed\n");
+ ret = false;
+ }
+
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ ret = false;
+ }
+
+ if (ret == true) {
+ printf(" OK\n");
+ }
+ return ret;
+}
+
+/*
+ * test if the ACLs are enforced for users.
+ * a normal testuser only gets the rights provided in the ACL for
+ * Everyone which does not include the SAMR_ACCESS_SHUTDOWN_SERVER
+ * right. If the ACLs are checked when a user connects
+ * a testuser that requests the accessmask with only this bit set
+ * the connect should fail.
+ */
+static bool test_samr_connect_user_acl_enforced(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct cli_credentials *test_credentials,
+ const struct dom_sid *test_sid)
+
+{
+ NTSTATUS status;
+ struct policy_handle uch;
+ bool ret = true;
+ struct dcerpc_pipe *test_p;
+ struct dcerpc_binding_handle *test_b;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+
+ printf("Testing if ACLs are enforced for non domain admin users when connecting to SAMR");
+
+
+ status = dcerpc_pipe_connect(tctx,
+ &test_p, binding, &ndr_table_samr,
+ test_credentials, tctx->ev, tctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status));
+ return false;
+ }
+ test_b = test_p->binding_handle;
+
+ /* connect to SAMR as the user */
+ status = torture_samr_Connect5(tctx, test_b, SAMR_ACCESS_SHUTDOWN_SERVER, &uch);
+ if (NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ printf(" OK\n");
+
+ /* disconnect the user */
+ talloc_free(test_p);
+
+ return ret;
+}
+
+/* check which bits in accessmask allows us to LookupDomain()
+ by default we must specify at least one of :
+ in the access mask to Connect5() in order to be allowed to perform
+ case 5: samr/opendomain
+ case 25: Maximum
+ case 28: GenericAll
+ case 29: GenericExecute
+ LookupDomain() on the policy handle returned from Connect5()
+*/
+static bool test_samr_accessmask_LookupDomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct samr_LookupDomain ld;
+ struct dom_sid2 *sid = NULL;
+ struct policy_handle ch;
+ struct lsa_String dn;
+ int i;
+ uint32_t mask;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ printf("Testing which bits in Connect5 accessmask allows us to LookupDomain\n");
+ mask = 1;
+ for (i=0;i<33;i++) {
+ printf("Testing Connect5/LookupDomain with access mask 0x%08x", mask);
+ status = torture_samr_Connect5(tctx, b, mask, &ch);
+ mask <<= 1;
+
+ switch (i) {
+ case 5:
+ case 25: /* Maximum */
+ case 28: /* GenericAll */
+ case 29: /* GenericExecute */
+ /* these bits set are expected to succeed by default */
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ld.in.connect_handle = &ch;
+ ld.in.domain_name = &dn;
+ ld.out.sid = &sid;
+ dn.string = lpcfg_workgroup(tctx->lp_ctx);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
+ "LookupDomain failed");
+ if (!NT_STATUS_IS_OK(ld.out.result)) {
+ printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ default:
+ printf(" expecting to fail");
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf(" OK\n");
+ continue;
+ }
+
+ ld.in.connect_handle = &ch;
+ ld.in.domain_name = &dn;
+ ld.out.sid = &sid;
+ dn.string = lpcfg_workgroup(tctx->lp_ctx);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
+ "LookupDomain failed");
+ if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, ld.out.result)) {
+ printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ }
+ printf(" OK\n");
+ }
+
+ return true;
+}
+
+/* check which bits in accessmask allows us to OpenDomain()
+ by default we must specify at least one of :
+ samr/opendomain
+ Maximum
+ GenericAll
+ GenericExecute
+ in the access mask to Connect5() in order to be allowed to perform
+ OpenDomain() on the policy handle returned from Connect5()
+*/
+static bool test_samr_accessmask_OpenDomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct samr_LookupDomain ld;
+ struct dom_sid2 *sid = NULL;
+ struct samr_OpenDomain od;
+ struct policy_handle ch;
+ struct policy_handle dh;
+ struct lsa_String dn;
+ int i;
+ uint32_t mask;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+
+ /* first we must grab the sid of the domain */
+ status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ld.in.connect_handle = &ch;
+ ld.in.domain_name = &dn;
+ ld.out.sid = &sid;
+ dn.string = lpcfg_workgroup(tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
+ "LookupDomain failed");
+ if (!NT_STATUS_IS_OK(ld.out.result)) {
+ printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
+ return false;
+ }
+
+
+
+ printf("Testing which bits in Connect5 accessmask allows us to OpenDomain\n");
+ mask = 1;
+ for (i=0;i<33;i++) {
+ printf("Testing Connect5/OpenDomain with access mask 0x%08x", mask);
+ status = torture_samr_Connect5(tctx, b, mask, &ch);
+ mask <<= 1;
+
+ switch (i) {
+ case 5:
+ case 25: /* Maximum */
+ case 28: /* GenericAll */
+ case 29: /* GenericExecute */
+ /* these bits set are expected to succeed by default */
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect5 failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ od.in.connect_handle = &ch;
+ od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ od.in.sid = sid;
+ od.out.domain_handle = &dh;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &od),
+ "OpenDomain failed");
+ if (!NT_STATUS_IS_OK(od.out.result)) {
+ printf("OpenDomain failed - %s\n", nt_errstr(od.out.result));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &dh);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ default:
+ printf(" expecting to fail");
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf(" OK\n");
+ continue;
+ }
+
+ status = torture_samr_Close(tctx, b, &ch);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ break;
+ }
+ printf(" OK\n");
+ }
+
+ return true;
+}
+
+static bool test_samr_connect(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ void *testuser;
+ const char *testuser_passwd;
+ struct cli_credentials *test_credentials;
+ bool ret = true;
+ const struct dom_sid *test_sid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "Skipping test against Samba 3");
+ }
+
+ /* create a test user */
+ testuser = torture_create_testuser(tctx, TEST_USER_NAME, lpcfg_workgroup(tctx->lp_ctx),
+ ACB_NORMAL, &testuser_passwd);
+ if (!testuser) {
+ printf("Failed to create test user\n");
+ return false;
+ }
+ test_credentials = cli_credentials_init(tctx);
+ cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED);
+ cli_credentials_set_domain(test_credentials, lpcfg_workgroup(tctx->lp_ctx),
+ CRED_SPECIFIED);
+ cli_credentials_set_username(test_credentials, TEST_USER_NAME, CRED_SPECIFIED);
+ cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED);
+ test_sid = torture_join_user_sid(testuser);
+
+
+ /* test if ACLs can be changed for the policy handle
+ * returned by Connect5
+ */
+ if (!test_samr_connect_user_acl(tctx, b, test_credentials, test_sid)) {
+ ret = false;
+ }
+
+ /* test if the ACLs that are reported from the Connect5
+ * policy handle is enforced.
+ * i.e. an ordinary user only has the same rights as Everybody
+ * ReadControl
+ * Samr/OpenDomain
+ * Samr/EnumDomains
+ * Samr/ConnectToServer
+ * is granted and should therefore not be able to connect when
+ * requesting SAMR_ACCESS_SHUTDOWN_SERVER
+ */
+ if (!test_samr_connect_user_acl_enforced(tctx, b, test_credentials, test_sid)) {
+ ret = false;
+ }
+
+ /* remove the test user */
+ torture_leave_domain(tctx, testuser);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_samr_accessmask(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.accessmask");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr);
+
+ torture_rpc_tcase_add_test(tcase, "connect", test_samr_connect);
+
+ /* test which bits in the accessmask to Connect5 will allow
+ * us to call OpenDomain() */
+ torture_rpc_tcase_add_test(tcase, "OpenDomain",
+ test_samr_accessmask_OpenDomain);
+
+ /* test which bits in the accessmask to Connect5 will allow
+ * us to call LookupDomain() */
+ torture_rpc_tcase_add_test(tcase, "LookupDomain",
+ test_samr_accessmask_LookupDomain);
+
+ /* test which bits in the accessmask to Connect5 will allow
+ * us to call EnumDomains() */
+ torture_rpc_tcase_add_test(tcase, "EnumDomains",
+ test_samr_accessmask_EnumDomains);
+
+ /* test which bits in the accessmask to Connect5
+ will allow us to connect to the server */
+ torture_rpc_tcase_add_test(tcase, "Connect5",
+ test_samr_accessmask_Connect5);
+
+ return suite;
+}
+
+static bool test_LookupRids(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *domain_handle,
+ uint32_t rid)
+{
+ struct samr_LookupRids r;
+ struct lsa_Strings names;
+ struct samr_Ids types;
+
+ torture_comment(tctx, "Testing LookupRids %d\n", rid);
+
+ r.in.domain_handle = domain_handle;
+ r.in.num_rids = 1;
+ r.in.rids = &rid;
+ r.out.names = &names;
+ r.out.types = &types;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupRids_r(b, tctx, &r),
+ "failed to call samr_LookupRids");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to call samr_LookupRids");
+
+ return true;
+}
+
+
+static bool test_user(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *domain_handle,
+ uint32_t access_mask,
+ struct samr_DispEntryGeneral *u)
+{
+ struct policy_handle user_handle;
+
+ torture_comment(tctx, "Testing user %s (%d)\n", u->account_name.string, u->rid);
+
+ torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, u->rid),
+ "failed to call lookuprids");
+
+ {
+ struct samr_OpenUser r;
+
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = access_mask;
+ r.in.rid = u->rid;
+ r.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
+ "failed to open user");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to open user");
+ }
+ {
+ struct samr_QueryUserInfo r;
+ union samr_UserInfo *info;
+ uint32_t levels[] = { 16, 21 };
+ int i;
+
+ r.in.user_handle = &user_handle;
+ r.out.info = &info;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+
+ torture_comment(tctx, "Testing QueryUserInfo rid: %d level: %d\n",
+ u->rid, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
+ talloc_asprintf(tctx, "failed to query user info level %d", r.in.level));
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "failed to query user info level %d", r.in.level));
+ }
+ }
+ {
+ struct samr_GetGroupsForUser r;
+ struct samr_RidWithAttributeArray *rids;
+
+ r.in.user_handle = &user_handle;
+ r.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetGroupsForUser_r(b, tctx, &r),
+ "failed to query groups for user");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query groups for user");
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_samr_Close(tctx, b, &user_handle),
+ "failed to close user handle");
+
+ return true;
+}
+
+static bool test_samr_group(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *domain_handle,
+ uint32_t access_mask,
+ struct samr_SamEntry *g)
+{
+ struct policy_handle group_handle;
+
+ torture_comment(tctx, "Testing group %s (%d)\n", g->name.string, g->idx);
+
+ torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, g->idx),
+ "failed to call lookuprids");
+ {
+ struct samr_OpenGroup r;
+
+ r.in.domain_handle = domain_handle;
+ r.in.access_mask = access_mask;
+ r.in.rid = g->idx;
+ r.out.group_handle = &group_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenGroup_r(b, tctx, &r),
+ "failed to open group");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to open group");
+ }
+ {
+ struct samr_QueryGroupMember r;
+ struct samr_RidAttrArray *rids;
+
+ r.in.group_handle = &group_handle;
+ r.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &r),
+ "failed to query group member");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to query group member");
+
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_samr_Close(tctx, b, &group_handle),
+ "failed to close group handle");
+
+ return true;
+}
+
+static bool test_samr_alias(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *domain_handle,
+ struct samr_SamEntry *a)
+{
+ torture_comment(tctx, "Testing alias %s (%d)\n", a->name.string, a->idx);
+
+ torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, a->idx),
+ "failed to call lookuprids");
+
+ {
+ struct samr_GetAliasMembership r;
+ struct lsa_SidArray sids;
+ struct samr_Ids rids;
+
+ ZERO_STRUCT(sids);
+
+ r.in.domain_handle = domain_handle;
+ r.in.sids = &sids;
+ r.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r),
+ "failed to get alias membership");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to get alias membership");
+ }
+
+
+ return true;
+}
+
+static bool test_samr_domain(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t access_mask,
+ const char *domain_name,
+ struct policy_handle *connect_handle,
+ struct policy_handle *domain_handle_p)
+{
+ struct policy_handle domain_handle;
+ struct dom_sid *domain_sid;
+
+ if (!domain_name) {
+ struct samr_EnumDomains r;
+ uint32_t resume_handle;
+ struct samr_SamArray *sam;
+ uint32_t num_entries;
+ int i;
+
+ r.in.connect_handle = connect_handle;
+ r.in.buf_size = 0xffff;
+ r.in.resume_handle = &resume_handle;
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r),
+ "failed to enum domains");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to enum domains");
+
+ torture_assert_int_equal(tctx, num_entries, 2,
+ "unexpected number of domains");
+
+ torture_assert(tctx, sam,
+ "no domain pointer returned");
+
+ for (i=0; i < sam->count; i++) {
+ if (!strequal(sam->entries[i].name.string, "builtin")) {
+ domain_name = sam->entries[i].name.string;
+ break;
+ }
+ }
+
+ torture_assert(tctx, domain_name,
+ "no domain found other than builtin found");
+ }
+
+ {
+ struct samr_LookupDomain r;
+ struct dom_sid2 *sid;
+ struct lsa_String name;
+
+ name.string = talloc_strdup(tctx, domain_name);
+
+ r.in.connect_handle = connect_handle;
+ r.in.domain_name = &name;
+ r.out.sid = &sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r),
+ "failed to lookup domain");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to lookup domain");
+
+ domain_sid = dom_sid_dup(tctx, sid);
+ }
+
+ {
+ struct samr_OpenDomain r;
+
+ r.in.connect_handle = connect_handle;
+ r.in.access_mask = access_mask;
+ r.in.sid = domain_sid;
+ r.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &r),
+ "failed to open domain");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to open domain");
+
+ }
+
+ {
+ struct samr_QueryDomainInfo r;
+ union samr_DomainInfo *info;
+ uint32_t levels[] = { 1, 2, 8, 12 };
+ int i;
+
+ r.in.domain_handle = &domain_handle;
+ r.out.info = &info;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i];
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r),
+ talloc_asprintf(tctx, "failed to query domain info level %d", r.in.level));
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "failed to query domain info level %d", r.in.level));
+ }
+
+ }
+
+ *domain_handle_p = domain_handle;
+
+ return true;
+}
+
+static void get_query_dispinfo_params(int loop_count,
+ uint32_t *max_entries,
+ uint32_t *buf_size)
+{
+ switch(loop_count) {
+ case 0:
+ *max_entries = 512;
+ *buf_size = 16383;
+ break;
+ case 1:
+ *max_entries = 1024;
+ *buf_size = 32766;
+ break;
+ case 2:
+ *max_entries = 2048;
+ *buf_size = 65532;
+ break;
+ case 3:
+ *max_entries = 4096;
+ *buf_size = 131064;
+ break;
+ default: /* loop_count >= 4 */
+ *max_entries = 4096;
+ *buf_size = 131071;
+ break;
+ }
+}
+
+
+static bool test_samr_users(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t access_mask,
+ struct policy_handle *domain_handle)
+{
+ {
+ struct samr_QueryDisplayInfo r;
+ uint32_t total_size;
+ uint32_t returned_size;
+ union samr_DispInfo info;
+ int loop_count = 0;
+
+ r.in.domain_handle = domain_handle;
+ r.in.level = 1;
+ r.in.start_idx = 0;
+
+ r.out.total_size = &total_size;
+ r.out.returned_size = &returned_size;
+ r.out.info = &info;
+
+ do {
+ int i;
+
+ r.in.max_entries = 0xffff;
+ r.in.buf_size = 0xffff;
+
+ get_query_dispinfo_params(loop_count,
+ &r.in.max_entries,
+ &r.in.buf_size);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r),
+ "QueryDisplayInfo failed");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to call QueryDisplayInfo");
+ }
+
+ for (i=0; i < info.info1.count; i++) {
+ torture_assert(tctx,
+ test_user(tctx, b, domain_handle, access_mask, &info.info1.entries[i]),
+ "failed to test user");
+ }
+ loop_count++;
+ r.in.start_idx += info.info1.count;
+
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return true;
+}
+
+static bool test_samr_groups(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t access_mask,
+ struct policy_handle *domain_handle)
+{
+ {
+ struct samr_EnumDomainGroups r;
+ uint32_t resume_handle = 0;
+ struct samr_SamArray *sam;
+ uint32_t num_entries;
+
+ r.in.domain_handle = domain_handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.max_size = 0xFFFF;
+
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ do {
+ int i;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r),
+ "EnumDomainGroups failed");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to call EnumDomainGroups");
+ }
+
+ for (i=0; i < num_entries; i++) {
+ torture_assert(tctx,
+ test_samr_group(tctx, b, domain_handle, access_mask, &sam->entries[i]),
+ "failed to test group");
+ }
+
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return true;
+}
+
+static bool test_samr_aliases(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t access_mask,
+ struct policy_handle *domain_handle)
+{
+ {
+ struct samr_EnumDomainAliases r;
+ uint32_t resume_handle = 0;
+ struct samr_SamArray *sam;
+ uint32_t num_entries;
+
+ r.in.domain_handle = domain_handle;
+ r.in.resume_handle = &resume_handle;
+ r.in.max_size = 0xFFFF;
+
+ r.out.sam = &sam;
+ r.out.num_entries = &num_entries;
+ r.out.resume_handle = &resume_handle;
+
+ do {
+ int i;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r),
+ "EnumDomainAliases failed");
+ if (NT_STATUS_IS_ERR(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "failed to call EnumDomainAliases");
+ }
+
+ for (i=0; i < num_entries; i++) {
+ torture_assert(tctx,
+ test_samr_alias(tctx, b, domain_handle, &sam->entries[i]),
+ "failed to test alias");
+ }
+
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return true;
+}
+
+static bool torture_rpc_samr_workstation_query(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct cli_credentials *machine_credentials)
+{
+ struct policy_handle connect_handle;
+ struct policy_handle domain_handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
+ &connect_handle),
+ "failed to connect to samr server");
+
+ torture_assert(tctx,
+ test_samr_domain(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
+ lpcfg_workgroup(tctx->lp_ctx),
+ &connect_handle, &domain_handle),
+ "failed to test domain");
+
+ torture_assert(tctx,
+ test_samr_users(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
+ &domain_handle),
+ "failed to test users");
+
+ torture_assert(tctx,
+ test_samr_groups(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
+ &domain_handle),
+ "failed to test groups");
+
+ torture_assert(tctx,
+ test_samr_aliases(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
+ &domain_handle),
+ "failed to test aliases");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_samr_Close(tctx, b, &domain_handle),
+ "failed to close domain handle");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_samr_Close(tctx, b, &connect_handle),
+ "failed to close connect handle");
+
+ return true;
+}
+
+/* The purpose of this test is to verify that an account authenticated as a
+ * domain member workstation can query a DC for various remote read calls all
+ * opening objects while requesting SEC_FLAG_MAXIMUM_ALLOWED access rights on
+ * the object open calls. This is the behavior of winbind (and most of samba's
+ * client code) - gd */
+
+struct torture_suite *torture_rpc_samr_workstation_auth(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.machine.auth");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr,
+ TEST_MACHINENAME);
+
+ torture_rpc_tcase_add_test_creds(tcase, "workstation_query",
+ torture_rpc_samr_workstation_query);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/samr_handletype.c b/source4/torture/rpc/samr_handletype.c
new file mode 100644
index 0000000..ab5e7d0
--- /dev/null
+++ b/source4/torture/rpc/samr_handletype.c
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for handle types on the SAMR pipe
+
+ Copyright (C) Samuel Cabrero <scabrero@samba.org> 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "libcli/security/security.h"
+
+enum samr_handle {
+ SAMR_HANDLE_CONNECT,
+ SAMR_HANDLE_DOMAIN,
+ SAMR_HANDLE_USER,
+ SAMR_HANDLE_GROUP,
+ SAMR_HANDLE_ALIAS
+};
+
+static NTSTATUS torture_samr_Close(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *h)
+{
+ NTSTATUS status;
+ struct samr_Close cl;
+
+ cl.in.handle = h;
+ cl.out.handle = h;
+ status = dcerpc_samr_Close_r(b, tctx, &cl);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return cl.out.result;
+}
+
+static NTSTATUS torture_samr_Connect5(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t mask, struct policy_handle *h)
+{
+ NTSTATUS status;
+ struct samr_Connect5 r5;
+ union samr_ConnectInfo info;
+ uint32_t level_out = 0;
+
+ info.info1.client_version = 0;
+ info.info1.supported_features = 0;
+ r5.in.system_name = "";
+ r5.in.level_in = 1;
+ r5.in.info_in = &info;
+ r5.out.info_out = &info;
+ r5.out.level_out = &level_out;
+ r5.out.connect_handle = h;
+ r5.in.access_mask = mask;
+
+ status = dcerpc_samr_Connect5_r(b, tctx, &r5);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return r5.out.result;
+}
+
+static bool test_samr_handletype_OpenDomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct samr_LookupDomain ld;
+ struct dom_sid2 *sid = NULL;
+ struct samr_OpenDomain od;
+ struct samr_OpenUser ou;
+ struct samr_OpenGroup og;
+ struct policy_handle ch;
+ struct policy_handle bad;
+ struct policy_handle dh;
+ struct policy_handle oh;
+ struct lsa_String dn;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ /* first we must grab the sid of the domain */
+ status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
+ torture_assert_ntstatus_ok(tctx, status, "Connect5 failed");
+
+ ld.in.connect_handle = &ch;
+ ld.in.domain_name = &dn;
+ ld.out.sid = &sid;
+ dn.string = lpcfg_workgroup(tctx->lp_ctx);
+ status = dcerpc_samr_LookupDomain_r(b, tctx, &ld);
+ torture_assert_ntstatus_ok(tctx, status, "LookupDomain failed");
+ torture_assert_ntstatus_ok(tctx, ld.out.result, "LookupDomain failed");
+
+ status = torture_samr_Connect5(tctx, b, 1, &ch);
+ torture_assert_ntstatus_ok(tctx, status, "Connect5 failed");
+
+ od.in.connect_handle = &bad;
+ od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ od.in.sid = sid;
+ od.out.domain_handle = &dh;
+
+ /* Open domain, wrong handle GUID */
+ bad = ch;
+ bad.uuid = GUID_random();
+
+ status = dcerpc_samr_OpenDomain_r(b, tctx, &od);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "OpenDomain succeeded with random GUID");
+
+ /* Open domain, wrong handle type */
+ bad = ch;
+ bad.handle_type = SAMR_HANDLE_USER;
+
+ status = dcerpc_samr_OpenDomain_r(b, tctx, &od);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "OpenDomain succeeded with wrong type");
+
+ /* Open domain */
+ bad = ch;
+
+ status = dcerpc_samr_OpenDomain_r(b, tctx, &od);
+ torture_assert_ntstatus_ok(tctx, status, "OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, od.out.result, "OpenDomain failed");
+
+ bad = dh;
+
+ /* Open user, wrong handle type */
+ ou.in.domain_handle = &bad;
+ ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ ou.in.rid = 501;
+ ou.out.user_handle = &oh;
+
+ bad.handle_type = SAMR_HANDLE_ALIAS;
+
+ status = dcerpc_samr_OpenUser_r(b, tctx, &ou);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "OpenUser succeeded with wrong type");
+
+ /* Open user */
+ bad.handle_type = SAMR_HANDLE_DOMAIN;
+
+ status = dcerpc_samr_OpenUser_r(b, tctx, &ou);
+ torture_assert_ntstatus_ok(tctx, status, "OpenUser failed");
+ torture_assert_ntstatus_ok(tctx, ou.out.result, "OpenUser failed");
+
+ /* Close user */
+ status = torture_samr_Close(tctx, b, &oh);
+ torture_assert_ntstatus_ok(tctx, status, "Close failed");
+
+ bad = dh;
+
+ /* Open group, wrong type */
+ og.in.domain_handle = &bad;
+ og.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ og.in.rid = 513;
+ og.out.group_handle = &oh;
+
+ bad.handle_type = SAMR_HANDLE_GROUP;
+
+ status = dcerpc_samr_OpenGroup_r(b, tctx, &og);
+ torture_assert_ntstatus_equal(tctx,
+ status,
+ NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "OpenGroup succeeded with wrong type");
+
+ /* Open group */
+ bad.handle_type = SAMR_HANDLE_DOMAIN;
+
+ status = dcerpc_samr_OpenGroup_r(b, tctx, &og);
+ torture_assert_ntstatus_ok(tctx, status, "OpenGroup failed");
+ torture_assert_ntstatus_ok(tctx, ou.out.result, "OpenGroup failed");
+
+ /* Close group */
+ status = torture_samr_Close(tctx, b, &oh);
+ torture_assert_ntstatus_ok(tctx, status, "Close failed");
+
+ /* Close connect */
+ status = torture_samr_Close(tctx, b, &ch);
+ torture_assert_ntstatus_ok(tctx, status, "Close failed");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_samr_handletype(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = NULL;
+ struct torture_rpc_tcase *tcase = NULL;
+
+ suite = torture_suite_create(mem_ctx, "samr.handletype");
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "samr",
+ &ndr_table_samr);
+
+ torture_rpc_tcase_add_test(tcase, "OpenDomainHandleType",
+ test_samr_handletype_OpenDomain);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/samr_priv.c b/source4/torture/rpc/samr_priv.c
new file mode 100644
index 0000000..a5aa4b7
--- /dev/null
+++ b/source4/torture/rpc/samr_priv.c
@@ -0,0 +1,580 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * test suite for samr rpc operations
+ *
+ * Copyright (c) 2011 Andreas Schneider
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "param/param.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "libcli/security/security.h"
+#include "torture/rpc/torture_rpc.h"
+
+#define TEST_ACCOUNT_NAME "guru"
+
+struct torture_user {
+ const char *username;
+ const char *password;
+ const char *domain;
+ uint32_t *builtin_memberships;
+ uint32_t num_builtin_memberships;
+ bool admin_rights;
+};
+
+struct torture_access_context {
+ struct dcerpc_pipe *pipe;
+ struct torture_user user;
+ struct test_join *join;
+};
+
+static void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+}
+
+static bool test_samr_queryUserInfo(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *user_handle)
+{
+ struct samr_QueryUserInfo r;
+ union samr_UserInfo *info;
+ NTSTATUS status;
+
+ r.in.level = UserGeneralInformation;
+ r.in.user_handle = user_handle;
+ r.out.info = &info;
+
+ status = dcerpc_samr_QueryUserInfo_r(b,
+ tctx,
+ &r);
+ torture_assert_ntstatus_ok(tctx, status, "queryUserInfo failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "queryUserInfo failed");
+
+ return true;
+}
+
+static bool test_LookupName(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ const char *name,
+ uint32_t *rid)
+{
+ NTSTATUS status;
+ struct samr_LookupNames n;
+ struct lsa_String sname[1];
+ struct samr_Ids rids, types;
+
+ init_lsa_String(&sname[0], name);
+
+ n.in.domain_handle = domain_handle;
+ n.in.num_names = 1;
+ n.in.names = sname;
+ n.out.rids = &rids;
+ n.out.types = &types;
+
+ status = dcerpc_samr_LookupNames_r(b, tctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ if (!NT_STATUS_IS_OK(n.out.result)) {
+ return false;
+ }
+
+ *rid = n.out.rids->ids[0];
+ return true;
+}
+
+static bool test_samr_CreateUser(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *domain_handle,
+ const char *name,
+ struct policy_handle *user_handle)
+{
+ struct lsa_String username;
+ struct samr_CreateUser r;
+ uint32_t rid = 0;
+ NTSTATUS status;
+
+ init_lsa_String(&username, name);
+
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.domain_handle = domain_handle;
+ r.in.account_name = &username;
+ r.out.user_handle = user_handle;
+ r.out.rid = &rid;
+
+ status = dcerpc_samr_CreateUser_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "CreateUser failed");
+
+ return NT_STATUS_IS_OK(r.out.result);
+}
+
+static bool test_samr_OpenUser(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *domain_handle,
+ const char *name,
+ struct policy_handle *user_handle,
+ bool expected)
+{
+ struct samr_OpenUser r;
+ uint32_t rid = 0;
+ NTSTATUS status;
+ bool ok;
+
+ ok = test_LookupName(b, tctx, domain_handle, name, &rid);
+ if (!ok && expected) {
+ torture_comment(tctx, " - lookup name for %s failed\n", name);
+ return true;
+ } else if (!ok) {
+ return false;
+ }
+
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.domain_handle = domain_handle;
+ r.in.rid = rid;
+ r.out.user_handle = user_handle;
+
+ status = dcerpc_samr_OpenUser_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "OpenUser failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "OpenUser failed");
+
+ return true;
+}
+
+static bool test_samr_openDomain(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *connect_handle,
+ const char *domain,
+ struct policy_handle *domain_handle)
+{
+ struct samr_LookupDomain r;
+ struct samr_OpenDomain r2;
+ struct lsa_String n;
+ struct dom_sid *sid;
+ NTSTATUS status;
+
+ r.in.connect_handle = connect_handle;
+ init_lsa_String(&n, domain);
+ r.in.domain_name = &n;
+ r.out.sid = &sid;
+
+ status = dcerpc_samr_LookupDomain_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "LookupDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "LookupDomain failed");
+
+ r2.in.connect_handle = connect_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.sid = sid;
+ r2.out.domain_handle = domain_handle;
+
+ status = dcerpc_samr_OpenDomain_r(b, tctx, &r2);
+ torture_assert_ntstatus_ok(tctx, status, "OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, r2.out.result, "OpenDomain failed");
+
+ return true;
+}
+
+static bool test_samr_Connect(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *connect_handle)
+{
+ struct samr_Connect r;
+ NTSTATUS status;
+
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.connect_handle = connect_handle;
+
+ status = dcerpc_samr_Connect_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "SAMR connect failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "SAMR connect failed");
+
+ return true;
+}
+
+static bool test_samr_create_user(struct torture_context *tctx,
+ struct torture_access_context *t,
+ const char *name)
+{
+ struct dcerpc_binding_handle *b = t->pipe->binding_handle;
+ struct policy_handle connect_handle;
+ struct policy_handle domain_handle;
+ struct policy_handle user_handle;
+ bool ok = false;
+
+ torture_comment(tctx, "Connecting to SAMR\n");
+ ZERO_STRUCT(connect_handle);
+ ok = test_samr_Connect(tctx, b, &connect_handle);
+ torture_assert(tctx, ok, "Unable to connect to domain");
+
+ torture_comment(tctx, "Opening domain %s\n", t->user.domain);
+ ZERO_STRUCT(domain_handle);
+ ok = test_samr_openDomain(tctx,
+ b,
+ &connect_handle,
+ t->user.domain,
+ &domain_handle);
+ torture_assert(tctx, ok, "Unable to open to domain");
+
+ torture_comment(tctx, "Creating account %s\n", name);
+ ZERO_STRUCT(user_handle);
+ ok = test_samr_CreateUser(tctx,
+ b,
+ &domain_handle,
+ name,
+ &user_handle);
+
+ /* We don't check ok with torture macros here because the
+ * caller might be looking for failure */
+ test_samr_handle_Close(b, tctx, &domain_handle);
+ test_samr_handle_Close(b, tctx, &connect_handle);
+
+ return ok;
+}
+
+static bool test_samr_userinfo_getinfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ bool expected)
+{
+ const char *name;
+ struct dcerpc_pipe *p2 = NULL;
+ struct dcerpc_binding_handle *b;
+ struct policy_handle connect_handle;
+ struct policy_handle domain_handle;
+ struct policy_handle user_handle;
+ NTSTATUS status;
+ uint32_t i = 0;
+ bool ok;
+
+ status = torture_rpc_connection(tctx, &p2, &ndr_table_samr);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Creating secondary connection failed");
+ b = p2->binding_handle;
+
+ torture_comment(tctx, " - 2nd connect\n");
+ /* connect */
+ ZERO_STRUCT(connect_handle);
+ ok = test_samr_Connect(tctx, b, &connect_handle);
+ torture_assert(tctx, ok, "Unable to connect to domain");
+
+ torture_comment(tctx, " - 2nd open domain\n");
+ /* open domain */
+ ZERO_STRUCT(domain_handle);
+ ok = test_samr_openDomain(tctx,
+ b,
+ &connect_handle,
+ torture_setting_string(tctx, "workgroup",
+ lpcfg_workgroup(tctx->lp_ctx)),
+ &domain_handle);
+ torture_assert(tctx, ok, "Unable to open to domain");
+
+ /* create user */
+ name = talloc_asprintf(tctx,
+ "%s%04d",
+ TEST_ACCOUNT_NAME,
+ i);
+
+ torture_comment(tctx, " - 2nd open user\n");
+ ZERO_STRUCT(user_handle);
+ ok = test_samr_OpenUser(tctx,
+ b,
+ &domain_handle,
+ name,
+ &user_handle,
+ expected);
+ torture_assert(tctx, ok, "Unable to open user");
+
+ if (!expected) {
+ torture_comment(tctx, " - 2nd query user\n");
+ ok = test_samr_queryUserInfo(tctx, b, &user_handle);
+ torture_assert(tctx, ok, "Unable to query user");
+
+ test_samr_handle_Close(b, tctx, &user_handle);
+ }
+
+ test_samr_handle_Close(b, tctx, &domain_handle);
+ test_samr_handle_Close(b, tctx, &connect_handle);
+
+ talloc_free(p2);
+
+ return true;
+}
+
+#define NUM_RUNS 20
+static bool torture_rpc_samr_caching(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct test_join *join;
+ const char *password = NULL;
+ const char *name;
+ NTSTATUS status;
+ uint32_t i = 0;
+ bool ok;
+
+ torture_comment(tctx, ">>> Testing User Info Caching\n");
+
+ /* create user */
+ name = talloc_asprintf(tctx,
+ "%s%04d",
+ TEST_ACCOUNT_NAME,
+ i);
+
+ torture_comment(tctx, "- Creating user %s\n", name);
+
+ join = torture_create_testuser(tctx,
+ name,
+ torture_setting_string(tctx, "workgroup",
+ lpcfg_workgroup(tctx->lp_ctx)),
+ ACB_NORMAL,
+ &password);
+ torture_assert(tctx, join, "failed to join domain");
+
+ torture_comment(tctx, "- Query user information\n");
+ for (i = 0; i < NUM_RUNS; i++) {
+ ok = test_samr_userinfo_getinfo(tctx, p, false);
+ torture_assert(tctx, ok, "test_samr_userinfo_getinfo failed");
+ }
+
+ torture_comment(tctx, "- Delete user\n");
+ status = torture_delete_testuser(tctx,
+ join,
+ name);
+ torture_assert_ntstatus_ok(tctx, status, "DeleteUser failed");
+
+ torture_comment(tctx, "- Try to query user information again (should fail)\n");
+ for (i = 0; i < NUM_RUNS; i++) {
+ ok = test_samr_userinfo_getinfo(tctx,
+ p,
+ true);
+ torture_assert(tctx, ok, "test_samr_userinfo_getinfo failed");
+ }
+
+ return true;
+}
+#undef NUM_RUNS
+
+static bool torture_rpc_samr_access_setup_membership(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ uint32_t num_members,
+ uint32_t *members,
+ struct dom_sid *user_sid)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle connect_handle, domain_handle;
+ int i;
+
+ torture_comment(tctx,
+ "Setting up BUILTIN membership for %s\n",
+ dom_sid_string(tctx, user_sid));
+
+ for (i=0; i < num_members; i++) {
+ torture_comment(tctx, "adding user to S-1-5-32-%d\n", members[i]);
+ }
+
+ /* connect */
+ {
+ struct samr_Connect2 r;
+ r.in.system_name = "";
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ ZERO_STRUCT(connect_handle);
+ r.out.connect_handle = &connect_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Connect2_r(b, tctx, &r),
+ "samr_Connect2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_Connect2 failed");
+ }
+
+ /* open domain */
+ {
+ struct samr_OpenDomain r;
+ r.in.connect_handle = &connect_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32");
+ ZERO_STRUCT(domain_handle);
+ r.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenDomain_r(b, tctx, &r),
+ "samr_OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_OpenDomain failed");
+ }
+
+ for (i = 0; i < num_members; i++) {
+
+ struct policy_handle alias_handle;
+
+ /* open alias */
+ {
+ struct samr_OpenAlias r;
+ r.in.domain_handle = &domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = members[i];
+ ZERO_STRUCT(alias_handle);
+ r.out.alias_handle = &alias_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenAlias_r(b, tctx, &r),
+ "samr_OpenAlias failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_OpenAlias failed");
+ }
+
+ /* add alias member */
+ {
+ struct samr_AddAliasMember r;
+ ZERO_STRUCT(alias_handle);
+ r.in.alias_handle = &alias_handle;
+ r.in.sid = user_sid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_AddAliasMember_r(b, tctx, &r),
+ "samr_AddAliasMember failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_AddAliasMember failed");
+ }
+
+ test_samr_handle_Close(b, tctx, &alias_handle);
+ }
+
+ test_samr_handle_Close(b, tctx, &domain_handle);
+ test_samr_handle_Close(b, tctx, &connect_handle);
+
+ return true;
+}
+
+static bool torture_rpc_samr_access_setup(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_access_context *t)
+{
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ struct cli_credentials *test_credentials;
+ struct test_join *join;
+ struct dom_sid *test_sid;
+ struct dcerpc_pipe *samr_pipe;
+
+ t->user.domain = torture_setting_string(tctx, "workgroup",
+ lpcfg_workgroup(tctx->lp_ctx)),
+
+ join = torture_create_testuser(tctx,
+ t->user.username,
+ t->user.domain,
+ ACB_NORMAL,
+ &t->user.password);
+ torture_assert(tctx, join, "failed to join domain");
+ t->join = join;
+
+ test_credentials = cli_credentials_init(tctx);
+
+ cli_credentials_set_workstation(test_credentials,
+ "localhost",
+ CRED_SPECIFIED);
+ cli_credentials_set_domain(test_credentials,
+ torture_setting_string(tctx, "workgroup",
+ lpcfg_workgroup(tctx->lp_ctx)),
+ CRED_SPECIFIED);
+ cli_credentials_set_username(test_credentials,
+ t->user.username,
+ CRED_SPECIFIED);
+ cli_credentials_set_password(test_credentials,
+ t->user.password,
+ CRED_SPECIFIED);
+ test_sid = discard_const_p(struct dom_sid,
+ torture_join_user_sid(t->join));
+
+ if (t->user.num_builtin_memberships) {
+ torture_assert(tctx,
+ torture_rpc_samr_access_setup_membership(tctx,
+ p,
+ t->user.num_builtin_memberships,
+ t->user.builtin_memberships,
+ test_sid),
+ "failed to setup membership");
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect(tctx,
+ &samr_pipe,
+ binding,
+ &ndr_table_samr,
+ test_credentials,
+ tctx->ev,
+ tctx->lp_ctx),
+ "Error connecting to server");
+
+ t->pipe = samr_pipe;
+
+ return true;
+}
+
+static bool torture_rpc_samr_access(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_access_context *t;
+ const char *testuser;
+ bool ok;
+
+ torture_comment(tctx, "Testing non-privileged user access\n");
+
+ t = talloc_zero(tctx, struct torture_access_context);
+ torture_assert(tctx, t, "talloc failed");
+
+ t->user.username = talloc_asprintf(t, "%s%04d", TEST_ACCOUNT_NAME, 100);
+
+ torture_comment(tctx, "*** Setting up non-privleged user\n"
+ "***\n");
+
+ ok = torture_rpc_samr_access_setup(tctx, p, t);
+ torture_assert(tctx, ok, "torture_rpc_samr_access_setup failed");
+
+ testuser = talloc_asprintf(t, "%s%04d", TEST_ACCOUNT_NAME, 200);
+
+ torture_comment(tctx, "*** Try to create user (%s) as non-privileged "
+ "user - should fail\n"
+ "***\n", testuser);
+
+ ok = test_samr_create_user(tctx, t, testuser);
+
+ torture_assert(tctx, ok == false, "*** Creating user was successful but it should fail");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_samr_priv(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(mem_ctx, "samr.priv");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite,
+ "samr",
+ &ndr_table_samr);
+
+ torture_rpc_tcase_add_test(tcase,
+ "caching",
+ torture_rpc_samr_caching);
+
+ torture_rpc_tcase_add_test(tcase,
+ "access",
+ torture_rpc_samr_access);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/samsync.c b/source4/torture/rpc/samsync.c
new file mode 100644
index 0000000..a8541d3
--- /dev/null
+++ b/source4/torture/rpc/samsync.c
@@ -0,0 +1,1798 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for netlogon rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+ Copyright (C) Tim Potter 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../lib/util/dlinklist.h"
+#include "../lib/crypto/crypto.h"
+#include "system/time.h"
+#include "torture/rpc/torture_rpc.h"
+#include "auth/gensec/gensec.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/samsync/samsync.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "param/param.h"
+#include "lib/crypto/gnutls_helpers.h"
+
+#define TEST_MACHINE_NAME "samsynctest"
+#define TEST_WKSTA_MACHINE_NAME "samsynctest2"
+#define TEST_USER_NAME "samsynctestuser"
+
+/*
+ try a netlogon SamLogon
+*/
+static NTSTATUS test_SamLogon(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ const char *domain, const char *account_name,
+ const char *workstation,
+ struct samr_Password *lm_hash,
+ struct samr_Password *nt_hash,
+ struct netr_SamInfo3 **info3)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogon r;
+ struct netr_Authenticator auth, auth2;
+ struct netr_NetworkInfo ninfo;
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ int rc;
+
+ ninfo.identity_info.domain_name.string = domain;
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.account_name.string = account_name;
+ ninfo.identity_info.workstation.string = workstation;
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ if (nt_hash) {
+ ninfo.nt.length = 24;
+ ninfo.nt.data = talloc_array(mem_ctx, uint8_t, 24);
+ rc = SMBOWFencrypt(nt_hash->hash, ninfo.challenge,
+ ninfo.nt.data);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ ninfo.nt.length = 0;
+ ninfo.nt.data = NULL;
+ }
+
+ if (lm_hash) {
+ ninfo.lm.length = 24;
+ ninfo.lm.data = talloc_array(mem_ctx, uint8_t, 24);
+ rc = SMBOWFencrypt(lm_hash->hash, ninfo.challenge,
+ ninfo.lm.data);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ ninfo.lm.length = 0;
+ ninfo.lm.data = NULL;
+ }
+
+ logon.network = &ninfo;
+
+ r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = workstation;
+ r.in.credential = &auth;
+ r.in.return_authenticator = &auth2;
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.logon = &logon;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+
+ ZERO_STRUCT(auth2);
+ netlogon_creds_client_authenticator(creds, &auth);
+
+ r.in.validation_level = 3;
+
+ status = dcerpc_netr_LogonSamLogon_r(b, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ if (info3) {
+ *info3 = validation.sam3;
+ }
+
+ return r.out.result;
+}
+
+struct samsync_state {
+/* we remember the sequence numbers so we can easily do a DatabaseDelta */
+ uint64_t seq_num[3];
+ const char *domain_name[2];
+ struct samsync_secret *secrets;
+ struct samsync_trusted_domain *trusted_domains;
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState *creds_netlogon_wksta;
+ struct policy_handle *connect_handle;
+ struct policy_handle *domain_handle[2];
+ struct dom_sid *sid[2];
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ struct dcerpc_pipe *p_netlogon_wksta;
+ struct dcerpc_pipe *p_samr;
+ struct dcerpc_binding_handle *b_samr;
+ struct dcerpc_pipe *p_lsa;
+ struct dcerpc_binding_handle *b_lsa;
+ struct policy_handle *lsa_handle;
+};
+
+struct samsync_secret {
+ struct samsync_secret *prev, *next;
+ DATA_BLOB secret;
+ const char *name;
+ NTTIME mtime;
+};
+
+struct samsync_trusted_domain {
+ struct samsync_trusted_domain *prev, *next;
+ struct dom_sid *sid;
+ const char *name;
+};
+
+static struct policy_handle *samsync_open_domain(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct samsync_state *samsync_state,
+ const char *domain,
+ struct dom_sid **sid_p)
+{
+ struct lsa_String name;
+ struct samr_OpenDomain o;
+ struct samr_LookupDomain l;
+ struct dom_sid2 *sid = NULL;
+ struct policy_handle *domain_handle = talloc(mem_ctx, struct policy_handle);
+ NTSTATUS nt_status;
+
+ name.string = domain;
+ l.in.connect_handle = samsync_state->connect_handle;
+ l.in.domain_name = &name;
+ l.out.sid = &sid;
+
+ nt_status = dcerpc_samr_LookupDomain_r(samsync_state->b_samr, mem_ctx, &l);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(nt_status));
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(l.out.result)) {
+ torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(l.out.result));
+ return NULL;
+ }
+
+ o.in.connect_handle = samsync_state->connect_handle;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.in.sid = *l.out.sid;
+ o.out.domain_handle = domain_handle;
+
+ if (sid_p) {
+ *sid_p = *l.out.sid;
+ }
+
+ nt_status = dcerpc_samr_OpenDomain_r(samsync_state->b_samr, mem_ctx, &o);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(nt_status));
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(o.out.result)) {
+ torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(o.out.result));
+ return NULL;
+ }
+
+ return domain_handle;
+}
+
+static struct sec_desc_buf *samsync_query_samr_sec_desc(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct samsync_state *samsync_state,
+ struct policy_handle *handle)
+{
+ struct samr_QuerySecurity r;
+ struct sec_desc_buf *sdbuf = NULL;
+ NTSTATUS status;
+
+ r.in.handle = handle;
+ r.in.sec_info = 0x7;
+ r.out.sdbuf = &sdbuf;
+
+ status = dcerpc_samr_QuerySecurity_r(samsync_state->b_samr, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "SAMR QuerySecurity failed - %s\n", nt_errstr(status));
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "SAMR QuerySecurity failed - %s\n", nt_errstr(r.out.result));
+ return NULL;
+ }
+
+ return sdbuf;
+}
+
+static struct sec_desc_buf *samsync_query_lsa_sec_desc(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct samsync_state *samsync_state,
+ struct policy_handle *handle)
+{
+ struct lsa_QuerySecurity r;
+ struct sec_desc_buf *sdbuf = NULL;
+ NTSTATUS status;
+
+ r.in.handle = handle;
+ r.in.sec_info = 0x7;
+ r.out.sdbuf = &sdbuf;
+
+ status = dcerpc_lsa_QuerySecurity_r(samsync_state->b_lsa, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "LSA QuerySecurity failed - %s\n", nt_errstr(status));
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "LSA QuerySecurity failed - %s\n", nt_errstr(r.out.result));
+ return NULL;
+ }
+
+ return sdbuf;
+}
+
+#define TEST_UINT64_EQUAL(i1, i2) do {\
+ if (i1 != i2) {\
+ torture_comment(tctx, "%s: uint64 mismatch: " #i1 ": 0x%016llx (%lld) != " #i2 ": 0x%016llx (%lld)\n", \
+ __location__, \
+ (long long)i1, (long long)i1, \
+ (long long)i2, (long long)i2);\
+ ret = false;\
+ } \
+} while (0)
+#define TEST_INT_EQUAL(i1, i2) do {\
+ if (i1 != i2) {\
+ torture_comment(tctx, "%s: integer mismatch: " #i1 ": 0x%08x (%d) != " #i2 ": 0x%08x (%d)\n", \
+ __location__, i1, i1, i2, i2); \
+ ret = false;\
+ } \
+} while (0)
+#define TEST_TIME_EQUAL(t1, t2) do {\
+ if (t1 != t2) {\
+ torture_comment(tctx, "%s: NTTIME mismatch: " #t1 ":%s != " #t2 ": %s\n", \
+ __location__, nt_time_string(mem_ctx, t1), nt_time_string(mem_ctx, t2));\
+ ret = false;\
+ } \
+} while (0)
+
+#define TEST_STRING_EQUAL(s1, s2) do {\
+ if (!((!s1.string || s1.string[0]=='\0') && (!s2.string || s2.string[0]=='\0')) \
+ && strcmp_safe(s1.string, s2.string) != 0) {\
+ torture_comment(tctx, "%s: string mismatch: " #s1 ":%s != " #s2 ": %s\n", \
+ __location__, s1.string, s2.string);\
+ ret = false;\
+ } \
+} while (0)
+
+#define TEST_BINARY_STRING_EQUAL(s1, s2) do {\
+ if (!((!s1.array || s1.array[0]=='\0') && (!s2.array || s2.array[0]=='\0')) \
+ && memcmp(s1.array, s2.array, s1.length * 2) != 0) {\
+ torture_comment(tctx, "%s: string mismatch: " #s1 ":%s != " #s2 ": %s\n", \
+ __location__, (const char *)s1.array, (const char *)s2.array);\
+ ret = false;\
+ } \
+} while (0)
+
+#define TEST_SID_EQUAL(s1, s2) do {\
+ if (!dom_sid_equal(s1, s2)) {\
+ torture_comment(tctx, "%s: dom_sid mismatch: " #s1 ":%s != " #s2 ": %s\n", \
+ __location__, dom_sid_string(mem_ctx, s1), dom_sid_string(mem_ctx, s2));\
+ ret = false;\
+ } \
+} while (0)
+
+/* The ~SEC_DESC_SACL_PRESENT is because we don't, as administrator,
+ * get back the SACL part of the SD when we ask over SAMR */
+
+#define TEST_SEC_DESC_EQUAL(sd1, pipe, handle) do {\
+ struct sec_desc_buf *sdbuf = samsync_query_ ##pipe## _sec_desc(tctx, mem_ctx, samsync_state, \
+ handle); \
+ if (!sdbuf || !sdbuf->sd) { \
+ torture_comment(tctx, "Could not obtain security descriptor to match " #sd1 "\n");\
+ ret = false; \
+ } else {\
+ if (!security_descriptor_mask_equal(sd1.sd, sdbuf->sd, \
+ ~SEC_DESC_SACL_PRESENT)) {\
+ torture_comment(tctx, "Security Descriptor Mismatch for %s:\n", #sd1);\
+ NDR_PRINT_DEBUG(security_descriptor, sd1.sd);\
+ NDR_PRINT_DEBUG(security_descriptor, sdbuf->sd);\
+ ret = false;\
+ }\
+ }\
+} while (0)
+
+static bool samsync_handle_domain(struct torture_context *tctx, TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
+ struct dom_sid *dom_sid;
+ struct samr_QueryDomainInfo q[14]; /* q[0] will be unused simple for clarity */
+ union samr_DomainInfo *info[14];
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13};
+ int i;
+ bool ret = true;
+
+ samsync_state->seq_num[database_id] =
+ domain->sequence_num;
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ break;
+ case SAM_DATABASE_BUILTIN:
+ if (strcasecmp_m("BUILTIN", domain->domain_name.string) != 0) {
+ torture_comment(tctx, "BUILTIN domain has different name: %s\n", domain->domain_name.string);
+ }
+ break;
+ case SAM_DATABASE_PRIVS:
+ torture_comment(tctx, "DOMAIN entry on privs DB!\n");
+ return false;
+ break;
+ }
+
+ if (!samsync_state->domain_name[database_id]) {
+ samsync_state->domain_name[database_id] =
+ talloc_strdup(samsync_state, domain->domain_name.string);
+ } else {
+ if (strcasecmp_m(samsync_state->domain_name[database_id], domain->domain_name.string) != 0) {
+ torture_comment(tctx, "Domain has name varies!: %s != %s\n", samsync_state->domain_name[database_id],
+ domain->domain_name.string);
+ return false;
+ }
+ }
+
+ if (!samsync_state->domain_handle[database_id]) {
+ samsync_state->domain_handle[database_id] =
+ samsync_open_domain(tctx,
+ samsync_state,
+ samsync_state,
+ samsync_state->domain_name[database_id],
+ &dom_sid);
+ }
+ if (samsync_state->domain_handle[database_id]) {
+ samsync_state->sid[database_id] = dom_sid_dup(samsync_state, dom_sid);
+ }
+
+ torture_comment(tctx, "\tsequence_nums[%d/%s]=%llu\n",
+ database_id, domain->domain_name.string,
+ (long long)samsync_state->seq_num[database_id]);
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ q[levels[i]].in.domain_handle = samsync_state->domain_handle[database_id];
+ q[levels[i]].in.level = levels[i];
+ q[levels[i]].out.info = &info[levels[i]];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_QueryDomainInfo_r(samsync_state->b_samr, mem_ctx, &q[levels[i]]),
+ talloc_asprintf(tctx, "QueryDomainInfo level %u failed", q[levels[i]].in.level));
+ torture_assert_ntstatus_ok(tctx, q[levels[i]].out.result,
+ talloc_asprintf(tctx, "QueryDomainInfo level %u failed", q[levels[i]].in.level));
+ }
+
+ TEST_STRING_EQUAL(info[5]->info5.domain_name, domain->domain_name);
+
+ TEST_STRING_EQUAL(info[2]->general.oem_information, domain->oem_information);
+ TEST_STRING_EQUAL(info[4]->oem.oem_information, domain->oem_information);
+ TEST_TIME_EQUAL(info[2]->general.force_logoff_time, domain->force_logoff_time);
+ TEST_TIME_EQUAL(info[3]->info3.force_logoff_time, domain->force_logoff_time);
+
+ TEST_TIME_EQUAL(info[1]->info1.min_password_length, domain->min_password_length);
+ TEST_TIME_EQUAL(info[1]->info1.password_history_length, domain->password_history_length);
+ TEST_TIME_EQUAL(info[1]->info1.max_password_age, domain->max_password_age);
+ TEST_TIME_EQUAL(info[1]->info1.min_password_age, domain->min_password_age);
+
+ TEST_UINT64_EQUAL(info[8]->info8.sequence_num,
+ domain->sequence_num);
+ TEST_TIME_EQUAL(info[8]->info8.domain_create_time,
+ domain->domain_create_time);
+ TEST_TIME_EQUAL(info[13]->info13.domain_create_time,
+ domain->domain_create_time);
+
+ TEST_SEC_DESC_EQUAL(domain->sdbuf, samr, samsync_state->domain_handle[database_id]);
+
+ return ret;
+}
+
+static bool samsync_handle_policy(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ struct netr_DELTA_POLICY *policy = delta->delta_union.policy;
+
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ case SAM_DATABASE_BUILTIN:
+ break;
+ case SAM_DATABASE_PRIVS:
+ torture_comment(tctx, "DOMAIN entry on privs DB!\n");
+ return false;
+ }
+
+ samsync_state->seq_num[database_id] =
+ policy->sequence_num;
+
+ if (!samsync_state->domain_name[SAM_DATABASE_DOMAIN]) {
+ samsync_state->domain_name[SAM_DATABASE_DOMAIN] =
+ talloc_strdup(samsync_state, policy->primary_domain_name.string);
+ } else {
+ if (strcasecmp_m(samsync_state->domain_name[SAM_DATABASE_DOMAIN], policy->primary_domain_name.string) != 0) {
+ torture_comment(tctx, "PRIMARY domain has name varies between DOMAIN and POLICY!: %s != %s\n", samsync_state->domain_name[SAM_DATABASE_DOMAIN],
+ policy->primary_domain_name.string);
+ return false;
+ }
+ }
+
+ if (!dom_sid_equal(samsync_state->sid[SAM_DATABASE_DOMAIN], policy->sid)) {
+ torture_comment(tctx, "Domain SID from POLICY (%s) does not match domain sid from SAMR (%s)\n",
+ dom_sid_string(mem_ctx, policy->sid), dom_sid_string(mem_ctx, samsync_state->sid[SAM_DATABASE_DOMAIN]));
+ return false;
+ }
+
+ torture_comment(tctx, "\tsequence_nums[%d/PRIVS]=%llu\n",
+ database_id,
+ (long long)samsync_state->seq_num[database_id]);
+ return true;
+}
+
+static bool samsync_handle_user(struct torture_context *tctx, TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ uint32_t rid = delta->delta_id_union.rid;
+ struct netr_DELTA_USER *user = delta->delta_union.user;
+ struct netr_SamInfo3 *info3 = NULL;
+ struct samr_Password lm_hash;
+ struct samr_Password nt_hash;
+ struct samr_Password *lm_hash_p = NULL;
+ struct samr_Password *nt_hash_p = NULL;
+ const char *domain;
+ const char *username = user->account_name.string;
+ NTSTATUS nt_status;
+ bool ret = true;
+ struct samr_OpenUser r;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ struct policy_handle user_handle;
+ struct samr_GetGroupsForUser getgr;
+ struct samr_RidWithAttributeArray *rids;
+
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ case SAM_DATABASE_BUILTIN:
+ break;
+ case SAM_DATABASE_PRIVS:
+ torture_comment(tctx, "DOMAIN entry on privs DB!\n");
+ return false;
+ }
+
+ domain = samsync_state->domain_name[database_id];
+
+ if (domain == NULL ||
+ samsync_state->domain_handle[database_id] == NULL) {
+ torture_comment(tctx, "SamSync needs domain information before the users\n");
+ return false;
+ }
+
+ r.in.domain_handle = samsync_state->domain_handle[database_id];
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.user_handle = &user_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenUser_r(samsync_state->b_samr, mem_ctx, &r),
+ talloc_asprintf(tctx, "OpenUser(%u) failed", rid));
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "OpenUser(%u) failed", rid));
+
+ q.in.user_handle = &user_handle;
+ q.in.level = 21;
+ q.out.info = &info;
+
+ TEST_SEC_DESC_EQUAL(user->sdbuf, samr, &user_handle);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_QueryUserInfo_r(samsync_state->b_samr, mem_ctx, &q),
+ talloc_asprintf(tctx, "OpenUserInfo level %u failed", q.in.level));
+ torture_assert_ntstatus_ok(tctx, q.out.result,
+ talloc_asprintf(tctx, "OpenUserInfo level %u failed", q.in.level));
+
+ getgr.in.user_handle = &user_handle;
+ getgr.out.rids = &rids;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_GetGroupsForUser_r(samsync_state->b_samr, mem_ctx, &getgr),
+ "GetGroupsForUser failed");
+ torture_assert_ntstatus_ok(tctx, getgr.out.result,
+ "GetGroupsForUser failed");
+
+ if (!test_samr_handle_Close(samsync_state->b_samr, tctx, &user_handle)) {
+ torture_comment(tctx, "samr_handle_Close failed\n");
+ ret = false;
+ }
+ if (!ret) {
+ return false;
+ }
+
+ TEST_STRING_EQUAL(info->info21.account_name, user->account_name);
+ TEST_STRING_EQUAL(info->info21.full_name, user->full_name);
+ TEST_INT_EQUAL(info->info21.rid, user->rid);
+ TEST_INT_EQUAL(info->info21.primary_gid, user->primary_gid);
+ TEST_STRING_EQUAL(info->info21.home_directory, user->home_directory);
+ TEST_STRING_EQUAL(info->info21.home_drive, user->home_drive);
+ TEST_STRING_EQUAL(info->info21.logon_script, user->logon_script);
+ TEST_STRING_EQUAL(info->info21.description, user->description);
+ TEST_STRING_EQUAL(info->info21.workstations, user->workstations);
+
+ TEST_TIME_EQUAL(info->info21.last_logon, user->last_logon);
+ TEST_TIME_EQUAL(info->info21.last_logoff, user->last_logoff);
+
+
+ TEST_INT_EQUAL(info->info21.logon_hours.units_per_week,
+ user->logon_hours.units_per_week);
+ if (ret) {
+ if (memcmp(info->info21.logon_hours.bits, user->logon_hours.bits,
+ info->info21.logon_hours.units_per_week/8) != 0) {
+ torture_comment(tctx, "Logon hours mismatch\n");
+ ret = false;
+ }
+ }
+
+ TEST_INT_EQUAL(info->info21.bad_password_count,
+ user->bad_password_count);
+ TEST_INT_EQUAL(info->info21.logon_count,
+ user->logon_count);
+
+ TEST_TIME_EQUAL(info->info21.last_password_change,
+ user->last_password_change);
+ TEST_TIME_EQUAL(info->info21.acct_expiry,
+ user->acct_expiry);
+
+ TEST_INT_EQUAL((info->info21.acct_flags & ~ACB_PW_EXPIRED), user->acct_flags);
+ if (user->acct_flags & ACB_PWNOEXP) {
+ if (info->info21.acct_flags & ACB_PW_EXPIRED) {
+ torture_comment(tctx, "ACB flags mismatch: both expired and no expiry!\n");
+ ret = false;
+ }
+ if (info->info21.force_password_change != (NTTIME)0x7FFFFFFFFFFFFFFFULL) {
+ torture_comment(tctx, "ACB flags mismatch: no password expiry, but force password change 0x%016llx (%lld) != 0x%016llx (%lld)\n",
+ (unsigned long long)info->info21.force_password_change,
+ (unsigned long long)info->info21.force_password_change,
+ (unsigned long long)0x7FFFFFFFFFFFFFFFULL, (unsigned long long)0x7FFFFFFFFFFFFFFFULL
+ );
+ ret = false;
+ }
+ }
+
+ TEST_INT_EQUAL(info->info21.nt_password_set, user->nt_password_present);
+ TEST_INT_EQUAL(info->info21.lm_password_set, user->lm_password_present);
+ TEST_INT_EQUAL(info->info21.password_expired, user->password_expired);
+
+ TEST_STRING_EQUAL(info->info21.comment, user->comment);
+ TEST_BINARY_STRING_EQUAL(info->info21.parameters, user->parameters);
+
+ TEST_INT_EQUAL(info->info21.country_code, user->country_code);
+ TEST_INT_EQUAL(info->info21.code_page, user->code_page);
+
+ TEST_STRING_EQUAL(info->info21.profile_path, user->profile_path);
+
+ if (user->lm_password_present) {
+ lm_hash_p = &lm_hash;
+ }
+ if (user->nt_password_present) {
+ nt_hash_p = &nt_hash;
+ }
+
+ if (user->user_private_info.SensitiveData) {
+ DATA_BLOB data;
+ struct netr_USER_KEYS keys;
+ enum ndr_err_code ndr_err;
+ data.data = user->user_private_info.SensitiveData;
+ data.length = user->user_private_info.DataLength;
+ ndr_err = ndr_pull_struct_blob(&data, mem_ctx, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ if (keys.keys.keys2.lmpassword.length == 16) {
+ lm_hash_p = &lm_hash;
+ }
+ if (keys.keys.keys2.ntpassword.length == 16) {
+ nt_hash_p = &nt_hash;
+ }
+ } else {
+ torture_comment(tctx, "Failed to parse Sensitive Data for %s:\n", username);
+#if 0
+ dump_data(0, data.data, data.length);
+#endif
+ return false;
+ }
+ }
+
+ if (nt_hash_p) {
+ DATA_BLOB nt_hash_blob = data_blob_const(nt_hash_p, 16);
+ DEBUG(100,("ACCOUNT [%s\\%-25s] NTHASH %s\n", samsync_state->domain_name[0], username, data_blob_hex_string_upper(mem_ctx, &nt_hash_blob)));
+ }
+ if (lm_hash_p) {
+ DATA_BLOB lm_hash_blob = data_blob_const(lm_hash_p, 16);
+ DEBUG(100,("ACCOUNT [%s\\%-25s] LMHASH %s\n", samsync_state->domain_name[0], username, data_blob_hex_string_upper(mem_ctx, &lm_hash_blob)));
+ }
+
+ nt_status = test_SamLogon(tctx,
+ samsync_state->p_netlogon_wksta, mem_ctx, samsync_state->creds_netlogon_wksta,
+ domain,
+ username,
+ TEST_WKSTA_MACHINE_NAME,
+ lm_hash_p,
+ nt_hash_p,
+ &info3);
+
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) {
+ if (user->acct_flags & ACB_DISABLED) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT)) {
+ if (user->acct_flags & ACB_WSTRUST) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT)) {
+ if (user->acct_flags & ACB_SVRTRUST) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) {
+ if (user->acct_flags & ACB_DOMTRUST) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) {
+ if (user->acct_flags & ACB_DOMTRUST) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
+ if (user->acct_flags & ACB_AUTOLOCK) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) {
+ if (info->info21.acct_flags & ACB_PW_EXPIRED) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+ if (!lm_hash_p && !nt_hash_p) {
+ return true;
+ }
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) {
+ /* We would need to know the server's current time to test this properly */
+ return true;
+ } else if (NT_STATUS_IS_OK(nt_status)) {
+ TEST_INT_EQUAL(user->rid, info3->base.rid);
+ TEST_INT_EQUAL(user->primary_gid, info3->base.primary_gid);
+ /* this is 0x0 from NT4 sp6 */
+ if (info3->base.acct_flags) {
+ TEST_INT_EQUAL(user->acct_flags, info3->base.acct_flags);
+ }
+ /* this is NULL from NT4 sp6 */
+ if (info3->base.account_name.string) {
+ TEST_STRING_EQUAL(user->account_name, info3->base.account_name);
+ }
+ /* this is NULL from Win2k3 */
+ if (info3->base.full_name.string) {
+ TEST_STRING_EQUAL(user->full_name, info3->base.full_name);
+ }
+ TEST_STRING_EQUAL(user->logon_script, info3->base.logon_script);
+ TEST_STRING_EQUAL(user->profile_path, info3->base.profile_path);
+ TEST_STRING_EQUAL(user->home_directory, info3->base.home_directory);
+ TEST_STRING_EQUAL(user->home_drive, info3->base.home_drive);
+ TEST_STRING_EQUAL(user->logon_script, info3->base.logon_script);
+
+
+ TEST_TIME_EQUAL(user->last_logon, info3->base.logon_time);
+ TEST_TIME_EQUAL(user->acct_expiry, info3->base.kickoff_time);
+ TEST_TIME_EQUAL(user->last_password_change, info3->base.last_password_change);
+ TEST_TIME_EQUAL(info->info21.force_password_change, info3->base.force_password_change);
+
+ /* Does the concept of a logoff time ever really
+ * exist? (not in any sensible way, according to the
+ * doco I read -- abartlet) */
+
+ /* This copes with the two different versions of 0 I see */
+ /* with NT4 sp6 we have the || case */
+ if (!((user->last_logoff == 0)
+ || (info3->base.logoff_time == 0x7fffffffffffffffLL))) {
+ TEST_TIME_EQUAL(user->last_logoff, info3->base.logoff_time);
+ }
+
+ TEST_INT_EQUAL(rids->count, info3->base.groups.count);
+ if (rids->count == info3->base.groups.count) {
+ int i, j;
+ int count = rids->count;
+ bool *matched = talloc_zero_array(mem_ctx, bool, rids->count);
+
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < count; j++) {
+ if ((rids->rids[i].rid ==
+ info3->base.groups.rids[j].rid)
+ && (rids->rids[i].attributes ==
+ info3->base.groups.rids[j].attributes)) {
+ matched[i] = true;
+ }
+ }
+ }
+
+ for (i = 0; i < rids->count; i++) {
+ if (matched[i] == false) {
+ ret = false;
+ torture_comment(tctx, "Could not find group RID %u found in getgroups in NETLOGON reply\n",
+ rids->rids[i].rid);
+ }
+ }
+ }
+ return ret;
+ } else {
+ torture_comment(tctx, "Could not validate password for user %s\\%s: %s\n",
+ domain, username, nt_errstr(nt_status));
+ return false;
+ }
+ return false;
+}
+
+static bool samsync_handle_alias(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ uint32_t rid = delta->delta_id_union.rid;
+ struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
+ bool ret = true;
+
+ struct samr_OpenAlias r;
+ struct samr_QueryAliasInfo q;
+ union samr_AliasInfo *info;
+ struct policy_handle alias_handle;
+
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ case SAM_DATABASE_BUILTIN:
+ break;
+ case SAM_DATABASE_PRIVS:
+ torture_comment(tctx, "DOMAIN entry on privs DB!\n");
+ return false;
+ }
+
+ if (samsync_state->domain_name[database_id] == NULL ||
+ samsync_state->domain_handle[database_id] == NULL) {
+ torture_comment(tctx, "SamSync needs domain information before the users\n");
+ return false;
+ }
+
+ r.in.domain_handle = samsync_state->domain_handle[database_id];
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.alias_handle = &alias_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenAlias_r(samsync_state->b_samr, mem_ctx, &r),
+ talloc_asprintf(tctx, "OpenUser(%u) failed", rid));
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "OpenUser(%u) failed", rid));
+
+ q.in.alias_handle = &alias_handle;
+ q.in.level = 1;
+ q.out.info = &info;
+
+ TEST_SEC_DESC_EQUAL(alias->sdbuf, samr, &alias_handle);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_QueryAliasInfo_r(samsync_state->b_samr, mem_ctx, &q),
+ "QueryAliasInfo failed");
+ if (!test_samr_handle_Close(samsync_state->b_samr, tctx, &alias_handle)) {
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_comment(tctx, "QueryAliasInfo level %u failed - %s\n",
+ q.in.level, nt_errstr(q.out.result));
+ return false;
+ }
+
+ TEST_STRING_EQUAL(info->all.name, alias->alias_name);
+ TEST_STRING_EQUAL(info->all.description, alias->description);
+ return ret;
+}
+
+static bool samsync_handle_group(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ uint32_t rid = delta->delta_id_union.rid;
+ struct netr_DELTA_GROUP *group = delta->delta_union.group;
+ bool ret = true;
+
+ struct samr_OpenGroup r;
+ struct samr_QueryGroupInfo q;
+ union samr_GroupInfo *info;
+ struct policy_handle group_handle;
+
+ switch (database_id) {
+ case SAM_DATABASE_DOMAIN:
+ case SAM_DATABASE_BUILTIN:
+ break;
+ case SAM_DATABASE_PRIVS:
+ torture_comment(tctx, "DOMAIN entry on privs DB!\n");
+ return false;
+ }
+
+ if (samsync_state->domain_name[database_id] == NULL ||
+ samsync_state->domain_handle[database_id] == NULL) {
+ torture_comment(tctx, "SamSync needs domain information before the users\n");
+ return false;
+ }
+
+ r.in.domain_handle = samsync_state->domain_handle[database_id];
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.group_handle = &group_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenGroup_r(samsync_state->b_samr, mem_ctx, &r),
+ talloc_asprintf(tctx, "OpenUser(%u) failed", rid));
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "OpenUser(%u) failed", rid));
+
+ q.in.group_handle = &group_handle;
+ q.in.level = 1;
+ q.out.info = &info;
+
+ TEST_SEC_DESC_EQUAL(group->sdbuf, samr, &group_handle);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_QueryGroupInfo_r(samsync_state->b_samr, mem_ctx, &q),
+ "QueryGroupInfo failed");
+ if (!test_samr_handle_Close(samsync_state->b_samr, tctx, &group_handle)) {
+ return false;
+ }
+
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_comment(tctx, "QueryGroupInfo level %u failed - %s\n",
+ q.in.level, nt_errstr(q.out.result));
+ return false;
+ }
+
+ TEST_STRING_EQUAL(info->all.name, group->group_name);
+ TEST_INT_EQUAL(info->all.attributes, group->attributes);
+ TEST_STRING_EQUAL(info->all.description, group->description);
+ return ret;
+}
+
+static bool samsync_handle_secret(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
+ const char *name = delta->delta_id_union.name;
+ struct samsync_secret *nsec = talloc(samsync_state, struct samsync_secret);
+ struct samsync_secret *old = talloc(mem_ctx, struct samsync_secret);
+ struct lsa_QuerySecret q;
+ struct lsa_OpenSecret o;
+ struct policy_handle sec_handle;
+ struct lsa_DATA_BUF_PTR bufp1;
+ struct lsa_DATA_BUF_PTR bufp2;
+ NTTIME nsec_mtime;
+ NTTIME old_mtime;
+ bool ret = true;
+ DATA_BLOB lsa_blob1, lsa_blob_out, session_key;
+ NTSTATUS status;
+
+ nsec->name = talloc_strdup(nsec, name);
+ nsec->secret = data_blob_talloc(nsec, secret->current_cipher.cipher_data, secret->current_cipher.maxlen);
+ nsec->mtime = secret->current_cipher_set_time;
+
+ DLIST_ADD(samsync_state->secrets, nsec);
+
+ old->name = talloc_strdup(old, name);
+ old->secret = data_blob_const(secret->old_cipher.cipher_data, secret->old_cipher.maxlen);
+ old->mtime = secret->old_cipher_set_time;
+
+ o.in.handle = samsync_state->lsa_handle;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.in.name.string = name;
+ o.out.sec_handle = &sec_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_OpenSecret_r(samsync_state->b_lsa, mem_ctx, &o),
+ "OpenSecret failed");
+ torture_assert_ntstatus_ok(tctx, o.out.result,
+ "OpenSecret failed");
+
+/*
+ We would like to do this, but it is NOT_SUPPORTED on win2k3
+ TEST_SEC_DESC_EQUAL(secret->sdbuf, lsa, &sec_handle);
+*/
+ status = dcerpc_fetch_session_key(samsync_state->p_lsa, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "dcerpc_fetch_session_key failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+
+ ZERO_STRUCT(nsec_mtime);
+ ZERO_STRUCT(old_mtime);
+
+ /* fetch the secret back again */
+ q.in.sec_handle = &sec_handle;
+ q.in.new_val = &bufp1;
+ q.in.new_mtime = &nsec_mtime;
+ q.in.old_val = &bufp2;
+ q.in.old_mtime = &old_mtime;
+
+ bufp1.buf = NULL;
+ bufp2.buf = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_QuerySecret_r(samsync_state->b_lsa, mem_ctx, &q),
+ "QuerySecret failed");
+ if (NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, q.out.result)) {
+ /* some things are just off limits */
+ return true;
+ } else if (!NT_STATUS_IS_OK(q.out.result)) {
+ torture_comment(tctx, "QuerySecret failed - %s\n", nt_errstr(q.out.result));
+ return false;
+ }
+
+ if (q.out.old_val->buf == NULL) {
+ /* probably just not available due to ACLs */
+ } else {
+ lsa_blob1.data = q.out.old_val->buf->data;
+ lsa_blob1.length = q.out.old_val->buf->length;
+
+ status = sess_decrypt_blob(mem_ctx, &lsa_blob1, &session_key, &lsa_blob_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to decrypt secrets OLD blob: %s\n", nt_errstr(status));
+ return false;
+ }
+
+ if (!q.out.old_mtime) {
+ torture_comment(tctx, "OLD mtime not available on LSA for secret %s\n", old->name);
+ ret = false;
+ }
+ if (old->mtime != *q.out.old_mtime) {
+ torture_comment(tctx, "OLD mtime on secret %s does not match between SAMSYNC (%s) and LSA (%s)\n",
+ old->name, nt_time_string(mem_ctx, old->mtime),
+ nt_time_string(mem_ctx, *q.out.old_mtime));
+ ret = false;
+ }
+
+ if (old->secret.length != lsa_blob_out.length) {
+ torture_comment(tctx, "Returned secret %s doesn't match: %d != %d\n",
+ old->name, (int)old->secret.length, (int)lsa_blob_out.length);
+ ret = false;
+ } else if (memcmp(lsa_blob_out.data,
+ old->secret.data, old->secret.length) != 0) {
+ torture_comment(tctx, "Returned secret %s doesn't match: \n",
+ old->name);
+ DEBUG(1, ("SamSync Secret:\n"));
+ dump_data(1, old->secret.data, old->secret.length);
+ DEBUG(1, ("LSA Secret:\n"));
+ dump_data(1, lsa_blob_out.data, lsa_blob_out.length);
+ ret = false;
+ }
+
+ }
+
+ if (q.out.new_val->buf == NULL) {
+ /* probably just not available due to ACLs */
+ } else {
+ lsa_blob1.data = q.out.new_val->buf->data;
+ lsa_blob1.length = q.out.new_val->buf->length;
+
+ status = sess_decrypt_blob(mem_ctx, &lsa_blob1, &session_key, &lsa_blob_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to decrypt secrets OLD blob\n");
+ return false;
+ }
+
+ if (!q.out.new_mtime) {
+ torture_comment(tctx, "NEW mtime not available on LSA for secret %s\n", nsec->name);
+ ret = false;
+ }
+ if (nsec->mtime != *q.out.new_mtime) {
+ torture_comment(tctx, "NEW mtime on secret %s does not match between SAMSYNC (%s) and LSA (%s)\n",
+ nsec->name, nt_time_string(mem_ctx, nsec->mtime),
+ nt_time_string(mem_ctx, *q.out.new_mtime));
+ ret = false;
+ }
+
+ if (nsec->secret.length != lsa_blob_out.length) {
+ torture_comment(tctx, "Returned secret %s doesn't match: %d != %d\n",
+ nsec->name, (int)nsec->secret.length, (int)lsa_blob_out.length);
+ ret = false;
+ } else if (memcmp(lsa_blob_out.data,
+ nsec->secret.data, nsec->secret.length) != 0) {
+ torture_comment(tctx, "Returned secret %s doesn't match: \n",
+ nsec->name);
+ DEBUG(1, ("SamSync Secret:\n"));
+ dump_data(1, nsec->secret.data, nsec->secret.length);
+ DEBUG(1, ("LSA Secret:\n"));
+ dump_data(1, lsa_blob_out.data, lsa_blob_out.length);
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+static bool samsync_handle_trusted_domain(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ bool ret = true;
+ struct netr_DELTA_TRUSTED_DOMAIN *trusted_domain = delta->delta_union.trusted_domain;
+ struct dom_sid *dom_sid = delta->delta_id_union.sid;
+
+ struct samsync_trusted_domain *ndom = talloc(samsync_state, struct samsync_trusted_domain);
+ struct lsa_OpenTrustedDomain t;
+ struct policy_handle trustdom_handle;
+ struct lsa_QueryTrustedDomainInfo q;
+ union lsa_TrustedDomainInfo *info[9];
+ union lsa_TrustedDomainInfo *_info = NULL;
+ int levels [] = {1, 3, 8};
+ int i;
+
+ ndom->name = talloc_strdup(ndom, trusted_domain->domain_name.string);
+ ndom->sid = dom_sid_dup(ndom, dom_sid);
+
+ t.in.handle = samsync_state->lsa_handle;
+ t.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ t.in.sid = dom_sid;
+ t.out.trustdom_handle = &trustdom_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_OpenTrustedDomain_r(samsync_state->b_lsa, mem_ctx, &t),
+ "OpenTrustedDomain failed");
+ torture_assert_ntstatus_ok(tctx, t.out.result,
+ "OpenTrustedDomain failed");
+
+ for (i=0; i< ARRAY_SIZE(levels); i++) {
+ q.in.trustdom_handle = &trustdom_handle;
+ q.in.level = levels[i];
+ q.out.info = &_info;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_QueryTrustedDomainInfo_r(samsync_state->b_lsa, mem_ctx, &q),
+ "QueryTrustedDomainInfo failed");
+ if (!NT_STATUS_IS_OK(q.out.result)) {
+ if (q.in.level == 8 && NT_STATUS_EQUAL(q.out.result, NT_STATUS_INVALID_PARAMETER)) {
+ info[levels[i]] = NULL;
+ continue;
+ }
+ torture_comment(tctx, "QueryInfoTrustedDomain level %d failed - %s\n",
+ levels[i], nt_errstr(q.out.result));
+ return false;
+ }
+ info[levels[i]] = _info;
+ }
+
+ if (info[8]) {
+ TEST_SID_EQUAL(info[8]->full_info.info_ex.sid, dom_sid);
+ TEST_STRING_EQUAL(info[8]->full_info.info_ex.netbios_name, trusted_domain->domain_name);
+ }
+ TEST_STRING_EQUAL(info[1]->name.netbios_name, trusted_domain->domain_name);
+ TEST_INT_EQUAL(info[3]->posix_offset.posix_offset, trusted_domain->posix_offset);
+/*
+ We would like to do this, but it is NOT_SUPPORTED on win2k3
+ TEST_SEC_DESC_EQUAL(trusted_domain->sdbuf, lsa, &trustdom_handle);
+*/
+ DLIST_ADD(samsync_state->trusted_domains, ndom);
+
+ return ret;
+}
+
+static bool samsync_handle_account(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx, struct samsync_state *samsync_state,
+ int database_id, struct netr_DELTA_ENUM *delta)
+{
+ bool ret = true;
+ struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
+ struct dom_sid *dom_sid = delta->delta_id_union.sid;
+
+ struct lsa_OpenAccount a;
+ struct policy_handle acct_handle;
+ struct lsa_EnumPrivsAccount e;
+ struct lsa_PrivilegeSet *privs = NULL;
+ struct lsa_LookupPrivName r;
+
+ int i, j;
+
+ bool *found_priv_in_lsa;
+
+ a.in.handle = samsync_state->lsa_handle;
+ a.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ a.in.sid = dom_sid;
+ a.out.acct_handle = &acct_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_OpenAccount_r(samsync_state->b_lsa, mem_ctx, &a),
+ "OpenAccount failed");
+ torture_assert_ntstatus_ok(tctx, a.out.result,
+ "OpenAccount failed");
+
+ TEST_SEC_DESC_EQUAL(account->sdbuf, lsa, &acct_handle);
+
+ found_priv_in_lsa = talloc_zero_array(mem_ctx, bool, account->privilege_entries);
+
+ e.in.handle = &acct_handle;
+ e.out.privs = &privs;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_EnumPrivsAccount_r(samsync_state->b_lsa, mem_ctx, &e),
+ "EnumPrivsAccount failed");
+ torture_assert_ntstatus_ok(tctx, e.out.result,
+ "EnumPrivsAccount failed");
+
+ if ((account->privilege_entries && !privs)) {
+ torture_comment(tctx, "Account %s has privileges in SamSync, but not LSA\n",
+ dom_sid_string(mem_ctx, dom_sid));
+ return false;
+ }
+
+ if (!account->privilege_entries && privs && privs->count) {
+ torture_comment(tctx, "Account %s has privileges in LSA, but not SamSync\n",
+ dom_sid_string(mem_ctx, dom_sid));
+ return false;
+ }
+
+ TEST_INT_EQUAL(account->privilege_entries, privs->count);
+
+ for (i=0;i< privs->count; i++) {
+
+ struct lsa_StringLarge *name = NULL;
+
+ r.in.handle = samsync_state->lsa_handle;
+ r.in.luid = &privs->set[i].luid;
+ r.out.name = &name;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_LookupPrivName_r(samsync_state->b_lsa, mem_ctx, &r),
+ "\nLookupPrivName failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "\nLookupPrivName failed");
+
+ if (!r.out.name) {
+ torture_comment(tctx, "\nLookupPrivName failed to return a name\n");
+ return false;
+ }
+ for (j=0;j<account->privilege_entries; j++) {
+ if (strcmp(name->string, account->privilege_name[j].string) == 0) {
+ found_priv_in_lsa[j] = true;
+ break;
+ }
+ }
+ }
+ for (j=0;j<account->privilege_entries; j++) {
+ if (!found_priv_in_lsa[j]) {
+ torture_comment(tctx, "Privilege %s on account %s not found in LSA\n", account->privilege_name[j].string,
+ dom_sid_string(mem_ctx, dom_sid));
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+/*
+ try a netlogon DatabaseSync
+*/
+static bool test_DatabaseSync(struct torture_context *tctx,
+ struct samsync_state *samsync_state,
+ TALLOC_CTX *mem_ctx)
+{
+ TALLOC_CTX *loop_ctx, *delta_ctx, *trustdom_ctx;
+ struct netr_DatabaseSync r;
+ const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS};
+ int i, d;
+ bool ret = true;
+ struct samsync_trusted_domain *t;
+ struct samsync_secret *s;
+ struct netr_Authenticator return_authenticator, credential;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+
+ const char *domain, *username;
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(samsync_state->p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.preferredmaximumlength = (uint32_t)-1;
+ r.in.return_authenticator = &return_authenticator;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+
+ for (i=0;i<ARRAY_SIZE(database_ids);i++) {
+
+ uint32_t sync_context = 0;
+
+ r.in.database_id = database_ids[i];
+ r.in.sync_context = &sync_context;
+ r.out.sync_context = &sync_context;
+
+ torture_comment(tctx, "Testing DatabaseSync of id %d\n", r.in.database_id);
+
+ do {
+ loop_ctx = talloc_named(mem_ctx, 0, "DatabaseSync loop context");
+ netlogon_creds_client_authenticator(samsync_state->creds, &credential);
+
+ r.in.credential = &credential;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_DatabaseSync_r(samsync_state->b, loop_ctx, &r),
+ "DatabaseSync failed");
+ if (!NT_STATUS_IS_OK(r.out.result) &&
+ !NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES)) {
+ torture_comment(tctx, "DatabaseSync - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ break;
+ }
+
+ if (!netlogon_creds_client_check(samsync_state->creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ r.in.sync_context = r.out.sync_context;
+
+ for (d=0; d < delta_enum_array->num_deltas; d++) {
+ delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
+
+ if (!NT_STATUS_IS_OK(samsync_fix_delta(delta_ctx, samsync_state->creds,
+ r.in.database_id,
+ &delta_enum_array->delta_enum[d]))) {
+ torture_comment(tctx, "Failed to decrypt delta\n");
+ ret = false;
+ }
+
+ switch (delta_enum_array->delta_enum[d].delta_type) {
+ case NETR_DELTA_DOMAIN:
+ if (!samsync_handle_domain(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_DOMAIN\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_GROUP:
+ if (!samsync_handle_group(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_USER\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_USER:
+ if (!samsync_handle_user(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_USER\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_ALIAS:
+ if (!samsync_handle_alias(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_ALIAS\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_POLICY:
+ if (!samsync_handle_policy(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_POLICY\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_TRUSTED_DOMAIN:
+ if (!samsync_handle_trusted_domain(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_TRUSTED_DOMAIN\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_ACCOUNT:
+ if (!samsync_handle_account(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_ACCOUNT\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_SECRET:
+ if (!samsync_handle_secret(tctx, delta_ctx, samsync_state,
+ r.in.database_id, &delta_enum_array->delta_enum[d])) {
+ torture_comment(tctx, "Failed to handle DELTA_SECRET\n");
+ ret = false;
+ }
+ break;
+ case NETR_DELTA_GROUP_MEMBER:
+ case NETR_DELTA_ALIAS_MEMBER:
+ /* These are harder to cross-check, and we expect them */
+ break;
+ case NETR_DELTA_DELETE_GROUP:
+ case NETR_DELTA_RENAME_GROUP:
+ case NETR_DELTA_DELETE_USER:
+ case NETR_DELTA_RENAME_USER:
+ case NETR_DELTA_DELETE_ALIAS:
+ case NETR_DELTA_RENAME_ALIAS:
+ case NETR_DELTA_DELETE_TRUST:
+ case NETR_DELTA_DELETE_ACCOUNT:
+ case NETR_DELTA_DELETE_SECRET:
+ case NETR_DELTA_DELETE_GROUP2:
+ case NETR_DELTA_DELETE_USER2:
+ case NETR_DELTA_MODIFY_COUNT:
+ default:
+ torture_comment(tctx, "Uxpected delta type %d\n", delta_enum_array->delta_enum[d].delta_type);
+ ret = false;
+ break;
+ }
+ talloc_free(delta_ctx);
+ }
+ talloc_free(loop_ctx);
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+
+ }
+
+ domain = samsync_state->domain_name[SAM_DATABASE_DOMAIN];
+ if (!domain) {
+ torture_comment(tctx, "Never got a DOMAIN object in samsync!\n");
+ return false;
+ }
+
+ trustdom_ctx = talloc_named(mem_ctx, 0, "test_DatabaseSync Trusted domains context");
+
+ username = talloc_asprintf(trustdom_ctx, "%s$", domain);
+ for (t=samsync_state->trusted_domains; t; t=t->next) {
+ char *secret_name = talloc_asprintf(trustdom_ctx, "G$$%s", t->name);
+ for (s=samsync_state->secrets; s; s=s->next) {
+ if (strcasecmp_m(s->name, secret_name) == 0) {
+ NTSTATUS nt_status;
+ struct samr_Password nt_hash;
+ mdfour(nt_hash.hash, s->secret.data, s->secret.length);
+
+ torture_comment(tctx, "Checking password for %s\\%s\n", t->name, username);
+ nt_status = test_SamLogon(tctx,
+ samsync_state->p_netlogon_wksta, trustdom_ctx, samsync_state->creds_netlogon_wksta,
+ t->name,
+ username,
+ TEST_WKSTA_MACHINE_NAME,
+ NULL,
+ &nt_hash,
+ NULL);
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_LOGON_SERVERS)) {
+ torture_comment(tctx, "Verifiction of trust password to %s failed: %s (the trusted domain is not available)\n",
+ t->name, nt_errstr(nt_status));
+
+ break;
+ }
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT)) {
+ torture_comment(tctx, "Verifiction of trust password to %s: should have failed (nologon interdomain trust account), instead: %s\n",
+ t->name, nt_errstr(nt_status));
+ ret = false;
+ }
+
+ /* break it */
+ nt_hash.hash[0]++;
+ nt_status = test_SamLogon(tctx,
+ samsync_state->p_netlogon_wksta, trustdom_ctx, samsync_state->creds_netlogon_wksta,
+ t->name,
+ username,
+ TEST_WKSTA_MACHINE_NAME,
+ NULL,
+ &nt_hash,
+ NULL);
+
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
+ torture_comment(tctx, "Verifiction of trust password to %s: should have failed (wrong password), instead: %s\n",
+ t->name, nt_errstr(nt_status));
+ ret = false;
+ }
+
+ break;
+ }
+ }
+ }
+ talloc_free(trustdom_ctx);
+ return ret;
+}
+
+
+/*
+ try a netlogon DatabaseDeltas
+*/
+static bool test_DatabaseDeltas(struct torture_context *tctx,
+ struct samsync_state *samsync_state, TALLOC_CTX *mem_ctx)
+{
+ TALLOC_CTX *loop_ctx;
+ struct netr_DatabaseDeltas r;
+ struct netr_Authenticator credential;
+ struct netr_Authenticator return_authenticator;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ const uint32_t database_ids[] = {0, 1, 2};
+ int i;
+ bool ret = true;
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(samsync_state->p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.preferredmaximumlength = (uint32_t)-1;
+ r.in.return_authenticator = &return_authenticator;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+
+ for (i=0;i<ARRAY_SIZE(database_ids);i++) {
+
+ uint64_t seq_num = samsync_state->seq_num[i];
+
+ r.in.database_id = database_ids[i];
+ r.in.sequence_num = &seq_num;
+ r.out.sequence_num = &seq_num;
+
+ if (seq_num == 0) continue;
+
+ /* this shows that the bdc doesn't need to do a single call for
+ * each seqnumber, and the pdc doesn't need to know about old values
+ * -- metze
+ */
+ seq_num -= 10;
+
+ torture_comment(tctx, "Testing DatabaseDeltas of id %d at %llu\n",
+ r.in.database_id, (long long)seq_num);
+
+ do {
+ loop_ctx = talloc_named(mem_ctx, 0, "test_DatabaseDeltas loop context");
+ netlogon_creds_client_authenticator(samsync_state->creds, &credential);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_DatabaseDeltas_r(samsync_state->b, loop_ctx, &r),
+ "DatabaseDeltas failed");
+ if (!NT_STATUS_IS_OK(r.out.result) &&
+ !NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES) &&
+ !NT_STATUS_EQUAL(r.out.result, NT_STATUS_SYNCHRONIZATION_REQUIRED)) {
+ torture_comment(tctx, "DatabaseDeltas - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ if (!netlogon_creds_client_check(samsync_state->creds, &return_authenticator.cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ seq_num++;
+ talloc_free(loop_ctx);
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return ret;
+}
+
+
+/*
+ try a netlogon DatabaseSync2
+*/
+static bool test_DatabaseSync2(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds)
+{
+ TALLOC_CTX *loop_ctx;
+ struct netr_DatabaseSync2 r;
+ const uint32_t database_ids[] = {0, 1, 2};
+ int i;
+ bool ret = true;
+ struct netr_Authenticator return_authenticator, credential;
+ struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(return_authenticator);
+
+ r.in.logon_server = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computername = TEST_MACHINE_NAME;
+ r.in.preferredmaximumlength = (uint32_t)-1;
+ r.in.return_authenticator = &return_authenticator;
+ r.out.return_authenticator = &return_authenticator;
+ r.out.delta_enum_array = &delta_enum_array;
+
+ for (i=0;i<ARRAY_SIZE(database_ids);i++) {
+
+ uint32_t sync_context = 0;
+
+ r.in.database_id = database_ids[i];
+ r.in.sync_context = &sync_context;
+ r.out.sync_context = &sync_context;
+ r.in.restart_state = 0;
+
+ torture_comment(tctx, "Testing DatabaseSync2 of id %d\n", r.in.database_id);
+
+ do {
+ loop_ctx = talloc_named(mem_ctx, 0, "test_DatabaseSync2 loop context");
+ netlogon_creds_client_authenticator(creds, &credential);
+
+ r.in.credential = &credential;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_DatabaseSync2_r(b, loop_ctx, &r),
+ "DatabaseSync2 failed");
+ if (!NT_STATUS_IS_OK(r.out.result) &&
+ !NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES)) {
+ torture_comment(tctx, "DatabaseSync2 - %s\n", nt_errstr(r.out.result));
+ ret = false;
+ }
+
+ if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
+ torture_comment(tctx, "Credential chaining failed\n");
+ }
+
+ talloc_free(loop_ctx);
+ } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
+ }
+
+ return ret;
+}
+
+
+
+bool torture_rpc_samsync(struct torture_context *torture)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct test_join *join_ctx;
+ struct test_join *join_ctx2;
+ struct test_join *user_ctx;
+ const char *machine_password;
+ const char *wksta_machine_password;
+ struct dcerpc_binding *b;
+ struct dcerpc_binding *b_netlogon_wksta;
+ struct samr_Connect c;
+ struct samr_SetDomainInfo s;
+ struct policy_handle *domain_policy;
+
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+ struct lsa_OpenPolicy2 r;
+ struct cli_credentials *credentials;
+ struct cli_credentials *credentials_wksta;
+
+ struct samsync_state *samsync_state;
+
+ char *test_machine_account;
+
+ char *test_wksta_machine_account;
+
+ mem_ctx = talloc_init("torture_rpc_netlogon");
+
+ test_machine_account = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
+ join_ctx = torture_create_testuser(torture, test_machine_account,
+ lpcfg_workgroup(torture->lp_ctx), ACB_SVRTRUST,
+ &machine_password);
+ if (!join_ctx) {
+ talloc_free(mem_ctx);
+ torture_comment(torture, "Failed to join as BDC\n");
+ return false;
+ }
+
+ test_wksta_machine_account = talloc_asprintf(mem_ctx, "%s$", TEST_WKSTA_MACHINE_NAME);
+ join_ctx2 = torture_create_testuser(torture, test_wksta_machine_account, lpcfg_workgroup(torture->lp_ctx), ACB_WSTRUST, &wksta_machine_password);
+ if (!join_ctx2) {
+ talloc_free(mem_ctx);
+ torture_comment(torture, "Failed to join as member\n");
+ return false;
+ }
+
+ user_ctx = torture_create_testuser(torture, TEST_USER_NAME,
+ lpcfg_workgroup(torture->lp_ctx),
+ ACB_NORMAL, NULL);
+ if (!user_ctx) {
+ talloc_free(mem_ctx);
+ torture_comment(torture, "Failed to create test account\n");
+ return false;
+ }
+
+ samsync_state = talloc_zero(mem_ctx, struct samsync_state);
+
+ samsync_state->p_samr = torture_join_samr_pipe(join_ctx);
+ samsync_state->b_samr = samsync_state->p_samr->binding_handle;
+ samsync_state->connect_handle = talloc_zero(samsync_state, struct policy_handle);
+ samsync_state->lsa_handle = talloc_zero(samsync_state, struct policy_handle);
+ c.in.system_name = NULL;
+ c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ c.out.connect_handle = samsync_state->connect_handle;
+
+ torture_assert_ntstatus_ok_goto(torture,
+ dcerpc_samr_Connect_r(samsync_state->b_samr, mem_ctx, &c),
+ ret, failed,
+ "samr_Connect failed");
+ torture_assert_ntstatus_ok_goto(torture, c.out.result,
+ ret, failed,
+ "samr_Connect failed");
+
+ domain_policy = samsync_open_domain(torture, mem_ctx, samsync_state, lpcfg_workgroup(torture->lp_ctx), NULL);
+ if (!domain_policy) {
+ torture_comment(torture, "samrsync_open_domain failed\n");
+ ret = false;
+ goto failed;
+ }
+
+ s.in.domain_handle = domain_policy;
+ s.in.level = 4;
+ s.in.info = talloc(mem_ctx, union samr_DomainInfo);
+
+ s.in.info->oem.oem_information.string
+ = talloc_asprintf(mem_ctx,
+ "Tortured by Samba4: %s",
+ timestring(mem_ctx, time(NULL)));
+ torture_assert_ntstatus_ok_goto(torture,
+ dcerpc_samr_SetDomainInfo_r(samsync_state->b_samr, mem_ctx, &s),
+ ret, failed,
+ "SetDomainInfo failed");
+
+ if (!test_samr_handle_Close(samsync_state->b_samr, torture, domain_policy)) {
+ ret = false;
+ goto failed;
+ }
+
+ torture_assert_ntstatus_ok_goto(torture, s.out.result,
+ ret, failed,
+ talloc_asprintf(torture, "SetDomainInfo level %u failed", s.in.level));
+
+ status = torture_rpc_connection(torture,
+ &samsync_state->p_lsa,
+ &ndr_table_lsarpc);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto failed;
+ }
+ samsync_state->b_lsa = samsync_state->p_lsa->binding_handle;
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.len = 0;
+ attr.root_dir = NULL;
+ attr.object_name = NULL;
+ attr.attributes = 0;
+ attr.sec_desc = NULL;
+ attr.sec_qos = &qos;
+
+ r.in.system_name = "\\";
+ r.in.attr = &attr;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = samsync_state->lsa_handle;
+
+ torture_assert_ntstatus_ok_goto(torture,
+ dcerpc_lsa_OpenPolicy2_r(samsync_state->b_lsa, mem_ctx, &r),
+ ret, failed,
+ "OpenPolicy2 failed");
+ torture_assert_ntstatus_ok_goto(torture, r.out.result,
+ ret, failed,
+ "OpenPolicy2 failed");
+
+ status = torture_rpc_binding(torture, &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto failed;
+ }
+
+ status = dcerpc_binding_set_flags(b,
+ DCERPC_SCHANNEL | DCERPC_SIGN,
+ DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(torture, status, "set flags");
+
+ credentials = cli_credentials_init(mem_ctx);
+
+ cli_credentials_set_workstation(credentials, TEST_MACHINE_NAME, CRED_SPECIFIED);
+ cli_credentials_set_domain(credentials, lpcfg_workgroup(torture->lp_ctx), CRED_SPECIFIED);
+ cli_credentials_set_username(credentials, test_machine_account, CRED_SPECIFIED);
+ cli_credentials_set_password(credentials, machine_password, CRED_SPECIFIED);
+ cli_credentials_set_secure_channel_type(credentials,
+ SEC_CHAN_BDC);
+
+ status = dcerpc_pipe_connect_b(samsync_state,
+ &samsync_state->p, b,
+ &ndr_table_netlogon,
+ credentials, torture->ev, torture->lp_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "Failed to connect to server as a BDC: %s\n", nt_errstr(status));
+ ret = false;
+ goto failed;
+ }
+ samsync_state->b = samsync_state->p->binding_handle;
+
+ samsync_state->creds = cli_credentials_get_netlogon_creds(credentials);
+ if (samsync_state->creds == NULL) {
+ ret = false;
+ }
+
+
+
+ status = torture_rpc_binding(torture, &b_netlogon_wksta);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto failed;
+ }
+
+ status = dcerpc_binding_set_flags(b_netlogon_wksta,
+ DCERPC_SCHANNEL | DCERPC_SIGN,
+ DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(torture, status, "set flags");
+
+ credentials_wksta = cli_credentials_init(mem_ctx);
+
+ cli_credentials_set_workstation(credentials_wksta, TEST_WKSTA_MACHINE_NAME, CRED_SPECIFIED);
+ cli_credentials_set_domain(credentials_wksta, lpcfg_workgroup(torture->lp_ctx), CRED_SPECIFIED);
+ cli_credentials_set_username(credentials_wksta, test_wksta_machine_account, CRED_SPECIFIED);
+ cli_credentials_set_password(credentials_wksta, wksta_machine_password, CRED_SPECIFIED);
+ cli_credentials_set_secure_channel_type(credentials_wksta,
+ SEC_CHAN_WKSTA);
+
+ status = dcerpc_pipe_connect_b(samsync_state,
+ &samsync_state->p_netlogon_wksta,
+ b_netlogon_wksta,
+ &ndr_table_netlogon,
+ credentials_wksta, torture->ev, torture->lp_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(torture, "Failed to connect to server as a Workstation: %s\n", nt_errstr(status));
+ ret = false;
+ goto failed;
+ }
+
+ samsync_state->creds_netlogon_wksta = cli_credentials_get_netlogon_creds(credentials_wksta);
+ if (samsync_state->creds_netlogon_wksta == NULL) {
+ torture_comment(torture, "Failed to obtail schanel creds!\n");
+ ret = false;
+ }
+
+ if (!test_DatabaseSync(torture, samsync_state, mem_ctx)) {
+ torture_comment(torture, "DatabaseSync failed\n");
+ ret = false;
+ }
+
+ if (!test_DatabaseDeltas(torture, samsync_state, mem_ctx)) {
+ torture_comment(torture, "DatabaseDeltas failed\n");
+ ret = false;
+ }
+
+ if (!test_DatabaseSync2(torture, samsync_state->p, mem_ctx, samsync_state->creds)) {
+ torture_comment(torture, "DatabaseSync2 failed\n");
+ ret = false;
+ }
+failed:
+
+ torture_leave_domain(torture, join_ctx);
+ torture_leave_domain(torture, join_ctx2);
+ torture_leave_domain(torture, user_ctx);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/rpc/scanner.c b/source4/torture/rpc/scanner.c
new file mode 100644
index 0000000..261c3b9
--- /dev/null
+++ b/source4/torture/rpc/scanner.c
@@ -0,0 +1,187 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ scanner for rpc calls
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_mgmt_c.h"
+#include "librpc/ndr/ndr_table.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+/*
+ work out how many calls there are for an interface
+ */
+static bool test_num_calls(struct torture_context *tctx,
+ const struct ndr_interface_table *iface,
+ TALLOC_CTX *mem_ctx,
+ struct ndr_syntax_id *id)
+{
+ struct dcerpc_pipe *p;
+ NTSTATUS status;
+ unsigned int i;
+ DATA_BLOB stub_in, stub_out;
+ struct ndr_interface_table _tbl;
+ const struct ndr_interface_table *tbl;
+
+ /* FIXME: This should be fixed when torture_rpc_connection
+ * takes a ndr_syntax_id */
+ tbl = ndr_table_by_syntax(id);
+ if (tbl == NULL) {
+ _tbl = *iface;
+ _tbl.name = "__unknown__";
+ _tbl.syntax_id = *id;
+ _tbl.num_calls = UINT32_MAX;
+ tbl = &_tbl;
+ }
+
+ status = torture_rpc_connection(tctx, &p, tbl);
+ if (!NT_STATUS_IS_OK(status)) {
+ char *uuid_str = GUID_string(mem_ctx, &id->uuid);
+ printf("Failed to connect to '%s' on '%s' - %s\n",
+ uuid_str, iface->name, nt_errstr(status));
+ talloc_free(uuid_str);
+ return true;
+ }
+
+ /* make null calls */
+ stub_in = data_blob_talloc(mem_ctx, NULL, 1000);
+ memset(stub_in.data, 0xFF, stub_in.length);
+
+ for (i=0;i<200;i++) {
+ bool ok;
+ uint32_t out_flags = 0;
+
+ status = dcerpc_binding_handle_raw_call(p->binding_handle,
+ NULL, i,
+ 0, /* in_flags */
+ stub_in.data,
+ stub_in.length,
+ mem_ctx,
+ &stub_out.data,
+ &stub_out.length,
+ &out_flags);
+ ok = dcerpc_binding_handle_is_connected(p->binding_handle);
+ if (!ok) {
+ printf("\tpipe disconnected at %u\n", i);
+ goto done;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ break;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ printf("\taccess denied at %u\n", i);
+ goto done;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ printf("\tprotocol error at %u\n", i);
+ }
+ }
+
+ printf("\t%d calls available\n", i);
+ if (tbl->num_calls == UINT32_MAX) {
+ printf("\tinterface not known in local IDL\n");
+ } else if (tbl->num_calls != i) {
+ printf("\tWARNING: local IDL defines %u calls\n",
+ (unsigned int)tbl->num_calls);
+ } else {
+ printf("\tOK: matches num_calls in local IDL\n");
+ }
+
+done:
+ talloc_free(p);
+ return true;
+}
+
+
+
+bool torture_rpc_scanner(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *loop_ctx;
+ bool ret = true;
+ const struct ndr_interface_list *l;
+ struct dcerpc_binding *b;
+ enum dcerpc_transport_t transport;
+
+ status = torture_rpc_binding(torture, &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ transport = dcerpc_binding_get_transport(b);
+
+ for (l=ndr_table_list();l;l=l->next) {
+ loop_ctx = talloc_named(torture, 0, "torture_rpc_scanner loop context");
+ /* some interfaces are not mappable */
+ if (l->table->num_calls == 0 ||
+ strcmp(l->table->name, "mgmt") == 0) {
+ talloc_free(loop_ctx);
+ continue;
+ }
+
+ printf("\nTesting pipe '%s'\n", l->table->name);
+
+ if (transport == NCACN_IP_TCP) {
+ status = dcerpc_epm_map_binding(torture, b, l->table,
+ torture->ev,
+ torture->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to map port for uuid %s\n",
+ GUID_string(loop_ctx, &l->table->syntax_id.uuid));
+ talloc_free(loop_ctx);
+ continue;
+ }
+ } else {
+ status = dcerpc_binding_set_string_option(b, "endpoint",
+ l->table->name);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(loop_ctx);
+ ret = false;
+ continue;
+ }
+ status = dcerpc_binding_set_abstract_syntax(b,
+ &l->table->syntax_id);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(loop_ctx);
+ ret = false;
+ continue;
+ }
+ }
+
+ lpcfg_set_cmdline(torture->lp_ctx, "torture:binding", dcerpc_binding_string(torture, b));
+
+ status = torture_rpc_connection(torture, &p, &ndr_table_mgmt);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(loop_ctx);
+ ret = false;
+ continue;
+ }
+
+ if (!test_inq_if_ids(torture, p->binding_handle, torture, test_num_calls, l->table)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c
new file mode 100644
index 0000000..d6dca36
--- /dev/null
+++ b/source4/torture/rpc/schannel.c
@@ -0,0 +1,1338 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "torture/rpc/torture_rpc.h"
+#include "lib/cmdline/cmdline.h"
+#include "../libcli/auth/schannel.h"
+#include "libcli/auth/libcli_auth.h"
+#include "libcli/security/security.h"
+#include "system/filesys.h"
+#include "param/param.h"
+#include "librpc/rpc/dcerpc_proto.h"
+#include "libcli/composite/composite.h"
+#include "lib/events/events.h"
+
+#define TEST_MACHINE_NAME "schannel"
+
+/*
+ try a netlogon SamLogon
+*/
+bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogonEx r;
+ struct netr_NetworkInfo ninfo;
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative = 1;
+ uint32_t _flags = 0;
+ DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+ int i;
+ int flags = CLI_CRED_NTLM_AUTH;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ struct netr_UserSessionKey key;
+ struct netr_LMSessionKey LMSessKey;
+ uint32_t validation_levels[] = { 2, 3 };
+ struct netr_SamBaseInfo *base = NULL;
+ const char *crypto_alg = "";
+ bool can_do_validation_6 = true;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ if (lpcfg_client_lanman_auth(tctx->lp_ctx)) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+
+ if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx)) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+ }
+
+ cli_credentials_get_ntlm_username_domain(samba_cmdline_get_creds(),
+ tctx,
+ &ninfo.identity_info.account_name.string,
+ &ninfo.identity_info.domain_name.string);
+
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+ chal = data_blob_const(ninfo.challenge,
+ sizeof(ninfo.challenge));
+
+ names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials),
+ cli_credentials_get_domain(credentials));
+
+ status = cli_credentials_get_ntlm_response(
+ samba_cmdline_get_creds(),
+ tctx,
+ &flags,
+ chal,
+ NULL, /* server_timestamp */
+ names_blob,
+ &lm_resp, &nt_resp,
+ NULL, NULL);
+ torture_assert_ntstatus_ok(tctx, status,
+ "cli_credentials_get_ntlm_response failed");
+
+ ninfo.lm.data = lm_resp.data;
+ ninfo.lm.length = lm_resp.length;
+
+ ninfo.nt.data = nt_resp.data;
+ ninfo.nt.length = nt_resp.length;
+
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
+
+ logon.network = &ninfo;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.logon= &logon;
+ r.in.flags = &_flags;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+ r.out.flags = &_flags;
+
+ /*
+ - retrieve level6
+ - save usrsession and lmsession key
+ - retrieve level 2
+ - calculate, compare
+ - retrieve level 3
+ - calculate, compare
+ */
+
+ if (creds) {
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ crypto_alg = "AES";
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ crypto_alg = "ARCFOUR";
+ }
+ }
+
+ dcerpc_binding_handle_auth_info(b, NULL, &auth_level);
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ r.in.validation_level = 6;
+
+ torture_comment(tctx,
+ "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "LogonSamLogonEx failed");
+ } else {
+ torture_comment(tctx,
+ "Skip auth_level[%u] Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ auth_level, ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+ r.out.result = NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
+ can_do_validation_6 = false;
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LogonSamLogonEx failed");
+
+ key = r.out.validation->sam6->base.key;
+ LMSessKey = r.out.validation->sam6->base.LMSessKey;
+
+ DEBUG(1,("unencrypted session keys from validation_level 6:\n"));
+ dump_data(1, r.out.validation->sam6->base.key.key, 16);
+ dump_data(1, r.out.validation->sam6->base.LMSessKey.key, 8);
+ }
+
+ for (i=0; i < ARRAY_SIZE(validation_levels); i++) {
+
+ r.in.validation_level = validation_levels[i];
+
+ torture_comment(tctx,
+ "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "LogonSamLogonEx failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LogonSamLogonEx failed");
+
+ if (creds == NULL) {
+ /* when this test is called without creds no point in
+ * testing the session keys */
+ continue;
+ }
+
+ switch (validation_levels[i]) {
+ case 2:
+ base = &r.out.validation->sam2->base;
+ break;
+ case 3:
+ base = &r.out.validation->sam3->base;
+ break;
+ default:
+ break;
+ }
+
+ DEBUG(1,("encrypted keys validation_level %d:\n",
+ validation_levels[i]));
+ dump_data(1, base->key.key, 16);
+ dump_data(1, base->LMSessKey.key, 8);
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_decrypt(creds, base->key.key, 16);
+ netlogon_creds_aes_decrypt(creds, base->LMSessKey.key, 8);
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ netlogon_creds_arcfour_crypt(creds, base->key.key, 16);
+ netlogon_creds_arcfour_crypt(creds, base->LMSessKey.key, 8);
+ }
+
+ DEBUG(1,("decrypted keys validation_level %d\n",
+ validation_levels[i]));
+
+ dump_data(1, base->key.key, 16);
+ dump_data(1, base->LMSessKey.key, 8);
+
+ if (!can_do_validation_6) {
+ /* we can't compare against unencrypted keys */
+ continue;
+ }
+
+ torture_assert_mem_equal(tctx,
+ base->key.key,
+ key.key,
+ 16,
+ "unexpected user session key\n");
+ torture_assert_mem_equal(tctx,
+ base->LMSessKey.key,
+ LMSessKey.key,
+ 8,
+ "unexpected LM session key\n");
+ }
+
+ return true;
+}
+
+static bool test_netlogon_ex_bug14932(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct cli_credentials *credentials,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+ struct netr_LogonSamLogonEx r;
+ struct netr_NetworkInfo ninfo;
+ union netr_LogonLevel logon;
+ union netr_Validation validation;
+ uint8_t authoritative = 1;
+ uint32_t _flags = 0;
+ static const char *netapp_magic =
+ "\x01\x01\x00\x00\x00\x00\x00\x00"
+ "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f"
+ "\xb8\x82\x3a\xf1\xb3\xdd\x08\x15"
+ "\x00\x00\x00\x00\x11\xa2\x08\x81"
+ "\x50\x38\x22\x78\x2b\x94\x47\xfe"
+ "\x54\x94\x7b\xff\x17\x27\x5a\xb4"
+ "\xf4\x18\xba\xdc\x2c\x38\xfd\x5b"
+ "\xfb\x0e\xc1\x85\x1e\xcc\x92\xbb"
+ "\x9b\xb1\xc4\xd5\x53\x14\xff\x8c"
+ "\x76\x49\xf5\x45\x90\x19\xa2";
+ NTTIME timestamp = BVAL(netapp_magic, 8);
+ DATA_BLOB names_blob = data_blob_string_const(netapp_magic + 28);
+ DATA_BLOB chal, lm_resp, nt_resp;
+ int i;
+ int flags = CLI_CRED_NTLM_AUTH;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct netr_UserSessionKey key;
+ struct netr_LMSessionKey LMSessKey;
+ uint32_t validation_levels[] = { 2, 3 };
+ struct netr_SamBaseInfo *base = NULL;
+ const char *crypto_alg = "";
+ bool can_do_validation_6 = true;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ flags |= CLI_CRED_NTLMv2_AUTH;
+
+ cli_credentials_get_ntlm_username_domain(samba_cmdline_get_creds(),
+ tctx,
+ &ninfo.identity_info.account_name.string,
+ &ninfo.identity_info.domain_name.string);
+
+ generate_random_buffer(ninfo.challenge,
+ sizeof(ninfo.challenge));
+
+ chal = data_blob_const(ninfo.challenge,
+ sizeof(ninfo.challenge));
+
+ status = cli_credentials_get_ntlm_response(
+ samba_cmdline_get_creds(),
+ tctx,
+ &flags,
+ chal,
+ &timestamp,
+ names_blob,
+ &lm_resp, &nt_resp,
+ NULL, NULL);
+ torture_assert_ntstatus_ok(tctx, status,
+ "cli_credentials_get_ntlm_response failed");
+
+ ninfo.lm.data = lm_resp.data;
+ ninfo.lm.length = lm_resp.length;
+
+ ninfo.nt.data = nt_resp.data;
+ ninfo.nt.length = nt_resp.length;
+
+ ninfo.identity_info.parameter_control = 0;
+ ninfo.identity_info.logon_id = 0;
+ ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);
+
+ logon.network = &ninfo;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = cli_credentials_get_workstation(credentials);
+ r.in.logon_level = NetlogonNetworkInformation;
+ r.in.logon= &logon;
+ r.in.flags = &_flags;
+ r.out.validation = &validation;
+ r.out.authoritative = &authoritative;
+ r.out.flags = &_flags;
+
+ /*
+ - retrieve level6
+ - save usrsession and lmsession key
+ - retrieve level 2
+ - calculate, compare
+ - retrieve level 3
+ - calculate, compare
+ */
+
+ if (creds != NULL) {
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ crypto_alg = "AES";
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ crypto_alg = "ARCFOUR";
+ }
+ }
+
+ dcerpc_binding_handle_auth_info(b, NULL, &auth_level);
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ r.in.validation_level = 6;
+
+ torture_comment(tctx,
+ "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "LogonSamLogonEx failed");
+ } else {
+ torture_comment(tctx,
+ "Skip auth_level[%u] Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ auth_level, ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+ r.out.result = NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
+ can_do_validation_6 = false;
+ } else {
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LogonSamLogonEx failed");
+
+ key = r.out.validation->sam6->base.key;
+ LMSessKey = r.out.validation->sam6->base.LMSessKey;
+
+ DEBUG(1,("unencrypted session keys from validation_level 6:\n"));
+ dump_data(1, r.out.validation->sam6->base.key.key, 16);
+ dump_data(1, r.out.validation->sam6->base.LMSessKey.key, 8);
+ }
+
+ for (i=0; i < ARRAY_SIZE(validation_levels); i++) {
+
+ r.in.validation_level = validation_levels[i];
+
+ torture_comment(tctx,
+ "Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
+ ninfo.identity_info.account_name.string, crypto_alg,
+ r.in.validation_level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
+ "LogonSamLogonEx failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "LogonSamLogonEx failed");
+
+ if (creds == NULL) {
+ /* when this test is called without creds no point in
+ * testing the session keys */
+ continue;
+ }
+
+ switch (validation_levels[i]) {
+ case 2:
+ base = &r.out.validation->sam2->base;
+ break;
+ case 3:
+ base = &r.out.validation->sam3->base;
+ break;
+ default:
+ break;
+ }
+
+ DEBUG(1,("encrypted keys validation_level %d:\n",
+ validation_levels[i]));
+ dump_data(1, base->key.key, 16);
+ dump_data(1, base->LMSessKey.key, 8);
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ netlogon_creds_aes_decrypt(creds, base->key.key, 16);
+ netlogon_creds_aes_decrypt(creds, base->LMSessKey.key, 8);
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ netlogon_creds_arcfour_crypt(creds, base->key.key, 16);
+ netlogon_creds_arcfour_crypt(creds, base->LMSessKey.key, 8);
+ }
+
+ DEBUG(1,("decrypted keys validation_level %d\n",
+ validation_levels[i]));
+
+ dump_data(1, base->key.key, 16);
+ dump_data(1, base->LMSessKey.key, 8);
+
+ if (!can_do_validation_6) {
+ /* we can't compare against unencrypted keys */
+ continue;
+ }
+
+ torture_assert_mem_equal(tctx,
+ base->key.key,
+ key.key,
+ 16,
+ "unexpected user session key\n");
+ torture_assert_mem_equal(tctx,
+ base->LMSessKey.key,
+ LMSessKey.key,
+ 8,
+ "unexpected LM session key\n");
+ }
+
+ return true;
+}
+
+/*
+ do some samr ops using the schannel connection
+ */
+static bool test_samr_ops(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b)
+{
+ struct samr_GetDomPwInfo r;
+ struct samr_PwInfo info;
+ struct samr_Connect connect_r;
+ struct samr_OpenDomain opendom;
+ int i;
+ struct lsa_String name;
+ struct policy_handle handle;
+ struct policy_handle domain_handle;
+
+ name.string = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.domain_name = &name;
+ r.out.info = &info;
+
+ connect_r.in.system_name = 0;
+ connect_r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ connect_r.out.connect_handle = &handle;
+
+ torture_comment(tctx, "Testing Connect and OpenDomain on BUILTIN\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_Connect_r(b, tctx, &connect_r),
+ "Connect failed");
+ if (!NT_STATUS_IS_OK(connect_r.out.result)) {
+ if (NT_STATUS_EQUAL(connect_r.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "Connect failed (expected, schannel mapped to anonymous): %s\n",
+ nt_errstr(connect_r.out.result));
+ } else {
+ torture_comment(tctx, "Connect failed - %s\n", nt_errstr(connect_r.out.result));
+ return false;
+ }
+ } else {
+ opendom.in.connect_handle = &handle;
+ opendom.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ opendom.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32");
+ opendom.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &opendom),
+ "OpenDomain failed");
+ if (!NT_STATUS_IS_OK(opendom.out.result)) {
+ torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(opendom.out.result));
+ return false;
+ }
+ }
+
+ torture_comment(tctx, "Testing GetDomPwInfo with name %s\n", r.in.domain_name->string);
+
+ /* do several ops to test credential chaining */
+ for (i=0;i<5;i++) {
+ torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetDomPwInfo_r(b, tctx, &r),
+ "GetDomPwInfo failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ if (!NT_STATUS_EQUAL(r.out.result, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "GetDomPwInfo op %d failed - %s\n", i, nt_errstr(r.out.result));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+/*
+ do some lsa ops using the schannel connection
+ */
+static bool test_lsa_ops(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct lsa_GetUserName r;
+ bool ret = true;
+ struct lsa_String *account_name_p = NULL;
+ struct lsa_String *authority_name_p = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "\nTesting GetUserName\n");
+
+ r.in.system_name = "\\";
+ r.in.account_name = &account_name_p;
+ r.in.authority_name = &authority_name_p;
+ r.out.account_name = &account_name_p;
+
+ /* do several ops to test credential chaining and various operations */
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_GetUserName_r(b, tctx, &r),
+ "lsa_GetUserName failed");
+
+ authority_name_p = *r.out.authority_name;
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "GetUserName failed - %s\n", nt_errstr(r.out.result));
+ return false;
+ } else {
+ if (!r.out.account_name) {
+ return false;
+ }
+
+ if (strcmp(account_name_p->string, "ANONYMOUS LOGON") != 0) {
+ torture_comment(tctx, "GetUserName returned wrong user: %s, expected %s\n",
+ account_name_p->string, "ANONYMOUS LOGON");
+ /* FIXME: gd */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ return false;
+ }
+ }
+ if (!authority_name_p || !authority_name_p->string) {
+ return false;
+ }
+
+ if (strcmp(authority_name_p->string, "NT AUTHORITY") != 0) {
+ torture_comment(tctx, "GetUserName returned wrong user: %s, expected %s\n",
+ authority_name_p->string, "NT AUTHORITY");
+ /* FIXME: gd */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ return false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ test a schannel connection with the given flags
+ */
+static bool test_schannel(struct torture_context *tctx,
+ uint16_t acct_flags, uint32_t dcerpc_flags,
+ int i)
+{
+ struct test_join *join_ctx;
+ NTSTATUS status;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ struct dcerpc_binding *b;
+ struct dcerpc_pipe *p = NULL;
+ struct dcerpc_pipe *p_netlogon = NULL;
+ struct dcerpc_pipe *p_netlogon2 = NULL;
+ struct dcerpc_pipe *p_netlogon3 = NULL;
+ struct dcerpc_pipe *p_samr2 = NULL;
+ struct dcerpc_pipe *p_lsa = NULL;
+ struct netlogon_creds_CredentialState *creds;
+ struct cli_credentials *credentials;
+ enum dcerpc_transport_t transport;
+
+ join_ctx = torture_join_domain(tctx,
+ talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, i),
+ acct_flags, &credentials);
+ torture_assert(tctx, join_ctx != NULL, "Failed to join domain");
+
+ status = dcerpc_parse_binding(tctx, binding, &b);
+ torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
+
+ status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ status = dcerpc_pipe_connect_b(tctx, &p, b, &ndr_table_samr,
+ credentials, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to connect to samr with schannel");
+
+ torture_assert(tctx, test_samr_ops(tctx, p->binding_handle),
+ "Failed to process schannel secured SAMR ops");
+
+ /* Also test that when we connect to the netlogon pipe, that
+ * the credentials we setup on the first pipe are valid for
+ * the second */
+
+ /* Swap the binding details from SAMR to NETLOGON */
+ status = dcerpc_epm_map_binding(tctx, b, &ndr_table_netlogon, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "epm map");
+
+ status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ status = dcerpc_secondary_auth_connection(p, b, &ndr_table_netlogon,
+ credentials, tctx->lp_ctx,
+ tctx, &p_netlogon);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
+
+ creds = cli_credentials_get_netlogon_creds(credentials);
+ torture_assert(tctx, (creds != NULL), "schannel creds");
+
+ /* checks the capabilities */
+ torture_assert(tctx, test_netlogon_capabilities(p_netlogon, tctx, credentials, creds),
+ "Failed to process schannel secured capability ops (on fresh connection)");
+
+ /* do a couple of logins */
+ torture_assert(tctx, test_netlogon_ops(p_netlogon, tctx, credentials, creds),
+ "Failed to process schannel secured NETLOGON ops");
+
+ torture_assert(tctx, test_netlogon_ex_ops(p_netlogon, tctx, credentials, creds),
+ "Failed to process schannel secured NETLOGON EX ops");
+
+ /* regression test for https://bugzilla.samba.org/show_bug.cgi?id=14932 */
+ torture_assert(tctx, test_netlogon_ex_bug14932(p_netlogon, tctx, credentials, creds),
+ "Failed to process schannel secured NETLOGON EX for BUG 14932");
+
+ /* we *MUST* use ncacn_np for openpolicy etc. */
+ transport = dcerpc_binding_get_transport(b);
+ status = dcerpc_binding_set_transport(b, NCACN_NP);
+ torture_assert_ntstatus_ok(tctx, status, "set transport");
+
+ /* Swap the binding details from SAMR to LSARPC */
+ status = dcerpc_epm_map_binding(tctx, b, &ndr_table_lsarpc, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "epm map");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p_lsa, b, &ndr_table_lsarpc,
+ credentials, tctx->ev, tctx->lp_ctx),
+ "failed to connect lsarpc with schannel");
+
+ torture_assert(tctx, test_lsa_ops(tctx, p_lsa),
+ "Failed to process schannel secured LSA ops");
+
+ talloc_free(p_lsa);
+ p_lsa = NULL;
+
+ /* we *MUST* use ncacn_ip_tcp for lookupsids3/lookupnames4 */
+ status = dcerpc_binding_set_transport(b, NCACN_IP_TCP);
+ torture_assert_ntstatus_ok(tctx, status, "set transport");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_epm_map_binding(tctx, b, &ndr_table_lsarpc, tctx->ev, tctx->lp_ctx),
+ "failed to call epm map");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &p_lsa, b, &ndr_table_lsarpc,
+ credentials, tctx->ev, tctx->lp_ctx),
+ "failed to connect lsarpc with schannel");
+
+ torture_assert(tctx,
+ test_many_LookupSids(p_lsa, tctx, NULL, LSA_LOOKUP_NAMES_ALL),
+ "LsaLookupSids3 failed!\n");
+
+ status = dcerpc_binding_set_transport(b, transport);
+ torture_assert_ntstatus_ok(tctx, status, "set transport");
+
+
+ /* Drop the socket, we want to start from scratch */
+ talloc_free(p);
+ p = NULL;
+
+ /* Now see what we are still allowed to do */
+
+ status = dcerpc_parse_binding(tctx, binding, &b);
+ torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
+
+ status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ status = dcerpc_pipe_connect_b(tctx, &p_samr2, b, &ndr_table_samr,
+ credentials, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to connect with schannel");
+
+ /* do a some SAMR operations. We have *not* done a new serverauthenticate */
+ torture_assert (tctx, test_samr_ops(tctx, p_samr2->binding_handle),
+ "Failed to process schannel secured SAMR ops (on fresh connection)");
+
+ /* Swap the binding details from SAMR to NETLOGON */
+ status = dcerpc_epm_map_binding(tctx, b, &ndr_table_netlogon, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "epm");
+
+ status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ status = dcerpc_secondary_auth_connection(p_samr2, b, &ndr_table_netlogon,
+ credentials, tctx->lp_ctx,
+ tctx, &p_netlogon2);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
+
+ /* checks the capabilities */
+ torture_assert(tctx, test_netlogon_capabilities(p_netlogon2, tctx, credentials, creds),
+ "Failed to process schannel secured capability ops (on fresh connection)");
+
+ /* Try the schannel-only SamLogonEx operation */
+ torture_assert(tctx, test_netlogon_ex_ops(p_netlogon2, tctx, credentials, creds),
+ "Failed to process schannel secured NETLOGON EX ops (on fresh connection)");
+
+
+ /* And the more traditional style, proving that the
+ * credentials chaining state is fully present */
+ torture_assert(tctx, test_netlogon_ops(p_netlogon2, tctx, credentials, creds),
+ "Failed to process schannel secured NETLOGON ops (on fresh connection)");
+
+ /* Drop the socket, we want to start from scratch (again) */
+ talloc_free(p_samr2);
+
+ /* We don't want schannel for this test */
+ status = dcerpc_binding_set_flags(b, 0, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ status = dcerpc_pipe_connect_b(tctx, &p_netlogon3, b, &ndr_table_netlogon,
+ credentials, tctx->ev, tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to connect without schannel");
+
+ torture_assert(tctx, !test_netlogon_ex_ops(p_netlogon3, tctx, credentials, creds),
+ "Processed NOT schannel secured NETLOGON EX ops without SCHANNEL (unsafe)");
+
+ /* Required because the previous call will mark the current context as having failed */
+ tctx->last_result = TORTURE_OK;
+ tctx->last_reason = NULL;
+
+ torture_assert(tctx, test_netlogon_ops(p_netlogon3, tctx, credentials, creds),
+ "Failed to processed NOT schannel secured NETLOGON ops without new ServerAuth");
+
+ torture_leave_domain(tctx, join_ctx);
+ return true;
+}
+
+/*
+ * Purpose of this test is to demonstrate that a netlogon server carefully deals
+ * with anonymous attempts to set passwords, in particular when the server
+ * enforces the use of schannel. This test makes most sense to be run in an
+ * environment where the netlogon server enforces use of schannel.
+ */
+
+static bool test_schannel_anonymous_setPassword(struct torture_context *tctx,
+ uint32_t dcerpc_flags,
+ bool use2)
+{
+ NTSTATUS status, result;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ struct dcerpc_binding *b;
+ struct dcerpc_pipe *p = NULL;
+ struct cli_credentials *credentials;
+ bool ok = true;
+
+ credentials = cli_credentials_init(NULL);
+ torture_assert(tctx, credentials != NULL, "Bad credentials");
+ cli_credentials_set_anonymous(credentials);
+
+ status = dcerpc_parse_binding(tctx, binding, &b);
+ torture_assert_ntstatus_ok(tctx, status, "Bad binding string");
+
+ status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(tctx, status, "set flags");
+
+ status = dcerpc_pipe_connect_b(tctx,
+ &p,
+ b,
+ &ndr_table_netlogon,
+ credentials,
+ tctx->ev,
+ tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to connect without schannel");
+
+ if (use2) {
+ struct netr_ServerPasswordSet2 r = {};
+ struct netr_Authenticator credential = {};
+ struct netr_Authenticator return_authenticator = {};
+ struct netr_CryptPassword new_password = {};
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = 0;
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ status = dcerpc_netr_ServerPasswordSet2_r(p->binding_handle, tctx, &r);
+ result = r.out.result;
+ } else {
+ struct netr_ServerPasswordSet r = {};
+ struct netr_Authenticator credential = {};
+ struct netr_Authenticator return_authenticator = {};
+ struct samr_Password new_password = {};
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.account_name = talloc_asprintf(tctx, "%s$", TEST_MACHINE_NAME);
+ r.in.secure_channel_type = 0;
+ r.in.computer_name = TEST_MACHINE_NAME;
+ r.in.credential = &credential;
+ r.in.new_password = &new_password;
+ r.out.return_authenticator = &return_authenticator;
+
+ status = dcerpc_netr_ServerPasswordSet_r(p->binding_handle, tctx, &r);
+ result = r.out.result;
+ }
+
+ torture_assert_ntstatus_ok(tctx, status, "ServerPasswordSet failed");
+
+ if (NT_STATUS_IS_OK(result)) {
+ torture_fail(tctx, "unexpectedly received NT_STATUS_OK");
+ }
+
+ return ok;
+}
+
+
+/*
+ a schannel test suite
+ */
+bool torture_rpc_schannel(struct torture_context *torture)
+{
+ bool ret = true;
+ struct {
+ uint16_t acct_flags;
+ uint32_t dcerpc_flags;
+ } tests[] = {
+ { ACB_WSTRUST, DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_AUTO},
+ { ACB_WSTRUST, DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_AUTO},
+ { ACB_WSTRUST, DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128},
+ { ACB_WSTRUST, DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128 },
+ { ACB_WSTRUST, DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_AES},
+ { ACB_WSTRUST, DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_AES },
+ { ACB_SVRTRUST, DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_AUTO},
+ { ACB_SVRTRUST, DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_AUTO},
+ { ACB_SVRTRUST, DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_128 },
+ { ACB_SVRTRUST, DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_128 },
+ { ACB_SVRTRUST, DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_AES },
+ { ACB_SVRTRUST, DCERPC_SCHANNEL | DCERPC_SEAL | DCERPC_SCHANNEL_AES }
+ };
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(tests);i++) {
+ torture_comment(torture, "Testing with acct_flags=0x%x dcerpc_flags=0x%x \n",
+ tests[i].acct_flags, tests[i].dcerpc_flags);
+
+ if (!test_schannel(torture,
+ tests[i].acct_flags, tests[i].dcerpc_flags,
+ i)) {
+ torture_comment(torture, "Failed with acct_flags=0x%x dcerpc_flags=0x%x \n",
+ tests[i].acct_flags, tests[i].dcerpc_flags);
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+bool torture_rpc_schannel_anon_setpw(struct torture_context *torture)
+{
+ bool ret = true;
+ bool ok;
+ uint32_t dcerpc_flags = DCERPC_SCHANNEL | DCERPC_SIGN | DCERPC_SCHANNEL_AUTO;
+
+ ok = test_schannel_anonymous_setPassword(torture,
+ dcerpc_flags,
+ true);
+ if (!ok) {
+ torture_comment(torture,
+ "Failed with dcerpc_flags=0x%x\n",
+ dcerpc_flags);
+ ret = false;
+ }
+
+ ok = test_schannel_anonymous_setPassword(torture,
+ dcerpc_flags,
+ false);
+ if (!ok) {
+ torture_comment(torture,
+ "Failed with dcerpc_flags=0x%x\n",
+ dcerpc_flags);
+ ret = false;
+ }
+
+ return ret;
+}
+
+/*
+ test two schannel connections
+ */
+bool torture_rpc_schannel2(struct torture_context *torture)
+{
+ struct test_join *join_ctx;
+ NTSTATUS status;
+ const char *binding = torture_setting_string(torture, "binding", NULL);
+ struct dcerpc_binding *b;
+ struct dcerpc_pipe *p1 = NULL, *p2 = NULL;
+ struct cli_credentials *credentials1, *credentials2;
+ uint32_t dcerpc_flags = DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO | DCERPC_SIGN;
+
+ join_ctx = torture_join_domain(torture, talloc_asprintf(torture, "%s2", TEST_MACHINE_NAME),
+ ACB_WSTRUST, &credentials1);
+ torture_assert(torture, join_ctx != NULL,
+ "Failed to join domain with acct_flags=ACB_WSTRUST");
+
+ credentials2 = cli_credentials_shallow_copy(torture, credentials1);
+ cli_credentials_set_netlogon_creds(credentials1, NULL);
+ cli_credentials_set_netlogon_creds(credentials2, NULL);
+
+ status = dcerpc_parse_binding(torture, binding, &b);
+ torture_assert_ntstatus_ok(torture, status, "Bad binding string");
+
+ status = dcerpc_binding_set_flags(b, dcerpc_flags, DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(torture, status, "set flags");
+
+ torture_comment(torture, "Opening first connection\n");
+ status = dcerpc_pipe_connect_b(torture, &p1, b, &ndr_table_netlogon,
+ credentials1, torture->ev, torture->lp_ctx);
+ torture_assert_ntstatus_ok(torture, status, "Failed to connect with schannel");
+
+ torture_comment(torture, "Opening second connection\n");
+ status = dcerpc_pipe_connect_b(torture, &p2, b, &ndr_table_netlogon,
+ credentials2, torture->ev, torture->lp_ctx);
+ torture_assert_ntstatus_ok(torture, status, "Failed to connect with schannel");
+
+ cli_credentials_set_netlogon_creds(credentials1, NULL);
+ cli_credentials_set_netlogon_creds(credentials2, NULL);
+
+ torture_comment(torture, "Testing logon on pipe1\n");
+ if (!test_netlogon_ex_ops(p1, torture, credentials1, NULL))
+ return false;
+
+ torture_comment(torture, "Testing logon on pipe2\n");
+ if (!test_netlogon_ex_ops(p2, torture, credentials2, NULL))
+ return false;
+
+ torture_comment(torture, "Again on pipe1\n");
+ if (!test_netlogon_ex_ops(p1, torture, credentials1, NULL))
+ return false;
+
+ torture_comment(torture, "Again on pipe2\n");
+ if (!test_netlogon_ex_ops(p2, torture, credentials2, NULL))
+ return false;
+
+ torture_leave_domain(torture, join_ctx);
+ return true;
+}
+
+struct torture_schannel_bench;
+
+struct torture_schannel_bench_conn {
+ struct torture_schannel_bench *s;
+ int index;
+ struct cli_credentials *wks_creds;
+ struct dcerpc_pipe *pipe;
+ struct netr_LogonSamLogonEx r;
+ struct netr_NetworkInfo ninfo;
+ TALLOC_CTX *tmp;
+ uint64_t total;
+ uint32_t count;
+};
+
+struct torture_schannel_bench {
+ struct torture_context *tctx;
+ bool progress;
+ int timelimit;
+ int nprocs;
+ int nconns;
+ struct torture_schannel_bench_conn *conns;
+ struct test_join *join_ctx1;
+ struct cli_credentials *wks_creds1;
+ struct test_join *join_ctx2;
+ struct cli_credentials *wks_creds2;
+ struct cli_credentials *user1_creds;
+ struct cli_credentials *user2_creds;
+ struct dcerpc_binding *b;
+ NTSTATUS error;
+ uint64_t total;
+ uint32_t count;
+ bool stopped;
+};
+
+#if 0
+static void torture_schannel_bench_connected(struct composite_context *c)
+{
+ struct torture_schannel_bench_conn *conn =
+ (struct torture_schannel_bench_conn *)c->async.private_data;
+ struct torture_schannel_bench *s = talloc_get_type(conn->s,
+ struct torture_schannel_bench);
+
+ s->error = dcerpc_pipe_connect_b_recv(c, s->conns, &conn->pipe);
+ torture_comment(s->tctx, "conn[%u]: %s\n", conn->index, nt_errstr(s->error));
+ if (NT_STATUS_IS_OK(s->error)) {
+ s->nconns++;
+ }
+}
+#endif
+
+static void torture_schannel_bench_recv(struct tevent_req *subreq);
+
+static bool torture_schannel_bench_start(struct torture_schannel_bench_conn *conn)
+{
+ struct torture_schannel_bench *s = conn->s;
+ NTSTATUS status;
+ DATA_BLOB names_blob, chal, lm_resp, nt_resp;
+ int flags = CLI_CRED_NTLM_AUTH;
+ struct tevent_req *subreq;
+ struct cli_credentials *user_creds;
+
+ if (conn->total % 2) {
+ user_creds = s->user1_creds;
+ } else {
+ user_creds = s->user2_creds;
+ }
+
+ if (lpcfg_client_lanman_auth(s->tctx->lp_ctx)) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+
+ if (lpcfg_client_ntlmv2_auth(s->tctx->lp_ctx)) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+ }
+
+ talloc_free(conn->tmp);
+ conn->tmp = talloc_new(s);
+ ZERO_STRUCT(conn->ninfo);
+ ZERO_STRUCT(conn->r);
+
+ cli_credentials_get_ntlm_username_domain(user_creds, conn->tmp,
+ &conn->ninfo.identity_info.account_name.string,
+ &conn->ninfo.identity_info.domain_name.string);
+
+ generate_random_buffer(conn->ninfo.challenge,
+ sizeof(conn->ninfo.challenge));
+ chal = data_blob_const(conn->ninfo.challenge,
+ sizeof(conn->ninfo.challenge));
+
+ names_blob = NTLMv2_generate_names_blob(conn->tmp,
+ cli_credentials_get_workstation(conn->wks_creds),
+ cli_credentials_get_domain(conn->wks_creds));
+
+ status = cli_credentials_get_ntlm_response(user_creds, conn->tmp,
+ &flags,
+ chal,
+ NULL, /* server_timestamp */
+ names_blob,
+ &lm_resp, &nt_resp,
+ NULL, NULL);
+ torture_assert_ntstatus_ok(s->tctx, status,
+ "cli_credentials_get_ntlm_response failed");
+
+ conn->ninfo.lm.data = lm_resp.data;
+ conn->ninfo.lm.length = lm_resp.length;
+
+ conn->ninfo.nt.data = nt_resp.data;
+ conn->ninfo.nt.length = nt_resp.length;
+
+ conn->ninfo.identity_info.parameter_control = 0;
+ conn->ninfo.identity_info.logon_id = 0;
+ conn->ninfo.identity_info.workstation.string = cli_credentials_get_workstation(conn->wks_creds);
+
+ conn->r.in.server_name = talloc_asprintf(conn->tmp, "\\\\%s", dcerpc_server_name(conn->pipe));
+ conn->r.in.computer_name = cli_credentials_get_workstation(conn->wks_creds);
+ conn->r.in.logon_level = NetlogonNetworkInformation;
+ conn->r.in.logon = talloc(conn->tmp, union netr_LogonLevel);
+ conn->r.in.logon->network = &conn->ninfo;
+ conn->r.in.flags = talloc(conn->tmp, uint32_t);
+ conn->r.in.validation_level = 2;
+ conn->r.out.validation = talloc(conn->tmp, union netr_Validation);
+ conn->r.out.authoritative = talloc(conn->tmp, uint8_t);
+ conn->r.out.flags = conn->r.in.flags;
+
+ subreq = dcerpc_netr_LogonSamLogonEx_r_send(s, s->tctx->ev,
+ conn->pipe->binding_handle,
+ &conn->r);
+ torture_assert(s->tctx, subreq, "Failed to setup LogonSamLogonEx request");
+
+ tevent_req_set_callback(subreq, torture_schannel_bench_recv, conn);
+
+ return true;
+}
+
+static void torture_schannel_bench_recv(struct tevent_req *subreq)
+{
+ bool ret;
+ struct torture_schannel_bench_conn *conn =
+ (struct torture_schannel_bench_conn *)tevent_req_callback_data_void(subreq);
+ struct torture_schannel_bench *s = talloc_get_type(conn->s,
+ struct torture_schannel_bench);
+
+ s->error = dcerpc_netr_LogonSamLogonEx_r_recv(subreq, subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(s->error)) {
+ return;
+ }
+
+ conn->total++;
+ conn->count++;
+
+ if (s->stopped) {
+ return;
+ }
+
+ ret = torture_schannel_bench_start(conn);
+ if (!ret) {
+ s->error = NT_STATUS_INTERNAL_ERROR;
+ }
+}
+
+/*
+ test multiple schannel connection in parallel
+ */
+bool torture_rpc_schannel_bench1(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ const char *binding = torture_setting_string(torture, "binding", NULL);
+ struct torture_schannel_bench *s;
+ struct timeval start;
+ struct timeval end;
+ int i;
+ const char *tmp;
+
+ s = talloc_zero(torture, struct torture_schannel_bench);
+ s->tctx = torture;
+ s->progress = torture_setting_bool(torture, "progress", true);
+ s->timelimit = torture_setting_int(torture, "timelimit", 10);
+ s->nprocs = torture_setting_int(torture, "nprocs", 4);
+ s->conns = talloc_zero_array(s, struct torture_schannel_bench_conn, s->nprocs);
+
+ s->user1_creds = cli_credentials_shallow_copy(s,
+ samba_cmdline_get_creds());
+ tmp = torture_setting_string(s->tctx, "extra_user1", NULL);
+ if (tmp) {
+ cli_credentials_parse_string(s->user1_creds, tmp, CRED_SPECIFIED);
+ }
+ s->user2_creds = cli_credentials_shallow_copy(s,
+ samba_cmdline_get_creds());
+ tmp = torture_setting_string(s->tctx, "extra_user2", NULL);
+ if (tmp) {
+ cli_credentials_parse_string(s->user1_creds, tmp, CRED_SPECIFIED);
+ }
+
+ s->join_ctx1 = torture_join_domain(s->tctx, talloc_asprintf(s, "%sb", TEST_MACHINE_NAME),
+ ACB_WSTRUST, &s->wks_creds1);
+ torture_assert(torture, s->join_ctx1 != NULL,
+ "Failed to join domain with acct_flags=ACB_WSTRUST");
+ s->join_ctx2 = torture_join_domain(s->tctx, talloc_asprintf(s, "%sc", TEST_MACHINE_NAME),
+ ACB_WSTRUST, &s->wks_creds2);
+ torture_assert(torture, s->join_ctx2 != NULL,
+ "Failed to join domain with acct_flags=ACB_WSTRUST");
+
+ cli_credentials_set_kerberos_state(s->wks_creds1,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SPECIFIED);
+ cli_credentials_set_kerberos_state(s->wks_creds2,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SPECIFIED);
+
+ for (i=0; i < s->nprocs; i++) {
+ struct cli_credentials *wks = s->wks_creds1;
+
+ if ((i % 2) && (torture_setting_bool(torture, "multijoin", false))) {
+ wks = s->wks_creds2;
+ }
+
+ s->conns[i].s = s;
+ s->conns[i].index = i;
+ s->conns[i].wks_creds = cli_credentials_shallow_copy(s->conns, wks);
+ cli_credentials_set_netlogon_creds(s->conns[i].wks_creds, NULL);
+ }
+
+ status = dcerpc_parse_binding(s, binding, &s->b);
+ torture_assert_ntstatus_ok(torture, status, "Bad binding string");
+
+ status = dcerpc_binding_set_flags(s->b, DCERPC_SCHANNEL | DCERPC_SIGN,
+ DCERPC_AUTH_OPTIONS);
+ torture_assert_ntstatus_ok(torture, status, "set flags");
+
+ torture_comment(torture, "Opening %d connections in parallel\n", s->nprocs);
+ for (i=0; i < s->nprocs; i++) {
+#if 1
+ s->error = dcerpc_pipe_connect_b(s->conns, &s->conns[i].pipe, s->b,
+ &ndr_table_netlogon,
+ s->conns[i].wks_creds,
+ torture->ev, torture->lp_ctx);
+ torture_assert_ntstatus_ok(torture, s->error, "Failed to connect with schannel");
+#else
+ /*
+ * This path doesn't work against windows,
+ * because of windows drops the connections
+ * which haven't reached a session setup yet
+ *
+ * The same as the reset on zero vc stuff.
+ */
+ struct composite_context *c;
+ c = dcerpc_pipe_connect_b_send(s->conns, s->b,
+ &ndr_table_netlogon,
+ s->conns[i].wks_creds,
+ torture->ev,
+ torture->lp_ctx);
+ torture_assert(torture, c != NULL, "Failed to setup connect");
+ c->async.fn = torture_schannel_bench_connected;
+ c->async.private_data = &s->conns[i];
+ }
+
+ while (NT_STATUS_IS_OK(s->error) && s->nprocs != s->nconns) {
+ int ev_ret = tevent_loop_once(torture->ev);
+ torture_assert(torture, ev_ret == 0, "tevent_loop_once failed");
+#endif
+ }
+ torture_assert_ntstatus_ok(torture, s->error, "Failed establish a connect");
+
+ /*
+ * Change the workstation password after establishing the netlogon
+ * schannel connections to prove that existing connections are not
+ * affected by a wks pwchange.
+ */
+
+ {
+ struct netr_ServerPasswordSet pwset;
+ char *password = generate_random_password(s->join_ctx1, 8, 255);
+ struct netlogon_creds_CredentialState *creds_state;
+ struct dcerpc_pipe *net_pipe;
+ struct netr_Authenticator credential, return_authenticator;
+ struct samr_Password new_password;
+
+ status = dcerpc_pipe_connect_b(s, &net_pipe, s->b,
+ &ndr_table_netlogon,
+ s->wks_creds1,
+ torture->ev, torture->lp_ctx);
+
+ torture_assert_ntstatus_ok(torture, status,
+ "dcerpc_pipe_connect_b failed");
+
+ pwset.in.server_name = talloc_asprintf(
+ net_pipe, "\\\\%s", dcerpc_server_name(net_pipe));
+ pwset.in.computer_name =
+ cli_credentials_get_workstation(s->wks_creds1);
+ pwset.in.account_name = talloc_asprintf(
+ net_pipe, "%s$", pwset.in.computer_name);
+ pwset.in.secure_channel_type = SEC_CHAN_WKSTA;
+ pwset.in.credential = &credential;
+ pwset.in.new_password = &new_password;
+ pwset.out.return_authenticator = &return_authenticator;
+
+ E_md4hash(password, new_password.hash);
+
+ creds_state = cli_credentials_get_netlogon_creds(
+ s->wks_creds1);
+ netlogon_creds_des_encrypt(creds_state, &new_password);
+ netlogon_creds_client_authenticator(creds_state, &credential);
+
+ torture_assert_ntstatus_ok(torture, dcerpc_netr_ServerPasswordSet_r(net_pipe->binding_handle, torture, &pwset),
+ "ServerPasswordSet failed");
+ torture_assert_ntstatus_ok(torture, pwset.out.result,
+ "ServerPasswordSet failed");
+
+ if (!netlogon_creds_client_check(creds_state,
+ &pwset.out.return_authenticator->cred)) {
+ torture_comment(torture, "Credential chaining failed\n");
+ }
+
+ cli_credentials_set_password(s->wks_creds1, password,
+ CRED_SPECIFIED);
+
+ talloc_free(net_pipe);
+
+ /* Just as a test, connect with the new creds */
+
+ cli_credentials_set_netlogon_creds(s->wks_creds1, NULL);
+
+ status = dcerpc_pipe_connect_b(s, &net_pipe, s->b,
+ &ndr_table_netlogon,
+ s->wks_creds1,
+ torture->ev, torture->lp_ctx);
+
+ torture_assert_ntstatus_ok(torture, status,
+ "dcerpc_pipe_connect_b failed");
+
+ talloc_free(net_pipe);
+ }
+
+ torture_comment(torture, "Start looping LogonSamLogonEx on %d connections for %d secs\n",
+ s->nprocs, s->timelimit);
+ for (i=0; i < s->nprocs; i++) {
+ ret = torture_schannel_bench_start(&s->conns[i]);
+ torture_assert(torture, ret, "Failed to setup LogonSamLogonEx");
+ }
+
+ start = timeval_current();
+ end = timeval_add(&start, s->timelimit, 0);
+
+ while (NT_STATUS_IS_OK(s->error) && !timeval_expired(&end)) {
+ int ev_ret = tevent_loop_once(torture->ev);
+ torture_assert(torture, ev_ret == 0, "tevent_loop_once failed");
+ }
+ torture_assert_ntstatus_ok(torture, s->error, "Failed some request");
+ s->stopped = true;
+ talloc_free(s->conns);
+
+ for (i=0; i < s->nprocs; i++) {
+ s->total += s->conns[i].total;
+ }
+
+ torture_comment(torture,
+ "Total ops[%llu] (%u ops/s)\n",
+ (unsigned long long)s->total,
+ (unsigned)s->total/s->timelimit);
+
+ torture_leave_domain(torture, s->join_ctx1);
+ torture_leave_domain(torture, s->join_ctx2);
+ return true;
+}
diff --git a/source4/torture/rpc/session_key.c b/source4/torture/rpc/session_key.c
new file mode 100644
index 0000000..96f9965
--- /dev/null
+++ b/source4/torture/rpc/session_key.c
@@ -0,0 +1,250 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for lsa rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+
+#include "libcli/auth/libcli_auth.h"
+#include "torture/rpc/torture_rpc.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+
+static void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+}
+
+static bool test_CreateSecret_basic(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct policy_handle *sec_handle)
+{
+ NTSTATUS status;
+ struct lsa_CreateSecret r;
+ struct lsa_SetSecret r3;
+ struct lsa_QuerySecret r4;
+ struct lsa_DATA_BUF buf1;
+ struct lsa_DATA_BUF_PTR bufp1;
+ DATA_BLOB enc_key;
+ DATA_BLOB session_key;
+ NTTIME old_mtime, new_mtime;
+ DATA_BLOB blob1;
+ const char *secret1 = "abcdef12345699qwerty";
+ char *secret2;
+ char *secname;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ secname = talloc_asprintf(tctx, "torturesecret-%08x", (unsigned int)random());
+
+ torture_comment(tctx, "Testing CreateSecret of %s\n", secname);
+
+ init_lsa_String(&r.in.name, secname);
+
+ r.in.handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.sec_handle = sec_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_CreateSecret_r(b, tctx, &r),
+ "CreateSecret failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "CreateSecret failed");
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_fetch_session_key failed");
+
+ enc_key = sess_encrypt_string(secret1, &session_key);
+
+ r3.in.sec_handle = sec_handle;
+ r3.in.new_val = &buf1;
+ r3.in.old_val = NULL;
+ r3.in.new_val->data = enc_key.data;
+ r3.in.new_val->length = enc_key.length;
+ r3.in.new_val->size = enc_key.length;
+
+ torture_comment(tctx, "Testing SetSecret\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_SetSecret_r(b, tctx, &r3),
+ "SetSecret failed");
+ torture_assert_ntstatus_ok(tctx, r3.out.result, "SetSecret failed");
+
+ r3.in.sec_handle = sec_handle;
+ r3.in.new_val = &buf1;
+ r3.in.old_val = NULL;
+ r3.in.new_val->data = enc_key.data;
+ r3.in.new_val->length = enc_key.length;
+ r3.in.new_val->size = enc_key.length;
+
+ /* break the encrypted data */
+ enc_key.data[0]++;
+
+ torture_comment(tctx, "Testing SetSecret with broken key\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_SetSecret_r(b, tctx, &r3),
+ "SetSecret failed");
+ torture_assert_ntstatus_equal(tctx, r3.out.result, NT_STATUS_UNKNOWN_REVISION,
+ "SetSecret should have failed UNKNOWN_REVISION");
+
+ data_blob_free(&enc_key);
+
+ ZERO_STRUCT(new_mtime);
+ ZERO_STRUCT(old_mtime);
+
+ /* fetch the secret back again */
+ r4.in.sec_handle = sec_handle;
+ r4.in.new_val = &bufp1;
+ r4.in.new_mtime = &new_mtime;
+ r4.in.old_val = NULL;
+ r4.in.old_mtime = NULL;
+
+ bufp1.buf = NULL;
+
+ torture_comment(tctx, "Testing QuerySecret\n");
+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(b, tctx, &r4),
+ "QuerySecret failed");
+ torture_assert_ntstatus_ok(tctx, r4.out.result, "QuerySecret failed");
+ if (r4.out.new_val == NULL || r4.out.new_val->buf == NULL)
+ torture_fail(tctx, "No secret buffer returned");
+ blob1.data = r4.out.new_val->buf->data;
+ blob1.length = r4.out.new_val->buf->size;
+
+ secret2 = sess_decrypt_string(tctx, &blob1, &session_key);
+
+ torture_assert_str_equal(tctx, secret1, secret2, "Returned secret invalid");
+
+ return true;
+}
+
+struct secret_settings {
+ uint32_t bindoptions;
+ bool keyexchange;
+ bool ntlm2;
+ bool lm_key;
+};
+
+static bool test_secrets(struct torture_context *torture, const void *_data)
+{
+ struct dcerpc_pipe *p;
+ struct policy_handle *handle;
+ struct dcerpc_binding *binding;
+ const struct secret_settings *settings =
+ (const struct secret_settings *)_data;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b;
+ struct policy_handle sec_handle = {0};
+ bool ok;
+
+ lpcfg_set_cmdline(torture->lp_ctx, "ntlmssp client:keyexchange", settings->keyexchange?"True":"False");
+ lpcfg_set_cmdline(torture->lp_ctx, "ntlmssp_client:ntlm2", settings->ntlm2?"True":"False");
+ lpcfg_set_cmdline(torture->lp_ctx, "ntlmssp_client:lm_key", settings->lm_key?"True":"False");
+
+ torture_assert_ntstatus_ok(torture, torture_rpc_binding(torture, &binding),
+ "Getting bindoptions");
+
+ status = dcerpc_binding_set_flags(binding, settings->bindoptions, 0);
+ torture_assert_ntstatus_ok(torture, status, "dcerpc_binding_set_flags");
+
+ status = dcerpc_pipe_connect_b(torture, &p, binding,
+ &ndr_table_lsarpc,
+ samba_cmdline_get_creds(),
+ torture->ev,
+ torture->lp_ctx);
+
+ torture_assert_ntstatus_ok(torture, status, "connect");
+ b = p->binding_handle;
+
+ if (!test_lsa_OpenPolicy2(b, torture, &handle)) {
+ talloc_free(p);
+ return false;
+ }
+
+ torture_assert(torture, handle, "OpenPolicy2 failed. This test cannot run against this server");
+
+ ok = test_CreateSecret_basic(p, torture, handle, &sec_handle);
+
+ if (is_valid_policy_hnd(&sec_handle)) {
+ struct lsa_DeleteObject d;
+
+ d.in.handle = &sec_handle;
+ d.out.handle = &sec_handle;
+
+ status = dcerpc_lsa_DeleteObject_r(b, torture, &d);
+ if (!NT_STATUS_IS_OK(status) ||
+ !NT_STATUS_IS_OK(d.out.result)) {
+ torture_warning(torture,
+ "Failed to delete secrets object");
+ }
+ }
+
+ talloc_free(p);
+ return ok;
+}
+
+static struct torture_tcase *add_test(struct torture_suite *suite, uint32_t bindoptions,
+ bool keyexchange, bool ntlm2, bool lm_key)
+{
+ char *name = NULL;
+ struct secret_settings *settings;
+
+ settings = talloc_zero(suite, struct secret_settings);
+ settings->bindoptions = bindoptions;
+
+ if (bindoptions == DCERPC_PUSH_BIGENDIAN)
+ name = talloc_strdup(suite, "bigendian");
+ else if (bindoptions == DCERPC_SEAL)
+ name = talloc_strdup(suite, "seal");
+ else if (bindoptions == 0)
+ name = talloc_strdup(suite, "none");
+ else
+ name = talloc_strdup(suite, "unknown");
+
+ name = talloc_asprintf_append_buffer(name, " keyexchange:%s", keyexchange?"yes":"no");
+ settings->keyexchange = keyexchange;
+
+ name = talloc_asprintf_append_buffer(name, " ntlm2:%s", ntlm2?"yes":"no");
+ settings->ntlm2 = ntlm2;
+
+ name = talloc_asprintf_append_buffer(name, " lm_key:%s", lm_key?"yes":"no");
+ settings->lm_key = lm_key;
+
+ return torture_suite_add_simple_tcase_const(suite, name, test_secrets,
+ settings);
+}
+
+static const bool bool_vals[] = { true, false };
+
+/* TEST session key correctness by pushing and pulling secrets */
+struct torture_suite *torture_rpc_lsa_secrets(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "lsa.secrets");
+ int keyexchange, ntlm2, lm_key;
+
+ for (keyexchange = 0; keyexchange < ARRAY_SIZE(bool_vals); keyexchange++) {
+ for (ntlm2 = 0; ntlm2 < ARRAY_SIZE(bool_vals); ntlm2++) {
+ for (lm_key = 0; lm_key < ARRAY_SIZE(bool_vals); lm_key++) {
+ add_test(suite, DCERPC_PUSH_BIGENDIAN, bool_vals[keyexchange], bool_vals[ntlm2],
+ bool_vals[lm_key]);
+ add_test(suite, DCERPC_SEAL, bool_vals[keyexchange], bool_vals[ntlm2], bool_vals[lm_key]);
+ add_test(suite, 0, bool_vals[keyexchange], bool_vals[ntlm2], bool_vals[lm_key]);
+ }
+ }
+ }
+
+ return suite;
+}
diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c
new file mode 100644
index 0000000..05a0aef
--- /dev/null
+++ b/source4/torture/rpc/spoolss.c
@@ -0,0 +1,11705 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for spoolss rpc operations
+
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Stefan Metzmacher 2005
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2009-2011,2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "librpc/gen_ndr/ndr_winreg_c.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "lib/registry/registry.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "lib/cmdline/cmdline.h"
+#include "system/filesys.h"
+#include "torture/ndr/ndr.h"
+#include "torture/smb2/proto.h"
+
+#define TORTURE_WELLKNOWN_PRINTER "torture_wkn_printer"
+#define TORTURE_PRINTER "torture_printer"
+#define TORTURE_WELLKNOWN_PRINTER_EX "torture_wkn_printer_ex"
+#define TORTURE_PRINTER_EX "torture_printer_ex"
+#define TORTURE_DRIVER "torture_driver"
+#define TORTURE_DRIVER_ADD "torture_driver_add"
+#define TORTURE_DRIVER_EX "torture_driver_ex"
+#define TORTURE_DRIVER_ADOBE "torture_driver_adobe"
+#define TORTURE_DRIVER_EX_ADOBE "torture_driver_ex_adobe"
+#define TORTURE_DRIVER_ADOBE_CUPSADDSMB "torture_driver_adobe_cupsaddsmb"
+#define TORTURE_DRIVER_TIMESTAMPS "torture_driver_timestamps"
+#define TORTURE_DRIVER_DELETER "torture_driver_deleter"
+#define TORTURE_DRIVER_COPY_DIR "torture_driver_copy_from_directory"
+#define TORTURE_DRIVER_DELETERIN "torture_driver_deleterin"
+#define TORTURE_PRINTER_STATIC1 "print1"
+
+#define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print"
+#define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers"
+#define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print"
+#define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms"
+#define TOP_LEVEL_CONTROL_PRINTERS_KEY TOP_LEVEL_CONTROL_KEY "\\Printers"
+#define TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY TOP_LEVEL_CONTROL_KEY "\\Environments"
+
+struct test_spoolss_context {
+ struct dcerpc_pipe *spoolss_pipe;
+
+ /* server environment */
+ const char *environment;
+
+ /* print server handle */
+ struct policy_handle server_handle;
+
+ /* for EnumPorts */
+ uint32_t port_count[3];
+ union spoolss_PortInfo *ports[3];
+
+ /* for EnumPrinterDrivers */
+ uint32_t driver_count[9];
+ union spoolss_DriverInfo *drivers[9];
+
+ /* for EnumMonitors */
+ uint32_t monitor_count[3];
+ union spoolss_MonitorInfo *monitors[3];
+
+ /* for EnumPrintProcessors */
+ uint32_t print_processor_count[2];
+ union spoolss_PrintProcessorInfo *print_processors[2];
+
+ /* for EnumPrinters */
+ uint32_t printer_count[6];
+ union spoolss_PrinterInfo *printers[6];
+};
+
+struct torture_driver_context {
+ struct {
+ const char *driver_directory;
+ const char *environment;
+ } local;
+ struct {
+ const char *driver_directory;
+ const char *driver_upload_directory;
+ const char *environment;
+ } remote;
+ struct spoolss_AddDriverInfo8 info8;
+ bool ex;
+};
+
+struct torture_printer_context {
+ struct dcerpc_pipe *spoolss_pipe;
+ struct spoolss_SetPrinterInfo2 info2;
+ struct torture_driver_context driver;
+ bool ex;
+ bool wellknown;
+ bool added_driver;
+ bool have_driver;
+ struct spoolss_DeviceMode *devmode;
+ struct policy_handle handle;
+};
+
+static bool upload_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d);
+static bool remove_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d);
+static bool fillup_printserver_info(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_driver_context *d);
+static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir);
+
+#define COMPARE_STRING(tctx, c,r,e) \
+ torture_assert_str_equal(tctx, c.e, r.e, "invalid value")
+
+/* not every compiler supports __typeof__() */
+#if (__GNUC__ >= 3)
+#define _CHECK_FIELD_SIZE(c,r,e,type) do {\
+ if (sizeof(__typeof__(c.e)) != sizeof(type)) { \
+ torture_fail(tctx, #c "." #e "field is not " #type "\n"); \
+ }\
+ if (sizeof(__typeof__(r.e)) != sizeof(type)) { \
+ torture_fail(tctx, #r "." #e "field is not " #type "\n"); \
+ }\
+} while(0)
+#else
+#define _CHECK_FIELD_SIZE(c,r,e,type) do {} while(0)
+#endif
+
+#define COMPARE_UINT32(tctx, c, r, e) do {\
+ _CHECK_FIELD_SIZE(c, r, e, uint32_t); \
+ torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
+} while(0)
+
+#define COMPARE_UINT64(tctx, c, r, e) do {\
+ _CHECK_FIELD_SIZE(c, r, e, uint64_t); \
+ torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
+} while(0)
+
+
+#define COMPARE_NTTIME(tctx, c, r, e) do {\
+ _CHECK_FIELD_SIZE(c, r, e, NTTIME); \
+ torture_assert_int_equal(tctx, c.e, r.e, "invalid value"); \
+} while(0)
+
+#define COMPARE_STRING_ARRAY(tctx, c,r,e) do {\
+ int __i; \
+ if (!c.e && !r.e) { \
+ break; \
+ } \
+ if (c.e && !r.e) { \
+ torture_fail(tctx, #r "." #e " field is NULL and " #c "." #e " is not\n"); \
+ } \
+ if (!c.e && r.e) { \
+ torture_fail(tctx, #c "." #e " field is NULL and " #r "." #e " is not\n"); \
+ } \
+ for (__i=0;c.e[__i] != NULL; __i++) { \
+ torture_assert_str_equal(tctx, c.e[__i], r.e[__i], "invalid value"); \
+ } \
+} while(0)
+
+#define CHECK_ALIGN(size, n) do {\
+ if (size % n) {\
+ torture_warning(tctx, "%d is *NOT* %d byte aligned, should be %d",\
+ size, n, size + n - (size % n));\
+ }\
+} while(0)
+
+#define DO_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
+
+#define CHECK_NEEDED_SIZE_ENUM_LEVEL(fn, info, level, count, needed, align) do { \
+ if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
+ uint32_t size = ndr_size_##fn##_info(tctx, level, count, info);\
+ uint32_t round_size = DO_ROUND(size, align);\
+ if (round_size != needed) {\
+ torture_warning(tctx, __location__": "#fn" level %d (count: %d) got unexpected needed size: %d, we calculated: %d", level, count, needed, round_size);\
+ CHECK_ALIGN(size, align);\
+ }\
+ }\
+} while(0)
+
+#define CHECK_NEEDED_SIZE_ENUM(fn, info, count, needed, align) do { \
+ if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
+ uint32_t size = ndr_size_##fn##_info(tctx, count, info);\
+ uint32_t round_size = DO_ROUND(size, align);\
+ if (round_size != needed) {\
+ torture_warning(tctx, __location__": "#fn" (count: %d) got unexpected needed size: %d, we calculated: %d", count, needed, round_size);\
+ CHECK_ALIGN(size, align);\
+ }\
+ }\
+} while(0)
+
+#define CHECK_NEEDED_SIZE_LEVEL(fn, info, level, needed, align) do { \
+ if (torture_setting_bool(tctx, "spoolss_check_size", false)) {\
+ uint32_t size = ndr_size_##fn(info, level, 0);\
+ uint32_t round_size = DO_ROUND(size, align);\
+ if (round_size != needed) {\
+ torture_warning(tctx, __location__": "#fn" level %d got unexpected needed size: %d, we calculated: %d", level, needed, round_size);\
+ CHECK_ALIGN(size, align);\
+ }\
+ }\
+} while(0)
+
+static bool PrinterInfo_to_SetPrinterInfo(struct torture_context *tctx,
+ const union spoolss_PrinterInfo *i,
+ uint32_t level,
+ union spoolss_SetPrinterInfo *s)
+{
+ switch (level) {
+ case 0:
+ s->info0 = talloc(tctx, struct spoolss_SetPrinterInfo0);
+ break;
+ case 2:
+ s->info2 = talloc(tctx, struct spoolss_SetPrinterInfo2);
+ s->info2->servername = i->info2.servername;
+ s->info2->printername = i->info2.printername;
+ s->info2->sharename = i->info2.sharename;
+ s->info2->portname = i->info2.portname;
+ s->info2->drivername = i->info2.drivername;
+ s->info2->comment = i->info2.comment;
+ s->info2->location = i->info2.location;
+ s->info2->devmode_ptr = 0;
+ s->info2->sepfile = i->info2.sepfile;
+ s->info2->printprocessor = i->info2.printprocessor;
+ s->info2->datatype = i->info2.datatype;
+ s->info2->parameters = i->info2.parameters;
+ s->info2->secdesc_ptr = 0;
+ s->info2->attributes = i->info2.attributes;
+ s->info2->priority = i->info2.priority;
+ s->info2->defaultpriority = i->info2.defaultpriority;
+ s->info2->starttime = i->info2.starttime;
+ s->info2->untiltime = i->info2.untiltime;
+ s->info2->status = i->info2.status;
+ s->info2->cjobs = i->info2.cjobs;
+ s->info2->averageppm = i->info2.averageppm;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_OpenPrinter_server(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *server_handle)
+{
+ NTSTATUS status;
+ struct spoolss_OpenPrinter op;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ op.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ op.in.datatype = NULL;
+ op.in.devmode_ctr.devmode= NULL;
+ op.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ op.out.handle = server_handle;
+
+ torture_comment(tctx, "Testing OpenPrinter(%s)\n", op.in.printername);
+
+ status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_OpenPrinter failed");
+ torture_assert_werr_ok(tctx, op.out.result, "dcerpc_spoolss_OpenPrinter failed");
+
+ return true;
+}
+
+static bool test_EnumPorts(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ struct spoolss_EnumPorts r;
+ uint16_t levels[] = { 1, 2 };
+ int i, j;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ DATA_BLOB blob;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PortInfo *info;
+
+ r.in.servername = "";
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPorts level %u\n", r.in.level);
+
+ status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
+ if (W_ERROR_IS_OK(r.out.result)) {
+ /* TODO: do some more checks here */
+ continue;
+ }
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "EnumPorts unexpected return code");
+
+ blob = data_blob_talloc_zero(ctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_EnumPorts_r(b, ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPorts failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
+
+ torture_assert(tctx, info, "EnumPorts returned no info");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, r.in.level, count, needed, 4);
+
+ ctx->port_count[level] = count;
+ ctx->ports[level] = info;
+ }
+
+ for (i=1;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ int old_level = levels[i-1];
+ torture_assert_int_equal(tctx, ctx->port_count[level], ctx->port_count[old_level],
+ "EnumPorts invalid value");
+ }
+ /* if the array sizes are not the same we would maybe segfault in the following code */
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ for (j=0;j<ctx->port_count[level];j++) {
+ union spoolss_PortInfo *cur = &ctx->ports[level][j];
+ union spoolss_PortInfo *ref = &ctx->ports[2][j];
+ switch (level) {
+ case 1:
+ COMPARE_STRING(tctx, cur->info1, ref->info2, port_name);
+ break;
+ case 2:
+ /* level 2 is our reference, and it makes no sense to compare it to itself */
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_GetPrintProcessorDirectory(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ NTSTATUS status;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_GetPrintProcessorDirectory r;
+ struct {
+ uint16_t level;
+ const char *server;
+ } levels[] = {{
+ .level = 1,
+ .server = NULL
+ },{
+ .level = 1,
+ .server = ""
+ },{
+ .level = 78,
+ .server = ""
+ },{
+ .level = 1,
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
+ },{
+ .level = 1024,
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
+ }
+ };
+ int i;
+ uint32_t needed;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i].level;
+ DATA_BLOB blob;
+
+ r.in.server = levels[i].server;
+ r.in.environment = ctx->environment;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_comment(tctx, "Testing GetPrintProcessorDirectory level %u\n", r.in.level);
+
+ status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "dcerpc_spoolss_GetPrintProcessorDirectory failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "GetPrintProcessorDirectory unexpected return code");
+
+ blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_GetPrintProcessorDirectory_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrintProcessorDirectory failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "GetPrintProcessorDirectory failed");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_PrintProcessorDirectoryInfo, r.out.info, r.in.level, needed, 2);
+ }
+
+ return true;
+}
+
+
+static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ NTSTATUS status;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_GetPrinterDriverDirectory r;
+ struct {
+ uint16_t level;
+ const char *server;
+ } levels[] = {{
+ .level = 1,
+ .server = NULL
+ },{
+ .level = 1,
+ .server = ""
+ },{
+ .level = 78,
+ .server = ""
+ },{
+ .level = 1,
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
+ },{
+ .level = 1024,
+ .server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p))
+ }
+ };
+ int i;
+ uint32_t needed;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i].level;
+ DATA_BLOB blob;
+
+ r.in.server = levels[i].server;
+ r.in.environment = ctx->environment;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_comment(tctx, "Testing GetPrinterDriverDirectory level %u\n", r.in.level);
+
+ status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "dcerpc_spoolss_GetPrinterDriverDirectory failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "GetPrinterDriverDirectory unexpected return code");
+
+ blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_GetPrinterDriverDirectory failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "GetPrinterDriverDirectory failed");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverDirectoryInfo, r.out.info, r.in.level, needed, 2);
+ }
+
+ return true;
+}
+
+static bool test_EnumPrinterDrivers_buffers(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *environment,
+ uint32_t level,
+ uint32_t offered,
+ uint32_t *count_p,
+ union spoolss_DriverInfo **info_p)
+{
+ struct spoolss_EnumPrinterDrivers r;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_DriverInfo *info;
+ DATA_BLOB buffer;
+
+ if (offered > 0) {
+ buffer = data_blob_talloc_zero(tctx, offered);
+ }
+
+ r.in.server = server_name;
+ r.in.environment = environment;
+ r.in.level = level;
+ r.in.buffer = offered ? &buffer : NULL;
+ r.in.offered = offered;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrinterDrivers(%s) level %u, offered: %u\n",
+ r.in.environment, r.in.level, r.in.offered);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
+ "EnumPrinterDrivers failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
+ "EnumPrinterDrivers failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "EnumPrinterDrivers failed");
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers, info, r.in.level, count, needed, 4);
+
+ return true;
+
+}
+
+
+static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *environment,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_DriverInfo **info_p)
+{
+ return test_EnumPrinterDrivers_buffers(tctx, b, server_name,
+ environment, level, 0,
+ count_p, info_p);
+}
+
+static bool test_EnumPrinterDrivers_findone(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *environment,
+ uint32_t level,
+ const char *driver_name,
+ union spoolss_DriverInfo *info_p)
+{
+ uint32_t count;
+ union spoolss_DriverInfo *info;
+ int i;
+ const char *environment_ret = NULL;
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_args(tctx, b, server_name, environment, level, &count, &info),
+ "failed to enumerate printer drivers");
+
+ for (i=0; i < count; i++) {
+ const char *driver_name_ret = "";
+ switch (level) {
+ case 1:
+ driver_name_ret = info[i].info1.driver_name;
+ break;
+ case 2:
+ driver_name_ret = info[i].info2.driver_name;
+ environment_ret = info[i].info2.architecture;
+ break;
+ case 3:
+ driver_name_ret = info[i].info3.driver_name;
+ environment_ret = info[i].info3.architecture;
+ break;
+ case 4:
+ driver_name_ret = info[i].info4.driver_name;
+ environment_ret = info[i].info4.architecture;
+ break;
+ case 5:
+ driver_name_ret = info[i].info5.driver_name;
+ environment_ret = info[i].info5.architecture;
+ break;
+ case 6:
+ driver_name_ret = info[i].info6.driver_name;
+ environment_ret = info[i].info6.architecture;
+ break;
+ case 7:
+ driver_name_ret = info[i].info7.driver_name;
+ break;
+ case 8:
+ driver_name_ret = info[i].info8.driver_name;
+ environment_ret = info[i].info8.architecture;
+ break;
+ default:
+ break;
+ }
+ if (environment_ret) {
+ torture_assert_str_equal(tctx, environment, environment_ret, "architecture mismatch");
+ }
+ if (strequal(driver_name, driver_name_ret)) {
+ if (info_p) {
+ *info_p = info[i];
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool test_EnumPrinterDrivers(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
+ uint16_t buffer_sizes[] = { 0, 1024, 6040, 0xffff };
+ int i, j, a;
+
+ /* FIXME: gd, come back and fix "" as server, and handle
+ * priority of returned error codes in torture test and samba 3
+ * server */
+ const char *server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ const char *environments[2];
+
+ environments[0] = SPOOLSS_ARCHITECTURE_ALL;
+ environments[1] = ctx->environment;
+
+ for (a=0;a<ARRAY_SIZE(environments);a++) {
+
+ for (i=0;i<ARRAY_SIZE(buffer_sizes);i++) {
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_buffers(tctx, b, server_name,
+ environments[a], 3,
+ buffer_sizes[i],
+ NULL, NULL),
+ "failed to enumerate drivers");
+ }
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ uint32_t count;
+ union spoolss_DriverInfo *info;
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_args(tctx, b, server_name, environments[a], level, &count, &info),
+ "failed to enumerate drivers");
+
+ ctx->driver_count[level] = count;
+ ctx->drivers[level] = info;
+ }
+
+ for (i=1;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ int old_level = levels[i-1];
+
+ torture_assert_int_equal(tctx, ctx->driver_count[level], ctx->driver_count[old_level],
+ "EnumPrinterDrivers invalid value");
+ }
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+
+ for (j=0;j<ctx->driver_count[level - 1];j++) {
+ union spoolss_DriverInfo *cur = &ctx->drivers[level - 1][j];
+ union spoolss_DriverInfo *ref = &ctx->drivers[8][j];
+
+ switch (level) {
+ case 1:
+ COMPARE_STRING(tctx, cur->info1, ref->info8, driver_name);
+ break;
+ case 2:
+ COMPARE_UINT32(tctx, cur->info2, ref->info8, version);
+ COMPARE_STRING(tctx, cur->info2, ref->info8, driver_name);
+ COMPARE_STRING(tctx, cur->info2, ref->info8, architecture);
+ COMPARE_STRING(tctx, cur->info2, ref->info8, driver_path);
+ COMPARE_STRING(tctx, cur->info2, ref->info8, data_file);
+ COMPARE_STRING(tctx, cur->info2, ref->info8, config_file);
+ break;
+ case 3:
+ COMPARE_UINT32(tctx, cur->info3, ref->info8, version);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, driver_name);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, architecture);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, driver_path);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, data_file);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, config_file);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, help_file);
+ COMPARE_STRING_ARRAY(tctx, cur->info3, ref->info8, dependent_files);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, monitor_name);
+ COMPARE_STRING(tctx, cur->info3, ref->info8, default_datatype);
+ break;
+ case 4:
+ COMPARE_UINT32(tctx, cur->info4, ref->info8, version);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, driver_name);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, architecture);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, driver_path);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, data_file);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, config_file);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, help_file);
+ COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, dependent_files);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, monitor_name);
+ COMPARE_STRING(tctx, cur->info4, ref->info8, default_datatype);
+ COMPARE_STRING_ARRAY(tctx, cur->info4, ref->info8, previous_names);
+ break;
+ case 5:
+ COMPARE_UINT32(tctx, cur->info5, ref->info8, version);
+ COMPARE_STRING(tctx, cur->info5, ref->info8, driver_name);
+ COMPARE_STRING(tctx, cur->info5, ref->info8, architecture);
+ COMPARE_STRING(tctx, cur->info5, ref->info8, driver_path);
+ COMPARE_STRING(tctx, cur->info5, ref->info8, data_file);
+ COMPARE_STRING(tctx, cur->info5, ref->info8, config_file);
+ /*COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_attributes);*/
+ /*COMPARE_UINT32(tctx, cur->info5, ref->info8, config_version);*/
+ /*TODO: ! COMPARE_UINT32(tctx, cur->info5, ref->info8, driver_version); */
+ break;
+ case 6:
+ COMPARE_UINT32(tctx, cur->info6, ref->info8, version);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, driver_name);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, architecture);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, driver_path);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, data_file);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, config_file);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, help_file);
+ COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, dependent_files);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, monitor_name);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, default_datatype);
+ COMPARE_STRING_ARRAY(tctx, cur->info6, ref->info8, previous_names);
+ COMPARE_NTTIME(tctx, cur->info6, ref->info8, driver_date);
+ COMPARE_UINT64(tctx, cur->info6, ref->info8, driver_version);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_name);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, manufacturer_url);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, hardware_id);
+ COMPARE_STRING(tctx, cur->info6, ref->info8, provider);
+ break;
+ case 8:
+ /* level 8 is our reference, and it makes no sense to compare it to itself */
+ break;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_EnumMonitors(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ struct spoolss_EnumMonitors r;
+ uint16_t levels[] = { 1, 2 };
+ int i, j;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ DATA_BLOB blob;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_MonitorInfo *info;
+
+ r.in.servername = "";
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumMonitors level %u\n", r.in.level);
+
+ status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
+ if (W_ERROR_IS_OK(r.out.result)) {
+ /* TODO: do some more checks here */
+ continue;
+ }
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "EnumMonitors failed");
+
+ blob = data_blob_talloc_zero(ctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_EnumMonitors_r(b, ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumMonitors failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumMonitors failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumMonitors, info, r.in.level, count, needed, 4);
+
+ ctx->monitor_count[level] = count;
+ ctx->monitors[level] = info;
+ }
+
+ for (i=1;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ int old_level = levels[i-1];
+ torture_assert_int_equal(tctx, ctx->monitor_count[level], ctx->monitor_count[old_level],
+ "EnumMonitors invalid value");
+ }
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ for (j=0;j<ctx->monitor_count[level];j++) {
+ union spoolss_MonitorInfo *cur = &ctx->monitors[level][j];
+ union spoolss_MonitorInfo *ref = &ctx->monitors[2][j];
+ switch (level) {
+ case 1:
+ COMPARE_STRING(tctx, cur->info1, ref->info2, monitor_name);
+ break;
+ case 2:
+ torture_assert_str_equal(tctx, ref->info2.environment, ctx->environment, "invalid environment");
+ /* level 2 is our reference, and it makes no sense to compare it to itself */
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_EnumPrintProcessors_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_PrintProcessorInfo **info_p,
+ WERROR expected_result)
+{
+ struct spoolss_EnumPrintProcessors r;
+ DATA_BLOB blob;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PrintProcessorInfo *info;
+
+ r.in.servername = "";
+ r.in.environment = environment;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrintProcessors(%s) level %u\n",
+ r.in.environment, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrintProcessors_r(b, tctx, &r),
+ "EnumPrintProcessors failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrintProcessors_r(b, tctx, &r),
+ "EnumPrintProcessors failed");
+ }
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "EnumPrintProcessors failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors, info, level, count, needed, 4);
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ return true;
+}
+
+static bool test_EnumPrintProcessors(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ uint16_t levels[] = {0, 1, 2, 3, 32, 256 };
+ uint16_t ok[] = {0, 1, 0, 0, 0, 0 };
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_EnumPrintProcessors_level(tctx, b, "phantasy", 1, NULL, NULL, WERR_INVALID_ENVIRONMENT),
+ "test_EnumPrintProcessors_level failed");
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ union spoolss_PrintProcessorInfo *info;
+ uint32_t count;
+ WERROR expected_result = ok[i] ? WERR_OK : WERR_INVALID_LEVEL;
+
+ torture_assert(tctx,
+ test_EnumPrintProcessors_level(tctx, b, ctx->environment, levels[i], &count, &info, expected_result),
+ "test_EnumPrintProcessors_level failed");
+ }
+
+ return true;
+}
+
+static bool test_EnumPrintProcessorDataTypes_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *print_processor_name,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_PrintProcDataTypesInfo **info_p,
+ WERROR expected_result)
+{
+ struct spoolss_EnumPrintProcessorDataTypes r;
+ DATA_BLOB blob;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PrintProcDataTypesInfo *info;
+
+ r.in.servername = "";
+ r.in.print_processor_name = print_processor_name;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrintProcessorDataTypes(%s) level %u\n",
+ r.in.print_processor_name, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrintProcessorDataTypes_r(b, tctx, &r),
+ "EnumPrintProcessorDataTypes failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrintProcessorDataTypes_r(b, tctx, &r),
+ "EnumPrintProcessorDataTypes failed");
+ }
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "EnumPrintProcessorDataTypes failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes, info, level, count, needed, 4);
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ return true;
+}
+
+static bool test_EnumPrintProcessorDataTypes(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ uint16_t levels[] = {0, 1, 2, 3, 32, 256 };
+ uint16_t ok[] = {0, 1, 0, 0, 0, 0 };
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_EnumPrintProcessorDataTypes_level(tctx, b, NULL, 1, NULL, NULL, WERR_UNKNOWN_PRINTPROCESSOR),
+ "test_EnumPrintProcessorDataTypes_level failed");
+
+ torture_assert(tctx,
+ test_EnumPrintProcessorDataTypes_level(tctx, b, "nonexisting", 1, NULL, NULL, WERR_UNKNOWN_PRINTPROCESSOR),
+ "test_EnumPrintProcessorDataTypes_level failed");
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ uint32_t count;
+ union spoolss_PrintProcDataTypesInfo *info;
+ WERROR expected_result = ok[i] ? WERR_OK : WERR_INVALID_LEVEL;
+
+ torture_assert(tctx,
+ test_EnumPrintProcessorDataTypes_level(tctx, b, "winprint", level, &count, &info, expected_result),
+ "test_EnumPrintProcessorDataTypes_level failed");
+ }
+
+ {
+ union spoolss_PrintProcessorInfo *info;
+ uint32_t count;
+
+ torture_assert(tctx,
+ test_EnumPrintProcessors_level(tctx, b, ctx->environment, 1, &count, &info, WERR_OK),
+ "test_EnumPrintProcessors_level failed");
+
+ for (i=0; i < count; i++) {
+ torture_assert(tctx,
+ test_EnumPrintProcessorDataTypes_level(tctx, b, info[i].info1.print_processor_name, 1, NULL, NULL, WERR_OK),
+ "test_EnumPrintProcessorDataTypes_level failed");
+ }
+ }
+
+
+ return true;
+}
+
+static bool test_EnumPrinters(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_EnumPrinters r;
+ NTSTATUS status;
+ uint16_t levels[] = { 0, 1, 2, 4, 5 };
+ int i, j;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ DATA_BLOB blob;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+
+ r.in.flags = PRINTER_ENUM_LOCAL;
+ r.in.server = "";
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
+
+ status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
+ if (W_ERROR_IS_OK(r.out.result)) {
+ /* TODO: do some more checks here */
+ continue;
+ }
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INSUFFICIENT_BUFFER,
+ "EnumPrinters unexpected return code");
+
+ blob = data_blob_talloc_zero(ctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EnumPrinters failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, needed, 4);
+
+ ctx->printer_count[level] = count;
+ ctx->printers[level] = info;
+ }
+
+ for (i=1;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ int old_level = levels[i-1];
+ torture_assert_int_equal(tctx, ctx->printer_count[level], ctx->printer_count[old_level],
+ "EnumPrinters invalid value");
+ }
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int level = levels[i];
+ for (j=0;j<ctx->printer_count[level];j++) {
+ union spoolss_PrinterInfo *cur = &ctx->printers[level][j];
+ union spoolss_PrinterInfo *ref = &ctx->printers[2][j];
+ switch (level) {
+ case 0:
+ COMPARE_STRING(tctx, cur->info0, ref->info2, printername);
+ COMPARE_STRING(tctx, cur->info0, ref->info2, servername);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, cjobs);
+ /*COMPARE_UINT32(tctx, cur->info0, ref->info2, total_jobs);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, total_bytes);
+ COMPARE_SPOOLSS_TIME(cur->info0, ref->info2, spoolss_Time time);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, global_counter);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, total_pages);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, version);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown10);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown11);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown12);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, session_counter);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown14);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, printer_errors);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown16);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown17);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown18);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown19);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, change_id);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown21);*/
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, status);
+ /*COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown23);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, c_setprinter);
+ COMPARE_UINT16(cur->info0, ref->info2, unknown25);
+ COMPARE_UINT16(cur->info0, ref->info2, unknown26);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown27);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown28);
+ COMPARE_UINT32(tctx, cur->info0, ref->info2, unknown29);*/
+ break;
+ case 1:
+ /*COMPARE_UINT32(tctx, cur->info1, ref->info2, flags);*/
+ /*COMPARE_STRING(tctx, cur->info1, ref->info2, name);*/
+ /*COMPARE_STRING(tctx, cur->info1, ref->info2, description);*/
+ COMPARE_STRING(tctx, cur->info1, ref->info2, comment);
+ break;
+ case 2:
+ /* level 2 is our reference, and it makes no sense to compare it to itself */
+ break;
+ case 4:
+ COMPARE_STRING(tctx, cur->info4, ref->info2, printername);
+ COMPARE_STRING(tctx, cur->info4, ref->info2, servername);
+ COMPARE_UINT32(tctx, cur->info4, ref->info2, attributes);
+ break;
+ case 5:
+ COMPARE_STRING(tctx, cur->info5, ref->info2, printername);
+ COMPARE_STRING(tctx, cur->info5, ref->info2, portname);
+ COMPARE_UINT32(tctx, cur->info5, ref->info2, attributes);
+ /*COMPARE_UINT32(tctx, cur->info5, ref->info2, device_not_selected_timeout);
+ COMPARE_UINT32(tctx, cur->info5, ref->info2, transmission_retry_timeout);*/
+ break;
+ }
+ }
+ }
+
+ /* TODO:
+ * - verify that the port of a printer was in the list returned by EnumPorts
+ */
+
+ return true;
+}
+
+static bool test_GetPrinterDriver2(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *environment);
+
+bool test_GetPrinter_level_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ WERROR expected_werror,
+ union spoolss_PrinterInfo *info)
+{
+ struct spoolss_GetPrinter r;
+ uint32_t needed;
+
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_comment(tctx, "Testing GetPrinter level %u\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
+ "GetPrinter failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinter_r(b, tctx, &r),
+ "GetPrinter failed");
+ }
+
+ torture_assert_werr_equal(tctx,
+ r.out.result, expected_werror,
+ "GetPrinter failed");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterInfo, r.out.info, r.in.level, needed, 4);
+
+ if (info && r.out.info) {
+ *info = *r.out.info;
+ }
+
+ return true;
+}
+
+bool test_GetPrinter_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ union spoolss_PrinterInfo *info)
+{
+ return test_GetPrinter_level_exp(tctx, b, handle, level, WERR_OK, info);
+}
+
+static bool test_GetPrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *environment)
+{
+ uint32_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ union spoolss_PrinterInfo info;
+
+ ZERO_STRUCT(info);
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, levels[i], &info),
+ "failed to call GetPrinter");
+
+ if ((levels[i] == 2) && info.info2.drivername && strlen(info.info2.drivername)) {
+ torture_assert(tctx,
+ test_GetPrinterDriver2(tctx, b, handle, info.info2.drivername, environment),
+ "failed to call test_GetPrinterDriver2");
+ }
+ }
+
+ return true;
+}
+
+static bool test_SetPrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct spoolss_SetPrinterInfoCtr *info_ctr,
+ struct spoolss_DevmodeContainer *devmode_ctr,
+ struct sec_desc_buf *secdesc_ctr,
+ enum spoolss_PrinterControl command)
+{
+ struct spoolss_SetPrinter r;
+
+ r.in.handle = handle;
+ r.in.info_ctr = info_ctr;
+ r.in.devmode_ctr = devmode_ctr;
+ r.in.secdesc_ctr = secdesc_ctr;
+ r.in.command = command;
+
+ torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
+ "failed to call SetPrinter");
+ torture_assert(tctx, (W_ERROR_EQUAL(r.out.result, WERR_OK)
+ || W_ERROR_EQUAL(r.out.result, WERR_IO_PENDING)),
+ "SetPrinter failed");
+
+ return true;
+}
+
+static bool test_SetPrinter_errors(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct spoolss_SetPrinter r;
+ uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ int i;
+
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info_ctr.level = 0;
+ info_ctr.info.info0 = NULL;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ r.in.handle = handle;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.in.command = 0;
+
+ torture_comment(tctx, "Testing SetPrinter all zero\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
+ "failed to call SetPrinter");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "failed to call SetPrinter");
+
+ again:
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ struct spoolss_SetPrinterInfo0 info0;
+ struct spoolss_SetPrinterInfo1 info1;
+ struct spoolss_SetPrinterInfo2 info2;
+ struct spoolss_SetPrinterInfo3 info3;
+ struct spoolss_SetPrinterInfo4 info4;
+ struct spoolss_SetPrinterInfo5 info5;
+ struct spoolss_SetPrinterInfo6 info6;
+ struct spoolss_SetPrinterInfo7 info7;
+ struct spoolss_SetPrinterInfo8 info8;
+ struct spoolss_SetPrinterInfo9 info9;
+
+
+ info_ctr.level = levels[i];
+ switch (levels[i]) {
+ case 0:
+ ZERO_STRUCT(info0);
+ info_ctr.info.info0 = &info0;
+ break;
+ case 1:
+ ZERO_STRUCT(info1);
+ info_ctr.info.info1 = &info1;
+ break;
+ case 2:
+ ZERO_STRUCT(info2);
+ info_ctr.info.info2 = &info2;
+ break;
+ case 3:
+ ZERO_STRUCT(info3);
+ info_ctr.info.info3 = &info3;
+ break;
+ case 4:
+ ZERO_STRUCT(info4);
+ info_ctr.info.info4 = &info4;
+ break;
+ case 5:
+ ZERO_STRUCT(info5);
+ info_ctr.info.info5 = &info5;
+ break;
+ case 6:
+ ZERO_STRUCT(info6);
+ info_ctr.info.info6 = &info6;
+ break;
+ case 7:
+ ZERO_STRUCT(info7);
+ info_ctr.info.info7 = &info7;
+ break;
+ case 8:
+ ZERO_STRUCT(info8);
+ info_ctr.info.info8 = &info8;
+ break;
+ case 9:
+ ZERO_STRUCT(info9);
+ info_ctr.info.info9 = &info9;
+ break;
+ }
+
+ torture_comment(tctx, "Testing SetPrinter level %d, command %d\n",
+ info_ctr.level, r.in.command);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
+ "failed to call SetPrinter");
+
+ switch (r.in.command) {
+ case SPOOLSS_PRINTER_CONTROL_UNPAUSE: /* 0 */
+ /* is ignored for all levels other then 0 */
+ if (info_ctr.level > 0) {
+ /* ignored then */
+ break;
+ }
+
+ FALL_THROUGH;
+ case SPOOLSS_PRINTER_CONTROL_PAUSE: /* 1 */
+ case SPOOLSS_PRINTER_CONTROL_RESUME: /* 2 */
+ case SPOOLSS_PRINTER_CONTROL_PURGE: /* 3 */
+ if (info_ctr.level > 0) {
+ /* is invalid for all levels other then 0 */
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
+ "unexpected error code returned");
+ continue;
+ } else {
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call SetPrinter with non 0 command");
+ continue;
+ }
+ break;
+
+ case SPOOLSS_PRINTER_CONTROL_SET_STATUS: /* 4 */
+ /* FIXME: gd needs further investigation */
+ default:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PRINTER_COMMAND,
+ "unexpected error code returned");
+ continue;
+ }
+
+ switch (info_ctr.level) {
+ case 1:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL,
+ "unexpected error code returned");
+ break;
+ case 2:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_UNKNOWN_PRINTER_DRIVER,
+ "unexpected error code returned");
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "unexpected error code returned");
+ break;
+ case 9:
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "unexpected error code returned");
+ break;
+ default:
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call SetPrinter");
+ break;
+ }
+ }
+
+ if (r.in.command < 5) {
+ r.in.command++;
+ goto again;
+ }
+
+ return true;
+}
+
+static void clear_info2(struct spoolss_SetPrinterInfoCtr *r)
+{
+ if ((r->level == 2) && (r->info.info2)) {
+ r->info.info2->secdesc_ptr = 0;
+ r->info.info2->devmode_ptr = 0;
+ }
+}
+
+static bool test_PrinterInfo(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_SetPrinter s;
+ struct spoolss_GetPrinter q;
+ struct spoolss_GetPrinter q0;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ union spoolss_PrinterInfo info;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ uint32_t needed = 0;
+ DATA_BLOB blob = data_blob_null;
+ bool ret = true;
+ int i;
+
+ uint32_t status_list[] = {
+ /* these do not stick
+ PRINTER_STATUS_PAUSED,
+ PRINTER_STATUS_ERROR,
+ PRINTER_STATUS_PENDING_DELETION, */
+ PRINTER_STATUS_PAPER_JAM,
+ PRINTER_STATUS_PAPER_OUT,
+ PRINTER_STATUS_MANUAL_FEED,
+ PRINTER_STATUS_PAPER_PROBLEM,
+ PRINTER_STATUS_OFFLINE,
+ PRINTER_STATUS_IO_ACTIVE,
+ PRINTER_STATUS_BUSY,
+ PRINTER_STATUS_PRINTING,
+ PRINTER_STATUS_OUTPUT_BIN_FULL,
+ PRINTER_STATUS_NOT_AVAILABLE,
+ PRINTER_STATUS_WAITING,
+ PRINTER_STATUS_PROCESSING,
+ PRINTER_STATUS_INITIALIZING,
+ PRINTER_STATUS_WARMING_UP,
+ PRINTER_STATUS_TONER_LOW,
+ PRINTER_STATUS_NO_TONER,
+ PRINTER_STATUS_PAGE_PUNT,
+ PRINTER_STATUS_USER_INTERVENTION,
+ PRINTER_STATUS_OUT_OF_MEMORY,
+ PRINTER_STATUS_DOOR_OPEN,
+ PRINTER_STATUS_SERVER_UNKNOWN,
+ PRINTER_STATUS_POWER_SAVE,
+ /* these do not stick
+ 0x02000000,
+ 0x04000000,
+ 0x08000000,
+ 0x10000000,
+ 0x20000000,
+ 0x40000000,
+ 0x80000000 */
+ };
+ uint32_t default_attribute = PRINTER_ATTRIBUTE_LOCAL;
+ uint32_t attribute_list[] = {
+ PRINTER_ATTRIBUTE_QUEUED,
+ /* fails with WERR_INVALID_DATATYPE:
+ PRINTER_ATTRIBUTE_DIRECT, */
+ /* does not stick
+ PRINTER_ATTRIBUTE_DEFAULT, */
+ PRINTER_ATTRIBUTE_SHARED,
+ /* does not stick
+ PRINTER_ATTRIBUTE_NETWORK, */
+ PRINTER_ATTRIBUTE_HIDDEN,
+ PRINTER_ATTRIBUTE_LOCAL,
+ PRINTER_ATTRIBUTE_ENABLE_DEVQ,
+ PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS,
+ PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,
+ PRINTER_ATTRIBUTE_WORK_OFFLINE,
+ /* does not stick
+ PRINTER_ATTRIBUTE_ENABLE_BIDI, */
+ /* fails with WERR_INVALID_DATATYPE:
+ PRINTER_ATTRIBUTE_RAW_ONLY, */
+ /* these do not stick
+ PRINTER_ATTRIBUTE_PUBLISHED,
+ PRINTER_ATTRIBUTE_FAX,
+ PRINTER_ATTRIBUTE_TS,
+ 0x00010000,
+ 0x00020000,
+ 0x00040000,
+ 0x00080000,
+ 0x00100000,
+ 0x00200000,
+ 0x00400000,
+ 0x00800000,
+ 0x01000000,
+ 0x02000000,
+ 0x04000000,
+ 0x08000000,
+ 0x10000000,
+ 0x20000000,
+ 0x40000000,
+ 0x80000000 */
+ };
+
+ torture_skip(tctx, "Printer Info test is currently broken, skipping");
+
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ s.in.handle = handle;
+ s.in.command = 0;
+ s.in.info_ctr = &info_ctr;
+ s.in.devmode_ctr = &devmode_ctr;
+ s.in.secdesc_ctr = &secdesc_ctr;
+
+ q.in.handle = handle;
+ q.out.info = &info;
+ q0 = q;
+
+#define TESTGETCALL(call, r, needed, blob) \
+ r.in.buffer = NULL; \
+ r.in.offered = 0;\
+ r.out.needed = &needed; \
+ status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
+ r.in.level, nt_errstr(status), __location__); \
+ ret = false; \
+ break; \
+ }\
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {\
+ blob = data_blob_talloc_zero(tctx, needed); \
+ r.in.buffer = &blob; \
+ r.in.offered = needed; \
+ }\
+ status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
+ r.in.level, nt_errstr(status), __location__); \
+ ret = false; \
+ break; \
+ } \
+ if (!W_ERROR_IS_OK(r.out.result)) { \
+ torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
+ r.in.level, win_errstr(r.out.result), __location__); \
+ ret = false; \
+ break; \
+ }
+
+
+#define TESTSETCALL_EXP(call, r, err) \
+ clear_info2(&info_ctr);\
+ status = dcerpc_spoolss_ ##call## _r(b, tctx, &r); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
+ r.in.info_ctr->level, nt_errstr(status), __location__); \
+ ret = false; \
+ break; \
+ } \
+ if (!W_ERROR_IS_OK(err)) { \
+ if (!W_ERROR_EQUAL(err, r.out.result)) { \
+ torture_comment(tctx, #call " level %u failed - %s, expected %s (%s)\n", \
+ r.in.info_ctr->level, win_errstr(r.out.result), win_errstr(err), __location__); \
+ ret = false; \
+ } \
+ break; \
+ } \
+ if (!W_ERROR_IS_OK(r.out.result)) { \
+ torture_comment(tctx, #call " level %u failed - %s (%s)\n", \
+ r.in.info_ctr->level, win_errstr(r.out.result), __location__); \
+ ret = false; \
+ break; \
+ }
+
+#define TESTSETCALL(call, r) \
+ TESTSETCALL_EXP(call, r, WERR_OK)
+
+#define STRING_EQUAL(s1, s2, field) \
+ if ((s1 && !s2) || (s2 && !s1) || strcmp(s1, s2)) { \
+ torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
+ #field, s2, __location__); \
+ ret = false; \
+ break; \
+ }
+
+#define MEM_EQUAL(s1, s2, length, field) \
+ if ((s1 && !s2) || (s2 && !s1) || memcmp(s1, s2, length)) { \
+ torture_comment(tctx, "Failed to set %s to '%s' (%s)\n", \
+ #field, (const char *)s2, __location__); \
+ ret = false; \
+ break; \
+ }
+
+#define INT_EQUAL(i1, i2, field) \
+ if (i1 != i2) { \
+ torture_comment(tctx, "Failed to set %s to 0x%llx - got 0x%llx (%s)\n", \
+ #field, (unsigned long long)i2, (unsigned long long)i1, __location__); \
+ ret = false; \
+ break; \
+ }
+
+#define SD_EQUAL(sd1, sd2, field) \
+ if (!security_descriptor_equal(sd1, sd2)) { \
+ torture_comment(tctx, "Failed to set %s (%s)\n", \
+ #field, __location__); \
+ ret = false; \
+ break; \
+ }
+
+#define TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, lvl1, field1, lvl2, field2, value, err) do { \
+ void *p; \
+ torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
+ q.in.level = lvl1; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ info_ctr.level = lvl1; \
+ p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
+ info_ctr.info.info ## lvl1->field1 = value;\
+ TESTSETCALL_EXP(SetPrinter, s, err) \
+ info_ctr.info.info ## lvl1->field1 = ""; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ info_ctr.info.info ## lvl1->field1 = value; \
+ STRING_EQUAL(info_ctr.info.info ## lvl1->field1, value, field1); \
+ q.in.level = lvl2; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ p = (void *)&q.out.info->info ## lvl2; \
+ info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)p; \
+ STRING_EQUAL(info_ctr.info.info ## lvl2->field2, value, field2); \
+ } while (0)
+
+#define TEST_PRINTERINFO_STRING(q, s, needed, blob, lvl1, field1, lvl2, field2, value) do { \
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, lvl1, field1, lvl2, field2, value, WERR_OK); \
+ } while (0);
+
+#define TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, lvl1, field1, lvl2, field2, value, exp_value) do { \
+ void *p; \
+ torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
+ q.in.level = lvl1; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ info_ctr.level = lvl1; \
+ p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
+ info_ctr.info.info ## lvl1->field1 = value; \
+ TESTSETCALL(SetPrinter, s) \
+ info_ctr.info.info ## lvl1->field1 = 0; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
+ INT_EQUAL(info_ctr.info.info ## lvl1->field1, exp_value, field1); \
+ q.in.level = lvl2; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ p = (void *)&q.out.info->info ## lvl2; \
+ info_ctr.info.info ## lvl2 = (struct spoolss_SetPrinterInfo ## lvl2 *)p; \
+ INT_EQUAL(info_ctr.info.info ## lvl2->field2, exp_value, field1); \
+ } while (0)
+
+#define TEST_PRINTERINFO_INT(q, s, needed, blob, lvl1, field1, lvl2, field2, value) do { \
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, lvl1, field1, lvl2, field2, value, value); \
+ } while (0)
+
+ q0.in.level = 0;
+ do { TESTGETCALL(GetPrinter, q0, needed, blob) } while (0);
+
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, comment, 1, comment, "xx2-1 comment");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, comment, 2, comment, "xx2-2 comment");
+
+ /* level 0 printername does not stick */
+/* TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, printername, 0, printername, "xx2-0 printer"); */
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, printername, 1, name, "xx2-1 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, printername, 2, printername, "xx2-2 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, printername, 4, printername, "xx2-4 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, printername, 5, printername, "xx2-5 printer");
+/* TEST_PRINTERINFO_STRING(q, s, needed, blob, 4, printername, 0, printername, "xx4-0 printer"); */
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 4, printername, 1, name, "xx4-1 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 4, printername, 2, printername, "xx4-2 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 4, printername, 4, printername, "xx4-4 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 4, printername, 5, printername, "xx4-5 printer");
+/* TEST_PRINTERINFO_STRING(q, s, needed, blob, 5, printername, 0, printername, "xx5-0 printer"); */
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 5, printername, 1, name, "xx5-1 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 5, printername, 2, printername, "xx5-2 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 5, printername, 4, printername, "xx5-4 printer");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 5, printername, 5, printername, "xx5-5 printer");
+
+ /* servername can be set but does not stick
+ TEST_PRINTERINFO_STRING(q, 2, servername, 0, servername, "xx2-0 servername");
+ TEST_PRINTERINFO_STRING(q, 2, servername, 2, servername, "xx2-2 servername");
+ TEST_PRINTERINFO_STRING(q, 2, servername, 4, servername, "xx2-4 servername");
+ */
+
+ /* passing an invalid port will result in WERR_UNKNOWN_PORT */
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 2, portname, 2, portname, "xx2-2 portname", WERR_UNKNOWN_PORT);
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 2, portname, 5, portname, "xx2-5 portname", WERR_UNKNOWN_PORT);
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 5, portname, 2, portname, "xx5-2 portname", WERR_UNKNOWN_PORT);
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 5, portname, 5, portname, "xx5-5 portname", WERR_UNKNOWN_PORT);
+
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, sharename, 2, sharename, "xx2-2 sharename");
+ /* passing an invalid driver will result in WERR_UNKNOWN_PRINTER_DRIVER */
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 2, drivername, 2, drivername, "xx2-2 drivername", WERR_UNKNOWN_PRINTER_DRIVER);
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, location, 2, location, "xx2-2 location");
+ /* passing an invalid sepfile will result in WERR_INVALID_SEPARATOR_FILE */
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 2, sepfile, 2, sepfile, "xx2-2 sepfile", WERR_INVALID_SEPARATOR_FILE);
+ /* passing an invalid printprocessor will result in WERR_UNKNOWN_PRINTPROCESSOR */
+ TEST_PRINTERINFO_STRING_EXP_ERR(q, s, needed, blob, 2, printprocessor, 2, printprocessor, "xx2-2 printprocessor", WERR_UNKNOWN_PRINTPROCESSOR);
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, datatype, 2, datatype, "xx2-2 datatype");
+ TEST_PRINTERINFO_STRING(q, s, needed, blob, 2, parameters, 2, parameters, "xx2-2 parameters");
+
+ for (i=0; i < ARRAY_SIZE(attribute_list); i++) {
+/* TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 2, attributes, 1, flags,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ ); */
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 2, attributes, 2, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 2, attributes, 4, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 2, attributes, 5, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+/* TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 4, attributes, 1, flags,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ ); */
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 4, attributes, 2, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 4, attributes, 4, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 4, attributes, 5, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+/* TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 5, attributes, 1, flags,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ ); */
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 5, attributes, 2, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 5, attributes, 4, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ TEST_PRINTERINFO_INT_EXP(q, s, needed, blob, 5, attributes, 5, attributes,
+ attribute_list[i],
+ (attribute_list[i] | default_attribute)
+ );
+ }
+
+ for (i=0; i < ARRAY_SIZE(status_list); i++) {
+ /* level 2 sets do not stick
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, status, 0, status, status_list[i]);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, status, 2, status, status_list[i]);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, status, 6, status, status_list[i]); */
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 6, status, 0, status, status_list[i]);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 6, status, 2, status, status_list[i]);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 6, status, 6, status, status_list[i]);
+ }
+
+ /* priorities need to be between 0 and 99
+ passing an invalid priority will result in WERR_INVALID_PRIORITY */
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, priority, 2, priority, 0);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, priority, 2, priority, 1);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, priority, 2, priority, 99);
+ /* TEST_PRINTERINFO_INT(q, s, needed, blob, 2, priority, 2, priority, 100); */
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, defaultpriority,2, defaultpriority, 0);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, defaultpriority,2, defaultpriority, 1);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, defaultpriority,2, defaultpriority, 99);
+ /* TEST_PRINTERINFO_INT(q, s, needed, blob, 2, defaultpriority,2, defaultpriority, 100); */
+
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, starttime, 2, starttime, __LINE__);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, untiltime, 2, untiltime, __LINE__);
+
+ /* does not stick
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, cjobs, 2, cjobs, __LINE__);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 2, averageppm, 2, averageppm, __LINE__); */
+
+ /* does not stick
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 5, device_not_selected_timeout, 5, device_not_selected_timeout, __LINE__);
+ TEST_PRINTERINFO_INT(q, s, needed, blob, 5, transmission_retry_timeout, 5, transmission_retry_timeout, __LINE__); */
+
+ /* FIXME: gd also test devmode and secdesc behavior */
+
+ {
+ /* verify composition of level 1 description field */
+ const char *description;
+ const char *tmp;
+
+ q0.in.level = 1;
+ do { TESTGETCALL(GetPrinter, q0, needed, blob) } while (0);
+
+ description = talloc_strdup(tctx, q0.out.info->info1.description);
+
+ q0.in.level = 2;
+ do { TESTGETCALL(GetPrinter, q0, needed, blob) } while (0);
+
+ tmp = talloc_asprintf(tctx, "%s,%s,%s",
+ q0.out.info->info2.printername,
+ q0.out.info->info2.drivername,
+ q0.out.info->info2.location);
+
+ do { STRING_EQUAL(description, tmp, "description")} while (0);
+ }
+
+ return ret;
+}
+
+static bool test_security_descriptor_equal(struct torture_context *tctx,
+ const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2)
+{
+ if (sd1 == sd2) {
+ return true;
+ }
+
+ if (!sd1 || !sd2) {
+ torture_comment(tctx, "%s\n", __location__);
+ return false;
+ }
+
+ torture_assert_int_equal(tctx, sd1->revision, sd2->revision, "revision mismatch");
+ torture_assert_int_equal(tctx, sd1->type, sd2->type, "type mismatch");
+
+ torture_assert_sid_equal(tctx, sd1->owner_sid, sd2->owner_sid, "owner mismatch");
+ torture_assert_sid_equal(tctx, sd1->group_sid, sd2->group_sid, "group mismatch");
+
+ if (!security_acl_equal(sd1->sacl, sd2->sacl)) {
+ torture_comment(tctx, "%s: sacl mismatch\n", __location__);
+ NDR_PRINT_DEBUG(security_acl, sd1->sacl);
+ NDR_PRINT_DEBUG(security_acl, sd2->sacl);
+ return false;
+ }
+ if (!security_acl_equal(sd1->dacl, sd2->dacl)) {
+ torture_comment(tctx, "%s: dacl mismatch\n", __location__);
+ NDR_PRINT_DEBUG(security_acl, sd1->dacl);
+ NDR_PRINT_DEBUG(security_acl, sd2->dacl);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_sd_set_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ struct security_descriptor *sd)
+{
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ union spoolss_SetPrinterInfo sinfo;
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfo3 info3;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ switch (level) {
+ case 2: {
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+ torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
+
+ info_ctr.level = 2;
+ info_ctr.info = sinfo;
+
+ break;
+ }
+ case 3: {
+
+ info3.sec_desc_ptr = 0;
+
+ info_ctr.level = 3;
+ info_ctr.info.info3 = &info3;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ secdesc_ctr.sd = sd;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
+
+ return true;
+}
+
+static bool test_PrinterInfo_SDs(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct security_descriptor *sd1, *sd2;
+ int i;
+
+ /* just compare level 2 and level 3 */
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ sd1 = info.info2.secdesc;
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 3, &info), "");
+
+ sd2 = info.info3.secdesc;
+
+ torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
+ "SD level 2 != SD level 3");
+
+
+ /* query level 2, set level 2, query level 2 */
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ sd1 = info.info2.secdesc;
+
+ torture_assert(tctx, test_sd_set_level(tctx, b, handle, 2, sd1), "");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ sd2 = info.info2.secdesc;
+ if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
+ torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
+ sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
+ }
+
+ torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
+ "SD level 2 != SD level 2 after SD has been set via level 2");
+
+
+ /* query level 2, set level 3, query level 2 */
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ sd1 = info.info2.secdesc;
+
+ torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ sd2 = info.info2.secdesc;
+
+ torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
+ "SD level 2 != SD level 2 after SD has been set via level 3");
+
+ /* set modified sd level 3, query level 2 */
+
+ for (i=0; i < 93; i++) {
+ struct security_ace a = {};
+ const char *sid_string = talloc_asprintf(tctx, "S-1-5-32-9999%i", i);
+ a.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ a.flags = 0;
+ a.size = 0; /* autogenerated */
+ a.access_mask = 0;
+ a.trustee = *dom_sid_parse_talloc(tctx, sid_string);
+ torture_assert_ntstatus_ok(tctx, security_descriptor_dacl_add(sd1, &a), "");
+ }
+
+ torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd1), "");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+ sd2 = info.info2.secdesc;
+
+ if (sd1->type & SEC_DESC_DACL_DEFAULTED) {
+ torture_comment(tctx, "removing SEC_DESC_DACL_DEFAULTED\n");
+ sd1->type &= ~SEC_DESC_DACL_DEFAULTED;
+ }
+
+ torture_assert(tctx, test_security_descriptor_equal(tctx, sd1, sd2),
+ "modified SD level 2 != SD level 2 after SD has been set via level 3");
+
+
+ return true;
+}
+
+/*
+ * wrapper call that saves original sd, runs tests, and restores sd
+ */
+
+static bool test_PrinterInfo_SD(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct security_descriptor *sd;
+ bool ret = true;
+
+ torture_comment(tctx, "Testing Printer Security Descriptors\n");
+
+ /* save original sd */
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to get initial security descriptor");
+
+ sd = security_descriptor_copy(tctx, info.info2.secdesc);
+
+ /* run tests */
+
+ ret = test_PrinterInfo_SDs(tctx, b, handle);
+
+ /* restore original sd */
+
+ torture_assert(tctx, test_sd_set_level(tctx, b, handle, 3, sd),
+ "failed to restore initial security descriptor");
+
+ torture_comment(tctx, "Printer Security Descriptors test %s\n\n",
+ ret ? "succeeded" : "failed");
+
+
+ return ret;
+}
+
+static bool test_devmode_set_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ struct spoolss_DeviceMode *devmode)
+{
+ struct spoolss_SetPrinterInfo8 info8;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ union spoolss_SetPrinterInfo sinfo;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ switch (level) {
+ case 2: {
+ union spoolss_PrinterInfo info;
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+ torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
+
+ info_ctr.level = 2;
+ info_ctr.info = sinfo;
+
+ break;
+ }
+ case 8: {
+ info8.devmode_ptr = 0;
+
+ info_ctr.level = 8;
+ info_ctr.info.info8 = &info8;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ devmode_ctr.devmode = devmode;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0), "");
+
+ return true;
+}
+
+
+static bool test_devicemode_equal(struct torture_context *tctx,
+ const struct spoolss_DeviceMode *d1,
+ const struct spoolss_DeviceMode *d2)
+{
+ if (d1 == d2) {
+ return true;
+ }
+
+ if (!d1 || !d2) {
+ torture_comment(tctx, "%s\n", __location__);
+ return false;
+ }
+ torture_assert_str_equal(tctx, d1->devicename, d2->devicename, "devicename mismatch");
+ torture_assert_int_equal(tctx, d1->specversion, d2->specversion, "specversion mismatch");
+ torture_assert_int_equal(tctx, d1->driverversion, d2->driverversion, "driverversion mismatch");
+ torture_assert_int_equal(tctx, d1->size, d2->size, "size mismatch");
+ torture_assert_int_equal(tctx, d1->__driverextra_length, d2->__driverextra_length, "__driverextra_length mismatch");
+ torture_assert_int_equal(tctx, d1->fields, d2->fields, "fields mismatch");
+ torture_assert_int_equal(tctx, d1->orientation, d2->orientation, "orientation mismatch");
+ torture_assert_int_equal(tctx, d1->papersize, d2->papersize, "papersize mismatch");
+ torture_assert_int_equal(tctx, d1->paperlength, d2->paperlength, "paperlength mismatch");
+ torture_assert_int_equal(tctx, d1->paperwidth, d2->paperwidth, "paperwidth mismatch");
+ torture_assert_int_equal(tctx, d1->scale, d2->scale, "scale mismatch");
+ torture_assert_int_equal(tctx, d1->copies, d2->copies, "copies mismatch");
+ torture_assert_int_equal(tctx, d1->defaultsource, d2->defaultsource, "defaultsource mismatch");
+ torture_assert_int_equal(tctx, d1->printquality, d2->printquality, "printquality mismatch");
+ torture_assert_int_equal(tctx, d1->color, d2->color, "color mismatch");
+ torture_assert_int_equal(tctx, d1->duplex, d2->duplex, "duplex mismatch");
+ torture_assert_int_equal(tctx, d1->yresolution, d2->yresolution, "yresolution mismatch");
+ torture_assert_int_equal(tctx, d1->ttoption, d2->ttoption, "ttoption mismatch");
+ torture_assert_int_equal(tctx, d1->collate, d2->collate, "collate mismatch");
+ torture_assert_str_equal(tctx, d1->formname, d2->formname, "formname mismatch");
+ torture_assert_int_equal(tctx, d1->logpixels, d2->logpixels, "logpixels mismatch");
+ torture_assert_int_equal(tctx, d1->bitsperpel, d2->bitsperpel, "bitsperpel mismatch");
+ torture_assert_int_equal(tctx, d1->pelswidth, d2->pelswidth, "pelswidth mismatch");
+ torture_assert_int_equal(tctx, d1->pelsheight, d2->pelsheight, "pelsheight mismatch");
+ torture_assert_int_equal(tctx, d1->displayflags, d2->displayflags, "displayflags mismatch");
+ torture_assert_int_equal(tctx, d1->displayfrequency, d2->displayfrequency, "displayfrequency mismatch");
+ torture_assert_int_equal(tctx, d1->icmmethod, d2->icmmethod, "icmmethod mismatch");
+ torture_assert_int_equal(tctx, d1->icmintent, d2->icmintent, "icmintent mismatch");
+ torture_assert_int_equal(tctx, d1->mediatype, d2->mediatype, "mediatype mismatch");
+ torture_assert_int_equal(tctx, d1->dithertype, d2->dithertype, "dithertype mismatch");
+ torture_assert_int_equal(tctx, d1->reserved1, d2->reserved1, "reserved1 mismatch");
+ torture_assert_int_equal(tctx, d1->reserved2, d2->reserved2, "reserved2 mismatch");
+ torture_assert_int_equal(tctx, d1->panningwidth, d2->panningwidth, "panningwidth mismatch");
+ torture_assert_int_equal(tctx, d1->panningheight, d2->panningheight, "panningheight mismatch");
+ torture_assert_data_blob_equal(tctx, d1->driverextra_data, d2->driverextra_data, "driverextra_data mismatch");
+
+ return true;
+}
+
+static bool test_devicemode_full(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct spoolss_SetPrinter s;
+ struct spoolss_GetPrinter q;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_SetPrinterInfo8 info8;
+ union spoolss_PrinterInfo info;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ uint32_t needed = 0;
+ DATA_BLOB blob = data_blob_null;
+ bool ret = true;
+ NTSTATUS status;
+
+#define TEST_DEVMODE_INT_EXP_RESULT(q, s, needed, blob, lvl1, field1, lvl2, field2, value, exp_value, expected_result) do { \
+ torture_comment(tctx, "field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
+ q.in.level = lvl1; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ info_ctr.level = lvl1; \
+ if (lvl1 == 2) {\
+ void *p = (void *)&q.out.info->info ## lvl1; \
+ info_ctr.info.info ## lvl1 = (struct spoolss_SetPrinterInfo ## lvl1 *)p; \
+ } else if (lvl1 == 8) {\
+ info_ctr.info.info ## lvl1 = &info8; \
+ }\
+ devmode_ctr.devmode = q.out.info->info ## lvl1.devmode; \
+ devmode_ctr.devmode->field1 = value; \
+ TESTSETCALL_EXP(SetPrinter, s, expected_result) \
+ if (W_ERROR_IS_OK(expected_result)) { \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ INT_EQUAL(q.out.info->info ## lvl1.devmode->field1, exp_value, field1); \
+ q.in.level = lvl2; \
+ TESTGETCALL(GetPrinter, q, needed, blob) \
+ INT_EQUAL(q.out.info->info ## lvl2.devmode->field2, exp_value, field1); \
+ }\
+ } while (0)
+
+#define TEST_DEVMODE_INT_EXP(q, s, needed, blob, lvl1, field1, lvl2, field2, value, expected_result) do { \
+ TEST_DEVMODE_INT_EXP_RESULT(q, s, needed, blob, lvl1, field1, lvl2, field2, value, value, expected_result); \
+ } while (0)
+
+#define TEST_DEVMODE_INT(q, s, needed, blob, lvl1, field1, lvl2, field2, value) do { \
+ TEST_DEVMODE_INT_EXP_RESULT(q, s, needed, blob, lvl1, field1, lvl2, field2, value, value, WERR_OK); \
+ } while (0)
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ ZERO_STRUCT(info8);
+
+ s.in.handle = handle;
+ s.in.command = 0;
+ s.in.info_ctr = &info_ctr;
+ s.in.devmode_ctr = &devmode_ctr;
+ s.in.secdesc_ctr = &secdesc_ctr;
+
+ q.in.handle = handle;
+ q.out.info = &info;
+
+#if 0
+ const char *devicename;/* [charset(UTF16)] */
+ enum spoolss_DeviceModeSpecVersion specversion;
+ uint16_t driverversion;
+ uint16_t __driverextra_length;/* [value(r->driverextra_data.length)] */
+ uint32_t fields;
+#endif
+ TEST_DEVMODE_INT_EXP(q, s, needed, blob, 8, size, 8, size, __LINE__, WERR_INVALID_PARAMETER);
+ TEST_DEVMODE_INT_EXP(q, s, needed, blob, 8, size, 8, size, 0, WERR_INVALID_PARAMETER);
+ TEST_DEVMODE_INT_EXP(q, s, needed, blob, 8, size, 8, size, 0xffff, WERR_INVALID_PARAMETER);
+ TEST_DEVMODE_INT_EXP(q, s, needed, blob, 8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0), (devmode_ctr.devmode->__driverextra_length > 0 ) ? WERR_INVALID_PARAMETER : WERR_OK);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0) - devmode_ctr.devmode->__driverextra_length);
+
+ devmode_ctr.devmode->driverextra_data = data_blob_string_const("foobar");
+ torture_assert(tctx,
+ test_devmode_set_level(tctx, b, handle, 8, devmode_ctr.devmode),
+ "failed to set devmode");
+
+ TEST_DEVMODE_INT_EXP(q, s, needed, blob, 8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0), (devmode_ctr.devmode->__driverextra_length > 0 ) ? WERR_INVALID_PARAMETER : WERR_OK);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, size, 8, size, ndr_size_spoolss_DeviceMode(devmode_ctr.devmode, 0) - devmode_ctr.devmode->__driverextra_length);
+
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, orientation, 8, orientation, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, papersize, 8, papersize, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, paperlength, 8, paperlength, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, paperwidth, 8, paperwidth, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, scale, 8, scale, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, copies, 8, copies, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, defaultsource, 8, defaultsource, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, printquality, 8, printquality, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, color, 8, color, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, duplex, 8, duplex, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, yresolution, 8, yresolution, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, ttoption, 8, ttoption, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, collate, 8, collate, __LINE__);
+#if 0
+ const char *formname;/* [charset(UTF16)] */
+#endif
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, logpixels, 8, logpixels, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, bitsperpel, 8, bitsperpel, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, pelswidth, 8, pelswidth, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, pelsheight, 8, pelsheight, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, displayflags, 8, displayflags, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, displayfrequency, 8, displayfrequency, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, icmmethod, 8, icmmethod, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, icmintent, 8, icmintent, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, mediatype, 8, mediatype, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, dithertype, 8, dithertype, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, reserved1, 8, reserved1, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, reserved2, 8, reserved2, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, panningwidth, 8, panningwidth, __LINE__);
+ TEST_DEVMODE_INT(q, s, needed, blob, 8, panningheight, 8, panningheight, __LINE__);
+
+ return ret;
+}
+
+static bool call_OpenPrinterEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ struct spoolss_DeviceMode *devmode,
+ struct policy_handle *handle);
+
+static bool test_PrinterInfo_DevModes(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *name)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_DeviceMode *devmode;
+ struct spoolss_DeviceMode *devmode2;
+ struct policy_handle handle_devmode;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ /* simply compare level8 and level2 devmode */
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
+
+ devmode = info.info8.devmode;
+
+ if (devmode && devmode->size == 0) {
+ torture_fail(tctx,
+ "devmode of zero size!");
+ }
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ devmode2 = info.info2.devmode;
+
+ if (devmode2 && devmode2->size == 0) {
+ torture_fail(tctx,
+ "devmode of zero size!");
+ }
+
+ torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
+ "DM level 8 != DM level 2");
+
+
+ /* set devicemode level 8 and see if it persists */
+
+ devmode->copies = 93;
+ devmode->formname = talloc_strdup(tctx, "Legal");
+
+ torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode), "");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
+
+ devmode2 = info.info8.devmode;
+
+ torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
+ "modified DM level 8 != DM level 8 after DM has been set via level 8");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ devmode2 = info.info2.devmode;
+
+ torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
+ "modified DM level 8 != DM level 2");
+
+
+ /* set devicemode level 2 and see if it persists */
+
+ devmode->copies = 39;
+ devmode->formname = talloc_strdup(tctx, "Executive");
+
+ torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 2, devmode), "");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info), "");
+
+ devmode2 = info.info8.devmode;
+
+ torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
+ "modified DM level 8 != DM level 8 after DM has been set via level 2");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ devmode2 = info.info2.devmode;
+
+ torture_assert(tctx, test_devicemode_equal(tctx, devmode, devmode2),
+ "modified DM level 8 != DM level 2");
+
+
+ /* check every single bit in public part of devicemode */
+
+ torture_assert(tctx, test_devicemode_full(tctx, b, handle),
+ "failed to set every single devicemode component");
+
+
+ /* change formname upon open and see if it persists in getprinter calls */
+
+ devmode->formname = talloc_strdup(tctx, "A4");
+ devmode->copies = 42;
+
+ torture_assert(tctx, call_OpenPrinterEx(tctx, p, name, devmode, &handle_devmode),
+ "failed to open printer handle");
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 8, &info), "");
+
+ devmode2 = info.info8.devmode;
+
+ if (strequal(devmode->devicename, devmode2->devicename)) {
+ torture_warning(tctx, "devicenames are the same\n");
+ } else {
+ torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
+ torture_comment(tctx, "devicename after level 8 get: %s\n", devmode2->devicename);
+ }
+
+ if (strequal(devmode->formname, devmode2->formname)) {
+ torture_warning(tctx, "formname are the same\n");
+ } else {
+ torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
+ torture_comment(tctx, "formname after level 8 get: %s\n", devmode2->formname);
+ }
+
+ if (devmode->copies == devmode2->copies) {
+ torture_warning(tctx, "copies are the same\n");
+ } else {
+ torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
+ torture_comment(tctx, "copies after level 8 get: %d\n", devmode2->copies);
+ }
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, &handle_devmode, 2, &info), "");
+
+ devmode2 = info.info2.devmode;
+
+ if (strequal(devmode->devicename, devmode2->devicename)) {
+ torture_warning(tctx, "devicenames are the same\n");
+ } else {
+ torture_comment(tctx, "devicename passed in for open: %s\n", devmode->devicename);
+ torture_comment(tctx, "devicename after level 2 get: %s\n", devmode2->devicename);
+ }
+
+ if (strequal(devmode->formname, devmode2->formname)) {
+ torture_warning(tctx, "formname is the same\n");
+ } else {
+ torture_comment(tctx, "formname passed in for open: %s\n", devmode->formname);
+ torture_comment(tctx, "formname after level 2 get: %s\n", devmode2->formname);
+ }
+
+ if (devmode->copies == devmode2->copies) {
+ torture_warning(tctx, "copies are the same\n");
+ } else {
+ torture_comment(tctx, "copies passed in for open: %d\n", devmode->copies);
+ torture_comment(tctx, "copies after level 2 get: %d\n", devmode2->copies);
+ }
+
+ test_ClosePrinter(tctx, b, &handle_devmode);
+
+ return true;
+}
+
+/*
+ * wrapper call that saves original devmode, runs tests, and restores devmode
+ */
+
+static bool test_PrinterInfo_DevMode(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *name,
+ struct spoolss_DeviceMode *addprinter_devmode)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_DeviceMode *devmode;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing Printer Devicemodes\n");
+
+ /* save original devmode */
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 8, &info),
+ "failed to get initial global devicemode");
+
+ devmode = info.info8.devmode;
+
+ if (devmode && devmode->size == 0) {
+ torture_fail(tctx,
+ "devmode of zero size!");
+ }
+
+ if (addprinter_devmode) {
+ if (!test_devicemode_equal(tctx, devmode, addprinter_devmode)) {
+ torture_warning(tctx, "current global DM is != DM provided in addprinter");
+ }
+ }
+
+ /* run tests */
+
+ ret = test_PrinterInfo_DevModes(tctx, p, handle, name);
+
+ /* restore original devmode */
+
+ torture_assert(tctx, test_devmode_set_level(tctx, b, handle, 8, devmode),
+ "failed to restore initial global device mode");
+
+ torture_comment(tctx, "Printer Devicemodes test %s\n\n",
+ ret ? "succeeded" : "failed");
+
+
+ return ret;
+}
+
+bool test_ClosePrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_ClosePrinter r;
+
+ r.in.handle = handle;
+ r.out.handle = handle;
+
+ torture_comment(tctx, "Testing ClosePrinter\n");
+
+ status = dcerpc_spoolss_ClosePrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result, "ClosePrinter failed");
+
+ return true;
+}
+
+static bool test_GetForm_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ uint32_t level,
+ union spoolss_FormInfo *info_p)
+{
+ NTSTATUS status;
+ struct spoolss_GetForm r;
+ uint32_t needed;
+
+ r.in.handle = handle;
+ r.in.form_name = form_name;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_comment(tctx, "Testing GetForm(%s) level %d\n", form_name, r.in.level);
+
+ status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ status = dcerpc_spoolss_GetForm_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetForm failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
+
+ torture_assert(tctx, r.out.info, "No form info returned");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "GetForm failed");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_FormInfo, r.out.info, r.in.level, needed, 4);
+
+ if (info_p) {
+ *info_p = *r.out.info;
+ }
+
+ return true;
+}
+
+static bool test_GetForm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ uint32_t level)
+{
+ return test_GetForm_args(tctx, b, handle, form_name, level, NULL);
+}
+
+static bool test_EnumForms(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_FormInfo **info_p)
+{
+ struct spoolss_EnumForms r;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_FormInfo *info;
+
+ r.in.handle = handle;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumForms level %d\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumForms_r(b, tctx, &r),
+ "EnumForms failed");
+
+ if ((r.in.level == 2) && (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL))) {
+ torture_skip(tctx, "EnumForms level 2 not supported");
+ }
+
+ if (print_server && W_ERROR_EQUAL(r.out.result, WERR_INVALID_HANDLE)) {
+ torture_fail(tctx, "EnumForms on the PrintServer isn't supported by test server (NT4)");
+ }
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumForms_r(b, tctx, &r),
+ "EnumForms failed");
+
+ torture_assert(tctx, info, "No forms returned");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumForms failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumForms, info, r.in.level, count, needed, 4);
+
+ if (info_p) {
+ *info_p = info;
+ }
+ if (count_p) {
+ *count_p = count;
+ }
+
+ return true;
+}
+
+static bool test_EnumForms_all(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server)
+{
+ uint32_t levels[] = { 1, 2 };
+ int i, j;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ uint32_t count = 0;
+ union spoolss_FormInfo *info = NULL;
+
+ torture_assert(tctx,
+ test_EnumForms(tctx, b, handle, print_server, levels[i], &count, &info),
+ "failed to enum forms");
+
+ for (j = 0; j < count; j++) {
+ if (!print_server) {
+ torture_assert(tctx,
+ test_GetForm(tctx, b, handle, info[j].info1.form_name, levels[i]),
+ "failed to get form");
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_EnumForms_find_one(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *form_name)
+{
+ union spoolss_FormInfo *info = NULL;
+ uint32_t count = 0;
+ bool found = false;
+ int i;
+
+ torture_assert(tctx,
+ test_EnumForms(tctx, b, handle, print_server, 1, &count, &info),
+ "failed to enumerate forms");
+
+ for (i=0; i<count; i++) {
+ if (strequal(form_name, info[i].info1.form_name)) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+static bool test_DeleteForm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ WERROR expected_result)
+{
+ struct spoolss_DeleteForm r;
+
+ r.in.handle = handle;
+ r.in.form_name = form_name;
+
+ torture_comment(tctx, "Testing DeleteForm(%s)\n", form_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
+ "DeleteForm failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeleteForm gave unexpected result");
+ if (W_ERROR_IS_OK(r.out.result)) {
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeleteForm_r(b, tctx, &r),
+ "2nd DeleteForm failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_FORM_NAME,
+ "2nd DeleteForm failed");
+ }
+
+ return true;
+}
+
+static bool test_AddForm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ union spoolss_AddFormInfo *info,
+ WERROR expected_result)
+{
+ struct spoolss_AddForm r;
+ struct spoolss_AddFormInfoCtr info_ctr;
+
+ info_ctr.level = level;
+ info_ctr.info = *info;
+
+ if (level != 1) {
+ torture_skip(tctx, "only level 1 supported");
+ }
+
+ r.in.handle = handle;
+ r.in.info_ctr = &info_ctr;
+
+ torture_comment(tctx, "Testing AddForm(%s) level %d, type %d\n",
+ r.in.info_ctr->info.info1->form_name, level,
+ r.in.info_ctr->info.info1->flags);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
+ "AddForm failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "AddForm gave unexpected result");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_AddForm_r(b, tctx, &r),
+ "2nd AddForm failed");
+ if (W_ERROR_EQUAL(expected_result, WERR_INVALID_PARAMETER)) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "2nd AddForm gave unexpected result");
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_FILE_EXISTS,
+ "2nd AddForm gave unexpected result");
+ }
+
+ return true;
+}
+
+static bool test_SetForm(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *form_name,
+ uint32_t level,
+ union spoolss_AddFormInfo *info)
+{
+ struct spoolss_SetForm r;
+ struct spoolss_AddFormInfoCtr info_ctr;
+
+ info_ctr.level = level;
+ info_ctr.info = *info;
+
+ r.in.handle = handle;
+ r.in.form_name = form_name;
+ r.in.info_ctr = &info_ctr;
+
+ torture_comment(tctx, "Testing SetForm(%s) level %d\n",
+ form_name, level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetForm_r(b, tctx, &r),
+ "SetForm failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SetForm failed");
+
+ return true;
+}
+
+static bool test_GetForm_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *form_name,
+ enum winreg_Type *w_type,
+ uint32_t *w_size,
+ uint32_t *w_length,
+ uint8_t **w_data);
+
+static bool test_Forms_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle,
+ const char *form_name,
+ struct spoolss_AddFormInfo1 *info1,
+ WERROR expected_add_result,
+ WERROR expected_delete_result)
+{
+ union spoolss_FormInfo info;
+ union spoolss_AddFormInfo add_info;
+
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
+
+ add_info.info1 = info1;
+
+ torture_assert(tctx,
+ test_AddForm(tctx, b, handle, 1, &add_info, expected_add_result),
+ "failed to add form");
+
+ if (winreg_handle && hive_handle && W_ERROR_IS_OK(expected_add_result)) {
+
+ struct spoolss_FormInfo1 i1;
+
+ torture_assert(tctx,
+ test_GetForm_winreg(tctx, winreg_handle, hive_handle, TOP_LEVEL_CONTROL_FORMS_KEY, form_name, &w_type, &w_size, &w_length, &w_data),
+ "failed to get form via winreg");
+
+ i1.size.width = IVAL(w_data, 0);
+ i1.size.height = IVAL(w_data, 4);
+ i1.area.left = IVAL(w_data, 8);
+ i1.area.top = IVAL(w_data, 12);
+ i1.area.right = IVAL(w_data, 16);
+ i1.area.bottom = IVAL(w_data, 20);
+ /* skip index here */
+ i1.flags = IVAL(w_data, 28);
+
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");
+ torture_assert_int_equal(tctx, w_size, 0x20, "unexpected size");
+ torture_assert_int_equal(tctx, w_length, 0x20, "unexpected length");
+ torture_assert_int_equal(tctx, i1.size.width, add_info.info1->size.width, "width mismatch");
+ torture_assert_int_equal(tctx, i1.size.height, add_info.info1->size.height, "height mismatch");
+ torture_assert_int_equal(tctx, i1.area.left, add_info.info1->area.left, "left mismatch");
+ torture_assert_int_equal(tctx, i1.area.top, add_info.info1->area.top, "top mismatch");
+ torture_assert_int_equal(tctx, i1.area.right, add_info.info1->area.right, "right mismatch");
+ torture_assert_int_equal(tctx, i1.area.bottom, add_info.info1->area.bottom, "bottom mismatch");
+ torture_assert_int_equal(tctx, i1.flags, add_info.info1->flags, "flags mismatch");
+ }
+
+ if (!print_server && W_ERROR_IS_OK(expected_add_result)) {
+ torture_assert(tctx,
+ test_GetForm_args(tctx, b, handle, form_name, 1, &info),
+ "failed to get added form");
+
+ torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
+ torture_assert_int_equal(tctx, info.info1.size.height, add_info.info1->size.height, "height mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.left, add_info.info1->area.left, "left mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.top, add_info.info1->area.top, "top mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.right, add_info.info1->area.right, "right mismatch");
+ torture_assert_int_equal(tctx, info.info1.area.bottom, add_info.info1->area.bottom, "bottom mismatch");
+ torture_assert_int_equal(tctx, info.info1.flags, add_info.info1->flags, "flags mismatch");
+
+ if (winreg_handle && hive_handle) {
+
+ struct spoolss_FormInfo1 i1;
+
+ i1.size.width = IVAL(w_data, 0);
+ i1.size.height = IVAL(w_data, 4);
+ i1.area.left = IVAL(w_data, 8);
+ i1.area.top = IVAL(w_data, 12);
+ i1.area.right = IVAL(w_data, 16);
+ i1.area.bottom = IVAL(w_data, 20);
+ /* skip index here */
+ i1.flags = IVAL(w_data, 28);
+
+ torture_assert_int_equal(tctx, i1.size.width, info.info1.size.width, "width mismatch");
+ torture_assert_int_equal(tctx, i1.size.height, info.info1.size.height, "height mismatch");
+ torture_assert_int_equal(tctx, i1.area.left, info.info1.area.left, "left mismatch");
+ torture_assert_int_equal(tctx, i1.area.top, info.info1.area.top, "top mismatch");
+ torture_assert_int_equal(tctx, i1.area.right, info.info1.area.right, "right mismatch");
+ torture_assert_int_equal(tctx, i1.area.bottom, info.info1.area.bottom, "bottom mismatch");
+ torture_assert_int_equal(tctx, i1.flags, info.info1.flags, "flags mismatch");
+ }
+
+ add_info.info1->size.width = 1234;
+
+ torture_assert(tctx,
+ test_SetForm(tctx, b, handle, form_name, 1, &add_info),
+ "failed to set form");
+ torture_assert(tctx,
+ test_GetForm_args(tctx, b, handle, form_name, 1, &info),
+ "failed to get set form");
+
+ torture_assert_int_equal(tctx, info.info1.size.width, add_info.info1->size.width, "width mismatch");
+ }
+
+ if (!W_ERROR_EQUAL(expected_add_result, WERR_INVALID_PARAMETER)) {
+ torture_assert(tctx,
+ test_EnumForms_find_one(tctx, b, handle, print_server, form_name),
+ "Newly added form not found in enum call");
+ }
+
+ torture_assert(tctx,
+ test_DeleteForm(tctx, b, handle, form_name, expected_delete_result),
+ "failed to delete form");
+
+ return true;
+}
+
+static bool test_Forms(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ const struct spoolss_FormSize size = {
+ .width = 50,
+ .height = 25
+ };
+ const struct spoolss_FormArea area = {
+ .left = 5,
+ .top = 10,
+ .right = 45,
+ .bottom = 15
+ };
+ int i;
+
+ struct {
+ struct spoolss_AddFormInfo1 info1;
+ WERROR expected_add_result;
+ WERROR expected_delete_result;
+ } forms[] = {
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_USER,
+ .form_name = "testform_user",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_OK,
+ .expected_delete_result = WERR_OK
+ },
+/*
+ weird, we can add a builtin form but we can never remove it
+ again - gd
+
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_BUILTIN,
+ .form_name = "testform_builtin",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_OK,
+ .expected_delete_result = WERR_INVALID_PARAMETER,
+ },
+*/
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_PRINTER,
+ .form_name = "testform_printer",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_OK,
+ .expected_delete_result = WERR_OK
+ },
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_USER,
+ .form_name = "Letter",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_FILE_EXISTS,
+ .expected_delete_result = WERR_INVALID_PARAMETER
+ },
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_BUILTIN,
+ .form_name = "Letter",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_FILE_EXISTS,
+ .expected_delete_result = WERR_INVALID_PARAMETER
+ },
+ {
+ .info1 = {
+ .flags = SPOOLSS_FORM_PRINTER,
+ .form_name = "Letter",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_FILE_EXISTS,
+ .expected_delete_result = WERR_INVALID_PARAMETER
+ },
+ {
+ .info1 = {
+ .flags = 12345,
+ .form_name = "invalid_flags",
+ .size = size,
+ .area = area,
+ },
+ .expected_add_result = WERR_INVALID_PARAMETER,
+ .expected_delete_result = WERR_INVALID_FORM_NAME
+ }
+
+ };
+
+ for (i=0; i < ARRAY_SIZE(forms); i++) {
+ torture_assert(tctx,
+ test_Forms_args(tctx, b, handle, print_server, printer_name,
+ winreg_handle, hive_handle,
+ forms[i].info1.form_name,
+ &forms[i].info1,
+ forms[i].expected_add_result,
+ forms[i].expected_delete_result),
+ talloc_asprintf(tctx, "failed to test form '%s'", forms[i].info1.form_name));
+ }
+
+ return true;
+}
+
+static bool test_EnumPorts_old(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ NTSTATUS status;
+ struct spoolss_EnumPorts r;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PortInfo *info;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.servername = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.in.level = 2;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPorts\n");
+
+ status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_EnumPorts_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "EnumPorts failed");
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
+
+ torture_assert(tctx, info, "No ports returned");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPorts failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPorts, info, 2, count, needed, 4);
+
+ return true;
+}
+
+static bool test_AddPort(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ NTSTATUS status;
+ struct spoolss_AddPort r;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ r.in.unknown = 0;
+ r.in.monitor_name = "foo";
+
+ torture_comment(tctx, "Testing AddPort\n");
+
+ status = dcerpc_spoolss_AddPort_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "AddPort failed");
+
+ /* win2k3 returns WERR_NOT_SUPPORTED */
+
+#if 0
+
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ printf("AddPort failed - %s\n", win_errstr(r.out.result));
+ return false;
+ }
+
+#endif
+
+ return true;
+}
+
+static bool test_GetJob_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ uint32_t level,
+ union spoolss_JobInfo *info_p)
+{
+ NTSTATUS status;
+ struct spoolss_GetJob r;
+ union spoolss_JobInfo info;
+ uint32_t needed;
+
+ r.in.handle = handle;
+ r.in.job_id = job_id;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing GetJob(%d), level %d\n", job_id, r.in.level);
+
+ status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
+ if (level == 0) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL, "Unexpected return code");
+ }
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_GetJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetJob failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "GetJob failed");
+ torture_assert(tctx, r.out.info, "No job info returned");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_JobInfo, r.out.info, r.in.level, needed, 4);
+
+ if (info_p) {
+ *info_p = *r.out.info;
+ }
+
+ return true;
+}
+
+#if 0
+static bool test_GetJob(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id)
+{
+ uint32_t levels[] = {0, 1, 2 /* 3, 4 */};
+ uint32_t i;
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+ torture_assert(tctx,
+ test_GetJob_args(tctx, b, handle, job_id, levels[i], NULL),
+ "GetJob failed");
+ }
+
+ return true;
+}
+#endif
+
+static bool test_SetJob(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ struct spoolss_JobInfoContainer *ctr,
+ enum spoolss_JobControl command)
+{
+ NTSTATUS status;
+ struct spoolss_SetJob r;
+
+ r.in.handle = handle;
+ r.in.job_id = job_id;
+ r.in.ctr = ctr;
+ r.in.command = command;
+
+ switch (command) {
+ case SPOOLSS_JOB_CONTROL_PAUSE:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_PAUSE\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_RESUME:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESUME\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_CANCEL:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_CANCEL\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_RESTART:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RESTART\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_DELETE:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_DELETE\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_RETAIN:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RETAIN\n", job_id);
+ break;
+ case SPOOLSS_JOB_CONTROL_RELEASE:
+ torture_comment(tctx, "Testing SetJob(%d), SPOOLSS_JOB_CONTROL_RELEASE\n", job_id);
+ break;
+ default:
+ torture_comment(tctx, "Testing SetJob(%d)\n", job_id);
+ break;
+ }
+
+ status = dcerpc_spoolss_SetJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "SetJob failed");
+ torture_assert_werr_ok(tctx, r.out.result, "SetJob failed");
+
+ return true;
+}
+
+static bool test_AddJob(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_AddJob r;
+ uint32_t needed;
+
+ r.in.level = 0;
+ r.in.handle = handle;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.in.buffer = r.out.buffer = NULL;
+
+ torture_comment(tctx, "Testing AddJob\n");
+
+ status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "AddJob failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL, "AddJob failed");
+
+ r.in.level = 1;
+
+ status = dcerpc_spoolss_AddJob_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "AddJob failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER, "AddJob failed");
+
+ return true;
+}
+
+
+static bool test_EnumJobs_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t level,
+ WERROR werr_expected,
+ uint32_t *count_p,
+ union spoolss_JobInfo **info_p)
+{
+ NTSTATUS status;
+ struct spoolss_EnumJobs r;
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_JobInfo *info;
+
+ r.in.handle = handle;
+ r.in.firstjob = 0;
+ r.in.numjobs = 0xffffffff;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumJobs level %d\n", level);
+
+ status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
+ torture_assert_werr_equal(tctx, r.out.result, werr_expected,
+ "EnumJobs failed");
+ torture_assert(tctx, info, "No jobs returned");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, needed, 4);
+
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, werr_expected,
+ "EnumJobs failed");
+ }
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ return true;
+}
+
+static bool test_JobPropertiesEnum(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id)
+{
+ struct spoolss_EnumJobNamedProperties r;
+ uint32_t pcProperties = 0;
+ struct spoolss_PrintNamedProperty *ppProperties = NULL;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.out.pcProperties = &pcProperties;
+ r.out.ppProperties = &ppProperties;
+
+ torture_comment(tctx, "Testing EnumJobNamedProperties(%d)\n", job_id);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumJobNamedProperties_r(b, tctx, &r),
+ "spoolss_EnumJobNamedProperties failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_EnumJobNamedProperties failed");
+
+ return true;
+}
+
+static bool test_JobPropertySet(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ struct spoolss_PrintNamedProperty *property)
+{
+ struct spoolss_SetJobNamedProperty r;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.in.pProperty = property;
+
+ torture_comment(tctx, "Testing SetJobNamedProperty(%d) %s - %d\n",
+ job_id, property->propertyName,
+ property->propertyValue.ePropertyType);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_SetJobNamedProperty_r(b, tctx, &r),
+ "spoolss_SetJobNamedProperty failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_SetJobNamedProperty failed");
+
+ return true;
+}
+
+static bool test_JobPropertyGetValue(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ const char *property_name,
+ struct spoolss_PrintPropertyValue *value)
+{
+ struct spoolss_GetJobNamedPropertyValue r;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.in.pszName = property_name;
+ r.out.pValue = value;
+
+ torture_comment(tctx, "Testing GetJobNamedPropertyValue(%d) %s\n",
+ job_id, property_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetJobNamedPropertyValue_r(b, tctx, &r),
+ "spoolss_GetJobNamedPropertyValue failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_GetJobNamedPropertyValue failed");
+
+ return true;
+}
+
+static bool test_JobPropertyDelete(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id,
+ const char *property_name)
+{
+ struct spoolss_DeleteJobNamedProperty r;
+
+ r.in.hPrinter = handle;
+ r.in.JobId = job_id;
+ r.in.pszName = property_name;
+
+ torture_comment(tctx, "Testing DeleteJobNamedProperty(%d) %s\n",
+ job_id, property_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeleteJobNamedProperty_r(b, tctx, &r),
+ "spoolss_DeleteJobNamedProperty failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_DeleteJobNamedProperty failed");
+
+ return true;
+}
+
+static bool test_DoPrintTest_add_one_job_common(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *document_name,
+ const char *datatype,
+ uint32_t *job_id)
+{
+ NTSTATUS status;
+ struct spoolss_StartDocPrinter s;
+ struct spoolss_DocumentInfoCtr info_ctr;
+ struct spoolss_DocumentInfo1 info1;
+ struct spoolss_StartPagePrinter sp;
+ struct spoolss_WritePrinter w;
+ struct spoolss_EndPagePrinter ep;
+ struct spoolss_EndDocPrinter e;
+ int i;
+ uint32_t num_written;
+
+ torture_comment(tctx, "Testing StartDocPrinter\n");
+
+ s.in.handle = handle;
+ s.in.info_ctr = &info_ctr;
+ s.out.job_id = job_id;
+
+ info1.document_name = document_name;
+ info1.output_file = NULL;
+ info1.datatype = datatype;
+
+ info_ctr.level = 1;
+ info_ctr.info.info1 = &info1;
+
+ status = dcerpc_spoolss_StartDocPrinter_r(b, tctx, &s);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_StartDocPrinter failed");
+ torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
+
+ for (i=1; i < 4; i++) {
+ union spoolss_JobInfo ginfo;
+ bool ok;
+
+ torture_comment(tctx, "Testing StartPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
+
+ sp.in.handle = handle;
+
+ status = dcerpc_spoolss_StartPagePrinter_r(b, tctx, &sp);
+ torture_assert_ntstatus_ok(tctx, status,
+ "dcerpc_spoolss_StartPagePrinter failed");
+ torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
+
+ ok = test_GetJob_args(tctx, b, handle, *job_id, 1, &ginfo);
+ if (!ok) {
+ torture_comment(tctx, "test_GetJob failed for JobId[%d]\n", *job_id);
+ }
+
+ torture_comment(tctx, "Testing WritePrinter: Page[%d], JobId[%d]\n", i, *job_id);
+
+ w.in.handle = handle;
+ w.in.data = data_blob_string_const(talloc_asprintf(tctx,"TortureTestPage: %d\nData\n",i));
+ w.out.num_written = &num_written;
+
+ status = dcerpc_spoolss_WritePrinter_r(b, tctx, &w);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_WritePrinter failed");
+ torture_assert_werr_ok(tctx, w.out.result, "WritePrinter failed");
+
+ torture_comment(tctx, "Testing EndPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
+
+ ep.in.handle = handle;
+
+ status = dcerpc_spoolss_EndPagePrinter_r(b, tctx, &ep);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndPagePrinter failed");
+ torture_assert_werr_ok(tctx, ep.out.result, "EndPagePrinter failed");
+ }
+
+ torture_comment(tctx, "Testing EndDocPrinter: JobId[%d]\n", *job_id);
+
+ e.in.handle = handle;
+
+ status = dcerpc_spoolss_EndDocPrinter_r(b, tctx, &e);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_spoolss_EndDocPrinter failed");
+ torture_assert_werr_ok(tctx, e.out.result, "EndDocPrinter failed");
+
+ return true;
+}
+
+static bool test_DoPrintTest_add_one_job(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *document_name,
+ uint32_t *job_id)
+{
+ test_DoPrintTest_add_one_job_common(tctx, b, handle, document_name, "RAW", job_id);
+
+ return true;
+}
+
+static bool test_DoPrintTest_add_one_job_v4(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *document_name,
+ uint32_t *job_id)
+{
+ test_DoPrintTest_add_one_job_common(tctx, b, handle, document_name, "XPS_PASS", job_id);
+
+ return true;
+}
+
+
+static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t num_jobs,
+ uint32_t *job_ids)
+{
+ uint32_t count;
+ union spoolss_JobInfo *info = NULL;
+ int i;
+
+ torture_assert(tctx,
+ test_AddJob(tctx, b, handle),
+ "AddJob failed");
+
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, handle, 1, WERR_OK, &count, &info),
+ "EnumJobs level 1 failed");
+
+ torture_assert_int_equal(tctx, count, num_jobs, "unexpected number of jobs in queue");
+
+ for (i=0; i < num_jobs; i++) {
+ union spoolss_JobInfo ginfo;
+ const char *document_name;
+ const char *new_document_name = "any_other_docname";
+ struct spoolss_JobInfoContainer ctr;
+ struct spoolss_SetJobInfo1 info1;
+
+ torture_assert_int_equal(tctx, info[i].info1.job_id, job_ids[i], "job id mismatch");
+
+ torture_assert(tctx,
+ test_GetJob_args(tctx, b, handle, info[i].info1.job_id, 1, &ginfo),
+ "failed to call test_GetJob");
+
+ torture_assert_int_equal(tctx, ginfo.info1.job_id, info[i].info1.job_id, "job id mismatch");
+
+ document_name = ginfo.info1.document_name;
+
+ info1.job_id = ginfo.info1.job_id;
+ info1.printer_name = ginfo.info1.printer_name;
+ info1.server_name = ginfo.info1.server_name;
+ info1.user_name = ginfo.info1.user_name;
+ info1.document_name = new_document_name;
+ info1.data_type = ginfo.info1.data_type;
+ info1.text_status = ginfo.info1.text_status;
+ info1.status = ginfo.info1.status;
+ info1.priority = ginfo.info1.priority;
+ info1.position = ginfo.info1.position;
+ info1.total_pages = ginfo.info1.total_pages;
+ info1.pages_printed = ginfo.info1.pages_printed;
+ info1.submitted = ginfo.info1.submitted;
+
+ ctr.level = 1;
+ ctr.info.info1 = &info1;
+
+ torture_assert(tctx,
+ test_SetJob(tctx, b, handle, info[i].info1.job_id, &ctr, 0),
+ "failed to call test_SetJob level 1");
+
+ torture_assert(tctx,
+ test_GetJob_args(tctx, b, handle, info[i].info1.job_id, 1, &ginfo),
+ "failed to call test_GetJob");
+
+ if (strequal(ginfo.info1.document_name, document_name)) {
+ torture_warning(tctx,
+ "document_name did *NOT* change from '%s' to '%s'\n",
+ document_name, new_document_name);
+ }
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ if (!test_SetJob(tctx, b, handle, info[i].info1.job_id, NULL, SPOOLSS_JOB_CONTROL_PAUSE)) {
+ torture_warning(tctx, "failed to pause printjob\n");
+ }
+ if (!test_SetJob(tctx, b, handle, info[i].info1.job_id, NULL, SPOOLSS_JOB_CONTROL_RESUME)) {
+ torture_warning(tctx, "failed to resume printjob\n");
+ }
+ }
+
+ return true;
+}
+
+static bool test_DoPrintTest(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ bool ret = true;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+
+ torture_comment(tctx, "Testing real print operations\n");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_DoPrintTest_add_one_job(tctx, b, handle, "TorturePrintJob", &job_ids[i]);
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE);
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_DoPrintTest_add_one_job_v4(tctx, b, handle, "TorturePrintJob v4", &job_ids[i]);
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE);
+ }
+
+ if (ret == true) {
+ torture_comment(tctx, "real print operations test succeeded\n\n");
+ }
+
+ return ret;
+}
+
+static bool test_DoPrintTest_extended(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ bool ret = true;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ torture_comment(tctx, "Testing real print operations (extended)\n");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_DoPrintTest_add_one_job(tctx, b, handle, "TorturePrintJob", &job_ids[i]);
+ }
+
+ ret &= test_DoPrintTest_check_jobs(tctx, b, handle, num_jobs, job_ids);
+
+ for (i=0; i < num_jobs; i++) {
+ ret &= test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE);
+ }
+
+ if (ret == true) {
+ torture_comment(tctx, "real print operations (extended) test succeeded\n\n");
+ }
+
+ return ret;
+}
+
+static bool test_JobPrintProperties_equal(struct torture_context *tctx,
+ struct spoolss_PrintPropertyValue *got,
+ struct spoolss_PrintNamedProperty *exp)
+{
+ torture_assert_int_equal(tctx,
+ got->ePropertyType,
+ exp->propertyValue.ePropertyType,
+ "ePropertyType");
+
+ switch (exp->propertyValue.ePropertyType) {
+ case kRpcPropertyTypeString:
+ torture_assert_str_equal(tctx,
+ got->value.propertyString,
+ exp->propertyValue.value.propertyString,
+ "propertyString");
+ break;
+ case kRpcPropertyTypeInt32:
+ torture_assert_int_equal(tctx,
+ got->value.propertyInt32,
+ exp->propertyValue.value.propertyInt32,
+ "propertyInt32");
+ break;
+ case kRpcPropertyTypeInt64:
+ torture_assert_u64_equal(tctx,
+ got->value.propertyInt64,
+ exp->propertyValue.value.propertyInt64,
+ "propertyInt64");
+ break;
+ case kRpcPropertyTypeByte:
+ torture_assert_int_equal(tctx,
+ got->value.propertyByte,
+ exp->propertyValue.value.propertyByte,
+ "propertyByte");
+ break;
+ case kRpcPropertyTypeBuffer:
+ torture_assert_int_equal(tctx,
+ got->value.propertyBlob.cbBuf,
+ exp->propertyValue.value.propertyBlob.cbBuf,
+ "propertyBlob.cbBuf");
+ torture_assert_mem_equal(tctx,
+ got->value.propertyBlob.pBuf,
+ exp->propertyValue.value.propertyBlob.pBuf,
+ exp->propertyValue.value.propertyBlob.cbBuf,
+ "propertyBlob.pBuf");
+
+ break;
+
+ }
+
+ return true;
+}
+
+static bool test_JobPrintProperties(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t job_id)
+{
+ struct spoolss_PrintNamedProperty in;
+ struct spoolss_PrintPropertyValue out;
+ int i;
+ DATA_BLOB blob = data_blob_string_const("blob");
+ struct {
+ const char *property_name;
+ enum spoolss_EPrintPropertyType type;
+ union spoolss_PrintPropertyValueUnion value;
+ WERROR expected_result;
+ } tests[] = {
+ {
+ .property_name = "torture_property_string",
+ .type = kRpcPropertyTypeString,
+ .value.propertyString = "torture_property_value_string",
+ },{
+ .property_name = "torture_property_int32",
+ .type = kRpcPropertyTypeInt32,
+ .value.propertyInt32 = 42,
+ },{
+ .property_name = "torture_property_int64",
+ .type = kRpcPropertyTypeInt64,
+ .value.propertyInt64 = 0xaffe,
+ },{
+ .property_name = "torture_property_byte",
+ .type = kRpcPropertyTypeByte,
+ .value.propertyByte = 0xab,
+ },{
+ .property_name = "torture_property_buffer",
+ .type = kRpcPropertyTypeBuffer,
+ .value.propertyBlob.cbBuf = blob.length,
+ .value.propertyBlob.pBuf = blob.data,
+ }
+ };
+
+ torture_assert(tctx,
+ test_JobPropertiesEnum(tctx, b, handle, job_id),
+ "failed to enum properties");
+
+ for (i=0; i <ARRAY_SIZE(tests); i++) {
+
+ in.propertyName = tests[i].property_name;
+ in.propertyValue.ePropertyType = tests[i].type;
+ in.propertyValue.value = tests[i].value;
+
+ torture_assert(tctx,
+ test_JobPropertySet(tctx, b, handle, job_id, &in),
+ "failed to set property");
+
+ torture_assert(tctx,
+ test_JobPropertyGetValue(tctx, b, handle, job_id, in.propertyName, &out),
+ "failed to get property");
+
+ torture_assert(tctx,
+ test_JobPrintProperties_equal(tctx, &out, &in),
+ "property unequal");
+
+ torture_assert(tctx,
+ test_JobPropertiesEnum(tctx, b, handle, job_id),
+ "failed to enum properties");
+
+ torture_assert(tctx,
+ test_JobPropertyDelete(tctx, b, handle, job_id, in.propertyName),
+ "failed to delete job property");
+ }
+
+ torture_assert(tctx,
+ test_JobPropertiesEnum(tctx, b, handle, job_id),
+ "failed to enum properties");
+
+ return true;
+}
+
+static bool test_DoPrintTest_properties(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ torture_comment(tctx, "Testing real print operations (properties)\n");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_DoPrintTest_add_one_job(tctx, b, handle, "TorturePrintJob", &job_ids[i]),
+ "failed to create print job");
+ }
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_JobPrintProperties(tctx, b, handle, job_ids[i]),
+ "failed to test job properties");
+ }
+
+
+ for (i=0; i < num_jobs; i++) {
+ torture_assert(tctx,
+ test_SetJob(tctx, b, handle, job_ids[i], NULL, SPOOLSS_JOB_CONTROL_DELETE),
+ "failed to delete printjob");
+ }
+
+ torture_comment(tctx, "real print operations (properties) test succeeded\n\n");
+
+ return true;
+}
+
+static bool test_PausePrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_SetPrinter r;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info_ctr.level = 0;
+ info_ctr.info.info0 = NULL;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ r.in.handle = handle;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.in.command = SPOOLSS_PRINTER_CONTROL_PAUSE;
+
+ torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PAUSE\n");
+
+ status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
+
+ return true;
+}
+
+static bool test_ResumePrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_SetPrinter r;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info_ctr.level = 0;
+ info_ctr.info.info0 = NULL;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ r.in.handle = handle;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.in.command = SPOOLSS_PRINTER_CONTROL_RESUME;
+
+ torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_RESUME\n");
+
+ status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
+
+ return true;
+}
+
+static bool test_printer_purge(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_SetPrinter r;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info_ctr.level = 0;
+ info_ctr.info.info0 = NULL;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ r.in.handle = handle;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.in.command = SPOOLSS_PRINTER_CONTROL_PURGE;
+
+ torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PURGE\n");
+
+ status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
+
+ return true;
+}
+
+static bool test_GetPrinterData_checktype(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type *expected_type,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p)
+{
+ NTSTATUS status;
+ struct spoolss_GetPrinterData r;
+ uint32_t needed;
+ enum winreg_Type type;
+ union spoolss_PrinterData data;
+
+ r.in.handle = handle;
+ r.in.value_name = value_name;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.type = &type;
+ r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
+
+ torture_comment(tctx, "Testing GetPrinterData(%s)\n", r.in.value_name);
+
+ status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ if (expected_type) {
+ torture_assert_int_equal(tctx, type, *expected_type, "unexpected type");
+ }
+ r.in.offered = needed;
+ r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
+ status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "GetPrinterData(%s) failed", r.in.value_name));
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, needed, 1);
+
+ if (type_p) {
+ *type_p = type;
+ }
+
+ if (data_p) {
+ *data_p = r.out.data;
+ }
+
+ if (needed_p) {
+ *needed_p = needed;
+ }
+
+ return true;
+}
+
+static bool test_GetPrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p)
+{
+ return test_GetPrinterData_checktype(tctx, b, handle, value_name,
+ NULL, type_p, data_p, needed_p);
+}
+
+static bool test_GetPrinterDataEx_checktype(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *value_name,
+ enum winreg_Type *expected_type,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p)
+{
+ NTSTATUS status;
+ struct spoolss_GetPrinterDataEx r;
+ enum winreg_Type type;
+ uint32_t needed;
+ union spoolss_PrinterData data;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.handle = handle;
+ r.in.key_name = key_name;
+ r.in.value_name = value_name;
+ r.in.offered = 0;
+ r.out.type = &type;
+ r.out.needed = &needed;
+ r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
+
+ torture_comment(tctx, "Testing GetPrinterDataEx(%s - %s)\n",
+ r.in.key_name, r.in.value_name);
+
+ status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ torture_skip(tctx, "GetPrinterDataEx not supported by server\n");
+ }
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
+ }
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ if (expected_type) {
+ torture_assert_int_equal(tctx, type, *expected_type, "unexpected type");
+ }
+ r.in.offered = needed;
+ r.out.data = talloc_zero_array(tctx, uint8_t, r.in.offered);
+ status = dcerpc_spoolss_GetPrinterDataEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinterDataEx failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "GetPrinterDataEx(%s - %s) failed", r.in.key_name, r.in.value_name));
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_PrinterData, &data, type, needed, 1);
+
+ if (type_p) {
+ *type_p = type;
+ }
+
+ if (data_p) {
+ *data_p = r.out.data;
+ }
+
+ if (needed_p) {
+ *needed_p = needed;
+ }
+
+ return true;
+}
+
+static bool test_GetPrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *value_name,
+ enum winreg_Type *type_p,
+ uint8_t **data_p,
+ uint32_t *needed_p)
+{
+ return test_GetPrinterDataEx_checktype(tctx, p, handle, key_name, value_name,
+ NULL, type_p, data_p, needed_p);
+}
+
+static bool test_get_environment(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char **architecture)
+{
+ DATA_BLOB blob;
+ enum winreg_Type type;
+ uint8_t *data;
+ uint32_t needed;
+
+ torture_assert(tctx,
+ test_GetPrinterData(tctx, b, handle, "Architecture", &type, &data, &needed),
+ "failed to get Architecture");
+
+ torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");
+
+ blob = data_blob_const(data, needed);
+ *architecture = reg_val_data_string(tctx, REG_SZ, blob);
+
+ return true;
+}
+
+static bool test_GetPrinterData_list(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *list[] = {
+ "W3SvcInstalled",
+ "BeepEnabled",
+ "EventLog",
+ /* "NetPopup", not on w2k8 */
+ /* "NetPopupToComputer", not on w2k8 */
+ "MajorVersion",
+ "MinorVersion",
+ "DefaultSpoolDirectory",
+ "Architecture",
+ "DsPresent",
+ "OSVersion",
+ /* "OSVersionEx", not on s3 */
+ "DNSMachineName"
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(list); i++) {
+ enum winreg_Type type = REG_NONE;
+ enum winreg_Type type_ex1 = REG_NONE;
+ enum winreg_Type type_ex2 = REG_NONE;
+ uint8_t *data;
+ uint8_t *data_ex1 = NULL;
+ uint8_t *data_ex2 = NULL;
+ uint32_t needed;
+ uint32_t needed_ex1 = 0;
+ uint32_t needed_ex2 = 0;
+
+ torture_assert(tctx, test_GetPrinterData(tctx, b, &ctx->server_handle, list[i], &type, &data, &needed),
+ talloc_asprintf(tctx, "GetPrinterData failed on %s\n", list[i]));
+ torture_assert(tctx, test_GetPrinterDataEx(tctx, p, &ctx->server_handle, "random_string", list[i], &type_ex1, &data_ex1, &needed_ex1),
+ talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
+ torture_assert(tctx, test_GetPrinterDataEx(tctx, p, &ctx->server_handle, "", list[i], &type_ex2, &data_ex2, &needed_ex2),
+ talloc_asprintf(tctx, "GetPrinterDataEx failed on %s\n", list[i]));
+ torture_assert_int_equal(tctx, type, type_ex1, "type mismatch");
+ torture_assert_int_equal(tctx, type, type_ex2, "type mismatch");
+ torture_assert_int_equal(tctx, needed, needed_ex1, "needed mismatch");
+ torture_assert_int_equal(tctx, needed, needed_ex2, "needed mismatch");
+ torture_assert_mem_equal(tctx, data, data_ex1, needed, "data mismatch");
+ torture_assert_mem_equal(tctx, data, data_ex2, needed, "data mismatch");
+ }
+
+ return true;
+}
+
+static bool test_EnumPrinterData(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ uint32_t enum_index,
+ uint32_t value_offered,
+ uint32_t data_offered,
+ enum winreg_Type *type_p,
+ uint32_t *value_needed_p,
+ uint32_t *data_needed_p,
+ const char **value_name_p,
+ uint8_t **data_p,
+ WERROR *result_p)
+{
+ struct spoolss_EnumPrinterData r;
+ uint32_t data_needed;
+ uint32_t value_needed;
+ enum winreg_Type type;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.handle = handle;
+ r.in.enum_index = enum_index;
+ r.in.value_offered = value_offered;
+ r.in.data_offered = data_offered;
+ r.out.data_needed = &data_needed;
+ r.out.value_needed = &value_needed;
+ r.out.type = &type;
+ r.out.data = talloc_zero_array(tctx, uint8_t, r.in.data_offered);
+ r.out.value_name = talloc_zero_array(tctx, const char, r.in.value_offered);
+
+ torture_comment(tctx, "Testing EnumPrinterData(%d)\n", enum_index);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinterData_r(b, tctx, &r),
+ "EnumPrinterData failed");
+
+ if (type_p) {
+ *type_p = type;
+ }
+ if (value_needed_p) {
+ *value_needed_p = value_needed;
+ }
+ if (data_needed_p) {
+ *data_needed_p = data_needed;
+ }
+ if (value_name_p) {
+ *value_name_p = r.out.value_name;
+ }
+ if (data_p) {
+ *data_p = r.out.data;
+ }
+ if (result_p) {
+ *result_p = r.out.result;
+ }
+
+ return true;
+}
+
+
+static bool test_EnumPrinterData_all(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ uint32_t enum_index = 0;
+ enum winreg_Type type;
+ uint32_t value_needed;
+ uint32_t data_needed;
+ uint8_t *data;
+ const char *value_name;
+ WERROR result;
+
+ torture_comment(tctx, "Testing EnumPrinterData\n");
+
+ do {
+ torture_assert(tctx,
+ test_EnumPrinterData(tctx, p, handle, enum_index, 0, 0,
+ &type, &value_needed, &data_needed,
+ &value_name, &data, &result),
+ "EnumPrinterData failed");
+
+ if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
+ break;
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterData(tctx, p, handle, enum_index, value_needed, data_needed,
+ &type, &value_needed, &data_needed,
+ &value_name, &data, &result),
+ "EnumPrinterData failed");
+
+ if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS)) {
+ break;
+ }
+
+ enum_index++;
+
+ } while (W_ERROR_IS_OK(result));
+
+ torture_comment(tctx, "EnumPrinterData test succeeded\n");
+
+ return true;
+}
+
+static bool test_EnumPrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ uint32_t *count_p,
+ struct spoolss_PrinterEnumValues **info_p)
+{
+ struct spoolss_EnumPrinterDataEx r;
+ struct spoolss_PrinterEnumValues *info;
+ uint32_t needed;
+ uint32_t count;
+
+ r.in.handle = handle;
+ r.in.key_name = key_name;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key_name);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
+ "EnumPrinterDataEx failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &r),
+ "EnumPrinterDataEx failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPrinterDataEx failed");
+
+ CHECK_NEEDED_SIZE_ENUM(spoolss_EnumPrinterDataEx, info, count, needed, 1);
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ return true;
+}
+
+static bool test_SetPrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type type,
+ uint8_t *data,
+ uint32_t offered);
+static bool test_DeletePrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name);
+
+static bool test_EnumPrinterData_consistency(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ uint32_t count;
+ struct spoolss_PrinterEnumValues *info;
+ int i;
+ uint32_t value_needed, data_needed;
+ uint32_t value_offered, data_offered;
+ WERROR result;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ enum winreg_Type type;
+ DATA_BLOB blob;
+
+ torture_comment(tctx, "Testing EnumPrinterData vs EnumPrinterDataEx consistency\n");
+
+ torture_assert(tctx, push_reg_sz(tctx, &blob, "torture_data1"), "");
+ type = REG_SZ;
+
+ torture_assert(tctx,
+ test_SetPrinterData(tctx, b, handle, "torture_value1", type, blob.data, blob.length),
+ "SetPrinterData failed");
+
+ blob = data_blob_string_const("torture_data2");
+
+ torture_assert(tctx,
+ test_SetPrinterData(tctx, b, handle, "torture_value2", REG_BINARY, blob.data, blob.length),
+ "SetPrinterData failed");
+
+ blob = data_blob_talloc(tctx, NULL, 4);
+ SIVAL(blob.data, 0, 0x11223344);
+
+ torture_assert(tctx,
+ test_SetPrinterData(tctx, b, handle, "torture_value3", type, blob.data, blob.length),
+ "SetPrinterData failed");
+
+ torture_assert(tctx,
+ test_EnumPrinterDataEx(tctx, b, handle, "PrinterDriverData", &count, &info),
+ "failed to call EnumPrinterDataEx");
+
+ /* get the max sizes for value and data */
+
+ torture_assert(tctx,
+ test_EnumPrinterData(tctx, p, handle, 0, 0, 0,
+ NULL, &value_needed, &data_needed,
+ NULL, NULL, &result),
+ "EnumPrinterData failed");
+ torture_assert_werr_ok(tctx, result, "unexpected result");
+
+ /* check if the reply from the EnumPrinterData really matches max values */
+
+ for (i=0; i < count; i++) {
+ if (info[i].value_name_len > value_needed) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "EnumPrinterDataEx gave a reply with value length %d which is larger then expected max value length %d from EnumPrinterData",
+ info[i].value_name_len, value_needed));
+ }
+ if (info[i].data_length > data_needed) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "EnumPrinterDataEx gave a reply with data length %d which is larger then expected max data length %d from EnumPrinterData",
+ info[i].data_length, data_needed));
+ }
+ }
+
+ /* assuming that both EnumPrinterData and EnumPrinterDataEx do either
+ * sort or not sort the replies by value name, we should be able to do
+ * the following entry comparison */
+
+ data_offered = data_needed;
+ value_offered = value_needed;
+
+ for (i=0; i < count; i++) {
+
+ const char *value_name;
+ uint8_t *data;
+
+ torture_assert(tctx,
+ test_EnumPrinterData(tctx, p, handle, i, value_offered, data_offered,
+ &type, &value_needed, &data_needed,
+ &value_name, &data, &result),
+ "EnumPrinterData failed");
+
+ if (i -1 == count) {
+ torture_assert_werr_equal(tctx, result, WERR_NO_MORE_ITEMS,
+ "unexpected result");
+ break;
+ } else {
+ torture_assert_werr_ok(tctx, result, "unexpected result");
+ }
+
+ torture_assert_int_equal(tctx, type, info[i].type, "type mismatch");
+ torture_assert_int_equal(tctx, value_needed, info[i].value_name_len, "value name length mismatch");
+ torture_assert_str_equal(tctx, value_name, info[i].value_name, "value name mismatch");
+ torture_assert_int_equal(tctx, data_needed, info[i].data_length, "data length mismatch");
+ torture_assert_mem_equal(tctx, data, info[i].data->data, info[i].data_length, "data mismatch");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterData(tctx, b, handle, "torture_value1"),
+ "DeletePrinterData failed");
+ torture_assert(tctx,
+ test_DeletePrinterData(tctx, b, handle, "torture_value2"),
+ "DeletePrinterData failed");
+ torture_assert(tctx,
+ test_DeletePrinterData(tctx, b, handle, "torture_value3"),
+ "DeletePrinterData failed");
+
+ torture_comment(tctx, "EnumPrinterData vs EnumPrinterDataEx consistency test succeeded\n\n");
+
+ return true;
+}
+
+static bool test_DeletePrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name)
+{
+ NTSTATUS status;
+ struct spoolss_DeletePrinterData r;
+
+ r.in.handle = handle;
+ r.in.value_name = value_name;
+
+ torture_comment(tctx, "Testing DeletePrinterData(%s)\n",
+ r.in.value_name);
+
+ status = dcerpc_spoolss_DeletePrinterData_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "DeletePrinterData failed");
+ torture_assert_werr_ok(tctx, r.out.result, "DeletePrinterData failed");
+
+ return true;
+}
+
+static bool test_DeletePrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *value_name)
+{
+ struct spoolss_DeletePrinterDataEx r;
+
+ r.in.handle = handle;
+ r.in.key_name = key_name;
+ r.in.value_name = value_name;
+
+ torture_comment(tctx, "Testing DeletePrinterDataEx(%s - %s)\n",
+ r.in.key_name, r.in.value_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterDataEx_r(b, tctx, &r),
+ "DeletePrinterDataEx failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "DeletePrinterDataEx failed");
+
+ return true;
+}
+
+static bool test_DeletePrinterKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name)
+{
+ struct spoolss_DeletePrinterKey r;
+
+ r.in.handle = handle;
+ r.in.key_name = key_name;
+
+ torture_comment(tctx, "Testing DeletePrinterKey(%s)\n", r.in.key_name);
+
+ if (strequal(key_name, "") && !torture_setting_bool(tctx, "dangerous", false)) {
+ torture_skip(tctx, "not wiping out printer registry - enable dangerous tests to use\n");
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterKey_r(b, tctx, &r),
+ "DeletePrinterKey failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "DeletePrinterKey failed");
+
+ return true;
+}
+
+static bool test_winreg_OpenHKLM(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct winreg_OpenHKLM r;
+
+ r.in.system_name = NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = handle;
+
+ torture_comment(tctx, "Testing winreg_OpenHKLM\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenHKLM_r(b, tctx, &r), "OpenHKLM failed");
+ torture_assert_werr_ok(tctx, r.out.result, "OpenHKLM failed");
+
+ return true;
+}
+
+static void init_winreg_String(struct winreg_String *name, const char *s)
+{
+ name->name = s;
+ if (s) {
+ name->name_len = 2 * (strlen_m(s) + 1);
+ name->name_size = name->name_len;
+ } else {
+ name->name_len = 0;
+ name->name_size = 0;
+ }
+}
+
+static bool test_winreg_OpenKey_opts(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *hive_handle,
+ const char *keyname,
+ uint32_t options,
+ struct policy_handle *key_handle)
+{
+ struct winreg_OpenKey r;
+
+ r.in.parent_handle = hive_handle;
+ init_winreg_String(&r.in.keyname, keyname);
+ r.in.options = options;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = key_handle;
+
+ torture_comment(tctx, "Testing winreg_OpenKey(%s)\n", keyname);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey_r(b, tctx, &r), "OpenKey failed");
+ torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
+
+ return true;
+}
+
+static bool test_winreg_OpenKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *hive_handle,
+ const char *keyname,
+ struct policy_handle *key_handle)
+{
+ return test_winreg_OpenKey_opts(tctx, b, hive_handle, keyname,
+ REG_OPTION_NON_VOLATILE, key_handle);
+}
+
+static bool test_winreg_CloseKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct winreg_CloseKey r;
+
+ r.in.handle = handle;
+ r.out.handle = handle;
+
+ torture_comment(tctx, "Testing winreg_CloseKey\n");
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey_r(b, tctx, &r), "CloseKey failed");
+ torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
+
+ return true;
+}
+
+bool test_winreg_QueryValue(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type *type_p,
+ uint32_t *data_size_p,
+ uint32_t *data_length_p,
+ uint8_t **data_p)
+{
+ struct winreg_QueryValue r;
+ enum winreg_Type type = REG_NONE;
+ uint32_t data_size = 0;
+ uint32_t data_length = 0;
+ struct winreg_String valuename;
+ uint8_t *data = NULL;
+
+ init_winreg_String(&valuename, value_name);
+
+ data = talloc_zero_array(tctx, uint8_t, 0);
+
+ r.in.handle = handle;
+ r.in.value_name = &valuename;
+ r.in.type = &type;
+ r.in.data_size = &data_size;
+ r.in.data_length = &data_length;
+ r.in.data = data;
+ r.out.type = &type;
+ r.out.data = data;
+ r.out.data_size = &data_size;
+ r.out.data_length = &data_length;
+
+ torture_comment(tctx, "Testing winreg_QueryValue(%s)\n", value_name);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ *r.in.data_size = *r.out.data_size;
+ data = talloc_zero_array(tctx, uint8_t, *r.in.data_size);
+ r.in.data = data;
+ r.out.data = data;
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
+ }
+ torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
+
+ if (type_p) {
+ *type_p = *r.out.type;
+ }
+ if (data_size_p) {
+ *data_size_p = *r.out.data_size;
+ }
+ if (data_length_p) {
+ *data_length_p = *r.out.data_length;
+ }
+ if (data_p) {
+ *data_p = r.out.data;
+ }
+
+ return true;
+}
+
+static bool test_winreg_query_printerdata(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ const char *key_name,
+ const char *value_name,
+ enum winreg_Type *w_type,
+ uint32_t *w_size,
+ uint32_t *w_length,
+ uint8_t **w_data)
+{
+ const char *printer_key;
+ struct policy_handle key_handle;
+
+ printer_key = talloc_asprintf(tctx, "%s\\%s\\%s",
+ TOP_LEVEL_PRINT_PRINTERS_KEY, printer_name, key_name);
+
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, b, handle, printer_key, &key_handle), "");
+
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, &key_handle, value_name, w_type, w_size, w_length, w_data), "");
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, b, &key_handle), "");
+
+ return true;
+}
+
+static bool test_GetForm_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *form_name,
+ enum winreg_Type *w_type,
+ uint32_t *w_size,
+ uint32_t *w_length,
+ uint8_t **w_data)
+{
+ struct policy_handle key_handle;
+
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, b, handle, key_name, &key_handle), "");
+
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, &key_handle, form_name, w_type, w_size, w_length, w_data), "");
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, b, &key_handle), "");
+
+ return true;
+}
+
+static bool test_winreg_symbolic_link(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *symlink_keyname,
+ const char *symlink_destination)
+{
+ /* check if the first key is a symlink to the second key */
+
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
+ struct policy_handle key_handle;
+ DATA_BLOB blob;
+ const char *str;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip winreg symlink test against samba");
+ }
+
+ torture_assert(tctx,
+ test_winreg_OpenKey_opts(tctx, b, handle, symlink_keyname, REG_OPTION_OPEN_LINK, &key_handle),
+ "failed to open key link");
+
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, &key_handle,
+ "SymbolicLinkValue",
+ &w_type, &w_size, &w_length, &w_data),
+ "failed to query for 'SymbolicLinkValue' attribute");
+
+ torture_assert_int_equal(tctx, w_type, REG_LINK, "unexpected type");
+
+ blob = data_blob(w_data, w_size);
+ str = reg_val_data_string(tctx, REG_SZ, blob);
+
+ torture_assert_str_equal(tctx, str, symlink_destination, "unexpected symlink target string");
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, b, &key_handle),
+ "failed to close key link");
+
+ return true;
+}
+
+static const char *strip_unc(const char *unc)
+{
+ char *name;
+
+ if (!unc) {
+ return NULL;
+ }
+
+ if (unc[0] == '\\' && unc[1] == '\\') {
+ unc +=2;
+ }
+
+ name = strchr(unc, '\\');
+ if (name) {
+ return name+1;
+ }
+
+ return unc;
+}
+
+static bool test_GetPrinterInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ union spoolss_PrinterInfo info;
+ const char *keys[] = {
+ TOP_LEVEL_CONTROL_PRINTERS_KEY,
+ TOP_LEVEL_PRINT_PRINTERS_KEY
+ };
+ int i;
+ const char *printername, *sharename;
+
+ torture_comment(tctx, "Testing Printer Info and winreg consistency\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to get printer info level 2");
+
+ printername = strip_unc(info.info2.printername);
+ sharename = strip_unc(info.info2.sharename);
+
+#define test_sz(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ const char *str;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_SZ, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ str = reg_val_data_string(tctx, REG_SZ, blob);\
+ if (w_size == 2 && iname == NULL) {\
+ /*torture_comment(tctx, "%s: \"\", %s: (null)\n", #wname, #iname);\ */\
+ } else {\
+ torture_assert_str_equal(tctx, str, iname,\
+ talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
+ }\
+} while(0);
+
+#define test_dword(wname, iname) \
+do {\
+ uint32_t value;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_DWORD, "unexpected type");\
+ torture_assert_int_equal(tctx, w_size, 4, "unexpected size");\
+ torture_assert_int_equal(tctx, w_length, 4, "unexpected length");\
+ value = IVAL(w_data, 0);\
+ torture_assert_int_equal(tctx, value, iname,\
+ talloc_asprintf(tctx, "%s - %s mismatch", #wname, #iname));\
+} while(0);
+
+#define test_binary(wname, iname) \
+do {\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
+ torture_assert_int_equal(tctx, w_size, iname.length, "unexpected length");\
+ torture_assert_mem_equal(tctx, w_data, iname.data, w_size, \
+ "binary unequal");\
+} while(0);
+
+
+#define test_dm(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ struct spoolss_DeviceMode dm;\
+ enum ndr_err_code ndr_err;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, &dm,\
+ (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);\
+ torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall dm");\
+ torture_assert(tctx, test_devicemode_equal(tctx, &dm, iname),\
+ "dm unequal");\
+} while(0);
+
+#define test_sd(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ struct security_descriptor sd;\
+ enum ndr_err_code ndr_err;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, &sd,\
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);\
+ torture_assert_ndr_success(tctx, ndr_err, "failed to unmarshall sd");\
+ torture_assert(tctx, test_security_descriptor_equal(tctx, &sd, iname),\
+ "sd unequal");\
+} while(0);
+
+#define test_multi_sz(wname, iname) \
+do {\
+ DATA_BLOB blob;\
+ const char **array;\
+ enum winreg_Type w_type;\
+ uint32_t w_size;\
+ uint32_t w_length;\
+ uint8_t *w_data;\
+ int i;\
+ torture_assert(tctx,\
+ test_winreg_QueryValue(tctx, winreg_handle, &key_handle, wname,\
+ &w_type, &w_size, &w_length, &w_data),\
+ "failed to query winreg");\
+ torture_assert_int_equal(tctx, w_type, REG_MULTI_SZ, "unexpected type");\
+ blob = data_blob(w_data, w_size);\
+ torture_assert(tctx, \
+ pull_reg_multi_sz(tctx, &blob, &array),\
+ "failed to pull multi sz");\
+ for (i=0; array[i] != NULL; i++) {\
+ torture_assert_str_equal(tctx, array[i], iname[i],\
+ talloc_asprintf(tctx, "%s - %s mismatch", #wname, iname[i]));\
+ }\
+} while(0);
+
+ if (!test_winreg_symbolic_link(tctx, winreg_handle, hive_handle,
+ TOP_LEVEL_CONTROL_PRINTERS_KEY,
+ "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"))
+ {
+ torture_warning(tctx, "failed to check for winreg symlink");
+ }
+
+ for (i=0; i < ARRAY_SIZE(keys); i++) {
+
+ const char *printer_key;
+ struct policy_handle key_handle;
+
+ printer_key = talloc_asprintf(tctx, "%s\\%s",
+ keys[i], printer_name);
+
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, winreg_handle, hive_handle, printer_key, &key_handle), "");
+
+ test_sz("Name", printername);
+ test_sz("Share Name", sharename);
+ test_sz("Port", info.info2.portname);
+ test_sz("Printer Driver", info.info2.drivername);
+ test_sz("Description", info.info2.comment);
+ test_sz("Location", info.info2.location);
+ test_sz("Separator File", info.info2.sepfile);
+ test_sz("Print Processor", info.info2.printprocessor);
+ test_sz("Datatype", info.info2.datatype);
+ test_sz("Parameters", info.info2.parameters);
+ /* winreg: 0, spoolss not */
+/* test_dword("Attributes", info.info2.attributes); */
+ test_dword("Priority", info.info2.priority);
+ test_dword("Default Priority", info.info2.defaultpriority);
+ /* winreg: 60, spoolss: 0 */
+/* test_dword("StartTime", info.info2.starttime); */
+/* test_dword("UntilTime", info.info2.untiltime); */
+ /* winreg != spoolss */
+/* test_dword("Status", info.info2.status); */
+ test_dm("Default DevMode", info.info2.devmode);
+ test_sd("Security", info.info2.secdesc);
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
+ }
+
+#undef test_dm
+
+ torture_comment(tctx, "Printer Info and winreg consistency test succeeded\n\n");
+
+ return true;
+}
+
+static bool test_GetPrintserverInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ union spoolss_PrinterInfo info;
+ struct policy_handle key_handle;
+
+ torture_comment(tctx,
+ "Testing Printserver Info and winreg consistency\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 3, &info),
+ "failed to get printer info level 2");
+
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, winreg_handle, hive_handle,
+ TOP_LEVEL_CONTROL_KEY, &key_handle), "");
+
+ test_sd("ServerSecurityDescriptor", info.info3.secdesc);
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
+
+#undef test_sd
+
+ torture_comment(tctx,
+ "Printserver Info and winreg consistency test succeeded\n\n");
+
+ return true;
+}
+
+
+static bool test_PrintProcessors(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ union spoolss_PrintProcessorInfo *info;
+ uint32_t count;
+ int i;
+
+ torture_comment(tctx, "Testing Print Processor Info and winreg consistency\n");
+
+ torture_assert(tctx,
+ test_EnumPrintProcessors_level(tctx, b, environment, 1, &count, &info, WERR_OK),
+ "failed to enum print processors level 1");
+
+ for (i=0; i < count; i++) {
+
+ const char *processor_key;
+ struct policy_handle key_handle;
+
+ processor_key = talloc_asprintf(tctx, "%s\\%s\\Print Processors\\%s",
+ TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY,
+ environment,
+ info[i].info1.print_processor_name);
+
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, winreg_handle, hive_handle, processor_key, &key_handle), "");
+
+ /* nothing to check in there so far */
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
+ }
+
+ torture_comment(tctx, "Print Processor Info and winreg consistency test succeeded\n\n");
+
+ return true;
+}
+
+static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *architecture,
+ uint32_t level,
+ uint32_t client_major_version,
+ uint32_t client_minor_version,
+ union spoolss_DriverInfo *info_p,
+ WERROR *result);
+
+static const char *strip_path(const char *path)
+{
+ char *p;
+
+ if (path == NULL) {
+ return NULL;
+ }
+
+ p = strrchr(path, '\\');
+ if (p) {
+ return p+1;
+ }
+
+ return path;
+}
+
+static const char **strip_paths(const char **path_array)
+{
+ int i;
+
+ if (path_array == NULL) {
+ return NULL;
+ }
+
+ for (i=0; path_array[i] != NULL; i++) {
+ path_array[i] = strip_path(path_array[i]);
+ }
+
+ return path_array;
+}
+
+static const char *driver_winreg_date(TALLOC_CTX *mem_ctx, NTTIME nt)
+{
+ time_t t;
+ struct tm *tm;
+
+ if (nt == 0) {
+ return talloc_strdup(mem_ctx, "01/01/1601");
+ }
+
+ t = nt_time_to_unix(nt);
+ tm = localtime(&t);
+
+ return talloc_asprintf(mem_ctx, "%02d/%02d/%04d",
+ tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
+}
+
+static const char *driver_winreg_version(TALLOC_CTX *mem_ctx, uint64_t v)
+{
+ return talloc_asprintf(mem_ctx, "%u.%u.%u.%u",
+ (unsigned)((v >> 48) & 0xFFFF),
+ (unsigned)((v >> 32) & 0xFFFF),
+ (unsigned)((v >> 16) & 0xFFFF),
+ (unsigned)(v & 0xFFFF));
+}
+
+static bool test_GetDriverInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ const char *driver_name,
+ const char *environment,
+ enum spoolss_DriverOSVersion version,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle,
+ const char *server_name_slash)
+{
+ WERROR result = WERR_OK;
+ union spoolss_DriverInfo info;
+ const char *driver_key;
+ struct policy_handle key_handle;
+
+ const char *driver_path;
+ const char *data_file;
+ const char *config_file;
+ const char *help_file;
+ const char **dependent_files;
+
+ const char *driver_date;
+ const char *inbox_driver_date;
+
+ const char *driver_version;
+ const char *inbox_driver_version;
+
+ ZERO_STRUCT(key_handle);
+
+ torture_comment(tctx, "Testing Driver Info and winreg consistency\n");
+
+ driver_key = talloc_asprintf(tctx, "%s\\%s\\Drivers\\Version-%d\\%s",
+ TOP_LEVEL_CONTROL_ENVIRONMENTS_KEY,
+ environment,
+ version,
+ driver_name);
+
+ torture_assert(tctx,
+ test_winreg_OpenKey(tctx, winreg_handle, hive_handle, driver_key, &key_handle),
+ "failed to open driver key");
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "w2k3", false)) {
+ goto try_level6;
+ }
+
+ if (handle) {
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 8, version, 0, &info, &result),
+ "failed to get driver info level 8");
+ } else {
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, environment, 8, driver_name, &info),
+ "failed to get driver info level 8");
+ }
+
+ if (W_ERROR_EQUAL(result, WERR_INVALID_LEVEL)) {
+ goto try_level6;
+ }
+
+ driver_path = strip_path(info.info8.driver_path);
+ data_file = strip_path(info.info8.data_file);
+ config_file = strip_path(info.info8.config_file);
+ help_file = strip_path(info.info8.help_file);
+ dependent_files = strip_paths(info.info8.dependent_files);
+
+ driver_date = driver_winreg_date(tctx, info.info8.driver_date);
+ inbox_driver_date = driver_winreg_date(tctx, info.info8.min_inbox_driver_ver_date);
+
+ driver_version = driver_winreg_version(tctx, info.info8.driver_version);
+ inbox_driver_version = driver_winreg_version(tctx, info.info8.min_inbox_driver_ver_version);
+
+ test_sz("Configuration File", config_file);
+ test_sz("Data File", data_file);
+ test_sz("Datatype", info.info8.default_datatype);
+ test_sz("Driver", driver_path);
+ test_sz("DriverDate", driver_date);
+ test_sz("DriverVersion", driver_version);
+ test_sz("HardwareID", info.info8.hardware_id);
+ test_sz("Help File", help_file);
+ test_sz("InfPath", info.info8.inf_path);
+ test_sz("Manufacturer", info.info8.manufacturer_name);
+ test_sz("MinInboxDriverVerDate", inbox_driver_date);
+ test_sz("MinInboxDriverVerVersion", inbox_driver_version);
+ test_sz("Monitor", info.info8.monitor_name);
+ test_sz("OEM URL", info.info8.manufacturer_url);
+ test_sz("Print Processor", info.info8.print_processor);
+ test_sz("Provider", info.info8.provider);
+ test_sz("VendorSetup", info.info8.vendor_setup);
+ test_multi_sz("ColorProfiles", info.info8.color_profiles);
+ test_multi_sz("Dependent Files", dependent_files);
+ test_multi_sz("CoreDependencies", info.info8.core_driver_dependencies);
+ test_multi_sz("Previous Names", info.info8.previous_names);
+/* test_dword("Attributes", ?); */
+ test_dword("PrinterDriverAttributes", info.info8.printer_driver_attributes);
+ test_dword("Version", info.info8.version);
+/* test_dword("TempDir", ?); */
+
+ try_level6:
+
+ if (handle) {
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 6, version, 0, &info, &result),
+ "failed to get driver info level 6");
+ } else {
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, environment, 6, driver_name, &info),
+ "failed to get driver info level 6");
+ }
+
+ driver_path = strip_path(info.info6.driver_path);
+ data_file = strip_path(info.info6.data_file);
+ config_file = strip_path(info.info6.config_file);
+ help_file = strip_path(info.info6.help_file);
+ dependent_files = strip_paths(info.info6.dependent_files);
+
+ driver_date = driver_winreg_date(tctx, info.info6.driver_date);
+
+ driver_version = driver_winreg_version(tctx, info.info6.driver_version);
+
+ test_sz("Configuration File", config_file);
+ test_sz("Data File", data_file);
+ test_sz("Datatype", info.info6.default_datatype);
+ test_sz("Driver", driver_path);
+ if (torture_setting_bool(tctx, "w2k3", false)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, 8);
+ push_nttime(blob.data, 0, info.info6.driver_date);
+ test_binary("DriverDate", blob);
+ SBVAL(blob.data, 0, info.info6.driver_version);
+ test_binary("DriverVersion", blob);
+ } else {
+ test_sz("DriverDate", driver_date);
+ test_sz("DriverVersion", driver_version);
+ }
+ test_sz("HardwareID", info.info6.hardware_id);
+ test_sz("Help File", help_file);
+ test_sz("Manufacturer", info.info6.manufacturer_name);
+ test_sz("Monitor", info.info6.monitor_name);
+ test_sz("OEM URL", info.info6.manufacturer_url);
+ test_sz("Provider", info.info6.provider);
+ test_multi_sz("Dependent Files", dependent_files);
+ test_multi_sz("Previous Names", info.info6.previous_names);
+/* test_dword("Attributes", ?); */
+ test_dword("Version", info.info6.version);
+/* test_dword("TempDir", ?); */
+
+ if (handle) {
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, environment, 3, version, 0, &info, &result),
+ "failed to get driver info level 3");
+ } else {
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, environment, 3, driver_name, &info),
+ "failed to get driver info level 3");
+ }
+
+ driver_path = strip_path(info.info3.driver_path);
+ data_file = strip_path(info.info3.data_file);
+ config_file = strip_path(info.info3.config_file);
+ help_file = strip_path(info.info3.help_file);
+ dependent_files = strip_paths(info.info3.dependent_files);
+
+ test_sz("Configuration File", config_file);
+ test_sz("Data File", data_file);
+ test_sz("Datatype", info.info3.default_datatype);
+ test_sz("Driver", driver_path);
+ test_sz("Help File", help_file);
+ test_sz("Monitor", info.info3.monitor_name);
+ test_multi_sz("Dependent Files", dependent_files);
+/* test_dword("Attributes", ?); */
+ test_dword("Version", info.info3.version);
+/* test_dword("TempDir", ?); */
+
+
+ torture_assert(tctx,
+ test_winreg_CloseKey(tctx, winreg_handle, &key_handle), "");
+
+ torture_comment(tctx, "Driver Info and winreg consistency test succeeded\n\n");
+
+ return true;
+}
+
+#undef test_sz
+#undef test_dword
+
+static bool test_SetPrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type type,
+ uint8_t *data,
+ uint32_t offered)
+{
+ struct spoolss_SetPrinterData r;
+
+ r.in.handle = handle;
+ r.in.value_name = value_name;
+ r.in.type = type;
+ r.in.data = data;
+ r.in.offered = offered;
+
+ torture_comment(tctx, "Testing SetPrinterData(%s)\n",
+ r.in.value_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_SetPrinterData_r(b, tctx, &r),
+ "SetPrinterData failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SetPrinterData failed");
+
+ return true;
+}
+
+static bool test_SetPrinterData_matrix(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ const char *values[] = {
+ "spootyfoot",
+ "spooty\\foot",
+#if 0
+ /* FIXME: not working with s3 atm. */
+ "spooty,foot",
+ "spooty,fo,ot",
+#endif
+ "spooty foot",
+#if 0
+ /* FIXME: not working with s3 atm. */
+ "spooty\\fo,ot",
+ "spooty,fo\\ot"
+#endif
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(values); i++) {
+
+ enum winreg_Type type, expected_type = REG_SZ;
+ DATA_BLOB blob;
+ uint8_t *data;
+ uint32_t needed;
+
+ torture_assert(tctx, push_reg_sz(tctx, &blob, "dog"), "");
+ type = REG_SZ;
+
+ torture_assert(tctx,
+ test_SetPrinterData(tctx, b, handle, values[i], REG_SZ, blob.data, blob.length),
+ "SetPrinterData failed");
+
+ torture_assert(tctx,
+ test_GetPrinterData_checktype(tctx, b, handle, values[i], &expected_type, &type, &data, &needed),
+ "GetPrinterData failed");
+
+ torture_assert_int_equal(tctx, type, REG_SZ, "type mismatch");
+ torture_assert_int_equal(tctx, needed, blob.length, "size mismatch");
+ torture_assert_mem_equal(tctx, data, blob.data, blob.length, "buffer mismatch");
+
+ if (winreg_handle && hive_handle) {
+
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
+
+ torture_assert(tctx,
+ test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
+ printer_name, "PrinterDriverData", values[i],
+ &w_type, &w_size, &w_length, &w_data), "");
+
+ torture_assert_int_equal(tctx, w_type, REG_SZ, "winreg type mismatch");
+ torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
+ torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
+ torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterData(tctx, b, handle, values[i]),
+ "DeletePrinterData failed");
+ }
+
+ return true;
+}
+
+
+static bool test_EnumPrinterKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char ***array);
+
+static bool test_SetPrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char *value_name,
+ enum winreg_Type type,
+ uint8_t *data,
+ uint32_t offered)
+{
+ NTSTATUS status;
+ struct spoolss_SetPrinterDataEx r;
+
+ r.in.handle = handle;
+ r.in.key_name = key_name;
+ r.in.value_name = value_name;
+ r.in.type = type;
+ r.in.data = data;
+ r.in.offered = offered;
+
+ torture_comment(tctx, "Testing SetPrinterDataEx(%s - %s) type: %s, offered: 0x%08x\n",
+ r.in.key_name, r.in.value_name, str_regtype(r.in.type), r.in.offered);
+
+ status = dcerpc_spoolss_SetPrinterDataEx_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "SetPrinterDataEx failed");
+ torture_assert_werr_ok(tctx, r.out.result, "SetPrinterDataEx failed");
+
+ return true;
+}
+
+static bool test_SetPrinterDataEx_keys(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *value_name = "dog";
+ const char *keys[] = {
+ "torturedataex",
+ "torture data ex",
+ "torturedataex_with_subkey\\subkey",
+ "torturedataex_with_subkey\\subkey:0",
+ "torturedataex_with_subkey\\subkey:1",
+ "torturedataex_with_subkey\\subkey\\subsubkey",
+ "torturedataex_with_subkey\\subkey\\subsubkey:0",
+ "torturedataex_with_subkey\\subkey\\subsubkey:1",
+ "torture,data",
+ "torture,data,ex",
+ "torture,data\\ex",
+ "torture\\data,ex",
+ "torture/data",
+ "torture/data ex",
+ "torture/data ex/sub",
+ "torture//data",
+ "torture//data ex",
+ "torture//data ex/sub",
+ "torture//data ex//sub",
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(keys); i++) {
+
+ char *c;
+ const char *key;
+ enum winreg_Type type;
+ DATA_BLOB blob_in, blob_out;
+ const char **subkeys;
+ uint32_t ecount;
+ struct spoolss_PrinterEnumValues *einfo;
+ uint32_t needed;
+
+ blob_in = data_blob_talloc(tctx, NULL, 42);
+
+ generate_random_buffer(blob_in.data, blob_in.length);
+
+ torture_assert(tctx,
+ test_SetPrinterDataEx(tctx, b, handle, keys[i], value_name, REG_BINARY, blob_in.data, blob_in.length),
+ "failed to call SetPrinterDataEx");
+
+ torture_assert(tctx,
+ test_GetPrinterDataEx(tctx, p, handle, keys[i], value_name, &type, &blob_out.data, &needed),
+ "failed to call GetPrinterDataEx");
+
+ blob_out.length = needed;
+ torture_assert(tctx,
+ test_EnumPrinterDataEx(tctx, b, handle, keys[i], &ecount, &einfo),
+ "failed to call EnumPrinterDataEx");
+
+ torture_assert_int_equal(tctx, type, REG_BINARY, "type mismatch");
+ torture_assert_int_equal(tctx, blob_out.length, blob_in.length, "size mismatch");
+ torture_assert_mem_equal(tctx, blob_out.data, blob_in.data, blob_in.length, "buffer mismatch");
+
+ torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
+ torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
+ torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
+ torture_assert_int_equal(tctx, einfo[0].type, REG_BINARY, "type mismatch");
+ torture_assert_int_equal(tctx, einfo[0].data_length, blob_in.length, "size mismatch");
+ if (einfo[0].data_length > 0) {
+ torture_assert_mem_equal(tctx, einfo[0].data->data, blob_in.data, blob_in.length, "buffer mismatch");
+ }
+
+ key = talloc_strdup(tctx, keys[i]);
+
+ if (!test_DeletePrinterDataEx(tctx, b, handle, keys[i], value_name)) {
+ return false;
+ }
+
+ c = strchr(key, '\\');
+ if (c) {
+ int k;
+
+ /* we have subkeys */
+
+ *c = 0;
+
+ if (!test_EnumPrinterKey(tctx, b, handle, key, &subkeys)) {
+ return false;
+ }
+
+ for (k=0; subkeys && subkeys[k]; k++) {
+
+ const char *current_key = talloc_asprintf(tctx, "%s\\%s", key, subkeys[k]);
+
+ if (!test_DeletePrinterKey(tctx, b, handle, current_key)) {
+ return false;
+ }
+ }
+
+ if (!test_DeletePrinterKey(tctx, b, handle, key)) {
+ return false;
+ }
+
+ } else {
+ if (!test_DeletePrinterKey(tctx, b, handle, key)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_SetPrinterDataEx_values(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *key = "torturedataex";
+ const char *values[] = {
+ "torture_value",
+ "torture value",
+ "torture,value",
+ "torture/value",
+ "torture\\value",
+ "torture\\\\value"
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(values); i++) {
+
+ enum winreg_Type type = REG_NONE;
+ DATA_BLOB blob_in = data_blob_null;
+ DATA_BLOB blob_out = data_blob_null;
+ uint32_t ecount;
+ struct spoolss_PrinterEnumValues *einfo;
+ uint32_t needed = 0;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ char *q;
+ q = strrchr(values[i], ',');
+ if (q) {
+ torture_comment(tctx, "skipping valuename '%s' including ',' character against Samba3\n",
+ values[i]);
+ continue;
+ }
+ }
+
+ blob_in = data_blob_talloc(tctx, NULL, 42);
+
+ generate_random_buffer(blob_in.data, blob_in.length);
+
+ torture_assert(tctx,
+ test_SetPrinterDataEx(tctx, b, handle, key, values[i], REG_BINARY, blob_in.data, blob_in.length),
+ "failed to call SetPrinterDataEx");
+
+ torture_assert(tctx,
+ test_GetPrinterDataEx(tctx, p, handle, key, values[i], &type, &blob_out.data, &needed),
+ "failed to call GetPrinterDataEx");
+
+ blob_out.length = needed;
+ torture_assert(tctx,
+ test_EnumPrinterDataEx(tctx, b, handle, key, &ecount, &einfo),
+ "failed to call EnumPrinterDataEx");
+
+ torture_assert_int_equal(tctx, type, REG_BINARY, "type mismatch");
+ torture_assert_int_equal(tctx, blob_out.length, blob_in.length, "size mismatch");
+ torture_assert_mem_equal(tctx, blob_out.data, blob_in.data, blob_in.length, "buffer mismatch");
+
+ torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
+ torture_assert_str_equal(tctx, einfo[0].value_name, values[i], "value_name mismatch");
+ torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(values[i])*2, "unexpected value_name_len");
+ torture_assert_int_equal(tctx, einfo[0].type, REG_BINARY, "type mismatch");
+ torture_assert_int_equal(tctx, einfo[0].data_length, blob_in.length, "size mismatch");
+ if (einfo[0].data_length > 0) {
+ torture_assert_mem_equal(tctx, einfo[0].data->data, blob_in.data, blob_in.length, "buffer mismatch");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDataEx(tctx, b, handle, key, values[i]),
+ "failed to call DeletePrinterDataEx");
+ }
+
+ return true;
+}
+
+
+static bool test_SetPrinterDataEx_matrix(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printername,
+ struct dcerpc_binding_handle *winreg_handle,
+ struct policy_handle *hive_handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *value_name = "dog";
+ const char *key_name = "torturedataex";
+ enum winreg_Type types[] = {
+ REG_SZ,
+ REG_MULTI_SZ,
+ REG_DWORD,
+ REG_BINARY
+ };
+ const char *str = "abcdefghi";
+ size_t t, s;
+
+ for (t=0; t < ARRAY_SIZE(types); t++) {
+ for (s=0; s < strlen(str); s++) {
+
+ enum winreg_Type type;
+ const char *string = talloc_strndup(tctx, str, s);
+ const char *array[2];
+ DATA_BLOB blob = data_blob_string_const(string);
+ DATA_BLOB data;
+ uint8_t *data_out;
+ uint32_t needed, offered = 0;
+ uint32_t ecount;
+ struct spoolss_PrinterEnumValues *einfo;
+
+ array[0] = talloc_strdup(tctx, string);
+ array[1] = NULL;
+
+ if (types[t] == REG_DWORD) {
+ s = 0xffff;
+ }
+
+ switch (types[t]) {
+ case REG_BINARY:
+ data = blob;
+ offered = blob.length;
+ break;
+ case REG_DWORD:
+ data = data_blob_talloc(tctx, NULL, 4);
+ SIVAL(data.data, 0, 0x12345678);
+ offered = 4;
+ break;
+ case REG_SZ:
+ torture_assert(tctx, push_reg_sz(tctx, &data, string), "");
+ type = REG_SZ;
+ offered = data.length;
+ /*strlen_m_term(data.string)*2;*/
+ break;
+ case REG_MULTI_SZ:
+ torture_assert(tctx, push_reg_multi_sz(tctx, &data, array), "");
+ type = REG_MULTI_SZ;
+ offered = data.length;
+ break;
+ default:
+ torture_fail(tctx, talloc_asprintf(tctx, "type %d untested\n", types[t]));
+ }
+
+ torture_assert(tctx,
+ test_SetPrinterDataEx(tctx, b, handle, key_name, value_name, types[t], data.data, offered),
+ "failed to call SetPrinterDataEx");
+
+ torture_assert(tctx,
+ test_GetPrinterDataEx_checktype(tctx, p, handle, key_name, value_name, &types[t], &type, &data_out, &needed),
+ "failed to call GetPrinterDataEx");
+
+ torture_assert(tctx,
+ test_EnumPrinterDataEx(tctx, b, handle, key_name, &ecount, &einfo),
+ "failed to call EnumPrinterDataEx");
+
+ torture_assert_int_equal(tctx, types[t], type, "type mismatch");
+ torture_assert_int_equal(tctx, needed, offered, "size mismatch");
+ torture_assert_mem_equal(tctx, data_out, data.data, offered, "buffer mismatch");
+
+ torture_assert_int_equal(tctx, ecount, 1, "unexpected enum count");
+ torture_assert_str_equal(tctx, einfo[0].value_name, value_name, "value_name mismatch");
+ torture_assert_int_equal(tctx, einfo[0].value_name_len, strlen_m_term(value_name)*2, "unexpected value_name_len");
+ torture_assert_int_equal(tctx, einfo[0].type, types[t], "type mismatch");
+ torture_assert_int_equal(tctx, einfo[0].data_length, offered, "size mismatch");
+ if (einfo[0].data_length > 0) {
+ torture_assert_mem_equal(tctx, einfo[0].data->data, data.data, offered, "buffer mismatch");
+ }
+
+ if (winreg_handle && hive_handle) {
+ enum winreg_Type w_type;
+ uint32_t w_size;
+ uint32_t w_length;
+ uint8_t *w_data;
+
+ torture_assert(tctx,
+ test_winreg_query_printerdata(tctx, winreg_handle, hive_handle,
+ printername, key_name, value_name,
+ &w_type, &w_size, &w_length, &w_data), "");
+
+ torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
+ torture_assert_int_equal(tctx, w_size, offered, "winreg size mismatch");
+ torture_assert_int_equal(tctx, w_length, offered, "winreg length mismatch");
+ torture_assert_mem_equal(tctx, w_data, data.data, offered, "winreg buffer mismatch");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDataEx(tctx, b, handle, key_name, value_name),
+ "failed to call DeletePrinterDataEx");
+ }
+ }
+
+ return true;
+}
+
+static bool test_PrinterData_winreg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printer_name)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret &= test_SetPrinterData_matrix(tctx, b, handle, printer_name, b2, &hive_handle);
+ ret &= test_SetPrinterDataEx_matrix(tctx, p, handle, printer_name, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_Forms_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ bool print_server,
+ const char *printer_name)
+{
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_Forms(tctx, b, handle, print_server, printer_name, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_PrinterInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printer_name)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_GetPrinterInfo_winreg(tctx, b, handle, printer_name, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_PrintserverInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_GetPrintserverInfo_winreg(tctx, b, handle, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+
+static bool test_DriverInfo_winreg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printer_name,
+ const char *driver_name,
+ const char *environment,
+ enum spoolss_DriverOSVersion version)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_GetDriverInfo_winreg(tctx, b, handle, printer_name, driver_name, environment, version, b2, &hive_handle, NULL);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_PrintProcessors_winreg(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment)
+{
+ struct dcerpc_pipe *p2;
+ bool ret = true;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_PrintProcessors(tctx, b, environment, b2, &hive_handle);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+
+ return ret;
+}
+
+static bool test_PrinterData_DsSpooler(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printer_name)
+{
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ union spoolss_SetPrinterInfo sinfo;
+ union spoolss_PrinterInfo info;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *pname;
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ torture_comment(tctx, "Testing DsSpooler <-> SetPrinter relations\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to query Printer level 2");
+
+ torture_assert(tctx,
+ PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo),
+ "failed to convert");
+
+ info_ctr.level = 2;
+ info_ctr.info = sinfo;
+
+#define TEST_SZ(wname, iname) \
+do {\
+ enum winreg_Type type;\
+ uint8_t *data;\
+ uint32_t needed;\
+ DATA_BLOB blob;\
+ const char *str;\
+ torture_assert(tctx,\
+ test_GetPrinterDataEx(tctx, p, handle, "DsSpooler", wname, &type, &data, &needed),\
+ "failed to query");\
+ torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");\
+ blob = data_blob_const(data, needed);\
+ torture_assert(tctx,\
+ pull_reg_sz(tctx, &blob, &str),\
+ "failed to pull REG_SZ");\
+ torture_assert_str_equal(tctx, str, iname, "unexpected result");\
+} while(0);
+
+
+#define TEST_SET_SZ(wname, iname, val) \
+do {\
+ enum winreg_Type type;\
+ uint8_t *data;\
+ uint32_t needed;\
+ DATA_BLOB blob;\
+ const char *str;\
+ sinfo.info2->iname = val;\
+ torture_assert(tctx,\
+ test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),\
+ "failed to call SetPrinter");\
+ torture_assert(tctx,\
+ test_GetPrinterDataEx(tctx, p, handle, "DsSpooler", wname, &type, &data, &needed),\
+ "failed to query");\
+ torture_assert_int_equal(tctx, type, REG_SZ, "unexpected type");\
+ blob = data_blob_const(data, needed);\
+ torture_assert(tctx,\
+ pull_reg_sz(tctx, &blob, &str),\
+ "failed to pull REG_SZ");\
+ torture_assert_str_equal(tctx, str, val, "unexpected result");\
+} while(0);
+
+#define TEST_SET_DWORD(wname, iname, val) \
+do {\
+ enum winreg_Type type;\
+ uint8_t *data;\
+ uint32_t needed;\
+ uint32_t value;\
+ sinfo.info2->iname = val;\
+ torture_assert(tctx,\
+ test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),\
+ "failed to call SetPrinter");\
+ torture_assert(tctx,\
+ test_GetPrinterDataEx(tctx, p, handle, "DsSpooler", wname, &type, &data, &needed),\
+ "failed to query");\
+ torture_assert_int_equal(tctx, type, REG_DWORD, "unexpected type");\
+ torture_assert_int_equal(tctx, needed, 4, "unexpected length");\
+ value = IVAL(data, 0); \
+ torture_assert_int_equal(tctx, value, val, "unexpected result");\
+} while(0);
+
+ TEST_SET_SZ("description", comment, "newval");
+ TEST_SET_SZ("location", location, "newval");
+ TEST_SET_SZ("driverName", drivername, "newval");
+/* TEST_SET_DWORD("priority", priority, 25); */
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to query Printer level 2");
+
+ TEST_SZ("description", info.info2.comment);
+ TEST_SZ("driverName", info.info2.drivername);
+ TEST_SZ("location", info.info2.location);
+
+ pname = strrchr(info.info2.printername, '\\');
+ if (pname == NULL) {
+ pname = info.info2.printername;
+ } else {
+ pname++;
+ }
+ TEST_SZ("printerName", pname);
+ /* TEST_SZ("printSeparatorFile", info.info2.sepfile); */
+ /* TEST_SZ("printShareName", info.info2.sharename); */
+
+ /* FIXME gd: complete the list */
+
+#undef TEST_SZ
+#undef TEST_SET_SZ
+#undef TEST_DWORD
+
+ torture_comment(tctx, "DsSpooler <-> SetPrinter relations test succeeded\n\n");
+
+ return true;
+}
+
+static bool test_print_processors_winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ return test_PrintProcessors_winreg(tctx, b, ctx->environment);
+}
+
+static bool test_AddPrintProcessor(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment,
+ const char *path_name,
+ const char *print_processor_name,
+ WERROR expected_error)
+{
+ struct spoolss_AddPrintProcessor r;
+
+ r.in.server = NULL;
+ r.in.architecture = environment;
+ r.in.path_name = path_name;
+ r.in.print_processor_name = print_processor_name;
+
+ torture_comment(tctx, "Testing AddPrintProcessor(%s)\n",
+ print_processor_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPrintProcessor_r(b, tctx, &r),
+ "spoolss_AddPrintProcessor failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ "spoolss_AddPrintProcessor failed");
+
+ return true;
+}
+
+static bool test_DeletePrintProcessor(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *environment,
+ const char *print_processor_name,
+ WERROR expected_error)
+{
+ struct spoolss_DeletePrintProcessor r;
+
+ r.in.server = NULL;
+ r.in.architecture = environment;
+ r.in.print_processor_name = print_processor_name;
+
+ torture_comment(tctx, "Testing DeletePrintProcessor(%s)\n",
+ print_processor_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrintProcessor_r(b, tctx, &r),
+ "spoolss_DeletePrintProcessor failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ "spoolss_DeletePrintProcessor failed");
+
+ return true;
+}
+
+static bool test_add_print_processor(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ int i;
+
+ struct {
+ const char *environment;
+ const char *path_name;
+ const char *print_processor_name;
+ WERROR expected_add_result;
+ WERROR expected_del_result;
+ } tests[] = {
+ {
+ .environment = ctx->environment,
+ .path_name = "",
+ .print_processor_name = "winprint",
+ .expected_add_result = WERR_PRINT_PROCESSOR_ALREADY_INSTALLED,
+ .expected_del_result = WERR_CAN_NOT_COMPLETE
+ },{
+ .environment = ctx->environment,
+ .path_name = "",
+ .print_processor_name = "unknown",
+ .expected_add_result = WERR_MOD_NOT_FOUND,
+ .expected_del_result = WERR_UNKNOWN_PRINTPROCESSOR
+ }
+ };
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+ torture_assert(tctx,
+ test_AddPrintProcessor(tctx, b,
+ tests[i].environment,
+ tests[i].path_name,
+ tests[i].print_processor_name,
+ tests[i].expected_add_result),
+ "add print processor failed");
+ torture_assert(tctx,
+ test_DeletePrintProcessor(tctx, b,
+ tests[i].environment,
+ tests[i].print_processor_name,
+ tests[i].expected_del_result),
+ "delete print processor failed");
+ }
+
+ return true;
+}
+
+static bool test_AddPerMachineConnection(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ const char *printername,
+ const char *printserver,
+ const char *provider,
+ WERROR expected_error)
+{
+ struct spoolss_AddPerMachineConnection r;
+ const char *composed_printername = printername;
+
+ if (servername != NULL) {
+ composed_printername = talloc_asprintf(tctx, "%s\\%s",
+ servername,
+ printername);
+ }
+ r.in.server = servername;
+ r.in.printername = composed_printername;
+ r.in.printserver = printserver;
+ r.in.provider = provider;
+
+ torture_comment(tctx, "Testing AddPerMachineConnection(%s|%s|%s)\n",
+ printername, printserver, provider);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPerMachineConnection_r(b, tctx, &r),
+ "spoolss_AddPerMachineConnection failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ "spoolss_AddPerMachineConnection failed");
+
+ return true;
+}
+
+static bool test_DeletePerMachineConnection(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ const char *printername,
+ WERROR expected_error)
+{
+ struct spoolss_DeletePerMachineConnection r;
+ const char *composed_printername = printername;
+
+ if (servername != NULL) {
+ composed_printername = talloc_asprintf(tctx, "%s\\%s",
+ servername,
+ printername);
+ }
+
+ r.in.server = servername;
+ r.in.printername = composed_printername;
+
+ torture_comment(tctx, "Testing DeletePerMachineConnection(%s)\n",
+ printername);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePerMachineConnection_r(b, tctx, &r),
+ "spoolss_DeletePerMachineConnection failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ "spoolss_DeletePerMachineConnection failed");
+
+ return true;
+}
+
+static bool test_EnumPerMachineConnections(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername)
+{
+ struct spoolss_EnumPerMachineConnections r;
+ DATA_BLOB blob = data_blob_null;
+ struct spoolss_PrinterInfo4 *info;
+ uint32_t needed;
+ uint32_t count;
+
+ r.in.server = servername;
+ r.in.buffer = &blob;
+ r.in.offered = 0;
+
+ r.out.info = &info;
+ r.out.needed = &needed;
+ r.out.count = &count;
+
+ torture_comment(tctx, "Testing EnumPerMachineConnections(%s)\n",
+ servername);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPerMachineConnections_r(b, tctx, &r),
+ "spoolss_EnumPerMachineConnections failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPerMachineConnections_r(b, tctx, &r),
+ "spoolss_EnumPerMachineConnections failed");
+ }
+ torture_assert_werr_ok(tctx, r.out.result,
+ "spoolss_EnumPerMachineConnections failed");
+
+ return true;
+}
+
+static bool test_addpermachineconnection(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ int i;
+
+ struct {
+ const char *servername;
+ const char *printername;
+ const char *printserver;
+ const char *provider;
+ WERROR expected_add_result;
+ WERROR expected_del_result;
+ } tests[] = {
+ {
+ .servername = NULL,
+ .printername = "foo",
+ .printserver = "",
+ .provider = "unknown",
+ .expected_add_result = WERR_INVALID_PRINTER_NAME,
+ .expected_del_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .servername = NULL,
+ .printername = "Microsoft Print to PDF",
+ .printserver = "samba.org",
+ .provider = "unknown",
+ .expected_add_result = WERR_INVALID_PRINTER_NAME,
+ .expected_del_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .servername = NULL,
+ .printername = "Microsoft Print to PDF",
+ .printserver = "samba.org",
+ .provider = "",
+ .expected_add_result = WERR_INVALID_PRINTER_NAME,
+ .expected_del_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .servername = server_name_slash,
+ .printername = "foo",
+ .printserver = "",
+ .provider = "unknown",
+ .expected_add_result = WERR_FILE_NOT_FOUND,
+ .expected_del_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .servername = server_name_slash,
+ .printername = "foo",
+ .printserver = "",
+ .provider = "",
+ .expected_add_result = WERR_OK,
+ .expected_del_result = WERR_OK
+ },{
+ .servername = server_name_slash,
+ .printername = "Microsoft Print to PDF",
+ .printserver = "samba.org",
+ .provider = "unknown",
+ .expected_add_result = WERR_FILE_NOT_FOUND,
+ .expected_del_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .servername = server_name_slash,
+ .printername = "Microsoft Print to PDF",
+ .printserver = "samba.org",
+ .provider = "",
+ .expected_add_result = WERR_OK,
+ .expected_del_result = WERR_OK
+ }
+ };
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+ torture_assert(tctx,
+ test_AddPerMachineConnection(tctx, b,
+ tests[i].servername,
+ tests[i].printername,
+ tests[i].printserver,
+ tests[i].provider,
+ tests[i].expected_add_result),
+ "add per machine connection failed");
+ torture_assert(tctx,
+ test_EnumPerMachineConnections(tctx, b,
+ tests[i].servername),
+ "enum per machine connections failed");
+ torture_assert(tctx,
+ test_DeletePerMachineConnection(tctx, b,
+ tests[i].servername,
+ tests[i].printername,
+ tests[i].expected_del_result),
+ "delete per machine connection failed");
+ torture_assert(tctx,
+ test_EnumPerMachineConnections(tctx, b,
+ tests[i].servername),
+ "enum per machine connections failed");
+ }
+
+ return true;
+}
+
+static bool test_GetChangeID_PrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t *change_id)
+{
+ enum winreg_Type type;
+ uint8_t *data;
+ uint32_t needed;
+
+ torture_assert(tctx,
+ test_GetPrinterData(tctx, b, handle, "ChangeID", &type, &data, &needed),
+ "failed to call GetPrinterData");
+
+ torture_assert(tctx, type == REG_DWORD, "unexpected type");
+ torture_assert_int_equal(tctx, needed, 4, "unexpected size");
+
+ *change_id = IVAL(data, 0);
+
+ return true;
+}
+
+static bool test_GetChangeID_PrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ uint32_t *change_id)
+{
+ enum winreg_Type type = REG_NONE;
+ uint8_t *data = NULL;
+ uint32_t needed = 0;
+
+ torture_assert(tctx,
+ test_GetPrinterDataEx(tctx, p, handle, "PrinterDriverData", "ChangeID", &type, &data, &needed),
+ "failed to call GetPrinterData");
+
+ torture_assert(tctx, type == REG_DWORD, "unexpected type");
+ torture_assert_int_equal(tctx, needed, 4, "unexpected size");
+
+ *change_id = IVAL(data, 0);
+
+ return true;
+}
+
+static bool test_GetChangeID_PrinterInfo(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t *change_id)
+{
+ union spoolss_PrinterInfo info;
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 0, &info),
+ "failed to query Printer level 0");
+
+ *change_id = info.info0.change_id;
+
+ return true;
+}
+
+static bool test_ChangeID(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ uint32_t change_id, change_id_ex, change_id_info;
+ uint32_t change_id2, change_id_ex2, change_id_info2;
+ union spoolss_PrinterInfo info;
+ const char *comment;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing ChangeID: id change test #1\n");
+
+ torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
+ "failed to query for ChangeID");
+
+ torture_assert_int_equal(tctx, change_id, change_id_ex,
+ "change_ids should all be equal");
+ torture_assert_int_equal(tctx, change_id_ex, change_id_info,
+ "change_ids should all be equal");
+
+
+ torture_comment(tctx, "Testing ChangeID: id change test #2\n");
+
+ torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to query Printer level 2");
+ torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
+ "failed to query for ChangeID");
+ torture_assert_int_equal(tctx, change_id, change_id_ex,
+ "change_id should not have changed");
+ torture_assert_int_equal(tctx, change_id_ex, change_id_info,
+ "change_id should not have changed");
+
+
+ torture_comment(tctx, "Testing ChangeID: id change test #3\n");
+
+ torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "failed to query Printer level 2");
+ comment = talloc_strdup(tctx, info.info2.comment);
+
+ {
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ union spoolss_SetPrinterInfo sinfo;
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+
+ torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
+ sinfo.info2->comment = "torture_comment";
+
+ info_ctr.level = 2;
+ info_ctr.info = sinfo;
+
+ torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
+ "failed to call SetPrinter");
+
+ sinfo.info2->comment = comment;
+
+ torture_assert(tctx, test_SetPrinter(tctx, b, handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
+ "failed to call SetPrinter");
+
+ }
+
+ torture_assert(tctx, test_GetChangeID_PrinterData(tctx, b, handle, &change_id2),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterDataEx(tctx, p, handle, &change_id_ex2),
+ "failed to query for ChangeID");
+ torture_assert(tctx, test_GetChangeID_PrinterInfo(tctx, b, handle, &change_id_info2),
+ "failed to query for ChangeID");
+
+ torture_assert_int_equal(tctx, change_id2, change_id_ex2,
+ "change_ids should all be equal");
+ torture_assert_int_equal(tctx, change_id_ex2, change_id_info2,
+ "change_ids should all be equal");
+
+ torture_assert(tctx, (change_id < change_id2),
+ talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
+ change_id2, change_id));
+ torture_assert(tctx, (change_id_ex < change_id_ex2),
+ talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
+ change_id_ex2, change_id_ex));
+ torture_assert(tctx, (change_id_info < change_id_info2),
+ talloc_asprintf(tctx, "change_id %d needs to be larger than change_id %d",
+ change_id_info2, change_id_info));
+
+ torture_comment(tctx, "ChangeID tests succeeded\n\n");
+
+ return true;
+}
+
+static bool test_SecondaryClosePrinter(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct cli_credentials *anon_creds;
+ const struct dcerpc_binding *binding2;
+ struct dcerpc_pipe *p2;
+ struct spoolss_ClosePrinter cp;
+
+ /* only makes sense on SMB */
+ if (p->conn->transport.transport != NCACN_NP) {
+ return true;
+ }
+
+ torture_comment(tctx, "Testing close on secondary pipe\n");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon failed");
+
+ binding2 = p->binding;
+ status = dcerpc_secondary_auth_connection(p, binding2, &ndr_table_spoolss,
+ anon_creds, tctx->lp_ctx,
+ tctx, &p2);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
+
+ cp.in.handle = handle;
+ cp.out.handle = handle;
+
+ status = dcerpc_spoolss_ClosePrinter_r(p2->binding_handle, tctx, &cp);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RPC_SS_CONTEXT_MISMATCH,
+ "ERROR: Allowed close on secondary connection");
+
+ talloc_free(p2);
+
+ return true;
+}
+
+static bool test_OpenPrinter_badname(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b, const char *name)
+{
+ NTSTATUS status;
+ struct spoolss_OpenPrinter op;
+ struct spoolss_OpenPrinterEx opEx;
+ struct policy_handle handle;
+ bool ret = true;
+
+ op.in.printername = name;
+ op.in.datatype = NULL;
+ op.in.devmode_ctr.devmode= NULL;
+ op.in.access_mask = 0;
+ op.out.handle = &handle;
+
+ torture_comment(tctx, "Testing OpenPrinter(%s) with bad name\n", op.in.printername);
+
+ status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &op);
+ torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
+ torture_assert_werr_equal(tctx, op.out.result, WERR_INVALID_PRINTER_NAME,
+ "unexpected result");
+
+ if (W_ERROR_IS_OK(op.out.result)) {
+ ret &=test_ClosePrinter(tctx, b, &handle);
+ }
+
+ opEx.in.printername = name;
+ opEx.in.datatype = NULL;
+ opEx.in.devmode_ctr.devmode = NULL;
+ opEx.in.access_mask = 0;
+ opEx.in.userlevel_ctr.level = 1;
+ opEx.in.userlevel_ctr.user_info.level1 = NULL;
+ opEx.out.handle = &handle;
+
+ torture_comment(tctx, "Testing OpenPrinterEx(%s) with bad name\n", opEx.in.printername);
+
+ status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &opEx);
+ torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
+ torture_assert_werr_equal(tctx, opEx.out.result, WERR_INVALID_PARAMETER,
+ "unexpected result");
+
+ if (W_ERROR_IS_OK(opEx.out.result)) {
+ ret &=test_ClosePrinter(tctx, b, &handle);
+ }
+
+ return ret;
+}
+
+static bool test_OpenPrinter_badname_list(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ const char *badnames[] = {
+ "__INVALID_PRINTER__",
+ "\\\\__INVALID_HOST__",
+ "",
+ "\\\\\\",
+ "\\\\\\__INVALID_PRINTER__"
+ };
+ const char *badname;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ const char *server_name = dcerpc_server_name(p);
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(badnames); i++) {
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, badnames[i]),
+ "");
+ }
+
+ badname = talloc_asprintf(tctx, "\\\\%s\\", server_name);
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, badname),
+ "");
+
+ badname = talloc_asprintf(tctx, "\\\\%s\\__INVALID_PRINTER__", server_name);
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, badname),
+ "");
+
+ return true;
+}
+
+static bool test_OpenPrinter(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ const char *environment,
+ bool open_only)
+{
+ NTSTATUS status;
+ struct spoolss_OpenPrinter r;
+ struct policy_handle handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.printername = name;
+ r.in.datatype = NULL;
+ r.in.devmode_ctr.devmode= NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
+
+ status = dcerpc_spoolss_OpenPrinter_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "OpenPrinter failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "OpenPrinter failed");
+
+ if (open_only) {
+ goto close_printer;
+ }
+
+ if (!test_GetPrinter(tctx, b, &handle, environment)) {
+ ret = false;
+ }
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
+ ret = false;
+ }
+ }
+
+ close_printer:
+ if (!test_ClosePrinter(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_OpenPrinterEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *printername,
+ const char *datatype,
+ struct spoolss_DeviceMode *devmode,
+ uint32_t access_mask,
+ struct spoolss_UserLevelCtr *userlevel_ctr,
+ struct policy_handle *handle,
+ WERROR expected_result)
+{
+ struct spoolss_OpenPrinterEx r;
+
+ r.in.printername = printername;
+ r.in.datatype = datatype;
+ r.in.devmode_ctr.devmode= devmode;
+ r.in.access_mask = access_mask;
+ r.in.userlevel_ctr = *userlevel_ctr;
+ r.out.handle = handle;
+
+ torture_comment(tctx, "Testing OpenPrinterEx(%s)\n", r.in.printername);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r),
+ "OpenPrinterEx failed");
+
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "OpenPrinterEx failed");
+
+ return true;
+}
+
+static bool call_OpenPrinterEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ struct spoolss_DeviceMode *devmode,
+ struct policy_handle *handle)
+{
+ struct spoolss_UserLevelCtr userlevel_ctr;
+ struct spoolss_UserLevel1 userlevel1;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ userlevel1.size = 1234;
+ userlevel1.client = "hello";
+ userlevel1.user = "spottyfoot!";
+ userlevel1.build = 1;
+ userlevel1.major = 2;
+ userlevel1.minor = 3;
+ userlevel1.processor = 4;
+
+ userlevel_ctr.level = 1;
+ userlevel_ctr.user_info.level1 = &userlevel1;
+
+ return test_OpenPrinterEx(tctx, b, name, NULL, devmode,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &userlevel_ctr,
+ handle,
+ WERR_OK);
+}
+
+static bool test_printer_rename(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ bool ret = true;
+ union spoolss_PrinterInfo info;
+ union spoolss_SetPrinterInfo sinfo;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ const char *printer_name;
+ const char *printer_name_orig;
+ const char *printer_name_new = "SAMBA smbtorture Test Printer (Copy 2)";
+ struct policy_handle new_handle;
+ const char *q;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ torture_comment(tctx, "Testing Printer rename operations\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &t->handle, 2, &info),
+ "failed to call GetPrinter level 2");
+
+ printer_name_orig = talloc_strdup(tctx, info.info2.printername);
+
+ q = strrchr(info.info2.printername, '\\');
+ if (q) {
+ torture_warning(tctx,
+ "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
+ }
+
+ torture_assert(tctx,
+ PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
+
+ sinfo.info2->printername = printer_name_new;
+
+ info_ctr.level = 2;
+ info_ctr.info = sinfo;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, &t->handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
+ "failed to call SetPrinter level 2");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &t->handle, 2, &info),
+ "failed to call GetPrinter level 2");
+
+ printer_name = talloc_strdup(tctx, info.info2.printername);
+
+ q = strrchr(info.info2.printername, '\\');
+ if (q) {
+ torture_warning(tctx,
+ "server returns printername %s incl. servername although we did not set servername", info.info2.printername);
+ q++;
+ printer_name = q;
+ }
+
+ torture_assert_str_equal(tctx, printer_name, printer_name_new,
+ "new printer name was not set");
+
+ /* samba currently cannot fully rename printers */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ torture_assert(tctx,
+ test_OpenPrinter_badname(tctx, b, printer_name_orig),
+ "still can open printer with oldname after rename");
+ } else {
+ torture_warning(tctx, "*not* checking for open with oldname after rename for samba3");
+ }
+
+ torture_assert(tctx,
+ call_OpenPrinterEx(tctx, p, printer_name_new, NULL, &new_handle),
+ "failed to open printer with new name");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &new_handle, 2, &info),
+ "failed to call GetPrinter level 2");
+
+ torture_assert_str_equal(tctx, info.info2.printername, printer_name_new,
+ "new printer name was not set");
+
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &new_handle),
+ "failed to close printer");
+
+ torture_comment(tctx, "Printer rename operations test succeeded\n\n");
+
+ return ret;
+}
+
+static bool test_openprinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *real_printername)
+{
+ struct spoolss_UserLevelCtr userlevel_ctr;
+ struct policy_handle handle;
+ struct spoolss_UserLevel1 userlevel1;
+ const char *printername = NULL;
+ int i;
+
+ struct {
+ const char *suffix;
+ WERROR expected_result;
+ } tests[] = {
+ {
+ .suffix = "rubbish",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ", LocalOnl",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ", localOnly",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ", localonl",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ",LocalOnl",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ",localOnl2",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ", DrvConver2t",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ", drvconvert",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ",drvconvert",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ", DrvConvert",
+ .expected_result = WERR_OK
+ },{
+ .suffix = " , DrvConvert",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ",DrvConvert",
+ .expected_result = WERR_OK
+ },{
+ .suffix = ", DrvConvertsadfasdf",
+ .expected_result = WERR_OK
+ },{
+ .suffix = ",DrvConvertasdfasd",
+ .expected_result = WERR_OK
+ },{
+ .suffix = ", LocalOnly",
+ .expected_result = WERR_OK
+ },{
+ .suffix = " , LocalOnly",
+ .expected_result = WERR_INVALID_PRINTER_NAME
+ },{
+ .suffix = ",LocalOnly",
+ .expected_result = WERR_OK
+ },{
+ .suffix = ", LocalOnlysagi4gjfkd",
+ .expected_result = WERR_OK
+ },{
+ .suffix = ",LocalOnlysagi4gjfkd",
+ .expected_result = WERR_OK
+ }
+ };
+
+ userlevel1.size = 1234;
+ userlevel1.client = "hello";
+ userlevel1.user = "spottyfoot!";
+ userlevel1.build = 1;
+ userlevel1.major = 2;
+ userlevel1.minor = 3;
+ userlevel1.processor = 4;
+
+ userlevel_ctr.level = 1;
+ userlevel_ctr.user_info.level1 = &userlevel1;
+
+ torture_comment(tctx, "Testing openprinterex printername pattern\n");
+
+ torture_assert(tctx,
+ test_OpenPrinterEx(tctx, b, real_printername, NULL, NULL, 0,
+ &userlevel_ctr, &handle,
+ WERR_OK),
+ "OpenPrinterEx failed");
+ test_ClosePrinter(tctx, b, &handle);
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+
+ printername = talloc_asprintf(tctx, "%s%s",
+ real_printername,
+ tests[i].suffix);
+
+ torture_assert(tctx,
+ test_OpenPrinterEx(tctx, b, printername, NULL, NULL, 0,
+ &userlevel_ctr, &handle,
+ tests[i].expected_result),
+ "OpenPrinterEx failed");
+ if (W_ERROR_IS_OK(tests[i].expected_result)) {
+ test_ClosePrinter(tctx, b, &handle);
+ }
+ }
+
+ return true;
+}
+
+
+static bool test_existing_printer_openprinterex(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ const char *environment)
+{
+ struct policy_handle handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_openprinter(tctx, b, name)) {
+ return false;
+ }
+
+ if (!call_OpenPrinterEx(tctx, p, name, NULL, &handle)) {
+ return false;
+ }
+
+ if (!test_PrinterInfo_SD(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ if (!test_GetPrinter(tctx, b, &handle, environment)) {
+ ret = false;
+ }
+
+ if (!test_EnumForms_all(tctx, b, &handle, false)) {
+ ret = false;
+ }
+
+ if (!test_Forms(tctx, b, &handle, false, name, NULL, NULL)) {
+ ret = false;
+ }
+
+ if (!test_Forms_winreg(tctx, b, &handle, false, name)) {
+ ret = false;
+ }
+
+ if (!test_EnumPrinterData_all(tctx, p, &handle)) {
+ ret = false;
+ }
+
+ if (!test_EnumPrinterDataEx(tctx, b, &handle, "PrinterDriverData", NULL, NULL)) {
+ ret = false;
+ }
+
+ if (!test_EnumPrinterData_consistency(tctx, p, &handle)) {
+ ret = false;
+ }
+
+ if (!test_printer_all_keys(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ if (!test_PausePrinter(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ if (!test_DoPrintTest(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ if (!test_ResumePrinter(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ if (!test_SetPrinterData_matrix(tctx, b, &handle, name, NULL, NULL)) {
+ ret = false;
+ }
+
+ if (!test_SetPrinterDataEx_matrix(tctx, p, &handle, name, NULL, NULL)) {
+ ret = false;
+ }
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (!test_SecondaryClosePrinter(tctx, p, &handle)) {
+ ret = false;
+ }
+ }
+
+ if (!test_ClosePrinter(tctx, b, &handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_EnumPrinters_old(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct spoolss_EnumPrinters r;
+ NTSTATUS status;
+ uint16_t levels[] = {1, 2, 4, 5};
+ int i;
+ bool ret = true;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ union spoolss_PrinterInfo *info;
+ int j;
+ uint32_t needed;
+ uint32_t count;
+
+ r.in.flags = PRINTER_ENUM_LOCAL;
+ r.in.server = "";
+ r.in.level = levels[i];
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrinters level %u\n", r.in.level);
+
+ status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ status = dcerpc_spoolss_EnumPrinters_r(b, tctx, &r);
+ }
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, needed, 4);
+
+ if (!info) {
+ torture_comment(tctx, "No printers returned\n");
+ return true;
+ }
+
+ for (j=0;j<count;j++) {
+ if (r.in.level == 1) {
+ char *unc = talloc_strdup(tctx, info[j].info1.name);
+ char *slash, *name, *full_name;
+ name = unc;
+ if (unc[0] == '\\' && unc[1] == '\\') {
+ unc +=2;
+ }
+ slash = strchr(unc, '\\');
+ if (slash) {
+ slash++;
+ name = slash;
+ }
+ full_name = talloc_asprintf(tctx, "\\\\%s\\%s",
+ dcerpc_server_name(p), name);
+ if (!test_OpenPrinter(tctx, p, name, ctx->environment, true)) {
+ ret = false;
+ }
+ if (!test_OpenPrinter(tctx, p, full_name, ctx->environment, true)) {
+ ret = false;
+ }
+ if (!test_OpenPrinter(tctx, p, name, ctx->environment, false)) {
+ ret = false;
+ }
+ if (!test_existing_printer_openprinterex(tctx, p, name, ctx->environment)) {
+ ret = false;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool test_EnumPrinters_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t flags,
+ const char *servername,
+ uint32_t level,
+ uint32_t *count_p,
+ union spoolss_PrinterInfo **info_p)
+{
+ struct spoolss_EnumPrinters r;
+ union spoolss_PrinterInfo *info;
+ uint32_t needed;
+ uint32_t count;
+
+ r.in.flags = flags;
+ r.in.server = servername;
+ r.in.level = level;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+ r.out.count = &count;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing EnumPrinters(%s) level %u\n",
+ r.in.server, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+ "EnumPrinters failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+ "EnumPrinters failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "EnumPrinters failed");
+
+ CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumPrinters, info, r.in.level, count, needed, 4);
+
+ if (count_p) {
+ *count_p = count;
+ }
+ if (info_p) {
+ *info_p = info;
+ }
+
+ return true;
+}
+
+static const char *get_short_printername(struct torture_context *tctx,
+ const char *name)
+{
+ const char *short_name;
+
+ if (name[0] == '\\' && name[1] == '\\') {
+ name += 2;
+ short_name = strchr(name, '\\');
+ if (short_name) {
+ return talloc_strdup(tctx, short_name+1);
+ }
+ }
+
+ return name;
+}
+
+static const char *get_full_printername(struct torture_context *tctx,
+ const char *name)
+{
+ const char *full_name = talloc_strdup(tctx, name);
+ char *p;
+
+ if (name && name[0] == '\\' && name[1] == '\\') {
+ name += 2;
+ p = strchr(name, '\\');
+ if (p) {
+ return full_name;
+ }
+ }
+
+ return NULL;
+}
+
+static bool test_OnePrinter_servername(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ const char *printername)
+{
+ union spoolss_PrinterInfo info;
+ const char *short_name = get_short_printername(tctx, printername);
+ const char *full_name = get_full_printername(tctx, printername);
+
+ if (short_name) {
+ struct policy_handle handle;
+ torture_assert(tctx,
+ call_OpenPrinterEx(tctx, p, short_name, NULL, &handle),
+ "failed to open printer");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &handle, 2, &info),
+ "failed to get printer info");
+
+ torture_assert_casestr_equal(tctx, info.info2.servername, NULL,
+ "unexpected servername");
+ torture_assert_casestr_equal(tctx, info.info2.printername, short_name,
+ "unexpected printername");
+
+ if (info.info2.devmode) {
+ const char *expected_devicename;
+ expected_devicename = talloc_strndup(tctx, short_name, MIN(strlen(short_name), 31));
+ torture_assert_casestr_equal(tctx, info.info2.devmode->devicename, expected_devicename,
+ "unexpected devicemode devicename");
+ }
+
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &handle),
+ "failed to close printer");
+ }
+
+ if (full_name) {
+ struct policy_handle handle;
+
+ torture_assert(tctx,
+ call_OpenPrinterEx(tctx, p, full_name, NULL, &handle),
+ "failed to open printer");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &handle, 2, &info),
+ "failed to get printer info");
+
+ torture_assert_casestr_equal(tctx, info.info2.servername, servername,
+ "unexpected servername");
+ torture_assert_casestr_equal(tctx, info.info2.printername, full_name,
+ "unexpected printername");
+
+ if (info.info2.devmode) {
+ const char *expected_devicename;
+ expected_devicename = talloc_strndup(tctx, full_name, MIN(strlen(full_name), 31));
+ torture_assert_casestr_equal(tctx, info.info2.devmode->devicename, expected_devicename,
+ "unexpected devicemode devicename");
+ }
+
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &handle),
+ "failed to close printer");
+ }
+
+ return true;
+}
+
+static bool test_EnumPrinters_servername(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+ const char *servername;
+ uint32_t flags = PRINTER_ENUM_NAME|PRINTER_ENUM_LOCAL;
+
+ torture_comment(tctx, "Testing servername behaviour in EnumPrinters and GetPrinters\n");
+
+ servername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ torture_assert(tctx,
+ test_EnumPrinters_level(tctx, b, flags, servername, 2, &count, &info),
+ "failed to enumerate printers");
+
+ for (i=0; i < count; i++) {
+
+ torture_assert_casestr_equal(tctx, info[i].info2.servername, servername,
+ "unexpected servername");
+
+ torture_assert(tctx,
+ test_OnePrinter_servername(tctx, p, b, servername, info[i].info2.printername),
+ "failed to check printer");
+ }
+
+ servername = "";
+
+ torture_assert(tctx,
+ test_EnumPrinters_level(tctx, b, flags, servername, 2, &count, &info),
+ "failed to enumerate printers");
+
+ for (i=0; i < count; i++) {
+
+ torture_assert_casestr_equal(tctx, info[i].info2.servername, NULL,
+ "unexpected servername");
+
+ torture_assert(tctx,
+ test_OnePrinter_servername(tctx, p, b, servername, info[i].info2.printername),
+ "failed to check printer");
+ }
+
+
+ return true;
+}
+
+#if 0
+static bool test_GetPrinterDriver(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name)
+{
+ struct spoolss_GetPrinterDriver r;
+ uint32_t needed;
+
+ r.in.handle = handle;
+ r.in.architecture = "W32X86";
+ r.in.level = 1;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_comment(tctx, "Testing GetPrinterDriver level %d\n", r.in.level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
+ "failed to call GetPrinterDriver");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_GetPrinterDriver_r(b, tctx, &r),
+ "failed to call GetPrinterDriver");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call GetPrinterDriver");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, needed, 4);
+
+ return true;
+}
+#endif
+
+static bool test_GetPrinterDriver2_level(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *architecture,
+ uint32_t level,
+ uint32_t client_major_version,
+ uint32_t client_minor_version,
+ union spoolss_DriverInfo *info_p,
+ WERROR *result_p)
+
+{
+ struct spoolss_GetPrinterDriver2 r;
+ uint32_t needed;
+ uint32_t server_major_version;
+ uint32_t server_minor_version;
+
+ r.in.handle = handle;
+ r.in.architecture = architecture;
+ r.in.client_major_version = client_major_version;
+ r.in.client_minor_version = client_minor_version;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.in.level = level;
+ r.out.needed = &needed;
+ r.out.server_major_version = &server_major_version;
+ r.out.server_minor_version = &server_minor_version;
+
+ torture_comment(tctx, "Testing GetPrinterDriver2(%s) level %d\n",
+ driver_name, r.in.level);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
+ "failed to call GetPrinterDriver2");
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &r),
+ "failed to call GetPrinterDriver2");
+ }
+
+ if (result_p) {
+ *result_p = r.out.result;
+ }
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INVALID_LEVEL)) {
+ switch (r.in.level) {
+ case 101:
+ case 8:
+ torture_comment(tctx,
+ "level %d not implemented, not considering as an error\n",
+ r.in.level);
+ return true;
+ default:
+ break;
+ }
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call GetPrinterDriver2");
+
+ CHECK_NEEDED_SIZE_LEVEL(spoolss_DriverInfo, r.out.info, r.in.level, needed, 4);
+
+ if (info_p) {
+ *info_p = *r.out.info;
+ }
+
+ return true;
+}
+
+static bool test_GetPrinterDriver2(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *driver_name,
+ const char *architecture)
+{
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6, 8, 101 };
+ int i;
+
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ torture_assert(tctx,
+ test_GetPrinterDriver2_level(tctx, b, handle, driver_name, architecture, levels[i], 3, 0, NULL, NULL),
+ "");
+ }
+
+ return true;
+}
+
+static bool test_EnumPrinterDrivers_old(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ uint16_t levels[] = {1, 2, 3, 4, 5, 6};
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ uint32_t count;
+ union spoolss_DriverInfo *info;
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_args(tctx, b, server_name, ctx->environment, levels[i], &count, &info),
+ "failed to enumerate drivers");
+
+ if (!info) {
+ torture_comment(tctx, "No printer drivers returned\n");
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool test_DeletePrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct spoolss_DeletePrinter r;
+
+ torture_comment(tctx, "Testing DeletePrinter\n");
+
+ r.in.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_DeletePrinter_r(b, tctx, &r),
+ "failed to delete printer");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to delete printer");
+
+ return true;
+}
+
+static bool test_EnumPrinters_findname(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t flags,
+ uint32_t level,
+ const char *name,
+ bool *found)
+{
+ struct spoolss_EnumPrinters e;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+ uint32_t needed;
+ int i;
+
+ *found = false;
+
+ e.in.flags = flags;
+ e.in.server = NULL;
+ e.in.level = level;
+ e.in.buffer = NULL;
+ e.in.offered = 0;
+ e.out.count = &count;
+ e.out.info = &info;
+ e.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
+ "failed to enum printers");
+
+ if (W_ERROR_EQUAL(e.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ e.in.buffer = &blob;
+ e.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e),
+ "failed to enum printers");
+ }
+
+ torture_assert_werr_ok(tctx, e.out.result,
+ "failed to enum printers");
+
+ for (i=0; i < count; i++) {
+
+ const char *current = NULL;
+ const char *q;
+
+ switch (level) {
+ case 1:
+ current = info[i].info1.name;
+ break;
+ }
+
+ if (strequal(current, name)) {
+ *found = true;
+ break;
+ }
+
+ q = strrchr(current, '\\');
+ if (q) {
+ if (!e.in.server) {
+ torture_warning(tctx,
+ "server returns printername %s incl. servername although we did not set servername", current);
+ }
+ q++;
+ if (strequal(q, name)) {
+ *found = true;
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_AddPrinter_wellknown(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *printername,
+ bool ex)
+{
+ WERROR result;
+ struct spoolss_AddPrinter r;
+ struct spoolss_AddPrinterEx rex;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_SetPrinterInfo1 info1;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ struct spoolss_UserLevelCtr userlevel_ctr;
+ struct policy_handle handle;
+ bool found = false;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ ZERO_STRUCT(userlevel_ctr);
+ ZERO_STRUCT(info1);
+
+ torture_comment(tctx, "Testing AddPrinter%s(%s) level 1\n",
+ ex ? "Ex":"", printername);
+
+ /* try to add printer to wellknown printer list (level 1) */
+
+ userlevel_ctr.level = 1;
+
+ info_ctr.info.info1 = &info1;
+ info_ctr.level = 1;
+
+ rex.in.server = NULL;
+ rex.in.info_ctr = &info_ctr;
+ rex.in.devmode_ctr = &devmode_ctr;
+ rex.in.secdesc_ctr = &secdesc_ctr;
+ rex.in.userlevel_ctr = &userlevel_ctr;
+ rex.out.handle = &handle;
+
+ r.in.server = NULL;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
+ "unexpected result code");
+
+ info1.name = printername;
+ info1.flags = PRINTER_ATTRIBUTE_SHARED;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
+ "unexpected result code");
+
+ /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
+ better do a real check to see the printer is really there */
+
+ torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
+ PRINTER_ENUM_NETWORK, 1,
+ printername,
+ &found),
+ "failed to enum printers");
+
+ torture_assert(tctx, found, "failed to find newly added printer");
+
+ info1.flags = 0;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
+ "unexpected result code");
+
+ /* bizarre protocol, WERR_PRINTER_ALREADY_EXISTS means success here,
+ better do a real check to see the printer has really been removed
+ from the well known printer list */
+
+ found = false;
+
+ torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
+ PRINTER_ENUM_NETWORK, 1,
+ printername,
+ &found),
+ "failed to enum printers");
+#if 0
+ torture_assert(tctx, !found, "printer still in well known printer list");
+#endif
+ return true;
+}
+
+static bool test_AddPrinter_normal(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle_p,
+ const char *printername,
+ const char *drivername,
+ const char *portname,
+ struct spoolss_DeviceMode *devmode,
+ bool ex)
+{
+ WERROR result;
+ struct spoolss_AddPrinter r;
+ struct spoolss_AddPrinterEx rex;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_SetPrinterInfo2 info2;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ struct spoolss_UserLevelCtr userlevel_ctr;
+ struct policy_handle handle;
+ bool found = false;
+ bool existing_printer_deleted = false;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ ZERO_STRUCT(userlevel_ctr);
+
+ torture_comment(tctx, "Testing AddPrinter%s(%s) level 2\n",
+ ex ? "Ex":"", printername);
+
+ devmode_ctr.devmode = devmode;
+
+ userlevel_ctr.level = 1;
+
+ rex.in.server = NULL;
+ rex.in.info_ctr = &info_ctr;
+ rex.in.devmode_ctr = &devmode_ctr;
+ rex.in.secdesc_ctr = &secdesc_ctr;
+ rex.in.userlevel_ctr = &userlevel_ctr;
+ rex.out.handle = &handle;
+
+ r.in.server = NULL;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.out.handle = &handle;
+
+ again:
+
+ /* try to add printer to printer list (level 2) */
+
+ ZERO_STRUCT(info2);
+
+ info_ctr.info.info2 = &info2;
+ info_ctr.level = 2;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_equal(tctx, result, WERR_INVALID_PRINTER_NAME,
+ "unexpected result code");
+
+ info2.printername = printername;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+
+ if (W_ERROR_EQUAL(result, WERR_PRINTER_ALREADY_EXISTS)) {
+ struct policy_handle printer_handle;
+
+ if (existing_printer_deleted) {
+ torture_fail(tctx, "already deleted printer still existing?");
+ }
+
+ torture_assert(tctx, call_OpenPrinterEx(tctx, p, printername, NULL, &printer_handle),
+ "failed to open printer handle");
+
+ torture_assert(tctx, test_DeletePrinter(tctx, b, &printer_handle),
+ "failed to delete printer");
+
+ torture_assert(tctx, test_ClosePrinter(tctx, b, &printer_handle),
+ "failed to close server handle");
+
+ existing_printer_deleted = true;
+
+ goto again;
+ }
+
+ torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PORT,
+ "unexpected result code");
+
+ info2.portname = portname;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTER_DRIVER,
+ "unexpected result code");
+
+ info2.drivername = drivername;
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+
+ /* w2k8r2 allows one to add printer w/o defining printprocessor */
+
+ if (!W_ERROR_IS_OK(result)) {
+ torture_assert_werr_equal(tctx, result, WERR_UNKNOWN_PRINTPROCESSOR,
+ "unexpected result code");
+
+ info2.printprocessor = "winprint";
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_ok(tctx, result,
+ "failed to add printer");
+ }
+
+ *handle_p = handle;
+
+ /* we are paranoid, really check if the printer is there now */
+
+ torture_assert(tctx, test_EnumPrinters_findname(tctx, b,
+ PRINTER_ENUM_LOCAL, 1,
+ printername,
+ &found),
+ "failed to enum printers");
+ torture_assert(tctx, found, "failed to find newly added printer");
+
+ torture_assert_ntstatus_ok(tctx, ex ? dcerpc_spoolss_AddPrinterEx_r(b, tctx, &rex) :
+ dcerpc_spoolss_AddPrinter_r(b, tctx, &r),
+ "failed to add printer");
+ result = ex ? rex.out.result : r.out.result;
+ torture_assert_werr_equal(tctx, result, WERR_PRINTER_ALREADY_EXISTS,
+ "unexpected result code");
+
+ return true;
+}
+
+static bool test_printer_info(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ bool ret = true;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping printer info cross tests against samba 3");
+ }
+
+ if (!test_PrinterInfo(tctx, b, &t->handle)) {
+ ret = false;
+ }
+
+ if (!test_SetPrinter_errors(tctx, b, &t->handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_EnumPrinterKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key_name,
+ const char ***array)
+{
+ struct spoolss_EnumPrinterKey r;
+ uint32_t needed = 0;
+ union spoolss_KeyNames key_buffer;
+ int32_t offered[] = { 0, 1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 256, 512, 1024, 2048 };
+ uint32_t _ndr_size;
+ int i;
+
+ r.in.handle = handle;
+ r.in.key_name = key_name;
+ r.out.key_buffer = &key_buffer;
+ r.out.needed = &needed;
+ r.out._ndr_size = &_ndr_size;
+
+ for (i=0; i < ARRAY_SIZE(offered); i++) {
+
+ if (offered[i] < 0 && needed) {
+ if (needed <= 4) {
+ continue;
+ }
+ r.in.offered = needed + offered[i];
+ } else {
+ r.in.offered = offered[i];
+ }
+
+ ZERO_STRUCT(key_buffer);
+
+ torture_comment(tctx, "Testing EnumPrinterKey(%s) with %d offered\n", r.in.key_name, r.in.offered);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
+ "failed to call EnumPrinterKey");
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+
+ torture_assert(tctx, (_ndr_size == r.in.offered/2),
+ talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
+ _ndr_size, r.in.offered/2));
+
+ r.in.offered = needed;
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &r),
+ "failed to call EnumPrinterKey");
+ }
+
+ if (offered[i] > 0) {
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call EnumPrinterKey");
+ }
+
+ torture_assert(tctx, (_ndr_size == r.in.offered/2),
+ talloc_asprintf(tctx, "EnumPrinterKey size mismatch, _ndr_size %d (expected %d)",
+ _ndr_size, r.in.offered/2));
+
+ torture_assert(tctx, (*r.out.needed <= r.in.offered),
+ talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= offered %d", *r.out.needed, r.in.offered));
+
+ torture_assert(tctx, (*r.out.needed <= _ndr_size * 2),
+ talloc_asprintf(tctx, "EnumPrinterKey size mismatch: needed %d is not <= _ndr_size %d * 2", *r.out.needed, _ndr_size));
+
+ if (key_buffer.string_array) {
+ uint32_t calc_needed = 0;
+ int s;
+ for (s=0; key_buffer.string_array[s]; s++) {
+ calc_needed += strlen_m_term(key_buffer.string_array[s])*2;
+ }
+ if (!key_buffer.string_array[0]) {
+ calc_needed += 2;
+ }
+ calc_needed += 2;
+
+ torture_assert_int_equal(tctx, *r.out.needed, calc_needed,
+ "EnumPrinterKey unexpected size");
+ }
+ }
+
+ if (array) {
+ *array = key_buffer.string_array;
+ }
+
+ return true;
+}
+
+bool test_printer_all_keys(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ const char **key_array = NULL;
+ int i;
+
+ torture_comment(tctx, "Testing Printer Keys\n");
+
+ torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, "", &key_array),
+ "failed to call test_EnumPrinterKey");
+
+ for (i=0; key_array && key_array[i]; i++) {
+ torture_assert(tctx, test_EnumPrinterKey(tctx, b, handle, key_array[i], NULL),
+ "failed to call test_EnumPrinterKey");
+ }
+ for (i=0; key_array && key_array[i]; i++) {
+ torture_assert(tctx, test_EnumPrinterDataEx(tctx, b, handle, key_array[i], NULL, NULL),
+ "failed to call test_EnumPrinterDataEx");
+ }
+
+ torture_comment(tctx, "Printer Keys test succeeded\n\n");
+
+ return true;
+}
+
+static bool test_openprinter_wrap(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *printername = t->info2.printername;
+
+ return test_openprinter(tctx, b, printername);
+}
+
+static bool test_csetprinter(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ const char *printername = talloc_asprintf(tctx, "%s2", t->info2.printername);
+ const char *drivername = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
+ const char *portname = t->info2.portname;
+
+ union spoolss_PrinterInfo info;
+ struct policy_handle new_handle, new_handle2;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "Testing c_setprinter\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &t->handle, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on initial printer handle: %d\n",
+ info.info0.c_setprinter);
+
+ /* check if c_setprinter on 1st handle increases after a printer has
+ * been added */
+
+ torture_assert(tctx,
+ test_AddPrinter_normal(tctx, p, &new_handle, printername, drivername, portname, NULL, false),
+ "failed to add new printer");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &t->handle, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on initial printer handle (after add): %d\n",
+ info.info0.c_setprinter);
+
+ /* check if c_setprinter on new handle increases after a printer has
+ * been added */
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &new_handle, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on created handle: %d\n",
+ info.info0.c_setprinter);
+
+ /* open the new printer and check if c_setprinter increases */
+
+ torture_assert(tctx,
+ call_OpenPrinterEx(tctx, p, printername, NULL, &new_handle2),
+ "failed to open created printer");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &new_handle2, 0, &info),
+ "failed to get level 0 printer info");
+ torture_comment(tctx, "csetprinter on new handle (after openprinter): %d\n",
+ info.info0.c_setprinter);
+
+ /* cleanup */
+
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &new_handle2),
+ "failed to close printer");
+ torture_assert(tctx,
+ test_DeletePrinter(tctx, b, &new_handle),
+ "failed to delete new printer");
+
+ return true;
+}
+
+static bool compose_local_driver_directory(struct torture_context *tctx,
+ const char *environment,
+ const char *local_dir,
+ const char **path)
+{
+ char *p;
+
+ p = strrchr(local_dir, '/');
+ if (!p) {
+ return NULL;
+ }
+ p++;
+
+ if (strequal(environment, SPOOLSS_ARCHITECTURE_x64)) {
+ if (!strequal(p, "x64")) {
+ *path = talloc_asprintf(tctx, "%s/x64", local_dir);
+ }
+ } else if (strequal(environment, SPOOLSS_ARCHITECTURE_NT_X86)) {
+ if (!strequal(p, "i386")) {
+ *path = talloc_asprintf(tctx, "%s/i386", local_dir);
+ }
+ } else {
+ torture_assert(tctx, "unknown environment: '%s'\n", environment);
+ }
+
+ return true;
+}
+
+#if 0
+static struct spoolss_DeviceMode *torture_devicemode(TALLOC_CTX *mem_ctx,
+ const char *devicename)
+{
+ struct spoolss_DeviceMode *r;
+
+ r = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
+ if (r == NULL) {
+ return NULL;
+ }
+
+ r->devicename = talloc_strdup(r, devicename);
+ r->specversion = DMSPEC_NT4_AND_ABOVE;
+ r->driverversion = 0x0600;
+ r->size = 0x00dc;
+ r->__driverextra_length = 0;
+ r->fields = DEVMODE_FORMNAME |
+ DEVMODE_TTOPTION |
+ DEVMODE_PRINTQUALITY |
+ DEVMODE_DEFAULTSOURCE |
+ DEVMODE_COPIES |
+ DEVMODE_SCALE |
+ DEVMODE_PAPERSIZE |
+ DEVMODE_ORIENTATION;
+ r->orientation = DMORIENT_PORTRAIT;
+ r->papersize = DMPAPER_LETTER;
+ r->paperlength = 0;
+ r->paperwidth = 0;
+ r->scale = 100;
+ r->copies = 55;
+ r->defaultsource = DMBIN_FORMSOURCE;
+ r->printquality = DMRES_HIGH;
+ r->color = DMRES_MONOCHROME;
+ r->duplex = DMDUP_SIMPLEX;
+ r->yresolution = 0;
+ r->ttoption = DMTT_SUBDEV;
+ r->collate = DMCOLLATE_FALSE;
+ r->formname = talloc_strdup(r, "Letter");
+
+ return r;
+}
+#endif
+
+static bool test_architecture_buffer(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ struct spoolss_OpenPrinterEx r;
+ struct spoolss_UserLevel1 u1;
+ struct policy_handle handle;
+ uint32_t architectures[] = {
+ PROCESSOR_ARCHITECTURE_INTEL,
+ PROCESSOR_ARCHITECTURE_IA64,
+ PROCESSOR_ARCHITECTURE_AMD64
+ };
+ uint32_t needed[3];
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i < ARRAY_SIZE(architectures); i++) {
+
+ torture_comment(tctx, "Testing OpenPrinterEx with architecture %d\n", architectures[i]);
+
+ u1.size = 0;
+ u1.client = NULL;
+ u1.user = NULL;
+ u1.build = 0;
+ u1.major = 3;
+ u1.minor = 0;
+ u1.processor = architectures[i];
+
+ r.in.printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.datatype = NULL;
+ r.in.devmode_ctr.devmode= NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.userlevel_ctr.level = 1;
+ r.in.userlevel_ctr.user_info.level1 = &u1;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r), "");
+ torture_assert_werr_ok(tctx, r.out.result, "");
+
+ {
+ struct spoolss_EnumPrinters e;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+
+ e.in.flags = PRINTER_ENUM_LOCAL;
+ e.in.server = NULL;
+ e.in.level = 2;
+ e.in.buffer = NULL;
+ e.in.offered = 0;
+ e.out.count = &count;
+ e.out.info = &info;
+ e.out.needed = &needed[i];
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_EnumPrinters_r(b, tctx, &e), "");
+#if 0
+ torture_comment(tctx, "needed was %d\n", needed[i]);
+#endif
+ }
+
+ torture_assert(tctx, test_ClosePrinter(tctx, b, &handle), "");
+ }
+
+ for (i=1; i < ARRAY_SIZE(architectures); i++) {
+ if (needed[i-1] != needed[i]) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx, "needed size %d for architecture %d != needed size %d for architecture %d\n",
+ needed[i-1], architectures[i-1], needed[i], architectures[i]));
+ }
+ }
+
+ return true;
+}
+
+static bool test_get_core_printer_drivers_arch_guid(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *architecture,
+ const char *guid_str,
+ const char **package_id)
+{
+ struct spoolss_GetCorePrinterDrivers r;
+ struct spoolss_CorePrinterDriver core_printer_drivers;
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, 2);
+ const char **s;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct GUID guid;
+
+ s = talloc_zero_array(tctx, const char *, 2);
+
+ r.in.servername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.architecture = "foobar";
+ r.in.core_driver_size = 0;
+ r.in.core_driver_dependencies = (uint16_t *)blob.data;
+ r.in.core_printer_driver_count = 0;
+ r.out.core_printer_drivers = &core_printer_drivers;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetCorePrinterDrivers_r(b, tctx, &r),
+ "spoolss_GetCorePrinterDrivers failed");
+ torture_assert_hresult_equal(tctx, r.out.result, HRES_E_INVALIDARG,
+ "spoolss_GetCorePrinterDrivers failed");
+
+ guid = GUID_random();
+ s[0] = GUID_string2(tctx, &guid);
+
+ torture_assert(tctx,
+ push_reg_multi_sz(tctx, &blob, s),
+ "push_reg_multi_sz failed");
+
+ r.in.core_driver_size = blob.length/2;
+ r.in.core_driver_dependencies = (uint16_t *)blob.data;
+ r.in.core_printer_driver_count = 1;
+ r.out.core_printer_drivers = talloc_zero_array(tctx, struct spoolss_CorePrinterDriver, r.in.core_printer_driver_count);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetCorePrinterDrivers_r(b, tctx, &r),
+ "spoolss_GetCorePrinterDrivers failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
+ "spoolss_GetCorePrinterDrivers failed");
+
+ r.in.architecture = architecture;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetCorePrinterDrivers_r(b, tctx, &r),
+ "spoolss_GetCorePrinterDrivers failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_NOT_FOUND,
+ "spoolss_GetCorePrinterDrivers failed");
+
+ s[0] = talloc_strdup(s, guid_str);
+
+ torture_assert(tctx,
+ push_reg_multi_sz(tctx, &blob, s),
+ "push_reg_multi_sz failed");
+
+ r.in.core_driver_size = blob.length/2;
+ r.in.core_driver_dependencies = (uint16_t *)blob.data;
+ r.in.core_printer_driver_count = 1;
+ r.out.core_printer_drivers = talloc_zero_array(tctx, struct spoolss_CorePrinterDriver, r.in.core_printer_driver_count);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetCorePrinterDrivers_r(b, tctx, &r),
+ "spoolss_GetCorePrinterDrivers failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "spoolss_GetCorePrinterDrivers failed");
+
+ if (package_id) {
+ *package_id = r.out.core_printer_drivers[0].szPackageID;
+ }
+
+ return true;
+}
+
+static bool test_get_core_printer_drivers(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ const char *architectures[] = {
+ SPOOLSS_ARCHITECTURE_NT_X86,
+ SPOOLSS_ARCHITECTURE_x64
+ };
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+
+ for (i=0; i < ARRAY_SIZE(architectures); i++) {
+
+ torture_comment(tctx, "Testing GetCorePrinterDrivers(\"%s\",\"%s\")\n",
+ architectures[i],
+ SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV);
+
+ torture_assert(tctx,
+ test_get_core_printer_drivers_arch_guid(tctx, p,
+ architectures[i],
+ SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV,
+ NULL),
+ "");
+ }
+
+ return true;
+}
+
+static bool test_get_printer_driver_package_path(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ const char *architectures[] = {
+ SPOOLSS_ARCHITECTURE_NT_X86,
+ SPOOLSS_ARCHITECTURE_x64
+ };
+ int i;
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i < ARRAY_SIZE(architectures); i++) {
+ struct spoolss_GetPrinterDriverPackagePath r;
+ uint32_t required = 0;
+ const char *package_id = NULL;
+
+ test_get_core_printer_drivers_arch_guid(tctx, p,
+ architectures[i],
+ SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV,
+ &package_id),
+
+ torture_comment(tctx, "Testing GetPrinterDriverPackagePath(\"%s\",\"%s\")\n",
+ architectures[i], package_id);
+
+ r.in.servername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.architecture = "foobar";
+ r.in.language = NULL;
+ r.in.package_id = "";
+ r.in.driver_package_cab_size = 0;
+ r.in.driver_package_cab = NULL;
+
+ r.out.required = &required;
+ r.out.driver_package_cab = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverPackagePath_r(b, tctx, &r),
+ "spoolss_GetPrinterDriverPackagePath failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INVALID_ENVIRONMENT,
+ "spoolss_GetPrinterDriverPackagePath failed");
+
+ r.in.architecture = architectures[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverPackagePath_r(b, tctx, &r),
+ "spoolss_GetPrinterDriverPackagePath failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_FILE_NOT_FOUND,
+ "spoolss_GetPrinterDriverPackagePath failed");
+
+ r.in.package_id = package_id;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverPackagePath_r(b, tctx, &r),
+ "spoolss_GetPrinterDriverPackagePath failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "spoolss_GetPrinterDriverPackagePath failed");
+
+ r.in.driver_package_cab_size = required;
+ r.in.driver_package_cab = talloc_zero_array(tctx, char, required);
+ r.out.driver_package_cab = talloc_zero_array(tctx, char, required);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverPackagePath_r(b, tctx, &r),
+ "spoolss_GetPrinterDriverPackagePath failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "spoolss_GetPrinterDriverPackagePath failed");
+
+ r.in.servername = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverPackagePath_r(b, tctx, &r),
+ "spoolss_GetPrinterDriverPackagePath failed");
+ torture_assert_werr_equal(tctx,
+ W_ERROR(WIN32_FROM_HRESULT(r.out.result)), WERR_INSUFFICIENT_BUFFER,
+ "spoolss_GetPrinterDriverPackagePath failed");
+
+ r.in.driver_package_cab_size = required;
+ r.in.driver_package_cab = talloc_zero_array(tctx, char, required);
+ r.out.driver_package_cab = talloc_zero_array(tctx, char, required);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverPackagePath_r(b, tctx, &r),
+ "spoolss_GetPrinterDriverPackagePath failed");
+ torture_assert_hresult_ok(tctx, r.out.result,
+ "spoolss_GetPrinterDriverPackagePath failed");
+
+ }
+
+ return true;
+}
+
+static bool test_get_printer_printserverhandle(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t levels[] = {0, 1, 2, /* 3,*/ 4, 5, 6, 7, 8};
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ torture_assert(tctx,
+ test_GetPrinter_level_exp(tctx, b, &ctx->server_handle,
+ levels[i], WERR_INVALID_LEVEL,
+ NULL),
+ "failed to call GetPrinter");
+ }
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &ctx->server_handle, 3, NULL),
+ "failed to call GetPrinter");
+
+ return true;
+}
+
+#define TEST_SID "S-1-5-21-1234567890-1234567890-1234567890-500"
+
+static bool test_set_printer_printserverhandle(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_SetPrinterInfo3 info3;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ struct security_descriptor *sd;
+ struct security_ace *ace;
+ struct dom_sid sid;
+ int i;
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &ctx->server_handle, 3, &info),
+ "failed to call GetPrinter");
+
+ secdesc_ctr.sd = info.info3.secdesc;
+ secdesc_ctr.sd->owner_sid = NULL;
+ secdesc_ctr.sd->group_sid = NULL;
+
+ sd = security_descriptor_copy(tctx, secdesc_ctr.sd);
+ if (sd == NULL) {
+ return false;
+ }
+
+ ace = security_ace_create(tctx,
+ TEST_SID,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_STD_REQUIRED,
+ SEC_ACE_FLAG_CONTAINER_INHERIT);
+ torture_assert(tctx, ace, "failed to create ace");
+
+ torture_assert_ntstatus_ok(tctx,
+ security_descriptor_dacl_add(sd, ace),
+ "failed to add ace");
+
+ secdesc_ctr.sd = sd;
+
+ info3.sec_desc_ptr = 0;
+
+ info_ctr.level = 3;
+ info_ctr.info.info3 = &info3;
+
+ ZERO_STRUCT(devmode_ctr);
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, &ctx->server_handle, &info_ctr,
+ &devmode_ctr, &secdesc_ctr, 0),
+ "failed to call SetPrinter");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &ctx->server_handle, 3, &info),
+ "failed to call GetPrinter");
+
+ for (i = 0; i < info.info3.secdesc->dacl->num_aces; i++) {
+ if (security_ace_equal(&info.info3.secdesc->dacl->aces[i], ace)) {
+ break;
+ }
+ }
+
+ if (i == info.info3.secdesc->dacl->num_aces) {
+ torture_fail(tctx, "ace not present");
+ }
+
+ torture_assert(tctx,
+ dom_sid_parse(TEST_SID, &sid),
+ "failed to parse sid");
+
+ torture_assert_ntstatus_ok(tctx,
+ security_descriptor_dacl_del(info.info3.secdesc, &sid),
+ "failed to remove ace from sd");
+
+ secdesc_ctr.sd = info.info3.secdesc;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, &ctx->server_handle, &info_ctr,
+ &devmode_ctr, &secdesc_ctr, 0),
+ "failed to call SetPrinter");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &ctx->server_handle, 3, &info),
+ "failed to call GetPrinter");
+
+ for (i = 0; i < info.info3.secdesc->dacl->num_aces; i++) {
+ if (security_ace_equal(&info.info3.secdesc->dacl->aces[i], ace)) {
+ torture_fail(tctx, "ace still present");
+ }
+ }
+
+ return true;
+}
+
+
+static bool test_PrintServer_Forms_Winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ return test_Forms_winreg(tctx, b, &ctx->server_handle, true, NULL);
+}
+
+static bool test_PrintServer_Forms(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ return test_Forms(tctx, b, &ctx->server_handle, true, NULL, NULL, NULL);
+}
+
+static bool test_PrintServer_EnumForms(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *ctx =
+ talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = ctx->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ return test_EnumForms_all(tctx, b, &ctx->server_handle, true);
+}
+
+static bool torture_rpc_spoolss_setup_common(struct torture_context *tctx, struct test_spoolss_context *t)
+{
+ NTSTATUS status;
+
+ status = torture_rpc_connection(tctx, &t->spoolss_pipe, &ndr_table_spoolss);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ torture_assert(tctx,
+ test_OpenPrinter_server(tctx, t->spoolss_pipe, &t->server_handle),
+ "failed to open printserver");
+ torture_assert(tctx,
+ test_get_environment(tctx, t->spoolss_pipe->binding_handle, &t->server_handle, &t->environment),
+ "failed to get environment");
+
+ return true;
+}
+
+static bool torture_rpc_spoolss_setup(struct torture_context *tctx, void **data)
+{
+ struct test_spoolss_context *t;
+
+ *data = t = talloc_zero(tctx, struct test_spoolss_context);
+
+ return torture_rpc_spoolss_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_teardown_common(struct torture_context *tctx, struct test_spoolss_context *t)
+{
+ test_ClosePrinter(tctx, t->spoolss_pipe->binding_handle, &t->server_handle);
+
+ return true;
+}
+
+static bool torture_rpc_spoolss_teardown(struct torture_context *tctx, void *data)
+{
+ struct test_spoolss_context *t = talloc_get_type(data, struct test_spoolss_context);
+ bool ret;
+
+ ret = torture_rpc_spoolss_teardown_common(tctx, t);
+ talloc_free(t);
+
+ return ret;
+}
+
+static bool torture_rpc_spoolss_printer_setup_common(struct torture_context *tctx, struct torture_printer_context *t)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ const char *server_name_slash;
+ const char *driver_name;
+ const char *printer_name;
+ const char *port_name;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &t->spoolss_pipe, &ndr_table_spoolss),
+ "Error connecting to server");
+
+ p = t->spoolss_pipe;
+ b = p->binding_handle;
+ server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ t->driver.info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ t->driver.info8.driver_name = TORTURE_DRIVER;
+ t->driver.info8.driver_path = "pscript5.dll";
+ t->driver.info8.data_file = "cups6.ppd";
+ t->driver.info8.config_file = "ps5ui.dll";
+ t->driver.info8.help_file = "pscript.hlp";
+ t->driver.info8.default_datatype = "RAW";
+ t->driver.info8.dependent_files = talloc_zero(t, struct spoolss_StringArray);
+ t->driver.info8.dependent_files->string = talloc_zero_array(t, const char *, 8 + 1);
+ t->driver.info8.dependent_files->string[0] = "pscript5.dll";
+ t->driver.info8.dependent_files->string[1] = "cups6.ppd";
+ t->driver.info8.dependent_files->string[2] = "ps5ui.dll";
+ t->driver.info8.dependent_files->string[3] = "pscript.hlp";
+ t->driver.info8.dependent_files->string[4] = "pscript.ntf";
+ t->driver.info8.dependent_files->string[5] = "cups6.ini";
+ t->driver.info8.dependent_files->string[6] = "cupsps6.dll";
+ t->driver.info8.dependent_files->string[7] = "cupsui6.dll";
+
+ t->driver.local.driver_directory= "/usr/share/cups/drivers";
+
+ t->info2.portname = "LPT1:";
+
+ printer_name = t->info2.printername;
+ port_name = t->info2.portname;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, &t->driver),
+ "failed to fillup printserver info");
+
+ t->driver.info8.architecture = talloc_strdup(t, t->driver.remote.environment);
+
+ torture_assert(tctx,
+ compose_local_driver_directory(tctx, t->driver.remote.environment,
+ t->driver.local.driver_directory,
+ &t->driver.local.driver_directory),
+ "failed to compose local driver directory");
+
+ t->info2.drivername = "Microsoft XPS Document Writer";
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, t->driver.remote.environment, 3, t->info2.drivername, NULL)) {
+ torture_comment(tctx, "driver '%s' (architecture: %s, version: 3) is present on server\n",
+ t->info2.drivername, t->driver.remote.environment);
+ t->have_driver = true;
+ goto try_add;
+ }
+
+ torture_comment(tctx, "driver '%s' (architecture: %s, version: 3) does not exist on the server\n",
+ t->info2.drivername, t->driver.remote.environment);
+
+ t->info2.drivername = "Microsoft XPS Document Writer v4";
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, t->driver.remote.environment, 3, t->info2.drivername, NULL)) {
+ torture_comment(tctx, "driver '%s' (architecture: %s, version: 4) is present on server\n",
+ t->info2.drivername, t->driver.remote.environment);
+ t->have_driver = true;
+ goto try_add;
+ }
+
+ torture_comment(tctx, "trying to upload own driver\n");
+
+ if (!directory_exist(t->driver.local.driver_directory)) {
+ torture_warning(tctx, "no local driver is available!");
+ t->have_driver = false;
+ goto try_add;
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), &t->driver),
+ "failed to upload printer driver");
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &t->driver.info8, 0, false, NULL),
+ "failed to add driver");
+
+ t->added_driver = true;
+ t->have_driver = true;
+
+ try_add:
+ driver_name = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
+
+ if (t->wellknown) {
+ torture_assert(tctx,
+ test_AddPrinter_wellknown(tctx, p, printer_name, t->ex),
+ "failed to add wellknown printer");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinter_normal(tctx, p, &t->handle, printer_name, driver_name, port_name, t->devmode, t->ex),
+ "failed to add printer");
+ }
+
+ return true;
+}
+
+static bool torture_rpc_spoolss_printer_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_printer_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_printer_context);
+
+ t->ex = false;
+ t->wellknown = false;
+ t->info2.printername = TORTURE_PRINTER;
+ t->devmode = NULL;
+
+ return torture_rpc_spoolss_printer_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_printerex_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_printer_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_printer_context);
+
+ t->ex = true;
+ t->wellknown = false;
+ t->info2.printername = TORTURE_PRINTER_EX;
+ t->devmode = NULL;
+
+ return torture_rpc_spoolss_printer_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_printerwkn_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_printer_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_printer_context);
+
+ t->ex = false;
+ t->wellknown = true;
+ t->info2.printername = TORTURE_WELLKNOWN_PRINTER;
+ t->devmode = NULL;
+
+ /* FIXME */
+ if (t->wellknown) {
+ torture_skip(tctx, "skipping AddPrinter level 1");
+ }
+
+ return torture_rpc_spoolss_printer_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_printerexwkn_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_printer_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_printer_context);
+
+ t->ex = true;
+ t->wellknown = true;
+ t->info2.printername = TORTURE_WELLKNOWN_PRINTER_EX;
+ t->devmode = NULL;
+
+ /* FIXME */
+ if (t->wellknown) {
+ torture_skip(tctx, "skipping AddPrinterEx level 1");
+ }
+
+ return torture_rpc_spoolss_printer_setup_common(tctx, t);
+}
+
+#if 0
+static bool torture_rpc_spoolss_printerdm_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_printer_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_printer_context);
+
+ t->ex = true;
+ t->wellknown = false;
+ t->info2.printername = TORTURE_PRINTER_EX;
+ t->devmode = torture_devicemode(t, TORTURE_PRINTER_EX);
+
+ return torture_rpc_spoolss_printer_setup_common(tctx, t);
+}
+#endif
+
+static bool test_DeletePrinterDriverEx_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *driver,
+ const char *environment,
+ uint32_t delete_flags,
+ uint32_t version,
+ WERROR expected_result);
+
+static bool torture_rpc_spoolss_printer_teardown_common(struct torture_context *tctx, struct torture_printer_context *t)
+{
+ bool found = false;
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = NULL;
+ const char *server_name_slash;
+ bool ok = true;
+
+ if (p == NULL) {
+ return true;
+ }
+ b = p->binding_handle;
+
+ server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ if (!t->wellknown) {
+ const char *printer_name = t->info2.printername;
+
+ torture_assert_goto(tctx,
+ test_DeletePrinter(tctx, b, &t->handle),
+ ok,
+ remove_driver,
+ "failed to delete printer");
+
+ torture_assert_goto(tctx,
+ test_EnumPrinters_findname(tctx, b, PRINTER_ENUM_LOCAL, 1,
+ printer_name, &found),
+ ok,
+ remove_driver,
+ "failed to enumerate printers");
+
+ torture_assert_goto(tctx,
+ !found,
+ ok,
+ remove_driver,
+ "deleted printer still there");
+ }
+
+
+remove_driver:
+ if (t->added_driver) {
+ ok = remove_printer_driver(tctx,
+ dcerpc_server_name(p),
+ &t->driver);
+ if (!ok) {
+ torture_warning(tctx,
+ "failed to remove printer driver\n");
+ }
+
+ ok = test_DeletePrinterDriverEx_exp(tctx, b,
+ server_name_slash,
+ t->driver.info8.driver_name,
+ t->driver.info8.architecture,
+ DPD_DELETE_ALL_FILES,
+ t->driver.info8.version,
+ WERR_OK);
+ if (!ok) {
+ torture_warning(tctx,
+ "failed to delete printer driver via "
+ "spoolss\n");
+ }
+ }
+
+ return ok;
+}
+
+static bool torture_rpc_spoolss_printer_teardown(struct torture_context *tctx, void *data)
+{
+ struct torture_printer_context *t = talloc_get_type(data, struct torture_printer_context);
+ bool ret;
+
+ ret = torture_rpc_spoolss_printer_teardown_common(tctx, t);
+ talloc_free(t);
+
+ return ret;
+}
+
+static bool test_print_test(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ torture_assert(tctx,
+ test_DoPrintTest(tctx, b, &t->handle),
+ "failed to do print test");
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
+static bool test_print_test_extended(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ bool ret = true;
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ ret = test_DoPrintTest_extended(tctx, b, &t->handle);
+ if (ret == false) {
+ torture_comment(tctx, "WARNING! failed to do extended print test\n");
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_comment(tctx, "non-critical for samba3\n");
+ ret = true;
+ tctx->last_result = TORTURE_SKIP;
+ }
+ }
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return ret;
+}
+
+static bool test_print_test_properties(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip printer job property tests against samba");
+ }
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ torture_assert(tctx,
+ test_DoPrintTest_properties(tctx, b, &t->handle),
+ "failed to test print job properties");
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
+/* use smbd file IO to spool a print job */
+static bool test_print_test_smbd(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ NTSTATUS status;
+ uint32_t count;
+ union spoolss_JobInfo *info = NULL;
+ int i;
+
+ struct smb2_tree *tree;
+ struct smb2_handle job_h;
+ struct smbcli_options options;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ /*
+ * Do not test against the dynamically added printers, printing via
+ * smbd means that a different spoolss process may handle the
+ * OpenPrinter request to the one that handled the AddPrinter request.
+ * This currently leads to an ugly race condition where one process
+ * sees the new printer and one doesn't.
+ */
+ const char *share = TORTURE_PRINTER_STATIC1;
+
+ torture_comment(tctx, "Testing smbd job spooling\n");
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx,
+ torture_setting_string(tctx, "host", NULL),
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to connect to SMB2 printer %s - %s\n",
+ share, nt_errstr(status));
+ return false;
+ }
+
+ status = torture_smb2_testfile(tree, "smbd_spooler_job", &job_h);
+ torture_assert_ntstatus_ok(tctx, status, "smbd spool job create");
+
+ status = smb2_util_write(tree, job_h, "exciting print job data", 0,
+ sizeof("exciting print job data"));
+ torture_assert_ntstatus_ok(tctx, status, "smbd spool job write");
+
+ /* check back end spoolss job was created */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs level 1 failed");
+
+ for (i = 0; i < count; i++) {
+ if (!strcmp(info[i].info1.document_name, "smbd_spooler_job")) {
+ break;
+ }
+ }
+ torture_assert(tctx, (i != count), "smbd_spooler_job not found");
+
+ status = smb2_util_close(tree, job_h);
+ torture_assert_ntstatus_ok(tctx, status, "smbd spool job close");
+
+ /* disconnect from printer share */
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+static bool test_print_test_purge(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ bool ret = true;
+ uint32_t count;
+ union spoolss_JobInfo *info;
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+ for (i=0; i < num_jobs; i++) {
+ ret = test_DoPrintTest_add_one_job(tctx, b, &t->handle,
+ "TorturePrintJob",
+ &job_ids[i]);
+ torture_assert(tctx, ret, "failed to add print job");
+ }
+
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs level 1 failed");
+
+ torture_assert_int_equal(tctx, count, num_jobs,
+ "unexpected number of jobs in queue");
+
+ torture_assert(tctx,
+ test_printer_purge(tctx, b, &t->handle),
+ "failed to purge printer");
+
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs level 1 failed");
+
+ torture_assert_int_equal(tctx, count, 0,
+ "unexpected number of jobs in queue");
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
+static bool test_printer_sd(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_PrinterInfo_SD(tctx, b, &t->handle),
+ "failed to test security descriptors");
+
+ return true;
+}
+
+static bool test_printer_dm(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_PrinterInfo_DevMode(tctx, p, &t->handle, t->info2.printername, t->devmode),
+ "failed to test devicemodes");
+
+ return true;
+}
+
+static bool test_printer_info_winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_PrinterInfo_winreg(tctx, p, &t->handle, t->info2.printername),
+ "failed to test printer info winreg");
+
+ return true;
+}
+
+static bool test_printserver_info_winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct test_spoolss_context *t =
+ (struct test_spoolss_context *)talloc_get_type_abort(private_data, struct test_spoolss_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_PrintserverInfo_winreg(tctx, p, &t->server_handle),
+ "failed to test printserver info winreg");
+
+ return true;
+}
+
+
+static bool test_printer_change_id(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_ChangeID(tctx, p, &t->handle),
+ "failed to test change id");
+
+ return true;
+}
+
+static bool test_printer_keys(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_printer_all_keys(tctx, b, &t->handle),
+ "failed to test printer keys");
+
+ return true;
+}
+
+static bool test_printer_data_consistency(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_EnumPrinterData_consistency(tctx, p, &t->handle),
+ "failed to test printer data consistency");
+
+ return true;
+}
+
+static bool test_printer_data_keys(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_SetPrinterDataEx_keys(tctx, p, &t->handle),
+ "failed to test printer data keys");
+
+ return true;
+}
+
+static bool test_printer_data_values(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_SetPrinterDataEx_values(tctx, p, &t->handle),
+ "failed to test printer data values");
+
+ return true;
+}
+
+static bool test_printer_data_set(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_SetPrinterDataEx_matrix(tctx, p, &t->handle, t->info2.printername, NULL, NULL),
+ "failed to test printer data set");
+
+ return true;
+}
+
+static bool test_printer_data_winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_PrinterData_winreg(tctx, p, &t->handle, t->info2.printername),
+ "failed to test printer data winreg");
+
+ return true;
+}
+
+static bool test_printer_data_dsspooler(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+
+ torture_assert(tctx,
+ test_PrinterData_DsSpooler(tctx, p, &t->handle, t->info2.printername),
+ "failed to test printer data winreg dsspooler");
+
+ return true;
+}
+
+static bool test_printer_ic(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle gdi_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip printer information context tests against samba");
+ }
+
+ {
+ struct spoolss_CreatePrinterIC r;
+ struct spoolss_DevmodeContainer devmode_ctr;
+
+ ZERO_STRUCT(devmode_ctr);
+
+ r.in.handle = &t->handle;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.out.gdi_handle = &gdi_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_CreatePrinterIC_r(b, tctx, &r),
+ "CreatePrinterIC failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "CreatePrinterIC failed");
+ }
+
+ {
+ struct spoolss_PlayGDIScriptOnPrinterIC r;
+ DATA_BLOB in,out;
+ int i;
+ uint32_t num_fonts = 0;
+
+ in = data_blob_string_const("");
+
+ r.in.gdi_handle = &gdi_handle;
+ r.in.pIn = in.data;
+ r.in.cIn = in.length;
+ r.in.ul = 0;
+
+ for (i = 0; i < 4; i++) {
+
+ out = data_blob_talloc_zero(tctx, i);
+
+ r.in.cOut = out.length;
+ r.out.pOut = out.data;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r),
+ "PlayGDIScriptOnPrinterIC failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_ENOUGH_MEMORY,
+ "PlayGDIScriptOnPrinterIC failed");
+ }
+
+ out = data_blob_talloc_zero(tctx, 4);
+
+ r.in.cOut = out.length;
+ r.out.pOut = out.data;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r),
+ "PlayGDIScriptOnPrinterIC failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_OK,
+ "PlayGDIScriptOnPrinterIC failed");
+
+ /* now we should have the required length, so retry with a
+ * buffer which is large enough to carry all font ids */
+
+ num_fonts = IVAL(r.out.pOut, 0);
+
+ torture_comment(tctx, "PlayGDIScriptOnPrinterIC gave font count of %d\n", num_fonts);
+
+ out = data_blob_talloc_zero(tctx,
+ num_fonts * sizeof(struct UNIVERSAL_FONT_ID) + 4);
+
+ r.in.cOut = out.length;
+ r.out.pOut = out.data;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_PlayGDIScriptOnPrinterIC_r(b, tctx, &r),
+ "PlayGDIScriptOnPrinterIC failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_OK,
+ "PlayGDIScriptOnPrinterIC failed");
+
+ }
+
+ {
+ struct spoolss_DeletePrinterIC r;
+
+ r.in.gdi_handle = &gdi_handle;
+ r.out.gdi_handle = &gdi_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterIC_r(b, tctx, &r),
+ "DeletePrinterIC failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "DeletePrinterIC failed");
+
+ }
+
+ return true;
+}
+
+static bool test_printer_bidi(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_SendRecvBidiData r;
+ struct RPC_BIDI_REQUEST_CONTAINER bidi_req;
+ struct RPC_BIDI_RESPONSE_CONTAINER *bidi_rep = NULL;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skip printer bidirectional tests against samba");
+ }
+
+ ZERO_STRUCT(bidi_req);
+
+ r.in.hPrinter = t->handle;
+ r.in.pAction = "foobar";
+ r.in.pReqData = &bidi_req;
+ r.out.ppRespData = &bidi_rep;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_SendRecvBidiData_r(b, tctx, &r),
+ "SendRecvBidiData failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "SendRecvBidiData failed");
+
+ if (!(t->info2.attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI)) {
+ torture_skip(tctx, "skipping further tests as printer is not BIDI enabled");
+ }
+
+ r.in.pAction = BIDI_ACTION_ENUM_SCHEMA;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_SendRecvBidiData_r(b, tctx, &r),
+ "SendRecvBidiData failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SendRecvBidiData failed");
+
+ return true;
+}
+
+static bool test_printer_set_publish(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfo7 info7;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info7.guid = "";
+ info7.action = DSPRINT_PUBLISH;
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ info_ctr.level = 7;
+ info_ctr.info.info7 = &info7;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, handle, &info_ctr,
+ &devmode_ctr, &secdesc_ctr, 0), "");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "");
+ torture_assert(tctx,
+ (info.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED),
+ "info2 publish flag not set");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 7, &info),
+ "");
+ if (info.info7.action & DSPRINT_PENDING) {
+ torture_comment(tctx, "publish is pending\n");
+ torture_assert_int_equal(tctx,
+ info.info7.action,
+ (DSPRINT_PENDING | DSPRINT_PUBLISH),
+ "info7 publish flag not set");
+ } else {
+ struct GUID guid;
+ char *ref_guid;
+ torture_assert_int_equal(tctx,
+ info.info7.action,
+ DSPRINT_PUBLISH,
+ "info7 publish flag not set");
+
+ /* GUID_from_string is able to parse both plain and
+ * curly-braced guids */
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(info.info7.guid,
+ &guid),
+ "invalid published printer GUID");
+
+ /* Build reference GUID string */
+ ref_guid = GUID_string2(tctx, &guid);
+ torture_assert_not_null(tctx, ref_guid, "ENOMEM");
+ ref_guid = talloc_strdup_upper(tctx, ref_guid);
+ torture_assert_not_null(tctx, ref_guid, "ENOMEM");
+ torture_assert_str_equal(tctx, info.info7.guid, ref_guid,
+ "invalid GUID format");
+ }
+
+ return true;
+}
+
+static bool test_printer_set_unpublish(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfo7 info7;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+
+ info7.action = DSPRINT_UNPUBLISH;
+ info7.guid = "";
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+ info_ctr.level = 7;
+ info_ctr.info.info7 = &info7;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, handle, &info_ctr,
+ &devmode_ctr, &secdesc_ctr, 0), "");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 2, &info),
+ "");
+ torture_assert(tctx,
+ !(info.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED),
+ "info2 publish flag still set");
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, handle, 7, &info),
+ "");
+
+ if (info.info7.action & DSPRINT_PENDING) {
+ struct GUID guid;
+ torture_comment(tctx, "unpublish is pending\n");
+ torture_assert_int_equal(tctx,
+ info.info7.action,
+ (DSPRINT_PENDING | DSPRINT_UNPUBLISH),
+ "info7 unpublish flag not set");
+ torture_assert_ntstatus_ok(tctx,
+ GUID_from_string(info.info7.guid,
+ &guid),
+ "invalid printer GUID");
+ } else {
+ torture_assert_int_equal(tctx,
+ info.info7.action, DSPRINT_UNPUBLISH,
+ "info7 unpublish flag not set");
+ }
+
+ return true;
+}
+
+static bool test_printer_publish_toggle(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ talloc_get_type_abort(private_data,
+ struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle *handle = &t->handle;
+ union spoolss_PrinterInfo info7;
+ union spoolss_PrinterInfo info2;
+
+ /* check publish status via level 7 and level 2 */
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 7, &info7),
+ "");
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info2),
+ "");
+
+ if (info2.info2.attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
+ torture_assert_int_equal(tctx,
+ info7.info7.action, DSPRINT_PUBLISH,
+ "info7 publish flag not set");
+ torture_assert(tctx, test_printer_set_unpublish(tctx, b, handle), "");
+ torture_assert(tctx, test_printer_set_publish(tctx, b, handle), "");
+ } else {
+ torture_assert_int_equal(tctx,
+ info7.info7.action, DSPRINT_UNPUBLISH,
+ "info7 unpublish flag not set");
+ torture_assert(tctx, test_printer_set_publish(tctx, b, handle), "");
+ torture_assert(tctx, test_printer_set_unpublish(tctx, b, handle), "");
+ }
+
+ return true;
+}
+
+static bool test_driver_info_winreg(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ const char *driver_name = t->added_driver ? t->driver.info8.driver_name : t->info2.drivername;
+
+ if (!t->have_driver) {
+ torture_skip(tctx, "skipping driver info winreg test as we don't have a driver");
+ }
+
+ torture_assert(tctx,
+ test_DriverInfo_winreg(tctx, p, &t->handle, t->info2.printername, driver_name, t->driver.remote.environment, 3),
+ "failed to test driver info winreg");
+
+ return true;
+}
+
+static bool test_print_job_enum(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ bool ret = true;
+ uint32_t num_jobs = 8;
+ uint32_t *job_ids;
+ int i;
+ union spoolss_JobInfo *info = NULL;
+ uint32_t count;
+
+ torture_assert(tctx,
+ test_PausePrinter(tctx, b, &t->handle),
+ "failed to pause printer");
+
+ /* purge in case of any jobs from previous tests */
+ torture_assert(tctx,
+ test_printer_purge(tctx, b, &t->handle),
+ "failed to purge printer");
+
+ /* enum before jobs, valid level */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, 0, "EnumJobs count");
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 2, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, 0, "EnumJobs count");
+ /* enum before jobs, invalid level - expect failure */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 100,
+ WERR_INVALID_LEVEL,
+ &count, &info),
+ "EnumJobs with invalid level");
+
+ job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+ for (i = 0; i < num_jobs; i++) {
+ ret = test_DoPrintTest_add_one_job(tctx, b, &t->handle,
+ "TorturePrintJob",
+ &job_ids[i]);
+ torture_assert(tctx, ret, "failed to add print job");
+ }
+
+ /* enum after jobs, valid level */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, num_jobs, "EnumJobs count");
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 2, WERR_OK,
+ &count, &info),
+ "EnumJobs with valid level");
+ torture_assert_int_equal(tctx, count, num_jobs, "EnumJobs count");
+ /* enum after jobs, invalid level - expect failure */
+ torture_assert(tctx,
+ test_EnumJobs_args(tctx, b, &t->handle, 100,
+ WERR_INVALID_LEVEL,
+ &count, &info),
+ "EnumJobs with invalid level");
+
+ for (i = 0; i < num_jobs; i++) {
+ test_SetJob(tctx, b, &t->handle, job_ids[i], NULL,
+ SPOOLSS_JOB_CONTROL_DELETE);
+ }
+
+ torture_assert(tctx,
+ test_ResumePrinter(tctx, b, &t->handle),
+ "failed to resume printer");
+
+ return true;
+}
+
+static bool test_printer_log_jobinfo(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct spoolss_BranchOfficeJobDataContainer info;
+ int i;
+
+ struct spoolss_LogJobInfoForBranchOffice r;
+
+ torture_comment(tctx, "Testing LogJobInfoForBranchOffice\n");
+
+ info.cJobDataEntries = 0;
+ info.JobData = NULL;
+
+ r.in.hPrinter = &t->handle;
+ r.in.pBranchOfficeJobDataContainer = &info;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_LogJobInfoForBranchOffice_r(b, tctx, &r),
+ "LogJobInfoForBranchOffice failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "LogJobInfoForBranchOffice failed");
+
+ info.cJobDataEntries = 1;
+ info.JobData = talloc_zero_array(tctx, struct spoolss_BranchOfficeJobData, info.cJobDataEntries);
+
+ info.JobData[0].eEventType = kLogOfflineFileFull;
+ info.JobData[0].JobId = 42;
+ info.JobData[0].JobInfo.LogOfflineFileFull.pMachineName = talloc_strdup(tctx, "mthelena");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_LogJobInfoForBranchOffice_r(b, tctx, &r),
+ "LogJobInfoForBranchOffice failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_OK,
+ "LogJobInfoForBranchOffice failed");
+
+ info.cJobDataEntries = 42;
+ info.JobData = talloc_zero_array(tctx, struct spoolss_BranchOfficeJobData, info.cJobDataEntries);
+
+ for (i=0; i < info.cJobDataEntries; i++) {
+ info.JobData[i].eEventType = kLogOfflineFileFull;
+ info.JobData[i].JobId = i;
+ info.JobData[i].JobInfo.LogOfflineFileFull.pMachineName = talloc_asprintf(tctx, "torture_%d", i);
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_LogJobInfoForBranchOffice_r(b, tctx, &r),
+ "LogJobInfoForBranchOffice failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_OK,
+ "LogJobInfoForBranchOffice failed");
+
+ return true;
+}
+
+static bool test_printer_os_versions(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_printer_context *t =
+ (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ union spoolss_PrinterInfo info;
+ DATA_BLOB blob;
+ uint8_t *data;
+ uint32_t length;
+ struct spoolss_OSVersion osversion;
+ uint8_t os_major, os_minor;
+ uint16_t os_build;
+ struct policy_handle server_handle;
+
+ torture_comment(tctx, "Testing OSVersion vs. PRINTER_INFO_STRESS\n");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &t->handle, 0, &info),
+ "failed to get level 0 printer info");
+
+ torture_assert(tctx,
+ test_OpenPrinter_server(tctx, p, &server_handle),
+ "failed to open printserver");
+
+ torture_assert(tctx,
+ test_GetPrinterData_checktype(tctx, b, &server_handle, "OSVersion",
+ NULL, NULL, &data, &length),
+ "failed to fetch OSVersion printer data");
+
+ test_ClosePrinter(tctx, b, &server_handle);
+
+ blob = data_blob_const(data, length);
+
+ torture_assert_ndr_success(tctx,
+ ndr_pull_struct_blob(&blob, tctx, &osversion,
+ (ndr_pull_flags_fn_t)ndr_pull_spoolss_OSVersion),
+ "failed to pull OSVersion");
+
+ os_major = CVAL(&info.info0.version, 0);
+ os_minor = CVAL(&info.info0.version, 1);
+ os_build = SVAL(&info.info0.version, 2);
+
+ torture_assert_int_equal(tctx, os_major, osversion.major, "major");
+ torture_assert_int_equal(tctx, os_minor, osversion.minor, "minor");
+ torture_assert_int_equal(tctx, os_build, osversion.build, "build");
+
+ return true;
+}
+
+
+void torture_tcase_printer(struct torture_tcase *tcase)
+{
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter_wrap);
+ torture_tcase_add_simple_test(tcase, "csetprinter", test_csetprinter);
+ torture_tcase_add_simple_test(tcase, "print_test", test_print_test);
+ torture_tcase_add_simple_test(tcase, "print_test_extended", test_print_test_extended);
+ torture_tcase_add_simple_test(tcase, "print_test_smbd", test_print_test_smbd);
+ torture_tcase_add_simple_test(tcase, "print_test_properties", test_print_test_properties);
+ torture_tcase_add_simple_test(tcase, "print_test_purge", test_print_test_purge);
+ torture_tcase_add_simple_test(tcase, "printer_info", test_printer_info);
+ torture_tcase_add_simple_test(tcase, "sd", test_printer_sd);
+ torture_tcase_add_simple_test(tcase, "dm", test_printer_dm);
+ torture_tcase_add_simple_test(tcase, "printer_info_winreg", test_printer_info_winreg);
+ torture_tcase_add_simple_test(tcase, "change_id", test_printer_change_id);
+ torture_tcase_add_simple_test(tcase, "keys", test_printer_keys);
+ torture_tcase_add_simple_test(tcase, "printerdata_consistency", test_printer_data_consistency);
+ torture_tcase_add_simple_test(tcase, "printerdata_keys", test_printer_data_keys);
+ torture_tcase_add_simple_test(tcase, "printerdata_values", test_printer_data_values);
+ torture_tcase_add_simple_test(tcase, "printerdata_set", test_printer_data_set);
+ torture_tcase_add_simple_test(tcase, "printerdata_winreg", test_printer_data_winreg);
+ torture_tcase_add_simple_test(tcase, "printerdata_dsspooler", test_printer_data_dsspooler);
+ torture_tcase_add_simple_test(tcase, "driver_info_winreg", test_driver_info_winreg);
+ torture_tcase_add_simple_test(tcase, "printer_rename", test_printer_rename);
+ torture_tcase_add_simple_test(tcase, "printer_ic", test_printer_ic);
+ torture_tcase_add_simple_test(tcase, "bidi", test_printer_bidi);
+ torture_tcase_add_simple_test(tcase, "publish_toggle",
+ test_printer_publish_toggle);
+ torture_tcase_add_simple_test(tcase, "print_job_enum", test_print_job_enum);
+ torture_tcase_add_simple_test(tcase, "log_jobinfo", test_printer_log_jobinfo);
+ torture_tcase_add_simple_test(tcase, "os_versions", test_printer_os_versions);
+}
+
+struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "printer");
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, "addprinter");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printer_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ torture_tcase_printer(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "addprinterex");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerex_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ torture_tcase_printer(tcase);
+
+ tcase = torture_suite_add_tcase(suite, "addprinterwkn");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerwkn_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ tcase = torture_suite_add_tcase(suite, "addprinterexwkn");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerexwkn_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+#if 0
+ /* test is not correct */
+ tcase = torture_suite_add_tcase(suite, "addprinterdm");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_printerdm_setup,
+ torture_rpc_spoolss_printer_teardown);
+
+ torture_tcase_printer(tcase);
+#endif
+ return suite;
+}
+
+struct torture_suite *torture_rpc_spoolss(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss");
+ struct torture_tcase *tcase = torture_suite_add_tcase(suite, "printserver");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_setup,
+ torture_rpc_spoolss_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter_badnamelist", test_OpenPrinter_badname_list);
+ torture_tcase_add_simple_test(tcase, "printer_data_list", test_GetPrinterData_list);
+ torture_tcase_add_simple_test(tcase, "enum_forms", test_PrintServer_EnumForms);
+ torture_tcase_add_simple_test(tcase, "forms", test_PrintServer_Forms);
+ torture_tcase_add_simple_test(tcase, "forms_winreg", test_PrintServer_Forms_Winreg);
+ torture_tcase_add_simple_test(tcase, "enum_ports", test_EnumPorts);
+ torture_tcase_add_simple_test(tcase, "add_port", test_AddPort);
+ torture_tcase_add_simple_test(tcase, "get_printer_driver_directory", test_GetPrinterDriverDirectory);
+ torture_tcase_add_simple_test(tcase, "get_print_processor_directory", test_GetPrintProcessorDirectory);
+ torture_tcase_add_simple_test(tcase, "enum_printer_drivers", test_EnumPrinterDrivers);
+ torture_tcase_add_simple_test(tcase, "enum_monitors", test_EnumMonitors);
+ torture_tcase_add_simple_test(tcase, "enum_print_processors", test_EnumPrintProcessors);
+ torture_tcase_add_simple_test(tcase, "print_processors_winreg", test_print_processors_winreg);
+ torture_tcase_add_simple_test(tcase, "add_processor", test_add_print_processor);
+ torture_tcase_add_simple_test(tcase, "enum_printprocdata", test_EnumPrintProcessorDataTypes);
+ torture_tcase_add_simple_test(tcase, "enum_printers", test_EnumPrinters);
+ torture_tcase_add_simple_test(tcase, "enum_ports_old", test_EnumPorts_old);
+ torture_tcase_add_simple_test(tcase, "enum_printers_old", test_EnumPrinters_old);
+ torture_tcase_add_simple_test(tcase, "enum_printers_servername", test_EnumPrinters_servername);
+ torture_tcase_add_simple_test(tcase, "enum_printer_drivers_old", test_EnumPrinterDrivers_old);
+ torture_tcase_add_simple_test(tcase, "architecture_buffer", test_architecture_buffer);
+ torture_tcase_add_simple_test(tcase, "get_core_printer_drivers", test_get_core_printer_drivers);
+ torture_tcase_add_simple_test(tcase, "get_printer_driver_package_path", test_get_printer_driver_package_path);
+ torture_tcase_add_simple_test(tcase, "get_printer", test_get_printer_printserverhandle);
+ torture_tcase_add_simple_test(tcase, "set_printer", test_set_printer_printserverhandle);
+ torture_tcase_add_simple_test(tcase, "printserver_info_winreg", test_printserver_info_winreg);
+ torture_tcase_add_simple_test(tcase, "addpermachineconnection", test_addpermachineconnection);
+
+ torture_suite_add_suite(suite, torture_rpc_spoolss_printer(suite));
+
+ return suite;
+}
+
+static bool test_GetPrinterDriverDirectory_getdir(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *environment,
+ const char **dir_p)
+{
+ struct spoolss_GetPrinterDriverDirectory r;
+ uint32_t needed;
+
+ r.in.server = server;
+ r.in.environment = environment;
+ r.in.level = 1;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
+ "failed to query driver directory");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_GetPrinterDriverDirectory_r(b, tctx, &r),
+ "failed to query driver directory");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to query driver directory");
+
+ if (dir_p) {
+ *dir_p = r.out.info->info1.directory_name;
+ }
+
+ return true;
+}
+
+static const char *get_driver_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
+{
+ if (info_ctr == NULL) {
+ return NULL;
+ }
+
+ switch (info_ctr->level) {
+ case 1:
+ return info_ctr->info.info1->driver_name;
+ case 2:
+ return info_ctr->info.info2->driver_name;
+ case 3:
+ return info_ctr->info.info3->driver_name;
+ case 4:
+ return info_ctr->info.info4->driver_name;
+ case 6:
+ return info_ctr->info.info6->driver_name;
+ case 8:
+ return info_ctr->info.info8->driver_name;
+ default:
+ return NULL;
+ }
+}
+
+static const char *get_environment_from_info(struct spoolss_AddDriverInfoCtr *info_ctr)
+{
+ if (info_ctr == NULL) {
+ return NULL;
+ }
+
+ switch (info_ctr->level) {
+ case 2:
+ return info_ctr->info.info2->architecture;
+ case 3:
+ return info_ctr->info.info3->architecture;
+ case 4:
+ return info_ctr->info.info4->architecture;
+ case 6:
+ return info_ctr->info.info6->architecture;
+ case 8:
+ return info_ctr->info.info8->architecture;
+ default:
+ return NULL;
+ }
+}
+
+
+static bool test_AddPrinterDriver_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ struct spoolss_AddDriverInfoCtr *info_ctr,
+ WERROR expected_result)
+{
+ struct spoolss_AddPrinterDriver r;
+ const char *drivername = get_driver_from_info(info_ctr);
+ const char *environment = get_environment_from_info(info_ctr);
+
+ r.in.servername = servername;
+ r.in.info_ctr = info_ctr;
+
+ torture_comment(tctx, "Testing AddPrinterDriver(%s) level: %d, environment: '%s'\n",
+ drivername, info_ctr->level, environment);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPrinterDriver_r(b, tctx, &r),
+ "spoolss_AddPrinterDriver failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "spoolss_AddPrinterDriver failed with unexpected result");
+
+ return true;
+
+}
+
+static bool test_AddPrinterDriverEx_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *servername,
+ struct spoolss_AddDriverInfoCtr *info_ctr,
+ uint32_t flags,
+ WERROR expected_result)
+{
+ struct spoolss_AddPrinterDriverEx r;
+ const char *drivername = get_driver_from_info(info_ctr);
+ const char *environment = get_environment_from_info(info_ctr);
+
+ r.in.servername = servername;
+ r.in.info_ctr = info_ctr;
+ r.in.flags = flags;
+
+ torture_comment(tctx, "Testing AddPrinterDriverEx(%s) level: %d, environment: '%s'\n",
+ drivername, info_ctr->level, environment);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_AddPrinterDriverEx_r(b, tctx, &r),
+ "AddPrinterDriverEx failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "AddPrinterDriverEx failed with unexpected result");
+
+ return true;
+}
+
+#define ASSERT_DRIVER_PATH(tctx, path, driver_dir, cmt) \
+ if (path && strlen(path)) {\
+ torture_assert_strn_equal(tctx, path, driver_dir, strlen(driver_dir), cmt); \
+ }
+
+static bool test_AddPrinterDriver_args_level_1(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo1 info1;
+
+ ZERO_STRUCT(info1);
+
+ info_ctr.level = 1;
+ info_ctr.info.info1 = &info1;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_LEVEL),
+ "failed to test AddPrinterDriverEx level 1");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_LEVEL),
+ "failed to test AddPrinterDriver level 1");
+ }
+
+ info1.driver_name = r->driver_name;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_LEVEL),
+ "failed to test AddPrinterDriverEx level 1");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_LEVEL),
+ "failed to test AddPrinterDriver level 1");
+ }
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_2(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo2 info2;
+ union spoolss_DriverInfo info;
+
+ ZERO_STRUCT(info2);
+
+ info_ctr.level = 2;
+ info_ctr.info.info2 = &info2;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.driver_name = r->driver_name;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.version = r->version;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.architecture = r->architecture;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.driver_path = r->driver_path;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.data_file = r->data_file;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ info2.config_file = r->config_file;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, 0, WERR_INVALID_PARAMETER),
+ "failed to test AddPrinterDriverEx");
+ }
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 2");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+ "failed to test AddPrinterDriver level 2");
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 2, r->driver_name, &info),
+ "failed to find added printer driver");
+
+ if (remote_driver_dir) {
+ ASSERT_DRIVER_PATH(tctx, info.info2.driver_path, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info2.data_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info2.config_file, remote_driver_dir, "unexpected path");
+ }
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_3(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo3 info3;
+ union spoolss_DriverInfo info;
+
+ info3.driver_name = r->driver_name;
+ info3.version = r->version;
+ info3.architecture = r->architecture;
+ info3.driver_path = r->driver_path;
+ info3.data_file = r->data_file;
+ info3.config_file = r->config_file;
+ info3.help_file = r->help_file;
+ info3.monitor_name = r->monitor_name;
+ info3.default_datatype = r->default_datatype;
+ info3._ndr_size_dependent_files = r->_ndr_size_dependent_files;
+ info3.dependent_files = r->dependent_files;
+
+ info_ctr.level = 3;
+ info_ctr.info.info3 = &info3;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 3");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+ "failed to test AddPrinterDriver level 3");
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 3, r->driver_name, &info),
+ "failed to find added printer driver");
+
+ if (remote_driver_dir) {
+ int i;
+ ASSERT_DRIVER_PATH(tctx, info.info3.driver_path, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info3.data_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info3.config_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info3.help_file, remote_driver_dir, "unexpected path");
+ for (i=0; info.info3.dependent_files && info.info3.dependent_files[i] != NULL; i++) {
+ ASSERT_DRIVER_PATH(tctx, info.info3.dependent_files[i], remote_driver_dir, "unexpected path");
+ }
+ }
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_4(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo4 info4;
+ union spoolss_DriverInfo info;
+
+ info4.version = r->version;
+ info4.driver_name = r->driver_name;
+ info4.architecture = r->architecture;
+ info4.driver_path = r->driver_path;
+ info4.data_file = r->data_file;
+ info4.config_file = r->config_file;
+ info4.help_file = r->help_file;
+ info4.monitor_name = r->monitor_name;
+ info4.default_datatype = r->default_datatype;
+ info4._ndr_size_dependent_files = r->_ndr_size_dependent_files;
+ info4.dependent_files = r->dependent_files;
+ info4._ndr_size_previous_names = r->_ndr_size_previous_names;
+ info4.previous_names = r->previous_names;
+
+ info_ctr.level = 4;
+ info_ctr.info.info4 = &info4;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 4");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_OK),
+ "failed to test AddPrinterDriver level 4");
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 4, r->driver_name, &info),
+ "failed to find added printer driver");
+
+ if (remote_driver_dir) {
+ int i;
+ ASSERT_DRIVER_PATH(tctx, info.info4.driver_path, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info4.data_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info4.config_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info4.help_file, remote_driver_dir, "unexpected path");
+ for (i=0; info.info4.dependent_files && info.info4.dependent_files[i] != NULL; i++) {
+ ASSERT_DRIVER_PATH(tctx, info.info4.dependent_files[i], remote_driver_dir, "unexpected path");
+ }
+ }
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_6(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ struct spoolss_AddDriverInfo6 info6;
+ union spoolss_DriverInfo info;
+
+ info6.version = r->version;
+ info6.driver_name = r->driver_name;
+ info6.architecture = r->architecture;
+ info6.driver_path = r->driver_path;
+ info6.data_file = r->data_file;
+ info6.config_file = r->config_file;
+ info6.help_file = r->help_file;
+ info6.monitor_name = r->monitor_name;
+ info6.default_datatype = r->default_datatype;
+ info6._ndr_size_dependent_files = r->_ndr_size_dependent_files;
+ info6.dependent_files = r->dependent_files;
+ info6._ndr_size_previous_names = r->_ndr_size_previous_names;
+ info6.previous_names = r->previous_names;
+ info6.driver_date = r->driver_date;
+ info6.driver_version = r->driver_version;
+ info6.manufacturer_name = r->manufacturer_name;
+ info6.manufacturer_url = r->manufacturer_url;
+ info6.hardware_id = r->hardware_id;
+ info6.provider = r->provider;
+
+ info_ctr.level = 6;
+ info_ctr.info.info6 = &info6;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 6");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_LEVEL),
+ "failed to test AddPrinterDriver level 6");
+ }
+
+ /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+ if (!ex) {
+ return true;
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 6, r->driver_name, &info),
+ "failed to find added printer driver");
+
+ if (remote_driver_dir) {
+ int i;
+ ASSERT_DRIVER_PATH(tctx, info.info6.driver_path, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info6.data_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info6.config_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info6.help_file, remote_driver_dir, "unexpected path");
+ for (i=0; info.info6.dependent_files && info.info6.dependent_files[i] != NULL; i++) {
+ ASSERT_DRIVER_PATH(tctx, info.info6.dependent_files[i], remote_driver_dir, "unexpected path");
+ }
+ }
+
+ torture_assert_nttime_equal(tctx, info.info6.driver_date, info6.driver_date, "driverdate mismatch");
+ torture_assert_u64_equal(tctx, info.info6.driver_version, info6.driver_version, "driverversion mismatch");
+
+ return true;
+}
+
+static bool test_AddPrinterDriver_args_level_8(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t flags,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ struct spoolss_AddDriverInfoCtr info_ctr;
+ union spoolss_DriverInfo info;
+
+ info_ctr.level = 8;
+ info_ctr.info.info8 = r;
+
+ if (ex) {
+ torture_assert(tctx,
+ test_AddPrinterDriverEx_exp(tctx, b, server_name, &info_ctr, flags, WERR_OK),
+ "failed to test AddPrinterDriverEx level 8");
+ } else {
+ torture_assert(tctx,
+ test_AddPrinterDriver_exp(tctx, b, server_name, &info_ctr, WERR_INVALID_LEVEL),
+ "failed to test AddPrinterDriver level 8");
+ }
+
+ /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+ if (!ex) {
+ return true;
+ }
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name, r->architecture, 8, r->driver_name, &info),
+ "failed to find added printer driver");
+
+ if (remote_driver_dir) {
+ int i;
+ ASSERT_DRIVER_PATH(tctx, info.info8.driver_path, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info8.data_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info8.config_file, remote_driver_dir, "unexpected path");
+ ASSERT_DRIVER_PATH(tctx, info.info8.help_file, remote_driver_dir, "unexpected path");
+ for (i=0; info.info8.dependent_files && info.info8.dependent_files[i] != NULL; i++) {
+ ASSERT_DRIVER_PATH(tctx, info.info8.dependent_files[i], remote_driver_dir, "unexpected path");
+ }
+ }
+
+ torture_assert_nttime_equal(tctx, info.info8.driver_date, r->driver_date, "driverdate mismatch");
+ torture_assert_u64_equal(tctx, info.info8.driver_version, r->driver_version, "driverversion mismatch");
+
+ return true;
+}
+
+#undef ASSERT_DRIVER_PATH
+
+static bool test_DeletePrinterDriver_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *driver,
+ const char *environment,
+ WERROR expected_result)
+{
+ struct spoolss_DeletePrinterDriver r;
+
+ r.in.server = server;
+ r.in.architecture = environment;
+ r.in.driver = driver;
+
+ torture_comment(tctx, "Testing DeletePrinterDriver(%s)\n", driver);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterDriver_r(b, tctx, &r),
+ "DeletePrinterDriver failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeletePrinterDriver failed with unexpected result");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriverEx_exp(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server,
+ const char *driver,
+ const char *environment,
+ uint32_t delete_flags,
+ uint32_t version,
+ WERROR expected_result)
+{
+ struct spoolss_DeletePrinterDriverEx r;
+
+ r.in.server = server;
+ r.in.architecture = environment;
+ r.in.driver = driver;
+ r.in.delete_flags = delete_flags;
+ r.in.version = version;
+
+ torture_comment(tctx, "Testing DeletePrinterDriverEx(%s)\n", driver);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_DeletePrinterDriverEx_r(b, tctx, &r),
+ "DeletePrinterDriverEx failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeletePrinterDriverEx failed with unexpected result");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriver(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *driver,
+ const char *environment)
+{
+ torture_assert(tctx,
+ test_DeletePrinterDriver_exp(tctx, b, server_name, driver, "FOOBAR", WERR_INVALID_ENVIRONMENT),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriver_exp(tctx, b, server_name, driver, environment, WERR_OK),
+ "failed to delete driver");
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name, environment, 1, driver, NULL)) {
+ torture_fail(tctx, "deleted driver still enumerated");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDriver_exp(tctx, b, server_name, driver, environment, WERR_UNKNOWN_PRINTER_DRIVER),
+ "2nd delete failed");
+
+ return true;
+}
+
+static bool test_DeletePrinterDriverEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ const char *driver,
+ const char *environment,
+ uint32_t delete_flags,
+ uint32_t version)
+{
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, "FOOBAR", delete_flags, version, WERR_INVALID_ENVIRONMENT),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, environment, delete_flags, version, WERR_OK),
+ "failed to delete driver");
+
+ if (test_EnumPrinterDrivers_findone(tctx, b, server_name, environment, 1, driver, NULL)) {
+ torture_fail(tctx, "deleted driver still enumerated");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name, driver, environment, delete_flags, version, WERR_UNKNOWN_PRINTER_DRIVER),
+ "2nd delete failed");
+
+ return true;
+}
+
+static bool test_PrinterDriver_args(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *server_name,
+ uint32_t level,
+ struct spoolss_AddDriverInfo8 *r,
+ uint32_t add_flags,
+ uint32_t delete_flags,
+ uint32_t delete_version,
+ bool ex,
+ const char *remote_driver_dir)
+{
+ bool ret = true;
+
+ switch (level) {
+ case 1:
+ ret = test_AddPrinterDriver_args_level_1(tctx, b, server_name, r, add_flags, ex, remote_driver_dir);
+ break;
+ case 2:
+ ret = test_AddPrinterDriver_args_level_2(tctx, b, server_name, r, add_flags, ex, remote_driver_dir);
+ break;
+ case 3:
+ ret = test_AddPrinterDriver_args_level_3(tctx, b, server_name, r, add_flags, ex, remote_driver_dir);
+ break;
+ case 4:
+ ret = test_AddPrinterDriver_args_level_4(tctx, b, server_name, r, add_flags, ex, remote_driver_dir);
+ break;
+ case 6:
+ ret = test_AddPrinterDriver_args_level_6(tctx, b, server_name, r, add_flags, ex, remote_driver_dir);
+ break;
+ case 8:
+ ret = test_AddPrinterDriver_args_level_8(tctx, b, server_name, r, add_flags, ex, remote_driver_dir);
+ break;
+ default:
+ return false;
+ }
+
+ if (ret == false) {
+ return ret;
+ }
+
+ if (level == 1) {
+ return ret;
+ }
+
+ /* spoolss_AddPrinterDriver does not deal with level 6 or 8 - gd */
+
+ if (!ex && (level == 6 || level == 8)) {
+ return ret;
+ }
+
+ {
+ struct dcerpc_pipe *p2;
+ struct policy_handle hive_handle;
+ struct dcerpc_binding_handle *b2;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &p2, &ndr_table_winreg),
+ "could not open winreg pipe");
+ b2 = p2->binding_handle;
+
+ torture_assert(tctx, test_winreg_OpenHKLM(tctx, b2, &hive_handle), "");
+
+ ret = test_GetDriverInfo_winreg(tctx, b, NULL, NULL, r->driver_name, r->architecture, r->version, b2, &hive_handle, server_name);
+
+ test_winreg_CloseKey(tctx, b2, &hive_handle);
+
+ talloc_free(p2);
+ }
+
+ if (ex) {
+ return test_DeletePrinterDriverEx(tctx, b, server_name, r->driver_name, r->architecture, delete_flags, r->version);
+ } else {
+ return test_DeletePrinterDriver(tctx, b, server_name, r->driver_name, r->architecture);
+ }
+}
+
+static bool fillup_printserver_info(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_driver_context *d)
+{
+ struct policy_handle server_handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ torture_assert(tctx,
+ test_OpenPrinter_server(tctx, p, &server_handle),
+ "failed to open printserver");
+ torture_assert(tctx,
+ test_get_environment(tctx, b, &server_handle, &d->remote.environment),
+ "failed to get environment");
+ torture_assert(tctx,
+ test_ClosePrinter(tctx, b, &server_handle),
+ "failed to close printserver");
+
+ torture_assert(tctx,
+ test_GetPrinterDriverDirectory_getdir(tctx, b, server_name_slash,
+ d->local.environment ? d->local.environment : d->remote.environment,
+ &d->remote.driver_directory),
+ "failed to get driver directory");
+
+ return true;
+}
+
+static const char *driver_directory_dir(const char *driver_directory)
+{
+ char *p;
+
+ p = strrchr(driver_directory, '\\');
+ if (p) {
+ return p+1;
+ }
+
+ return NULL;
+}
+
+static const char *driver_directory_share(struct torture_context *tctx,
+ const char *driver_directory)
+{
+ const char *p;
+ char *tok;
+
+ if (driver_directory[0] == '\\' && driver_directory[1] == '\\') {
+ driver_directory += 2;
+ }
+
+ p = talloc_strdup(tctx, driver_directory);
+
+ torture_assert(tctx,
+ next_token_talloc(tctx, &p, &tok, "\\"),
+ "cannot explode uri");
+ torture_assert(tctx,
+ next_token_talloc(tctx, &p, &tok, "\\"),
+ "cannot explode uri");
+
+ return tok;
+}
+
+#define CREATE_PRINTER_DRIVER_PATH(_d, _file) \
+ talloc_asprintf((_d), "%s\\%s\\%s", (_d)->remote.driver_directory, (_d)->remote.driver_upload_directory, (_file))
+
+
+static bool create_printer_driver_directory(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d)
+{
+ char *driver_dir;
+
+ if (d->remote.driver_upload_directory == NULL) {
+ return true;
+ }
+
+ driver_dir = talloc_asprintf(tctx,
+ "%s\\%s",
+ driver_directory_dir(d->remote.driver_directory),
+ d->remote.driver_upload_directory);
+ torture_assert_not_null(tctx, driver_dir, "ENOMEM");
+
+ torture_comment(tctx,
+ "Create remote driver directory: %s\n",
+ driver_dir);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_mkdir(cli->tree,
+ driver_dir),
+ "Failed to create driver directory");
+
+ return true;
+}
+
+static bool upload_printer_driver_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d,
+ const char *file_name)
+{
+ FILE *f;
+ int fnum;
+ uint8_t *buf;
+ int maxwrite = 64512;
+ off_t nread = 0;
+ size_t start = 0;
+ const char *remote_dir = driver_directory_dir(d->remote.driver_directory);
+ const char *remote_name;
+ const char *local_name;
+ const char *p;
+
+ if (!file_name || strlen(file_name) == 0) {
+ return true;
+ }
+
+ p = strrchr(file_name, '\\');
+ if (p == NULL) {
+ p = file_name;
+ } else {
+ p++;
+ }
+
+ local_name = talloc_asprintf(tctx, "%s/%s", d->local.driver_directory, p);
+ torture_assert_not_null(tctx, local_name, "ENOMEM");
+ if (d->remote.driver_upload_directory != NULL) {
+ remote_name = talloc_asprintf(tctx,
+ "%s\\%s\\%s",
+ remote_dir,
+ d->remote.driver_upload_directory,
+ p);
+ } else {
+ remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, p);
+ }
+ torture_assert_not_null(tctx, remote_name, "ENOMEM");
+
+ torture_comment(tctx, "Uploading %s to %s\n", local_name, remote_name);
+
+ fnum = smbcli_open(cli->tree, remote_name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+ if (fnum == -1) {
+ torture_fail(tctx, talloc_asprintf(tctx, "failed to open remote file: %s\n", remote_name));
+ }
+
+ f = fopen(local_name, "r");
+ if (f == NULL) {
+ torture_fail(tctx, talloc_asprintf(tctx, "failed to open local file: %s\n", local_name));
+ }
+
+ buf = talloc_array(tctx, uint8_t, maxwrite);
+ if (!buf) {
+ fclose(f);
+ return false;
+ }
+
+ while (!feof(f)) {
+ int n = maxwrite;
+ int ret;
+
+ if ((n = fread(buf, 1, n, f)) < 1) {
+ if((n == 0) && feof(f))
+ break; /* Empty local file. */
+
+ torture_warning(tctx,
+ "failed to read file: %s\n", strerror(errno));
+ break;
+ }
+
+ ret = smbcli_write(cli->tree, fnum, 0, buf, nread + start, n);
+
+ if (n != ret) {
+ torture_warning(tctx,
+ "failed to write file: %s\n", smbcli_errstr(cli->tree));
+ break;
+ }
+
+ nread += n;
+ }
+
+ fclose(f);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli->tree, fnum),
+ "failed to close file");
+
+ return true;
+}
+
+static bool connect_printer_driver_share(struct torture_context *tctx,
+ const char *server_name,
+ const char *share_name,
+ struct smbcli_state **cli)
+{
+ struct smbcli_options smb_options;
+ struct smbcli_session_options smb_session_options;
+
+ torture_comment(tctx, "Connecting printer driver share '%s' on '%s'\n",
+ share_name, server_name);
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &smb_options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &smb_session_options);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_full_connection(tctx, cli, server_name,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share_name, NULL,
+ lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev,
+ &smb_options,
+ &smb_session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)),
+ "failed to open driver share");
+
+ return true;
+}
+
+static bool upload_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d)
+{
+ struct smbcli_state *cli;
+ const char *share_name = driver_directory_share(tctx, d->remote.driver_directory);
+ int i;
+
+ torture_assert(tctx,
+ connect_printer_driver_share(tctx, server_name, share_name, &cli),
+ "failed to connect to driver share");
+
+ torture_comment(tctx, "Uploading printer driver files to \\\\%s\\%s\n",
+ server_name, share_name);
+
+ torture_assert(tctx,
+ create_printer_driver_directory(tctx, cli, d),
+ "failed to create driver directory");
+
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.driver_path),
+ "failed to upload driver_path");
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.data_file),
+ "failed to upload data_file");
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.config_file),
+ "failed to upload config_file");
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.help_file),
+ "failed to upload help_file");
+ if (d->info8.dependent_files) {
+ for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
+ torture_assert(tctx,
+ upload_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]),
+ "failed to upload dependent_files");
+ }
+ }
+
+ talloc_free(cli);
+
+ return true;
+}
+
+static bool check_printer_driver_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d,
+ const char *file_name)
+{
+ const char *remote_arch_dir = driver_directory_dir(d->remote.driver_directory);
+ const char *remote_name = talloc_asprintf(tctx, "%s\\%d\\%s",
+ remote_arch_dir,
+ d->info8.version,
+ file_name);
+ int fnum;
+
+ torture_assert(tctx, (file_name && strlen(file_name) != 0), "invalid filename");
+
+ torture_comment(tctx, "checking for driver file at %s\n", remote_name);
+
+ fnum = smbcli_open(cli->tree, remote_name, O_RDONLY, DENY_NONE);
+ if (fnum == -1) {
+ return false;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_close(cli->tree, fnum),
+ "failed to close driver file");
+
+ return true;
+}
+
+static bool check_printer_driver_files(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d,
+ bool expect_exist)
+{
+ struct smbcli_state *cli;
+ const char *share_name = driver_directory_share(tctx, d->remote.driver_directory);
+ int i;
+
+ torture_assert(tctx,
+ connect_printer_driver_share(tctx, server_name, share_name, &cli),
+ "failed to connect to driver share");
+
+ torture_comment(tctx, "checking %sexistent driver files at \\\\%s\\%s\n",
+ (expect_exist ? "": "non-"),
+ server_name, share_name);
+
+ if (d->info8.driver_path && d->info8.driver_path[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.driver_path) == expect_exist,
+ "failed driver_path check");
+ }
+ if (d->info8.data_file && d->info8.data_file[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.data_file) == expect_exist,
+ "failed data_file check");
+ }
+ if (d->info8.config_file && d->info8.config_file[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.config_file) == expect_exist,
+ "failed config_file check");
+ }
+ if (d->info8.help_file && d->info8.help_file[0]) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.help_file) == expect_exist,
+ "failed help_file check");
+ }
+ if (d->info8.dependent_files) {
+ for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
+ torture_assert(tctx,
+ check_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]) == expect_exist,
+ "failed dependent_files check");
+ }
+ }
+
+ talloc_free(cli);
+
+ return true;
+}
+
+static bool remove_printer_driver_file(struct torture_context *tctx,
+ struct smbcli_state *cli,
+ struct torture_driver_context *d,
+ const char *file_name)
+{
+ const char *remote_name;
+ const char *remote_dir = driver_directory_dir(d->remote.driver_directory);
+
+ if (!file_name || strlen(file_name) == 0) {
+ return true;
+ }
+
+ remote_name = talloc_asprintf(tctx, "%s\\%s", remote_dir, file_name);
+
+ torture_comment(tctx, "Removing %s\n", remote_name);
+
+ torture_assert_ntstatus_ok(tctx,
+ smbcli_unlink(cli->tree, remote_name),
+ "failed to unlink");
+
+ return true;
+}
+
+static bool remove_printer_driver(struct torture_context *tctx,
+ const char *server_name,
+ struct torture_driver_context *d)
+{
+ struct smbcli_state *cli;
+ const char *share_name = driver_directory_share(tctx, d->remote.driver_directory);
+ int i;
+
+ torture_assert(tctx,
+ connect_printer_driver_share(tctx, server_name, share_name, &cli),
+ "failed to connect to driver share");
+
+ torture_comment(tctx, "Removing printer driver files from \\\\%s\\%s\n",
+ server_name, share_name);
+
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.driver_path),
+ "failed to remove driver_path");
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.data_file),
+ "failed to remove data_file");
+ if (!strequal(d->info8.config_file, d->info8.driver_path)) {
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.config_file),
+ "failed to remove config_file");
+ }
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.help_file),
+ "failed to remove help_file");
+ if (d->info8.dependent_files) {
+ for (i=0; d->info8.dependent_files->string && d->info8.dependent_files->string[i] != NULL; i++) {
+ if (strequal(d->info8.dependent_files->string[i], d->info8.driver_path) ||
+ strequal(d->info8.dependent_files->string[i], d->info8.data_file) ||
+ strequal(d->info8.dependent_files->string[i], d->info8.config_file) ||
+ strequal(d->info8.dependent_files->string[i], d->info8.help_file)) {
+ continue;
+ }
+ torture_assert(tctx,
+ remove_printer_driver_file(tctx, cli, d, d->info8.dependent_files->string[i]),
+ "failed to remove dependent_files");
+ }
+ }
+
+ talloc_free(cli);
+
+ return true;
+
+}
+
+static bool test_add_driver_arg(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_driver_context *d)
+{
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ uint32_t levels[] = { 1, 2, 3, 4, 6, 8 };
+ int i;
+ struct spoolss_AddDriverInfo8 info8;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ uint32_t delete_flags = 0;
+
+ ZERO_STRUCT(info8);
+
+ torture_comment(tctx, "Testing PrinterDriver%s '%s' for environment '%s'\n",
+ d->ex ? "Ex" : "", d->info8.driver_name, d->local.environment);
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to upload printer driver");
+
+ info8 = d->info8;
+ if (d->info8.dependent_files) {
+ info8.dependent_files = talloc_zero(tctx, struct spoolss_StringArray);
+ if (d->info8.dependent_files->string) {
+ for (i=0; d->info8.dependent_files->string[i] != NULL; i++) {
+ }
+ info8.dependent_files->string = talloc_zero_array(info8.dependent_files, const char *, i+1);
+ for (i=0; d->info8.dependent_files->string[i] != NULL; i++) {
+ info8.dependent_files->string[i] = talloc_strdup(info8.dependent_files->string, d->info8.dependent_files->string[i]);
+ }
+ }
+ }
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ switch (levels[i]) {
+ case 2:
+ case 4:
+ torture_comment(tctx, "skipping level %d against samba\n", levels[i]);
+ continue;
+ default:
+ break;
+ }
+ }
+ if (torture_setting_bool(tctx, "w2k3", false)) {
+ switch (levels[i]) {
+ case 8:
+ torture_comment(tctx, "skipping level %d against w2k3\n", levels[i]);
+ continue;
+ default:
+ break;
+ }
+ }
+
+ torture_comment(tctx,
+ "Testing PrinterDriver%s '%s' add & delete level %d\n",
+ d->ex ? "Ex" : "", info8.driver_name, levels[i]);
+
+ ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, d->ex, d->remote.driver_directory);
+ }
+
+ info8.driver_path = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.driver_path);
+ info8.data_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.data_file);
+ if (d->info8.config_file) {
+ info8.config_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.config_file);
+ }
+ if (d->info8.help_file) {
+ info8.help_file = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.help_file);
+ }
+ if (d->info8.dependent_files && d->info8.dependent_files->string) {
+ for (i=0; d->info8.dependent_files->string[i] != NULL; i++) {
+ info8.dependent_files->string[i] = talloc_asprintf(tctx, "%s\\%s", d->remote.driver_directory, d->info8.dependent_files->string[i]);
+ }
+ }
+
+ for (i=0; i < ARRAY_SIZE(levels); i++) {
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ switch (levels[i]) {
+ case 2:
+ case 4:
+ continue;
+ default:
+ break;
+ }
+ }
+ if (torture_setting_bool(tctx, "w2k3", false)) {
+ switch (levels[i]) {
+ case 8:
+ torture_comment(tctx, "skipping level %d against w2k3\n", levels[i]);
+ continue;
+ default:
+ break;
+ }
+ }
+
+ torture_comment(tctx,
+ "Testing PrinterDriver%s '%s' add & delete level %d (full unc paths)\n",
+ d->ex ? "Ex" : "", info8.driver_name, levels[i]);
+
+ ret &= test_PrinterDriver_args(tctx, b, server_name_slash, levels[i], &info8, add_flags, delete_flags, d->info8.version, d->ex, d->remote.driver_directory);
+ }
+
+ torture_assert(tctx,
+ remove_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to remove printer driver");
+
+ torture_comment(tctx, "\n");
+
+ return ret;
+}
+
+static bool test_add_driver_ex_64(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_x64);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_EX;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->ex = true;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_ex_32(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_NT_X86);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_EX;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->ex = true;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_64(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_x64);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_ADD;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->ex = false;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_32(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_NT_X86);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_ADD;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->ex = false;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_adobe(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping adobe test which only works against samba3");
+ }
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, "Windows 4.0");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/adobe/");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_9X;
+ d->info8.driver_name = TORTURE_DRIVER_ADOBE;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "ADOBEPS4.DRV");
+ d->info8.data_file = talloc_strdup(d, "DEFPRTR2.PPD");
+ d->info8.config_file = talloc_strdup(d, "ADOBEPS4.DRV");
+#if 0
+ d->info8.help_file = talloc_strdup(d, "ADOBEPS4.HLP");
+ d->info8.monitor_name = talloc_strdup(d, "PSMON.DLL");
+#endif
+ d->ex = false;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_adobe_cupsaddsmb(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+ struct spoolss_StringArray *a;
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping cupsaddsmb test which only works against samba3");
+ }
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, "Windows 4.0");
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/adobe/");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_9X;
+ d->info8.driver_name = TORTURE_DRIVER_ADOBE_CUPSADDSMB;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "ADOBEPS4.DRV");
+ d->info8.data_file = talloc_strdup(d, "DEFPRTR2.PPD");
+ d->info8.config_file = NULL;
+ d->info8.help_file = talloc_strdup(d, "ADOBEPS4.HLP");
+ d->info8.monitor_name = talloc_strdup(d, "PSMON.DLL");
+ d->info8.default_datatype = talloc_strdup(d, "RAW");
+
+ a = talloc_zero(d, struct spoolss_StringArray);
+ a->string = talloc_zero_array(a, const char *, 7);
+ a->string[0] = talloc_strdup(a->string, "ADOBEPS4.DRV");
+ a->string[1] = talloc_strdup(a->string, "DEFPRTR2.PPD");
+ a->string[2] = talloc_strdup(a->string, "ADOBEPS4.HLP");
+ a->string[3] = talloc_strdup(a->string, "PSMON.DLL");
+ a->string[4] = talloc_strdup(a->string, "ADFONTS.MFM");
+ a->string[5] = talloc_strdup(a->string, "ICONLIB.DLL");
+
+ d->info8.dependent_files = a;
+ d->ex = false;
+
+ return test_add_driver_arg(tctx, p, d);
+}
+
+static bool test_add_driver_timestamps(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+ struct timeval t = timeval_current();
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_NT_X86);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_TIMESTAMPS;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->info8.driver_date = timeval_to_nttime(&t);
+ d->ex = true;
+
+ torture_assert(tctx,
+ test_add_driver_arg(tctx, p, d),
+ "");
+
+ unix_to_nt_time(&d->info8.driver_date, 1);
+
+ torture_assert(tctx,
+ test_add_driver_arg(tctx, p, d),
+ "");
+
+ return true;
+}
+
+static bool test_multiple_drivers(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ int i;
+ struct spoolss_AddDriverInfo8 info8;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ uint32_t delete_flags = 0;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_NT_X86);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/i386");
+
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->info8.architecture = d->local.environment;
+ d->ex = true;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to upload printer driver");
+
+ info8 = d->info8;
+
+ for (i=0; i < 3; i++) {
+ info8.driver_name = talloc_asprintf(d, "torture_test_driver_%d", i);
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &info8, add_flags, true, NULL),
+ "failed to add driver");
+ }
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash, "torture_test_driver_0", info8.architecture, delete_flags, info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, info8.architecture, 3, "torture_test_driver_1", NULL),
+ "torture_test_driver_1 no longer on the server");
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, info8.architecture, 3, "torture_test_driver_2", NULL),
+ "torture_test_driver_2 no longer on the server");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash, "torture_test_driver_1", info8.architecture, delete_flags, info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ test_EnumPrinterDrivers_findone(tctx, b, server_name_slash, info8.architecture, 3, "torture_test_driver_2", NULL),
+ "torture_test_driver_2 no longer on the server");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash, "torture_test_driver_2", info8.architecture, delete_flags, info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ remove_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to remove printer driver");
+
+ return true;
+}
+
+static bool test_driver_copy_from_directory(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *architecture)
+{
+ struct torture_driver_context *d;
+ struct spoolss_StringArray *a;
+ uint32_t add_flags = APD_COPY_NEW_FILES|APD_COPY_FROM_DIRECTORY|APD_RETURN_BLOCKING_STATUS_CODE;
+ uint32_t delete_flags = DPD_DELETE_ALL_FILES;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx,
+ "\\\\%s",
+ dcerpc_server_name(p));
+ struct GUID guid = GUID_random();
+ bool ok = false;
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+ torture_assert_not_null(tctx, d, "ENOMEM");
+
+ d->local.environment = talloc_strdup(d, architecture);
+ torture_assert_not_null_goto(tctx, d->local.environment, ok, done, "ENOMEM");
+
+ if (strequal(architecture, SPOOLSS_ARCHITECTURE_x64)) {
+ d->local.driver_directory =
+ talloc_strdup(d, "/usr/share/cups/drivers/x64");
+ } else {
+ d->local.driver_directory =
+ talloc_strdup(d, "/usr/share/cups/drivers/i386");
+ }
+ torture_assert_not_null_goto(tctx, d->local.driver_directory, ok, done, "ENOMEM");
+
+ d->remote.driver_upload_directory = GUID_string2(d, &guid);
+ torture_assert_not_null_goto(tctx, d->remote.driver_upload_directory, ok, done, "ENOMEM");
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d),
+ "failed to fillup printserver info");
+
+ d->ex = true;
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_COPY_DIR;
+ d->info8.architecture = d->local.environment;
+
+ d->info8.driver_path = CREATE_PRINTER_DRIVER_PATH(d, "pscript5.dll");
+ torture_assert_not_null_goto(tctx, d->info8.driver_path, ok, done, "ENOMEM");
+ d->info8.data_file = CREATE_PRINTER_DRIVER_PATH(d, "cups6.ppd");
+ torture_assert_not_null_goto(tctx, d->info8.data_file, ok, done, "ENOMEM");
+ d->info8.config_file = CREATE_PRINTER_DRIVER_PATH(d, "cupsui6.dll");
+ torture_assert_not_null_goto(tctx, d->info8.config_file, ok, done, "ENOMEM");
+ d->info8.help_file = CREATE_PRINTER_DRIVER_PATH(d, "pscript.hlp");
+ torture_assert_not_null_goto(tctx, d->info8.help_file, ok, done, "ENOMEM");
+
+ a = talloc_zero(d, struct spoolss_StringArray);
+ torture_assert_not_null_goto(tctx, a, ok, done, "ENOMEM");
+ a->string = talloc_zero_array(a, const char *, 3);
+ torture_assert_not_null_goto(tctx, a->string, ok, done, "ENOMEM");
+ a->string[0] = CREATE_PRINTER_DRIVER_PATH(d, "cups6.inf");
+ torture_assert_not_null_goto(tctx, a->string[0], ok, done, "ENOMEM");
+ a->string[1] = CREATE_PRINTER_DRIVER_PATH(d, "cups6.ini");
+ torture_assert_not_null_goto(tctx, a->string[1], ok, done, "ENOMEM");
+
+ d->info8.dependent_files = a;
+
+ if (!directory_exist(d->local.driver_directory)) {
+ torture_skip(tctx,
+ "Skipping Printer Driver test as no local drivers "
+ "are available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to upload printer driver");
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx,
+ b,
+ server_name_slash,
+ &d->info8,
+ add_flags,
+ true,
+ NULL),
+ "failed to add driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx,
+ b,
+ server_name_slash,
+ d->info8.driver_name,
+ d->local.environment,
+ delete_flags,
+ d->info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ check_printer_driver_files(tctx,
+ dcerpc_server_name(p),
+ d,
+ false),
+ "printer driver file check failed");
+
+ ok = true;
+done:
+ talloc_free(d);
+ return ok;
+}
+
+static bool test_driver_copy_from_directory_64(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_driver_copy_from_directory(tctx, p, SPOOLSS_ARCHITECTURE_x64);
+}
+
+static bool test_driver_copy_from_directory_32(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_driver_copy_from_directory(tctx, p, SPOOLSS_ARCHITECTURE_NT_X86);
+}
+
+static bool test_del_driver_all_files(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d;
+ struct spoolss_StringArray *a;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ uint32_t delete_flags = DPD_DELETE_ALL_FILES;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ d = talloc_zero(tctx, struct torture_driver_context);
+
+ d->local.environment = talloc_strdup(d, SPOOLSS_ARCHITECTURE_x64);
+ d->local.driver_directory = talloc_strdup(d, "/usr/share/cups/drivers/x64");
+
+ d->ex = true;
+ d->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d->info8.driver_name = TORTURE_DRIVER_DELETER;
+ d->info8.architecture = d->local.environment;
+ d->info8.driver_path = talloc_strdup(d, "pscript5.dll");
+ d->info8.data_file = talloc_strdup(d, "cups6.ppd");
+ d->info8.config_file = talloc_strdup(d, "cupsui6.dll");
+ d->info8.help_file = talloc_strdup(d, "pscript.hlp");
+
+ a = talloc_zero(d, struct spoolss_StringArray);
+ a->string = talloc_zero_array(a, const char *, 3);
+ a->string[0] = talloc_strdup(a->string, "cups6.inf");
+ a->string[1] = talloc_strdup(a->string, "cups6.ini");
+
+ d->info8.dependent_files = a;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d),
+ "failed to upload printer driver");
+
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d->info8, add_flags, true, NULL),
+ "failed to add driver");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx(tctx, b, server_name_slash,
+ d->info8.driver_name,
+ d->info8.architecture,
+ delete_flags,
+ d->info8.version),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d, false),
+ "printer driver file check failed");
+
+ talloc_free(d);
+ return true;
+}
+
+static bool test_del_driver_unused_files(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_driver_context *d1;
+ struct torture_driver_context *d2;
+ uint32_t add_flags = APD_COPY_NEW_FILES;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *server_name_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ d1 = talloc_zero(tctx, struct torture_driver_context);
+ d1->ex = true;
+
+ d1->local.environment = talloc_strdup(d1, SPOOLSS_ARCHITECTURE_x64);
+ d1->local.driver_directory = talloc_strdup(d1, "/usr/share/cups/drivers/x64");
+
+ d1->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d1->info8.driver_name = TORTURE_DRIVER_DELETER;
+ d1->info8.architecture = NULL;
+ d1->info8.driver_path = talloc_strdup(d1, "pscript5.dll");
+ d1->info8.data_file = talloc_strdup(d1, "cups6.ppd");
+ d1->info8.config_file = talloc_strdup(d1, "cupsui6.dll");
+ d1->info8.help_file = talloc_strdup(d1, "pscript.hlp");
+ d1->info8.architecture = d1->local.environment;
+
+ d2 = talloc_zero(tctx, struct torture_driver_context);
+ d2->ex = true;
+
+ d2->local.environment = talloc_strdup(d2, SPOOLSS_ARCHITECTURE_x64);
+ d2->local.driver_directory = talloc_strdup(d2, "/usr/share/cups/drivers/x64");
+
+ d2->info8.version = SPOOLSS_DRIVER_VERSION_200X;
+ d2->info8.driver_name = TORTURE_DRIVER_DELETERIN;
+ d2->info8.architecture = NULL;
+ d2->info8.driver_path = talloc_strdup(d2, "pscript5.dll"); /* overlapping */
+ d2->info8.data_file = talloc_strdup(d2, "cupsps6.dll");
+ d2->info8.config_file = talloc_strdup(d2, "cups6.ini");
+ d2->info8.help_file = talloc_strdup(d2, "pscript.hlp"); /* overlapping */
+ d2->info8.architecture = d2->local.environment;
+
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d1),
+ "failed to fillup printserver info");
+ torture_assert(tctx,
+ fillup_printserver_info(tctx, p, d2),
+ "failed to fillup printserver info");
+
+ if (!directory_exist(d1->local.driver_directory)) {
+ torture_skip(tctx, "Skipping Printer Driver test as no local driver is available");
+ }
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d1),
+ "failed to upload printer driver");
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d1->info8, add_flags, true, NULL),
+ "failed to add driver");
+
+ torture_assert(tctx,
+ upload_printer_driver(tctx, dcerpc_server_name(p), d2),
+ "failed to upload printer driver");
+ torture_assert(tctx,
+ test_AddPrinterDriver_args_level_3(tctx, b, server_name_slash, &d2->info8, add_flags, true, NULL),
+ "failed to add driver");
+
+ /* some files are in use by a separate driver, should fail */
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash,
+ d1->info8.driver_name,
+ d1->info8.architecture,
+ DPD_DELETE_ALL_FILES,
+ d1->info8.version,
+ WERR_PRINTER_DRIVER_IN_USE),
+ "invalid delete driver response");
+
+ /* should only delete files not in use by other driver */
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash,
+ d1->info8.driver_name,
+ d1->info8.architecture,
+ DPD_DELETE_UNUSED_FILES,
+ d1->info8.version,
+ WERR_OK),
+ "failed to delete driver (unused files)");
+
+ /* check non-overlapping were deleted */
+ d1->info8.driver_path = NULL;
+ d1->info8.help_file = NULL;
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d1, false),
+ "printer driver file check failed");
+ /* d2 files should be uneffected */
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d2, true),
+ "printer driver file check failed");
+
+ torture_assert(tctx,
+ test_DeletePrinterDriverEx_exp(tctx, b, server_name_slash,
+ d2->info8.driver_name,
+ d2->info8.architecture,
+ DPD_DELETE_ALL_FILES,
+ d2->info8.version,
+ WERR_OK),
+ "failed to delete driver");
+
+ torture_assert(tctx,
+ check_printer_driver_files(tctx, dcerpc_server_name(p), d2, false),
+ "printer driver file check failed");
+
+ talloc_free(d1);
+ talloc_free(d2);
+ return true;
+}
+
+struct torture_suite *torture_rpc_spoolss_driver(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.driver");
+
+ struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
+ "driver", &ndr_table_spoolss);
+ torture_rpc_tcase_add_test(tcase, "add_driver_64", test_add_driver_64);
+ torture_rpc_tcase_add_test(tcase, "add_driver_ex_64", test_add_driver_ex_64);
+
+ torture_rpc_tcase_add_test(tcase, "add_driver_32", test_add_driver_32);
+ torture_rpc_tcase_add_test(tcase, "add_driver_ex_32", test_add_driver_ex_32);
+
+ torture_rpc_tcase_add_test(tcase, "add_driver_adobe", test_add_driver_adobe);
+
+ torture_rpc_tcase_add_test(tcase, "add_driver_adobe_cupsaddsmb", test_add_driver_adobe_cupsaddsmb);
+
+ torture_rpc_tcase_add_test(tcase, "add_driver_timestamps", test_add_driver_timestamps);
+
+ torture_rpc_tcase_add_test(tcase, "multiple_drivers", test_multiple_drivers);
+
+ torture_rpc_tcase_add_test(tcase,
+ "test_driver_copy_from_directory_64",
+ test_driver_copy_from_directory_64);
+
+ torture_rpc_tcase_add_test(tcase,
+ "test_driver_copy_from_directory_32",
+ test_driver_copy_from_directory_32);
+
+ torture_rpc_tcase_add_test(tcase, "del_driver_all_files", test_del_driver_all_files);
+
+ torture_rpc_tcase_add_test(tcase, "del_driver_unused_files", test_del_driver_unused_files);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/spoolss_access.c b/source4/torture/rpc/spoolss_access.c
new file mode 100644
index 0000000..b0d5265
--- /dev/null
+++ b/source4/torture/rpc/spoolss_access.c
@@ -0,0 +1,905 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for spoolss rpc operations
+
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "lib/cmdline/cmdline.h"
+
+#define TORTURE_USER "torture_user"
+#define TORTURE_USER_ADMINGROUP "torture_user_544"
+#define TORTURE_USER_PRINTOPGROUP "torture_user_550"
+#define TORTURE_USER_PRINTOPPRIV "torture_user_priv"
+#define TORTURE_USER_SD "torture_user_sd"
+#define TORTURE_WORKSTATION "torture_workstation"
+
+struct torture_user {
+ const char *username;
+ void *testuser;
+ uint32_t *builtin_memberships;
+ uint32_t num_builtin_memberships;
+ const char **privs;
+ uint32_t num_privs;
+ bool privs_present;
+ bool sd;
+ bool admin_rights;
+ bool system_security;
+};
+
+struct torture_access_context {
+ struct dcerpc_pipe *spoolss_pipe;
+ const char *printername;
+ struct security_descriptor *sd_orig;
+ struct torture_user user;
+};
+
+static bool test_openprinter_handle(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ const char *printername,
+ const char *username,
+ uint32_t access_mask,
+ WERROR expected_result,
+ struct policy_handle *handle)
+{
+ struct spoolss_OpenPrinterEx r;
+ struct spoolss_UserLevel1 level1;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ level1.size = 28;
+ level1.client = talloc_asprintf(tctx, "\\\\%s", "smbtorture");
+ level1.user = username;
+ /* Windows 7 and Windows Server 2008 R2 */
+ level1.build = 7007;
+ level1.major = 6;
+ level1.minor = 1;
+ level1.processor= 0;
+
+ r.in.printername = printername;
+ r.in.datatype = NULL;
+ r.in.devmode_ctr.devmode= NULL;
+ r.in.access_mask = access_mask;
+ r.in.userlevel_ctr.level = 1;
+ r.in.userlevel_ctr.user_info.level1 = &level1;
+ r.out.handle = handle;
+
+ torture_comment(tctx, "Testing OpenPrinterEx(%s) with access_mask 0x%08x (%s)\n",
+ r.in.printername, r.in.access_mask, name);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &r),
+ "OpenPrinterEx failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ talloc_asprintf(tctx, "OpenPrinterEx(%s) as '%s' with access_mask: 0x%08x (%s) failed",
+ r.in.printername, username, r.in.access_mask, name));
+
+ return true;
+}
+
+static bool test_openprinter_access(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name,
+ const char *printername,
+ const char *username,
+ uint32_t access_mask,
+ WERROR expected_result)
+{
+ struct policy_handle handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ bool ret = true;
+
+ ZERO_STRUCT(handle);
+
+ if (printername == NULL) {
+ torture_comment(tctx, "skipping test %s as there is no printer\n", name);
+ return true;
+ }
+
+ ret = test_openprinter_handle(tctx, p, name, printername, username, access_mask, expected_result, &handle);
+ if (is_valid_policy_hnd(&handle)) {
+ test_ClosePrinter(tctx, b, &handle);
+ }
+
+ return ret;
+}
+
+static bool spoolss_access_setup_membership(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ uint32_t num_members,
+ uint32_t *members,
+ struct dom_sid *user_sid)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle connect_handle, domain_handle;
+ int i;
+
+ torture_comment(tctx,
+ "Setting up BUILTIN membership for %s\n",
+ dom_sid_string(tctx, user_sid));
+ for (i=0; i < num_members; i++) {
+ torture_comment(tctx, "adding user to S-1-5-32-%d\n", members[i]);
+ }
+
+ {
+ struct samr_Connect2 r;
+ r.in.system_name = "";
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.connect_handle = &connect_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_Connect2_r(b, tctx, &r),
+ "samr_Connect2 failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_Connect2 failed");
+ }
+
+ {
+ struct samr_OpenDomain r;
+ r.in.connect_handle = &connect_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.sid = dom_sid_parse_talloc(tctx, "S-1-5-32");
+ r.out.domain_handle = &domain_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenDomain_r(b, tctx, &r),
+ "samr_OpenDomain failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_OpenDomain failed");
+ }
+
+ for (i=0; i < num_members; i++) {
+
+ struct policy_handle alias_handle;
+
+ {
+ struct samr_OpenAlias r;
+ r.in.domain_handle = &domain_handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = members[i];
+ r.out.alias_handle = &alias_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_OpenAlias_r(b, tctx, &r),
+ "samr_OpenAlias failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_OpenAlias failed");
+ }
+
+ {
+ struct samr_AddAliasMember r;
+ r.in.alias_handle = &alias_handle;
+ r.in.sid = user_sid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_samr_AddAliasMember_r(b, tctx, &r),
+ "samr_AddAliasMember failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "samr_AddAliasMember failed");
+ }
+
+ test_samr_handle_Close(b, tctx, &alias_handle);
+ }
+
+ test_samr_handle_Close(b, tctx, &domain_handle);
+ test_samr_handle_Close(b, tctx, &connect_handle);
+
+ return true;
+}
+
+static void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
+{
+ name->string = s;
+}
+static void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+}
+
+static bool spoolss_access_setup_privs(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ uint32_t num_privs,
+ const char **privs,
+ struct dom_sid *user_sid,
+ bool *privs_present)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle *handle;
+ int i;
+
+ torture_assert(tctx,
+ test_lsa_OpenPolicy2(b, tctx, &handle),
+ "failed to open policy");
+
+ for (i=0; i < num_privs; i++) {
+ struct lsa_LookupPrivValue r;
+ struct lsa_LUID luid;
+ struct lsa_String name;
+
+ init_lsa_String(&name, privs[i]);
+
+ r.in.handle = handle;
+ r.in.name = &name;
+ r.out.luid = &luid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_LookupPrivValue_r(b, tctx, &r),
+ "lsa_LookupPrivValue failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "lsa_LookupPrivValue failed for '%s' with %s\n",
+ privs[i], nt_errstr(r.out.result));
+ *privs_present = false;
+ return true;
+ }
+ }
+
+ *privs_present = true;
+
+ {
+ struct lsa_AddAccountRights r;
+ struct lsa_RightSet rights;
+
+ rights.count = num_privs;
+ rights.names = talloc_zero_array(tctx, struct lsa_StringLarge, rights.count);
+
+ for (i=0; i < rights.count; i++) {
+ init_lsa_StringLarge(&rights.names[i], privs[i]);
+ }
+
+ r.in.handle = handle;
+ r.in.sid = user_sid;
+ r.in.rights = &rights;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_AddAccountRights_r(b, tctx, &r),
+ "lsa_AddAccountRights failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "lsa_AddAccountRights failed");
+ }
+
+ test_lsa_Close(b, tctx, handle);
+
+ return true;
+}
+
+static bool test_SetPrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct spoolss_SetPrinterInfoCtr *info_ctr,
+ struct spoolss_DevmodeContainer *devmode_ctr,
+ struct sec_desc_buf *secdesc_ctr,
+ enum spoolss_PrinterControl command)
+{
+ struct spoolss_SetPrinter r;
+
+ r.in.handle = handle;
+ r.in.info_ctr = info_ctr;
+ r.in.devmode_ctr = devmode_ctr;
+ r.in.secdesc_ctr = secdesc_ctr;
+ r.in.command = command;
+
+ torture_comment(tctx, "Testing SetPrinter level %d\n", r.in.info_ctr->level);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r),
+ "failed to call SetPrinter");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to call SetPrinter");
+
+ return true;
+}
+
+static bool spoolss_access_setup_sd(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *printername,
+ const struct dom_sid *user_sid,
+ struct security_descriptor **sd_orig)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle handle;
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_SetPrinterInfo3 info3;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ struct security_ace *ace;
+ struct security_descriptor *sd;
+
+ torture_assert(tctx,
+ test_openprinter_handle(tctx, p, "", printername, "", SEC_FLAG_MAXIMUM_ALLOWED, WERR_OK, &handle),
+ "failed to open printer");
+
+ torture_assert(tctx,
+ test_GetPrinter_level(tctx, b, &handle, 3, &info),
+ "failed to get sd");
+
+ sd = security_descriptor_copy(tctx, info.info3.secdesc);
+ *sd_orig = security_descriptor_copy(tctx, info.info3.secdesc);
+
+ ace = talloc_zero(tctx, struct security_ace);
+
+ ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace->flags = 0;
+ ace->access_mask = PRINTER_ALL_ACCESS;
+ ace->trustee = *user_sid;
+
+ torture_assert_ntstatus_ok(tctx,
+ security_descriptor_dacl_add(sd, ace),
+ "failed to add new ace");
+
+ ace = talloc_zero(tctx, struct security_ace);
+
+ ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace->flags = SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY;
+ ace->access_mask = SEC_GENERIC_ALL;
+ ace->trustee = *user_sid;
+
+ torture_assert_ntstatus_ok(tctx,
+ security_descriptor_dacl_add(sd, ace),
+ "failed to add new ace");
+
+ ZERO_STRUCT(info3);
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ info_ctr.level = 3;
+ info_ctr.info.info3 = &info3;
+ secdesc_ctr.sd = sd;
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, &handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
+ "failed to set sd");
+
+ return true;
+}
+
+static bool test_EnumPrinters_findone(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char **printername)
+{
+ struct spoolss_EnumPrinters r;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+ uint32_t needed;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ *printername = NULL;
+
+ r.in.flags = PRINTER_ENUM_LOCAL;
+ r.in.server = NULL;
+ r.in.level = 1;
+ r.in.buffer = NULL;
+ r.in.offered = 0;
+ r.out.count = &count;
+ r.out.info = &info;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+ "failed to enum printers");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, needed);
+ r.in.buffer = &blob;
+ r.in.offered = needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_EnumPrinters_r(b, tctx, &r),
+ "failed to enum printers");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to enum printers");
+
+ for (i=0; i < count; i++) {
+
+ if (count > 1 && strequal(info[i].info1.name, "Microsoft XPS Document Writer")) {
+ continue;
+ }
+
+ torture_comment(tctx, "testing printer: %s\n",
+ info[i].info1.name);
+
+ *printername = talloc_strdup(tctx, info[i].info1.name);
+
+ break;
+ }
+
+ return true;
+}
+
+static bool torture_rpc_spoolss_access_setup_common(struct torture_context *tctx, struct torture_access_context *t)
+{
+ void *testuser;
+ const char *testuser_passwd;
+ struct cli_credentials *test_credentials;
+ struct dom_sid *test_sid;
+ struct dcerpc_pipe *p;
+ const char *printername;
+ const char *binding = torture_setting_string(tctx, "binding", NULL);
+ struct dcerpc_pipe *spoolss_pipe;
+
+ testuser = torture_create_testuser_max_pwlen(tctx, t->user.username,
+ torture_setting_string(tctx, "workgroup", NULL),
+ ACB_NORMAL,
+ &testuser_passwd,
+ 32);
+ if (!testuser) {
+ torture_fail(tctx, "Failed to create test user");
+ }
+
+ test_credentials = cli_credentials_init(tctx);
+ cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED);
+ cli_credentials_set_domain(test_credentials, lpcfg_workgroup(tctx->lp_ctx),
+ CRED_SPECIFIED);
+ cli_credentials_set_username(test_credentials, t->user.username, CRED_SPECIFIED);
+ cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED);
+ test_sid = discard_const_p(struct dom_sid,
+ torture_join_user_sid(testuser));
+
+ if (t->user.num_builtin_memberships) {
+ struct dcerpc_pipe *samr_pipe = torture_join_samr_pipe(testuser);
+
+ torture_assert(tctx,
+ spoolss_access_setup_membership(tctx, samr_pipe,
+ t->user.num_builtin_memberships,
+ t->user.builtin_memberships,
+ test_sid),
+ "failed to setup membership");
+ }
+
+ if (t->user.num_privs) {
+ struct dcerpc_pipe *lsa_pipe;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &lsa_pipe, &ndr_table_lsarpc),
+ "Error connecting to server");
+
+ torture_assert(tctx,
+ spoolss_access_setup_privs(tctx, lsa_pipe,
+ t->user.num_privs,
+ t->user.privs,
+ test_sid,
+ &t->user.privs_present),
+ "failed to setup privs");
+ talloc_free(lsa_pipe);
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &spoolss_pipe, &ndr_table_spoolss),
+ "Error connecting to server");
+
+ torture_assert(tctx,
+ test_EnumPrinters_findone(tctx, spoolss_pipe, &printername),
+ "failed to enumerate printers");
+
+ if (t->user.sd && printername) {
+ torture_assert(tctx,
+ spoolss_access_setup_sd(tctx, spoolss_pipe,
+ printername,
+ test_sid,
+ &t->sd_orig),
+ "failed to setup sd");
+ }
+
+ talloc_free(spoolss_pipe);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect(tctx, &p, binding, &ndr_table_spoolss,
+ test_credentials, tctx->ev, tctx->lp_ctx),
+ "Error connecting to server");
+
+ t->spoolss_pipe = p;
+ t->printername = printername;
+ t->user.testuser = testuser;
+
+ return true;
+}
+
+static bool torture_rpc_spoolss_access_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_access_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_access_context);
+
+ t->user.username = talloc_strdup(t, TORTURE_USER);
+
+ return torture_rpc_spoolss_access_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_access_admin_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_access_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_access_context);
+
+ t->user.num_builtin_memberships = 1;
+ t->user.builtin_memberships = talloc_zero_array(t, uint32_t, t->user.num_builtin_memberships);
+ t->user.builtin_memberships[0] = BUILTIN_RID_ADMINISTRATORS;
+ t->user.username = talloc_strdup(t, TORTURE_USER_ADMINGROUP);
+ t->user.admin_rights = true;
+ t->user.system_security = true;
+
+ return torture_rpc_spoolss_access_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_access_printop_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_access_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_access_context);
+
+ t->user.num_builtin_memberships = 1;
+ t->user.builtin_memberships = talloc_zero_array(t, uint32_t, t->user.num_builtin_memberships);
+ t->user.builtin_memberships[0] = BUILTIN_RID_PRINT_OPERATORS;
+ t->user.username = talloc_strdup(t, TORTURE_USER_PRINTOPGROUP);
+ t->user.admin_rights = true;
+
+ return torture_rpc_spoolss_access_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_access_priv_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_access_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_access_context);
+
+ t->user.username = talloc_strdup(t, TORTURE_USER_PRINTOPPRIV);
+ t->user.num_privs = 1;
+ t->user.privs = talloc_zero_array(t, const char *, t->user.num_privs);
+ t->user.privs[0] = talloc_strdup(t, "SePrintOperatorPrivilege");
+ t->user.admin_rights = true;
+
+ return torture_rpc_spoolss_access_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_access_sd_setup(struct torture_context *tctx, void **data)
+{
+ struct torture_access_context *t;
+
+ *data = t = talloc_zero(tctx, struct torture_access_context);
+
+ t->user.username = talloc_strdup(t, TORTURE_USER_SD);
+ t->user.sd = true;
+ t->user.admin_rights = true;
+
+ return torture_rpc_spoolss_access_setup_common(tctx, t);
+}
+
+static bool torture_rpc_spoolss_access_teardown_common(struct torture_context *tctx, struct torture_access_context *t)
+{
+ if (t->user.testuser) {
+ torture_leave_domain(tctx, t->user.testuser);
+ }
+
+ /* remove membership ? */
+ if (t->user.num_builtin_memberships) {
+ }
+
+ /* remove privs ? */
+ if (t->user.num_privs) {
+ }
+
+ /* restore sd */
+ if (t->user.sd && t->printername) {
+ struct policy_handle handle;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_SetPrinterInfo3 info3;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ struct dcerpc_pipe *spoolss_pipe;
+ struct dcerpc_binding_handle *b;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection(tctx, &spoolss_pipe, &ndr_table_spoolss),
+ "Error connecting to server");
+
+ b = spoolss_pipe->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+ ZERO_STRUCT(info3);
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ info_ctr.level = 3;
+ info_ctr.info.info3 = &info3;
+ secdesc_ctr.sd = t->sd_orig;
+
+ torture_assert(tctx,
+ test_openprinter_handle(tctx, spoolss_pipe, "", t->printername, "", SEC_FLAG_MAXIMUM_ALLOWED, WERR_OK, &handle),
+ "failed to open printer");
+
+ torture_assert(tctx,
+ test_SetPrinter(tctx, b, &handle, &info_ctr, &devmode_ctr, &secdesc_ctr, 0),
+ "failed to set sd");
+
+ talloc_free(spoolss_pipe);
+ }
+
+ return true;
+}
+
+static bool torture_rpc_spoolss_access_teardown(struct torture_context *tctx, void *data)
+{
+ struct torture_access_context *t = talloc_get_type(data, struct torture_access_context);
+ bool ret;
+
+ ret = torture_rpc_spoolss_access_teardown_common(tctx, t);
+ talloc_free(t);
+
+ return ret;
+}
+
+static bool test_openprinter(struct torture_context *tctx,
+ void *private_data)
+{
+ struct torture_access_context *t =
+ (struct torture_access_context *)talloc_get_type_abort(private_data, struct torture_access_context);
+ struct dcerpc_pipe *p = t->spoolss_pipe;
+ bool ret = true;
+ const char *username = t->user.username;
+ const char *servername_slash = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ int i;
+
+ struct {
+ const char *name;
+ uint32_t access_mask;
+ const char *printername;
+ WERROR expected_result;
+ } checks[] = {
+
+ /* printserver handle tests */
+
+ {
+ .name = "0",
+ .access_mask = 0,
+ .printername = servername_slash,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SEC_FLAG_MAXIMUM_ALLOWED",
+ .access_mask = SEC_FLAG_MAXIMUM_ALLOWED,
+ .printername = servername_slash,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SERVER_ACCESS_ENUMERATE",
+ .access_mask = SERVER_ACCESS_ENUMERATE,
+ .printername = servername_slash,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SERVER_ACCESS_ADMINISTER",
+ .access_mask = SERVER_ACCESS_ADMINISTER,
+ .printername = servername_slash,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "SERVER_READ",
+ .access_mask = SERVER_READ,
+ .printername = servername_slash,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SERVER_WRITE",
+ .access_mask = SERVER_WRITE,
+ .printername = servername_slash,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "SERVER_EXECUTE",
+ .access_mask = SERVER_EXECUTE,
+ .printername = servername_slash,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SERVER_ALL_ACCESS",
+ .access_mask = SERVER_ALL_ACCESS,
+ .printername = servername_slash,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+
+ /* printer handle tests */
+
+ {
+ .name = "0",
+ .access_mask = 0,
+ .printername = t->printername,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SEC_FLAG_MAXIMUM_ALLOWED",
+ .access_mask = SEC_FLAG_MAXIMUM_ALLOWED,
+ .printername = t->printername,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SEC_FLAG_SYSTEM_SECURITY",
+ .access_mask = SEC_FLAG_SYSTEM_SECURITY,
+ .printername = t->printername,
+ .expected_result = t->user.system_security ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "0x010e0000",
+ .access_mask = 0x010e0000,
+ .printername = t->printername,
+ .expected_result = t->user.system_security ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "PRINTER_ACCESS_USE",
+ .access_mask = PRINTER_ACCESS_USE,
+ .printername = t->printername,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "SEC_STD_READ_CONTROL",
+ .access_mask = SEC_STD_READ_CONTROL,
+ .printername = t->printername,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "PRINTER_ACCESS_ADMINISTER",
+ .access_mask = PRINTER_ACCESS_ADMINISTER,
+ .printername = t->printername,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "SEC_STD_WRITE_DAC",
+ .access_mask = SEC_STD_WRITE_DAC,
+ .printername = t->printername,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "SEC_STD_WRITE_OWNER",
+ .access_mask = SEC_STD_WRITE_OWNER,
+ .printername = t->printername,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "PRINTER_READ",
+ .access_mask = PRINTER_READ,
+ .printername = t->printername,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "PRINTER_WRITE",
+ .access_mask = PRINTER_WRITE,
+ .printername = t->printername,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ },
+ {
+ .name = "PRINTER_EXECUTE",
+ .access_mask = PRINTER_EXECUTE,
+ .printername = t->printername,
+ .expected_result = WERR_OK
+ },
+ {
+ .name = "PRINTER_ALL_ACCESS",
+ .access_mask = PRINTER_ALL_ACCESS,
+ .printername = t->printername,
+ .expected_result = t->user.admin_rights ? WERR_OK : WERR_ACCESS_DENIED
+ }
+ };
+
+ if (t->user.num_privs && !t->user.privs_present) {
+ torture_skip(tctx, "skipping test as not all required privileges are present on the server\n");
+ }
+
+ for (i=0; i < ARRAY_SIZE(checks); i++) {
+ ret &= test_openprinter_access(tctx, p,
+ checks[i].name,
+ checks[i].printername,
+ username,
+ checks[i].access_mask,
+ checks[i].expected_result);
+ }
+
+ return ret;
+}
+
+static bool test_openprinter_wrap(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct torture_access_context *t;
+ const char *printername;
+ bool ret = true;
+
+ t = talloc_zero(tctx, struct torture_access_context);
+
+ t->user.username = talloc_strdup(tctx, "dummy");
+ t->spoolss_pipe = p;
+
+ torture_assert(tctx,
+ test_EnumPrinters_findone(tctx, p, &printername),
+ "failed to enumerate printers");
+
+ t->printername = printername;
+
+ ret = test_openprinter(tctx, (void *)t);
+
+ talloc_free(t);
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_spoolss_access(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.access");
+ struct torture_tcase *tcase;
+ struct torture_rpc_tcase *rpc_tcase;
+
+ tcase = torture_suite_add_tcase(suite, "normaluser");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_access_setup,
+ torture_rpc_spoolss_access_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter);
+
+ tcase = torture_suite_add_tcase(suite, "adminuser");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_access_admin_setup,
+ torture_rpc_spoolss_access_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter);
+
+ tcase = torture_suite_add_tcase(suite, "printopuser");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_access_printop_setup,
+ torture_rpc_spoolss_access_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter);
+
+ tcase = torture_suite_add_tcase(suite, "printopuserpriv");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_access_priv_setup,
+ torture_rpc_spoolss_access_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter);
+
+ tcase = torture_suite_add_tcase(suite, "normaluser_sd");
+
+ torture_tcase_set_fixture(tcase,
+ torture_rpc_spoolss_access_sd_setup,
+ torture_rpc_spoolss_access_teardown);
+
+ torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter);
+
+ rpc_tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "workstation",
+ &ndr_table_spoolss,
+ TORTURE_WORKSTATION);
+
+ torture_rpc_tcase_add_test(rpc_tcase, "openprinter", test_openprinter_wrap);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/spoolss_notify.c b/source4/torture/rpc/spoolss_notify.c
new file mode 100644
index 0000000..bd9dac4
--- /dev/null
+++ b/source4/torture/rpc/spoolss_notify.c
@@ -0,0 +1,636 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for spoolss rpc notify operations
+
+ Copyright (C) Jelmer Vernooij 2007
+ Copyright (C) Guenther Deschner 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "torture/rpc/torture_rpc.h"
+#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/dcerpc_server_proto.h"
+#include "rpc_server/service_rpc.h"
+#include "samba/process_model.h"
+#include "smb_server/smb_server.h"
+#include "lib/socket/netif.h"
+#include "ntvfs/ntvfs.h"
+#include "param/param.h"
+
+static struct dcesrv_context_callbacks srv_cb = {
+ .log.successful_authz = log_successful_dcesrv_authz_event,
+ .auth.gensec_prepare = dcesrv_gensec_prepare,
+ .assoc_group.find = dcesrv_assoc_group_find_s4,
+};
+
+static NTSTATUS spoolss__op_bind(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ return NT_STATUS_OK;
+}
+
+static void spoolss__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
+{
+}
+
+static NTSTATUS spoolss__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
+{
+ enum ndr_err_code ndr_err;
+ uint16_t opnum = dce_call->pkt.u.request.opnum;
+
+ dce_call->fault_code = 0;
+
+ if (opnum >= ndr_table_spoolss.num_calls) {
+ dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
+ return NT_STATUS_NET_WRITE_FAULT;
+ }
+
+ *r = talloc_size(mem_ctx, ndr_table_spoolss.calls[opnum].struct_size);
+ NT_STATUS_HAVE_NO_MEMORY(*r);
+
+ /* unravel the NDR for the packet */
+ ndr_err = ndr_table_spoolss.calls[opnum].ndr_pull(pull, NDR_IN, *r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ dce_call->fault_code = DCERPC_FAULT_NDR;
+ return NT_STATUS_NET_WRITE_FAULT;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* Note that received_packets are allocated on the NULL context
+ * because no other context appears to stay around long enough. */
+static struct received_packet {
+ uint16_t opnum;
+ void *r;
+ struct received_packet *prev, *next;
+} *received_packets = NULL;
+
+static void free_received_packets(void)
+{
+ struct received_packet *rp;
+ struct received_packet *rp_next;
+
+ for (rp = received_packets; rp; rp = rp_next) {
+ rp_next = rp->next;
+ DLIST_REMOVE(received_packets, rp);
+ talloc_unlink(rp, rp->r);
+ talloc_free(rp);
+ }
+ received_packets = NULL;
+}
+
+static WERROR _spoolss_ReplyOpenPrinter(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct spoolss_ReplyOpenPrinter *r)
+{
+ DEBUG(1,("_spoolss_ReplyOpenPrinter\n"));
+
+ NDR_PRINT_IN_DEBUG(spoolss_ReplyOpenPrinter, r);
+
+ r->out.handle = talloc(r, struct policy_handle);
+ r->out.handle->handle_type = 42;
+ r->out.handle->uuid = GUID_random();
+ r->out.result = WERR_OK;
+
+ NDR_PRINT_OUT_DEBUG(spoolss_ReplyOpenPrinter, r);
+
+ return WERR_OK;
+}
+
+static WERROR _spoolss_ReplyClosePrinter(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct spoolss_ReplyClosePrinter *r)
+{
+ DEBUG(1,("_spoolss_ReplyClosePrinter\n"));
+
+ NDR_PRINT_IN_DEBUG(spoolss_ReplyClosePrinter, r);
+
+ ZERO_STRUCTP(r->out.handle);
+ r->out.result = WERR_OK;
+
+ NDR_PRINT_OUT_DEBUG(spoolss_ReplyClosePrinter, r);
+
+ return WERR_OK;
+}
+
+static WERROR _spoolss_RouterReplyPrinterEx(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct spoolss_RouterReplyPrinterEx *r)
+{
+ DEBUG(1,("_spoolss_RouterReplyPrinterEx\n"));
+
+ NDR_PRINT_IN_DEBUG(spoolss_RouterReplyPrinterEx, r);
+
+ r->out.reply_result = talloc(r, uint32_t);
+ *r->out.reply_result = 0;
+ r->out.result = WERR_OK;
+
+ NDR_PRINT_OUT_DEBUG(spoolss_RouterReplyPrinterEx, r);
+
+ return WERR_OK;
+}
+
+static NTSTATUS spoolss__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
+{
+ uint16_t opnum = dce_call->pkt.u.request.opnum;
+ struct received_packet *rp;
+
+ rp = talloc_zero(NULL, struct received_packet);
+ rp->opnum = opnum;
+ rp->r = talloc_reference(rp, r);
+
+ DLIST_ADD_END(received_packets, rp);
+
+ switch (opnum) {
+ case 58: {
+ struct spoolss_ReplyOpenPrinter *r2 = (struct spoolss_ReplyOpenPrinter *)r;
+ r2->out.result = _spoolss_ReplyOpenPrinter(dce_call, mem_ctx, r2);
+ break;
+ }
+ case 60: {
+ struct spoolss_ReplyClosePrinter *r2 = (struct spoolss_ReplyClosePrinter *)r;
+ r2->out.result = _spoolss_ReplyClosePrinter(dce_call, mem_ctx, r2);
+ break;
+ }
+ case 66: {
+ struct spoolss_RouterReplyPrinterEx *r2 = (struct spoolss_RouterReplyPrinterEx *)r;
+ r2->out.result = _spoolss_RouterReplyPrinterEx(dce_call, mem_ctx, r2);
+ break;
+ }
+
+ default:
+ dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
+ break;
+ }
+
+ if (dce_call->fault_code != 0) {
+ return NT_STATUS_NET_WRITE_FAULT;
+ }
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS spoolss__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
+{
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS spoolss__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
+{
+ enum ndr_err_code ndr_err;
+ uint16_t opnum = dce_call->pkt.u.request.opnum;
+
+ ndr_err = ndr_table_spoolss.calls[opnum].ndr_push(push, NDR_OUT, r);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ dce_call->fault_code = DCERPC_FAULT_NDR;
+ return NT_STATUS_NET_WRITE_FAULT;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static const struct dcesrv_interface notify_test_spoolss_interface = {
+ .name = "spoolss",
+ .syntax_id = {{0x12345678,0x1234,0xabcd,{0xef,0x00},{0x01,0x23,0x45,0x67,0x89,0xab}},1.0},
+ .bind = spoolss__op_bind,
+ .unbind = spoolss__op_unbind,
+ .ndr_pull = spoolss__op_ndr_pull,
+ .dispatch = spoolss__op_dispatch,
+ .reply = spoolss__op_reply,
+ .ndr_push = spoolss__op_ndr_push
+};
+
+static bool spoolss__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
+{
+ if (notify_test_spoolss_interface.syntax_id.if_version == if_version &&
+ GUID_equal(&notify_test_spoolss_interface.syntax_id.uuid, uuid)) {
+ memcpy(iface,&notify_test_spoolss_interface, sizeof(*iface));
+ return true;
+ }
+
+ return false;
+}
+
+static bool spoolss__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
+{
+ if (strcmp(notify_test_spoolss_interface.name, name)==0) {
+ memcpy(iface, &notify_test_spoolss_interface, sizeof(*iface));
+ return true;
+ }
+
+ return false;
+}
+
+static NTSTATUS spoolss__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
+{
+ uint32_t i;
+
+ for (i=0;i<ndr_table_spoolss.endpoints->count;i++) {
+ NTSTATUS ret;
+ const char *name = ndr_table_spoolss.endpoints->names[i];
+
+ ret = dcesrv_interface_register(dce_ctx,
+ name,
+ NULL,
+ &notify_test_spoolss_interface,
+ NULL);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1,("spoolss_op_init_server: failed to register endpoint '%s'\n",name));
+ return ret;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS spoolss__op_shutdown_server(struct dcesrv_context *dce_ctx,
+ const struct dcesrv_endpoint_server *ep_server)
+{
+ return NT_STATUS_OK;
+}
+
+static bool test_OpenPrinter(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *printername)
+{
+ struct spoolss_OpenPrinter r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+
+ r.in.printername = printername;
+ r.in.datatype = NULL;
+ r.in.devmode_ctr.devmode= NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = handle;
+
+ torture_comment(tctx, "Testing OpenPrinter(%s)\n", r.in.printername);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_OpenPrinter_r(b, tctx, &r),
+ "OpenPrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "OpenPrinter failed");
+
+ return true;
+}
+
+static struct spoolss_NotifyOption *setup_printserver_NotifyOption(struct torture_context *tctx)
+{
+ struct spoolss_NotifyOption *o;
+
+ o = talloc_zero(tctx, struct spoolss_NotifyOption);
+
+ o->version = 2;
+ o->flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
+
+ o->count = 2;
+ o->types = talloc_zero_array(o, struct spoolss_NotifyOptionType, o->count);
+
+ o->types[0].type = PRINTER_NOTIFY_TYPE;
+ o->types[0].count = 1;
+ o->types[0].fields = talloc_array(o->types, union spoolss_Field, o->types[0].count);
+ o->types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME;
+
+ o->types[1].type = JOB_NOTIFY_TYPE;
+ o->types[1].count = 1;
+ o->types[1].fields = talloc_array(o->types, union spoolss_Field, o->types[1].count);
+ o->types[1].fields[0].field = JOB_NOTIFY_FIELD_MACHINE_NAME;
+
+ return o;
+}
+
+#if 0
+static struct spoolss_NotifyOption *setup_printer_NotifyOption(struct torture_context *tctx)
+{
+ struct spoolss_NotifyOption *o;
+
+ o = talloc_zero(tctx, struct spoolss_NotifyOption);
+
+ o->version = 2;
+ o->flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
+
+ o->count = 1;
+ o->types = talloc_zero_array(o, struct spoolss_NotifyOptionType, o->count);
+
+ o->types[0].type = PRINTER_NOTIFY_TYPE;
+ o->types[0].count = 1;
+ o->types[0].fields = talloc_array(o->types, union spoolss_Field, o->types[0].count);
+ o->types[0].fields[0].field = PRINTER_NOTIFY_FIELD_COMMENT;
+
+ return o;
+}
+#endif
+
+static bool test_RemoteFindFirstPrinterChangeNotifyEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *address,
+ struct spoolss_NotifyOption *option)
+{
+ struct spoolss_RemoteFindFirstPrinterChangeNotifyEx r;
+ const char *local_machine = talloc_asprintf(tctx, "\\\\%s", address);
+
+ torture_comment(tctx, "Testing RemoteFindFirstPrinterChangeNotifyEx(%s)\n", local_machine);
+
+ r.in.flags = 0;
+ r.in.local_machine = local_machine;
+ r.in.options = 0;
+ r.in.printer_local = 0;
+ r.in.notify_options = option;
+ r.in.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx_r(b, tctx, &r),
+ "RemoteFindFirstPrinterChangeNotifyEx failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "error return code for RemoteFindFirstPrinterChangeNotifyEx");
+
+ return true;
+}
+
+static bool test_RouterRefreshPrinterChangeNotify(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct spoolss_NotifyOption *options,
+ struct spoolss_NotifyInfo **info)
+{
+ struct spoolss_RouterRefreshPrinterChangeNotify r;
+
+ torture_comment(tctx, "Testing RouterRefreshPrinterChangeNotify\n");
+
+ r.in.handle = handle;
+ r.in.change_low = 0;
+ r.in.options = options;
+ r.out.info = info;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_RouterRefreshPrinterChangeNotify_r(b, tctx, &r),
+ "RouterRefreshPrinterChangeNotify failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "error return code for RouterRefreshPrinterChangeNotify");
+
+ return true;
+}
+
+#if 0
+static bool test_SetPrinter(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ union spoolss_PrinterInfo info;
+ struct spoolss_SetPrinter r;
+ struct spoolss_SetPrinterInfo2 info2;
+ struct spoolss_SetPrinterInfoCtr info_ctr;
+ struct spoolss_DevmodeContainer devmode_ctr;
+ struct sec_desc_buf secdesc_ctr;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
+
+ ZERO_STRUCT(devmode_ctr);
+ ZERO_STRUCT(secdesc_ctr);
+
+ info2.servername = info.info2.servername;
+ info2.printername = info.info2.printername;
+ info2.sharename = info.info2.sharename;
+ info2.portname = info.info2.portname;
+ info2.drivername = info.info2.drivername;
+ info2.comment = talloc_asprintf(tctx, "torture_comment %d\n", (int)time(NULL));
+ info2.location = info.info2.location;
+ info2.devmode_ptr = 0;
+ info2.sepfile = info.info2.sepfile;
+ info2.printprocessor = info.info2.printprocessor;
+ info2.datatype = info.info2.datatype;
+ info2.parameters = info.info2.parameters;
+ info2.secdesc_ptr = 0;
+ info2.attributes = info.info2.attributes;
+ info2.priority = info.info2.priority;
+ info2.defaultpriority = info.info2.defaultpriority;
+ info2.starttime = info.info2.starttime;
+ info2.untiltime = info.info2.untiltime;
+ info2.status = info.info2.status;
+ info2.cjobs = info.info2.cjobs;
+ info2.averageppm = info.info2.averageppm;
+
+ info_ctr.level = 2;
+ info_ctr.info.info2 = &info2;
+
+ r.in.handle = handle;
+ r.in.info_ctr = &info_ctr;
+ r.in.devmode_ctr = &devmode_ctr;
+ r.in.secdesc_ctr = &secdesc_ctr;
+ r.in.command = 0;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_spoolss_SetPrinter_r(b, tctx, &r), "SetPrinter failed");
+ torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
+
+ return true;
+}
+#endif
+
+static bool test_start_dcerpc_server(struct torture_context *tctx,
+ struct tevent_context *event_ctx,
+ struct dcesrv_context **dce_ctx_p,
+ const char **address_p)
+{
+ struct dcesrv_endpoint_server ep_server;
+ NTSTATUS status;
+ struct dcesrv_context *dce_ctx;
+ const char *endpoints[] = { "spoolss", NULL };
+ struct dcesrv_endpoint *e;
+ const char *address;
+ struct interface *ifaces;
+
+ ntvfs_init(tctx->lp_ctx);
+
+ /* fill in our name */
+ ep_server.name = "spoolss";
+
+ ep_server.initialized = false;
+
+ /* fill in all the operations */
+ ep_server.init_server = spoolss__op_init_server;
+ ep_server.shutdown_server = spoolss__op_shutdown_server;
+
+ ep_server.interface_by_uuid = spoolss__op_interface_by_uuid;
+ ep_server.interface_by_name = spoolss__op_interface_by_name;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_register_ep_server(&ep_server),
+ "unable to register spoolss server");
+
+ lpcfg_set_cmdline(tctx->lp_ctx, "dcerpc endpoint servers", "spoolss");
+
+ load_interface_list(tctx, tctx->lp_ctx, &ifaces);
+ address = iface_list_first_v4(ifaces);
+
+ torture_comment(tctx, "Listening for callbacks on %s\n", address);
+
+ status = process_model_init(tctx->lp_ctx);
+ torture_assert_ntstatus_ok(tctx, status,
+ "unable to initialize process models");
+
+ status = smbsrv_add_socket(tctx, event_ctx, tctx->lp_ctx,
+ process_model_startup("single"),
+ address, NULL);
+ torture_assert_ntstatus_ok(tctx, status, "starting smb server");
+
+ status = dcesrv_init_context(tctx, tctx->lp_ctx, &srv_cb, &dce_ctx);
+ torture_assert_ntstatus_ok(tctx, status,
+ "unable to initialize DCE/RPC server");
+
+ status = dcesrv_init_ep_servers(dce_ctx, endpoints);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "unable to initialize DCE/RPC ep servers");
+
+ for (e=dce_ctx->endpoint_list;e;e=e->next) {
+ status = dcesrv_add_ep(dce_ctx, tctx->lp_ctx,
+ e, tctx->ev,
+ process_model_startup("single"), NULL);
+ torture_assert_ntstatus_ok(tctx, status,
+ "unable listen on dcerpc endpoint server");
+ }
+
+ *dce_ctx_p = dce_ctx;
+ *address_p = address;
+
+ return true;
+}
+
+static struct received_packet *last_packet(struct received_packet *p)
+{
+ struct received_packet *tmp;
+ for (tmp = p; tmp->next; tmp = tmp->next) {
+ }
+ return tmp;
+}
+
+static bool test_RFFPCNEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct dcesrv_context *dce_ctx;
+ struct policy_handle handle;
+ const char *address;
+ struct received_packet *tmp;
+ struct spoolss_NotifyOption *server_option = setup_printserver_NotifyOption(tctx);
+#if 0
+ struct spoolss_NotifyOption *printer_option = setup_printer_NotifyOption(tctx);
+#endif
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *printername = NULL;
+ struct spoolss_NotifyInfo *info = NULL;
+
+ free_received_packets();
+
+ /* Start DCE/RPC server */
+ torture_assert(tctx, test_start_dcerpc_server(tctx, tctx->ev, &dce_ctx, &address), "");
+
+ printername = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+
+ torture_assert(tctx, test_OpenPrinter(tctx, p, &handle, printername), "");
+ torture_assert(tctx, test_RemoteFindFirstPrinterChangeNotifyEx(tctx, b, &handle, address, server_option), "");
+ torture_assert(tctx, received_packets, "no packets received");
+ torture_assert_int_equal(tctx, received_packets->opnum, NDR_SPOOLSS_REPLYOPENPRINTER,
+ "no ReplyOpenPrinter packet after RemoteFindFirstPrinterChangeNotifyEx");
+ torture_assert(tctx, test_RouterRefreshPrinterChangeNotify(tctx, b, &handle, NULL, &info), "");
+ torture_assert(tctx, test_RouterRefreshPrinterChangeNotify(tctx, b, &handle, server_option, &info), "");
+ torture_assert(tctx, test_ClosePrinter(tctx, b, &handle), "");
+ tmp = last_packet(received_packets);
+ torture_assert_int_equal(tctx, tmp->opnum, NDR_SPOOLSS_REPLYCLOSEPRINTER,
+ "no ReplyClosePrinter packet after ClosePrinter");
+#if 0
+ printername = talloc_asprintf(tctx, "\\\\%s\\%s", dcerpc_server_name(p), name);
+
+ torture_assert(tctx, test_OpenPrinter(tctx, p, &handle, "Epson AL-2600"), "");
+ torture_assert(tctx, test_RemoteFindFirstPrinterChangeNotifyEx(tctx, p, &handle, address, printer_option), "");
+ tmp = last_packet(received_packets);
+ torture_assert_int_equal(tctx, tmp->opnum, NDR_SPOOLSS_REPLYOPENPRINTER,
+ "no ReplyOpenPrinter packet after RemoteFindFirstPrinterChangeNotifyEx");
+ torture_assert(tctx, test_RouterRefreshPrinterChangeNotify(tctx, p, &handle, NULL, &info), "");
+ torture_assert(tctx, test_RouterRefreshPrinterChangeNotify(tctx, p, &handle, printer_option, &info), "");
+ torture_assert(tctx, test_SetPrinter(tctx, p, &handle), "");
+ tmp = last_packet(received_packets);
+ torture_assert_int_equal(tctx, tmp->opnum, NDR_SPOOLSS_ROUTERREPLYPRINTEREX,
+ "no RouterReplyPrinterEx packet after ClosePrinter");
+ torture_assert(tctx, test_ClosePrinter(tctx, p, &handle), "");
+ tmp = last_packet(received_packets);
+ torture_assert_int_equal(tctx, tmp->opnum, NDR_SPOOLSS_REPLYCLOSEPRINTER,
+ "no ReplyClosePrinter packet after ClosePrinter");
+#endif
+ /* Shut down DCE/RPC server */
+ talloc_free(dce_ctx);
+ free_received_packets();
+
+ return true;
+}
+
+/** Test that makes sure that calling ReplyOpenPrinter()
+ * on Samba 4 will cause an irpc broadcast call.
+ */
+static bool test_ReplyOpenPrinter(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct spoolss_ReplyOpenPrinter r;
+ struct spoolss_ReplyClosePrinter s;
+ struct policy_handle h;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_skip(tctx, "skipping ReplyOpenPrinter server implementation test against s3\n");
+ }
+
+ r.in.server_name = "earth";
+ r.in.printer_local = 2;
+ r.in.type = REG_DWORD;
+ r.in.bufsize = 0;
+ r.in.buffer = NULL;
+ r.out.handle = &h;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_ReplyOpenPrinter_r(b, tctx, &r),
+ "spoolss_ReplyOpenPrinter call failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "error return code");
+
+ s.in.handle = &h;
+ s.out.handle = &h;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_spoolss_ReplyClosePrinter_r(b, tctx, &s),
+ "spoolss_ReplyClosePrinter call failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "error return code");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_spoolss_notify(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.notify");
+
+ struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
+ "notify", &ndr_table_spoolss);
+
+ torture_rpc_tcase_add_test(tcase, "testRFFPCNEx", test_RFFPCNEx);
+ torture_rpc_tcase_add_test(tcase, "testReplyOpenPrinter", test_ReplyOpenPrinter);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/spoolss_win.c b/source4/torture/rpc/spoolss_win.c
new file mode 100644
index 0000000..9162acd
--- /dev/null
+++ b/source4/torture/rpc/spoolss_win.c
@@ -0,0 +1,612 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for spoolss rpc operations as performed by various win versions
+
+ Copyright (C) Kai Blin 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_spoolss_c.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "param/param.h"
+
+struct test_spoolss_win_context {
+ /* EnumPrinters */
+ uint32_t printer_count;
+ union spoolss_PrinterInfo *printer_info;
+ union spoolss_PrinterInfo *current_info;
+
+ /* EnumPrinterKeys */
+ const char **printer_keys;
+
+ bool printer_has_driver;
+};
+
+/* This is a convenience function for all OpenPrinterEx calls */
+static bool test_OpenPrinterEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *printer_name,
+ uint32_t access_mask)
+{
+ NTSTATUS status;
+ struct spoolss_OpenPrinterEx op;
+ struct spoolss_UserLevel1 ul_1;
+
+ torture_comment(tctx, "Opening printer '%s'\n", printer_name);
+
+ op.in.printername = talloc_strdup(tctx, printer_name);
+ op.in.datatype = NULL;
+ op.in.devmode_ctr.devmode = NULL;
+ op.in.access_mask = access_mask;
+ op.in.userlevel_ctr.level = 1;
+ op.in.userlevel_ctr.user_info.level1 = &ul_1;
+ op.out.handle = handle;
+
+ ul_1.size = 1234;
+ ul_1.client = "\\clientname";
+ ul_1.user = "username";
+ ul_1.build = 1;
+ ul_1.major = 2;
+ ul_1.minor = 3;
+ ul_1.processor = 4567;
+
+ status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &op);
+ torture_assert_ntstatus_ok(tctx, status, "OpenPrinterEx failed");
+ torture_assert_werr_ok(tctx, op.out.result, "OpenPrinterEx failed");
+
+ return true;
+}
+
+static bool test_OpenPrinterAsAdmin(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ const char *printername)
+{
+ NTSTATUS status;
+ struct spoolss_OpenPrinterEx op;
+ struct spoolss_ClosePrinter cp;
+ struct spoolss_UserLevel1 ul_1;
+ struct policy_handle handle;
+
+ ul_1.size = 1234;
+ ul_1.client = "\\clientname";
+ ul_1.user = "username";
+ ul_1.build = 1;
+ ul_1.major = 2;
+ ul_1.minor = 3;
+ ul_1.processor = 4567;
+
+ op.in.printername = talloc_strdup(tctx, printername);
+ op.in.datatype = NULL;
+ op.in.devmode_ctr.devmode = NULL;
+ op.in.access_mask = SERVER_ALL_ACCESS;
+ op.in.userlevel_ctr.level = 1;
+ op.in.userlevel_ctr.user_info.level1 = &ul_1;
+ op.out.handle = &handle;
+
+ cp.in.handle = &handle;
+ cp.out.handle = &handle;
+
+ torture_comment(tctx, "Testing OpenPrinterEx(%s) with admin rights\n",
+ op.in.printername);
+
+ status = dcerpc_spoolss_OpenPrinterEx_r(b, tctx, &op);
+
+ if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(op.out.result)) {
+ status = dcerpc_spoolss_ClosePrinter_r(b, tctx, &cp);
+ torture_assert_ntstatus_ok(tctx, status, "ClosePrinter failed");
+ }
+
+ return true;
+}
+
+
+
+/* This replicates the opening sequence of OpenPrinterEx calls XP does */
+static bool test_OpenPrinterSequence(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle)
+{
+ bool ret;
+ char *printername = talloc_asprintf(tctx, "\\\\%s",
+ dcerpc_server_name(p));
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ /* First, see if we can open the printer read_only */
+ ret = test_OpenPrinterEx(tctx, b, handle, printername, 0);
+ torture_assert(tctx, ret == true, "OpenPrinterEx failed.");
+
+ ret = test_ClosePrinter(tctx, b, handle);
+ torture_assert(tctx, ret, "ClosePrinter failed");
+
+ /* Now let's see if we have admin rights to it. */
+ ret = test_OpenPrinterAsAdmin(tctx, b, printername);
+ torture_assert(tctx, ret == true,
+ "OpenPrinterEx as admin failed unexpectedly.");
+
+ ret = test_OpenPrinterEx(tctx, b, handle, printername, SERVER_EXECUTE);
+ torture_assert(tctx, ret == true, "OpenPrinterEx failed.");
+
+ return true;
+}
+
+static bool test_GetPrinterData(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *value_name,
+ WERROR expected_werr,
+ uint32_t expected_value)
+{
+ NTSTATUS status;
+ struct spoolss_GetPrinterData gpd;
+ uint32_t needed;
+ enum winreg_Type type;
+ uint8_t *data = talloc_zero_array(tctx, uint8_t, 4);
+
+ torture_comment(tctx, "Testing GetPrinterData(%s).\n", value_name);
+ gpd.in.handle = handle;
+ gpd.in.value_name = value_name;
+ gpd.in.offered = 4;
+ gpd.out.needed = &needed;
+ gpd.out.type = &type;
+ gpd.out.data = data;
+
+ status = dcerpc_spoolss_GetPrinterData_r(b, tctx, &gpd);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinterData failed.");
+ torture_assert_werr_equal(tctx, gpd.out.result, expected_werr,
+ "GetPrinterData did not return expected error value.");
+
+ if (W_ERROR_IS_OK(expected_werr)) {
+ uint32_t value = IVAL(data, 0);
+ torture_assert_int_equal(tctx, value,
+ expected_value,
+ talloc_asprintf(tctx, "GetPrinterData for %s did not return expected value.", value_name));
+ }
+ return true;
+}
+
+static bool test_EnumPrinters(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct test_spoolss_win_context *ctx,
+ uint32_t initial_blob_size)
+{
+ NTSTATUS status;
+ struct spoolss_EnumPrinters ep;
+ DATA_BLOB blob = data_blob_talloc_zero(ctx, initial_blob_size);
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_PrinterInfo *info;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ep.in.flags = PRINTER_ENUM_NAME;
+ ep.in.server = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ ep.in.level = 2;
+ ep.in.buffer = &blob;
+ ep.in.offered = initial_blob_size;
+ ep.out.needed = &needed;
+ ep.out.count = &count;
+ ep.out.info = &info;
+
+ status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &ep);
+ torture_assert_ntstatus_ok(tctx, status, "EnumPrinters failed.");
+
+ if (W_ERROR_EQUAL(ep.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(ctx, needed);
+ ep.in.buffer = &blob;
+ ep.in.offered = needed;
+ status = dcerpc_spoolss_EnumPrinters_r(b, ctx, &ep);
+ torture_assert_ntstatus_ok(tctx, status,"EnumPrinters failed.");
+ }
+
+ torture_assert_werr_ok(tctx, ep.out.result, "EnumPrinters failed.");
+
+ ctx->printer_count = count;
+ ctx->printer_info = info;
+
+ torture_comment(tctx, "Found %d printer(s).\n", ctx->printer_count);
+
+ return true;
+}
+
+static bool test_GetPrinter(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ struct test_spoolss_win_context *ctx,
+ uint32_t level,
+ uint32_t initial_blob_size)
+{
+ NTSTATUS status;
+ struct spoolss_GetPrinter gp;
+ DATA_BLOB blob = data_blob_talloc_zero(ctx, initial_blob_size);
+ uint32_t needed;
+
+ torture_comment(tctx, "Test GetPrinter level %d\n", level);
+
+ gp.in.handle = handle;
+ gp.in.level = level;
+ gp.in.buffer = (initial_blob_size == 0)?NULL:&blob;
+ gp.in.offered = initial_blob_size;
+ gp.out.needed = &needed;
+
+ status = dcerpc_spoolss_GetPrinter_r(b, tctx, &gp);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed");
+
+ if (W_ERROR_EQUAL(gp.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(ctx, needed);
+ gp.in.buffer = &blob;
+ gp.in.offered = needed;
+ status = dcerpc_spoolss_GetPrinter_r(b, tctx, &gp);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinter failed");
+ }
+
+ torture_assert_werr_ok(tctx, gp.out.result, "GetPrinter failed");
+
+ ctx->current_info = gp.out.info;
+
+ if (level == 2 && gp.out.info) {
+ ctx->printer_has_driver = gp.out.info->info2.drivername &&
+ strlen(gp.out.info->info2.drivername);
+ }
+
+ return true;
+}
+
+static bool test_EnumJobs(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_EnumJobs ej;
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, 1024);
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_JobInfo *info;
+
+ torture_comment(tctx, "Test EnumJobs\n");
+
+ ZERO_STRUCT(ej);
+ ej.in.handle = handle;
+ ej.in.firstjob = 0;
+ ej.in.numjobs = 0;
+ ej.in.level = 2;
+ ej.in.buffer = &blob;
+ ej.in.offered = 1024;
+ ej.out.needed = &needed;
+ ej.out.count = &count;
+ ej.out.info = &info;
+
+ status = dcerpc_spoolss_EnumJobs_r(b, tctx, &ej);
+ torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
+ if (W_ERROR_EQUAL(ej.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(tctx, needed);
+ ej.in.offered = needed;
+ ej.in.buffer = &blob;
+ status = dcerpc_spoolss_EnumJobs_r(b, tctx, &ej);
+ torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
+ }
+ torture_assert_werr_ok(tctx, ej.out.result, "EnumJobs failed");
+
+ return true;
+}
+
+static bool test_GetPrinterDriver2(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct test_spoolss_win_context *ctx,
+ struct policy_handle *handle)
+{
+ NTSTATUS status;
+ struct spoolss_GetPrinterDriver2 gpd2;
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, 87424);
+ uint32_t needed;
+ uint32_t server_major_version;
+ uint32_t server_minor_version;
+
+ torture_comment(tctx, "Testing GetPrinterDriver2\n");
+
+ gpd2.in.handle = handle;
+ gpd2.in.architecture = "Windows NT x86";
+ gpd2.in.level = 101;
+ gpd2.in.buffer = &blob;
+ gpd2.in.offered = 87424;
+ gpd2.in.client_major_version = 3;
+ gpd2.in.client_minor_version = 0;
+ gpd2.out.needed = &needed;
+ gpd2.out.server_major_version = &server_major_version;
+ gpd2.out.server_minor_version = &server_minor_version;
+
+ status = dcerpc_spoolss_GetPrinterDriver2_r(b, tctx, &gpd2);
+ torture_assert_ntstatus_ok(tctx, status, "GetPrinterDriver2 failed");
+
+ if (ctx->printer_has_driver) {
+ torture_assert_werr_ok(tctx, gpd2.out.result,
+ "GetPrinterDriver2 failed.");
+ }
+
+ return true;
+}
+
+static bool test_EnumForms(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ uint32_t initial_blob_size)
+{
+ NTSTATUS status;
+ struct spoolss_EnumForms ef;
+ DATA_BLOB blob = data_blob_talloc_zero(tctx, initial_blob_size);
+ uint32_t needed;
+ uint32_t count;
+ union spoolss_FormInfo *info;
+
+ torture_comment(tctx, "Testing EnumForms\n");
+
+ ef.in.handle = handle;
+ ef.in.level = 1;
+ ef.in.buffer = (initial_blob_size == 0)?NULL:&blob;
+ ef.in.offered = initial_blob_size;
+ ef.out.needed = &needed;
+ ef.out.count = &count;
+ ef.out.info = &info;
+
+ status = dcerpc_spoolss_EnumForms_r(b, tctx, &ef);
+ torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
+
+ if (W_ERROR_EQUAL(ef.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ blob = data_blob_talloc_zero(tctx, needed);
+ ef.in.buffer = &blob;
+ ef.in.offered = needed;
+ status = dcerpc_spoolss_EnumForms_r(b, tctx, &ef);
+ torture_assert_ntstatus_ok(tctx, status, "EnumForms failed");
+ }
+
+ torture_assert_werr_ok(tctx, ef.out.result, "EnumForms failed");
+
+ return true;
+}
+
+static bool test_EnumPrinterKey(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char* key,
+ struct test_spoolss_win_context *ctx)
+{
+ NTSTATUS status;
+ struct spoolss_EnumPrinterKey epk;
+ uint32_t needed = 0;
+ union spoolss_KeyNames key_buffer;
+ uint32_t _ndr_size;
+
+ torture_comment(tctx, "Testing EnumPrinterKey(%s)\n", key);
+
+ epk.in.handle = handle;
+ epk.in.key_name = talloc_strdup(tctx, key);
+ epk.in.offered = 0;
+ epk.out.needed = &needed;
+ epk.out.key_buffer = &key_buffer;
+ epk.out._ndr_size = &_ndr_size;
+
+ status = dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &epk);
+ torture_assert_ntstatus_ok(tctx, status, "EnumPrinterKey failed");
+
+ if (W_ERROR_EQUAL(epk.out.result, WERR_MORE_DATA)) {
+ epk.in.offered = needed;
+ status = dcerpc_spoolss_EnumPrinterKey_r(b, tctx, &epk);
+ torture_assert_ntstatus_ok(tctx, status,
+ "EnumPrinterKey failed");
+ }
+
+ torture_assert_werr_ok(tctx, epk.out.result, "EnumPrinterKey failed");
+
+ ctx->printer_keys = key_buffer.string_array;
+
+ return true;
+}
+
+static bool test_EnumPrinterDataEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key,
+ uint32_t initial_blob_size,
+ WERROR expected_error)
+{
+ NTSTATUS status;
+ struct spoolss_EnumPrinterDataEx epde;
+ struct spoolss_PrinterEnumValues *info;
+ uint32_t needed;
+ uint32_t count;
+
+ torture_comment(tctx, "Testing EnumPrinterDataEx(%s)\n", key);
+
+ epde.in.handle = handle;
+ epde.in.key_name = talloc_strdup(tctx, key);
+ epde.in.offered = 0;
+ epde.out.needed = &needed;
+ epde.out.count = &count;
+ epde.out.info = &info;
+
+ status = dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &epde);
+ torture_assert_ntstatus_ok(tctx, status, "EnumPrinterDataEx failed.");
+ if (W_ERROR_EQUAL(epde.out.result, WERR_MORE_DATA)) {
+ epde.in.offered = needed;
+ status = dcerpc_spoolss_EnumPrinterDataEx_r(b, tctx, &epde);
+ torture_assert_ntstatus_ok(tctx, status,
+ "EnumPrinterDataEx failed.");
+ }
+
+ torture_assert_werr_equal(tctx, epde.out.result, expected_error,
+ "EnumPrinterDataEx failed.");
+
+ return true;
+}
+
+static bool test_WinXP(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ bool ret = true;
+ struct test_spoolss_win_context *ctx, *tmp_ctx;
+ struct policy_handle handle01, handle02, handle03, handle04;
+ /* Sometimes a handle stays unused. In order to make this clear in the
+ * code, the unused_handle structures are used for that. */
+ struct policy_handle unused_handle1, unused_handle2;
+ char *server_name;
+ uint32_t i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ctx = talloc_zero(tctx, struct test_spoolss_win_context);
+ tmp_ctx = talloc_zero(tctx, struct test_spoolss_win_context);
+
+ ret &= test_OpenPrinterSequence(tctx, p, &handle01);
+ ret &= test_GetPrinterData(tctx, b, &handle01,"UISingleJobStatusString",
+ WERR_INVALID_PARAMETER, 0);
+ torture_comment(tctx, "Skip RemoteFindNextPrinterChangeNotifyEx test\n");
+
+ server_name = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(p));
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle1, server_name, 0);
+
+ ret &= test_EnumPrinters(tctx, p, ctx, 1024);
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle02, server_name, 0);
+ ret &= test_GetPrinterData(tctx, b, &handle02, "MajorVersion", WERR_OK,
+ 3);
+ ret &= test_ClosePrinter(tctx, b, &handle02);
+
+ /* If no printers were found, skip all tests that need a printer */
+ if (ctx->printer_count == 0) {
+ goto end_testWinXP;
+ }
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle02,
+ ctx->printer_info[0].info2.printername,
+ PRINTER_ACCESS_USE);
+ ret &= test_GetPrinter(tctx, b, &handle02, ctx, 2, 0);
+
+ torture_assert_str_equal(tctx, ctx->current_info->info2.printername,
+ ctx->printer_info[0].info2.printername,
+ "GetPrinter returned unexpected printername");
+ /*FIXME: Test more components of the PrinterInfo2 struct */
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle03,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_GetPrinter(tctx, b, &handle03, ctx, 0, 1164);
+ ret &= test_GetPrinter(tctx, b, &handle03, ctx, 2, 0);
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle04,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_GetPrinter(tctx, b, &handle04, ctx, 2, 0);
+ ret &= test_ClosePrinter(tctx, b, &handle04);
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle04,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_GetPrinter(tctx, b, &handle04, ctx, 2, 4096);
+ ret &= test_ClosePrinter(tctx, b, &handle04);
+
+ ret &= test_OpenPrinterAsAdmin(tctx, b,
+ ctx->printer_info[0].info2.printername);
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle04,
+ ctx->printer_info[0].info2.printername, PRINTER_READ);
+ ret &= test_GetPrinterData(tctx, b, &handle04,"UISingleJobStatusString",
+ WERR_FILE_NOT_FOUND, 0);
+ torture_comment(tctx, "Skip RemoteFindNextPrinterChangeNotifyEx test\n");
+
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle2,
+ ctx->printer_info[0].info2.printername, 0);
+
+ ret &= test_EnumJobs(tctx, b, &handle04);
+ ret &= test_GetPrinter(tctx, b, &handle04, ctx, 2, 4096);
+
+ ret &= test_ClosePrinter(tctx, b, &unused_handle2);
+ ret &= test_ClosePrinter(tctx, b, &handle04);
+
+ ret &= test_EnumPrinters(tctx, p, ctx, 1556);
+ ret &= test_GetPrinterDriver2(tctx, b, ctx, &handle03);
+ ret &= test_EnumForms(tctx, b, &handle03, 0);
+
+ ret &= test_EnumPrinterKey(tctx, b, &handle03, "", ctx);
+
+ for (i=0; ctx->printer_keys && ctx->printer_keys[i] != NULL; i++) {
+
+ ret &= test_EnumPrinterKey(tctx, b, &handle03,
+ ctx->printer_keys[i],
+ tmp_ctx);
+ ret &= test_EnumPrinterDataEx(tctx, b, &handle03,
+ ctx->printer_keys[i], 0,
+ WERR_OK);
+ }
+
+ ret &= test_EnumPrinterDataEx(tctx, b, &handle03, "", 0,
+ WERR_INVALID_PARAMETER);
+
+ ret &= test_GetPrinter(tctx, b, &handle03, tmp_ctx, 2, 0);
+
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle2,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_ClosePrinter(tctx, b, &unused_handle2);
+
+ ret &= test_GetPrinter(tctx, b, &handle03, tmp_ctx, 2, 2556);
+
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle2,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_ClosePrinter(tctx, b, &unused_handle2);
+
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle2,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_ClosePrinter(tctx, b, &unused_handle2);
+
+ ret &= test_GetPrinter(tctx, b, &handle03, tmp_ctx, 7, 0);
+
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle2,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_ClosePrinter(tctx, b, &unused_handle2);
+
+ ret &= test_ClosePrinter(tctx, b, &handle03);
+
+ ret &= test_OpenPrinterEx(tctx, b, &unused_handle2,
+ ctx->printer_info[0].info2.printername, 0);
+ ret &= test_ClosePrinter(tctx, b, &unused_handle2);
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle03, server_name, 0);
+ ret &= test_GetPrinterData(tctx, b, &handle03, "W3SvcInstalled",
+ WERR_OK, 0);
+ ret &= test_ClosePrinter(tctx, b, &handle03);
+
+ ret &= test_ClosePrinter(tctx, b, &unused_handle1);
+ ret &= test_ClosePrinter(tctx, b, &handle02);
+
+ ret &= test_OpenPrinterEx(tctx, b, &handle02,
+ ctx->printer_info[0].info2.sharename, 0);
+ ret &= test_GetPrinter(tctx, b, &handle02, tmp_ctx, 2, 0);
+ ret &= test_ClosePrinter(tctx, b, &handle02);
+
+end_testWinXP:
+ ret &= test_ClosePrinter(tctx, b, &handle01);
+
+ talloc_free(tmp_ctx);
+ talloc_free(ctx);
+ return ret;
+}
+
+struct torture_suite *torture_rpc_spoolss_win(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "spoolss.win");
+
+ struct torture_rpc_tcase *tcase = torture_suite_add_rpc_iface_tcase(suite,
+ "win", &ndr_table_spoolss);
+
+ torture_rpc_tcase_add_test(tcase, "testWinXP", test_WinXP);
+
+ return suite;
+}
+
diff --git a/source4/torture/rpc/srvsvc.c b/source4/torture/rpc/srvsvc.c
new file mode 100644
index 0000000..c777f36
--- /dev/null
+++ b/source4/torture/rpc/srvsvc.c
@@ -0,0 +1,1206 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for srvsvc rpc operations
+
+ Copyright (C) Stefan (metze) Metzmacher 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "torture/rpc/torture_rpc.h"
+
+/**************************/
+/* srvsvc_NetCharDev */
+/**************************/
+static bool test_NetCharDevGetInfo(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *devname)
+{
+ NTSTATUS status;
+ struct srvsvc_NetCharDevGetInfo r;
+ union srvsvc_NetCharDevInfo info;
+ uint32_t levels[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.device_name = devname;
+ r.out.info = &info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ r.in.level = levels[i];
+ torture_comment(tctx, "Testing NetCharDevGetInfo level %u on device '%s'\n",
+ r.in.level, r.in.device_name);
+ status = dcerpc_srvsvc_NetCharDevGetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetCharDevGetInfo failed");
+ torture_assert_werr_ok(tctx, r.out.result, "NetCharDevGetInfo failed");
+ }
+
+ return true;
+}
+
+static bool test_NetCharDevControl(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *devname)
+{
+ NTSTATUS status;
+ struct srvsvc_NetCharDevControl r;
+ uint32_t opcodes[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.device_name = devname;
+
+ for (i=0;i<ARRAY_SIZE(opcodes);i++) {
+ ZERO_STRUCT(r.out);
+ r.in.opcode = opcodes[i];
+ torture_comment(tctx, "Testing NetCharDevControl opcode %u on device '%s'\n",
+ r.in.opcode, r.in.device_name);
+ status = dcerpc_srvsvc_NetCharDevControl_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetCharDevControl failed");
+ torture_assert_werr_ok(tctx, r.out.result, "NetCharDevControl failed");
+ }
+
+ return true;
+}
+
+static bool test_NetCharDevEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetCharDevEnum r;
+ struct srvsvc_NetCharDevInfoCtr info_ctr;
+ struct srvsvc_NetCharDevCtr0 c0;
+ struct srvsvc_NetCharDevCtr0 c1;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.info_ctr = &info_ctr;
+ r.out.totalentries = &totalentries;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int j;
+
+ info_ctr.level = levels[i];
+
+ switch(info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr0 = &c1;
+ break;
+ }
+
+ torture_comment(tctx, "Testing NetCharDevEnum level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetCharDevEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetCharDevEnum failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "NetCharDevEnum failed: %s\n", win_errstr(r.out.result));
+ continue;
+ }
+
+ /* call test_NetCharDevGetInfo and test_NetCharDevControl for each returned share */
+ if (info_ctr.level == 1) {
+ for (j=0;j<r.out.info_ctr->ctr.ctr1->count;j++) {
+ const char *device;
+ device = r.out.info_ctr->ctr.ctr1->array[j].device;
+ if (!test_NetCharDevGetInfo(p, tctx, device)) {
+ return false;
+ }
+ if (!test_NetCharDevControl(p, tctx, device)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetCharDevQ */
+/**************************/
+static bool test_NetCharDevQGetInfo(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *devicequeue)
+{
+ NTSTATUS status;
+ struct srvsvc_NetCharDevQGetInfo r;
+ union srvsvc_NetCharDevQInfo info;
+ uint32_t levels[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.queue_name = devicequeue;
+ r.in.user = talloc_asprintf(tctx,"Administrator");
+ r.out.info = &info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ r.in.level = levels[i];
+ torture_comment(tctx, "Testing NetCharDevQGetInfo level %u on devicequeue '%s'\n",
+ r.in.level, r.in.queue_name);
+ status = dcerpc_srvsvc_NetCharDevQGetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetCharDevQGetInfo failed");
+ torture_assert_werr_ok(tctx, r.out.result, "NetCharDevQGetInfo failed");
+ }
+
+ return true;
+}
+
+#if 0
+static bool test_NetCharDevQSetInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ const char *devicequeue)
+{
+ NTSTATUS status;
+ struct srvsvc_NetCharDevQSetInfo r;
+ uint32_t parm_error;
+ uint32_t levels[] = {0, 1};
+ int i;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.queue_name = devicequeue;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ ZERO_STRUCT(r.out);
+ parm_error = 0;
+ r.in.level = levels[i];
+ d_printf("testing NetCharDevQSetInfo level %u on devicequeue '%s'\n",
+ r.in.level, devicequeue);
+ switch (r.in.level) {
+ case 0:
+ r.in.info.info0 = talloc(mem_ctx, struct srvsvc_NetCharDevQInfo0);
+ r.in.info.info0->device = r.in.queue_name;
+ break;
+ case 1:
+ r.in.info.info1 = talloc(mem_ctx, struct srvsvc_NetCharDevQInfo1);
+ r.in.info.info1->device = r.in.queue_name;
+ r.in.info.info1->priority = 0x000;
+ r.in.info.info1->devices = r.in.queue_name;
+ r.in.info.info1->users = 0x000;
+ r.in.info.info1->num_ahead = 0x000;
+ break;
+ default:
+ break;
+ }
+ r.in.parm_error = &parm_error;
+ status = dcerpc_srvsvc_NetCharDevQSetInfo_r(b, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("NetCharDevQSetInfo level %u on devicequeue '%s' failed - %s\n",
+ r.in.level, r.in.queue_name, nt_errstr(status));
+ ret = false;
+ continue;
+ }
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ d_printf("NetCharDevQSetInfo level %u on devicequeue '%s' failed - %s\n",
+ r.in.level, r.in.queue_name, win_errstr(r.out.result));
+ continue;
+ }
+ }
+
+ return ret;
+}
+#endif
+
+static bool test_NetCharDevQEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetCharDevQEnum r;
+ struct srvsvc_NetCharDevQInfoCtr info_ctr;
+ struct srvsvc_NetCharDevQCtr0 c0;
+ struct srvsvc_NetCharDevQCtr1 c1;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.user = talloc_asprintf(tctx,"%s","Administrator");
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ int j;
+
+ info_ctr.level = levels[i];
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ }
+ torture_comment(tctx, "Testing NetCharDevQEnum level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetCharDevQEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetCharDevQEnum failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "NetCharDevQEnum failed: %s\n", win_errstr(r.out.result));
+ continue;
+ }
+
+ /* call test_NetCharDevGetInfo and test_NetCharDevControl for each returned share */
+ if (info_ctr.level == 1) {
+ for (j=0;j<r.out.info_ctr->ctr.ctr1->count;j++) {
+ const char *device;
+ device = r.out.info_ctr->ctr.ctr1->array[j].device;
+ if (!test_NetCharDevQGetInfo(p, tctx, device)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetConn */
+/**************************/
+static bool test_NetConnEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetConnEnum r;
+ struct srvsvc_NetConnInfoCtr info_ctr;
+ struct srvsvc_NetConnCtr0 c0;
+ struct srvsvc_NetConnCtr1 c1;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.path = talloc_asprintf(tctx,"%s","IPC$");
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ info_ctr.level = levels[i];
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ }
+
+ torture_comment(tctx, "Testing NetConnEnum level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetConnEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetConnEnum failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "NetConnEnum failed: %s\n", win_errstr(r.out.result));
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetFile */
+/**************************/
+static bool test_NetFileEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetFileEnum r;
+ struct srvsvc_NetFileInfoCtr info_ctr;
+ struct srvsvc_NetFileCtr2 c2;
+ struct srvsvc_NetFileCtr3 c3;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {2, 3};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.path = NULL;
+ r.in.user = NULL;
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)4096;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ info_ctr.level = levels[i];
+
+ switch (info_ctr.level) {
+ case 2:
+ ZERO_STRUCT(c2);
+ info_ctr.ctr.ctr2 = &c2;
+ break;
+ case 3:
+ ZERO_STRUCT(c3);
+ info_ctr.ctr.ctr3 = &c3;
+ break;
+ }
+ torture_comment(tctx, "Testing NetFileEnum level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetFileEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetFileEnum failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "NetFileEnum failed: %s\n", win_errstr(r.out.result));
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetSess */
+/**************************/
+static bool test_NetSessEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetSessEnum r;
+ struct srvsvc_NetSessInfoCtr info_ctr;
+ struct srvsvc_NetSessCtr0 c0;
+ struct srvsvc_NetSessCtr1 c1;
+ struct srvsvc_NetSessCtr2 c2;
+ struct srvsvc_NetSessCtr10 c10;
+ struct srvsvc_NetSessCtr502 c502;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0, 1, 2, 10, 502};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.client = NULL;
+ r.in.user = NULL;
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ info_ctr.level = levels[i];
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ case 2:
+ ZERO_STRUCT(c2);
+ info_ctr.ctr.ctr2 = &c2;
+ break;
+ case 10:
+ ZERO_STRUCT(c10);
+ info_ctr.ctr.ctr10 = &c10;
+ break;
+ case 502:
+ ZERO_STRUCT(c502);
+ info_ctr.ctr.ctr502 = &c502;
+ break;
+ }
+
+ torture_comment(tctx, "Testing NetSessEnum level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetSessEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetSessEnum failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "NetSessEnum failed: %s\n", win_errstr(r.out.result));
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetShare */
+/**************************/
+static bool test_NetShareCheck(struct dcerpc_pipe *p, struct torture_context *tctx,
+ const char *device_name)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareCheck r;
+ enum srvsvc_ShareType type;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.device_name = device_name;
+ r.out.type = &type;
+
+ torture_comment(tctx,
+ "Testing NetShareCheck on device '%s'\n", r.in.device_name);
+
+ status = dcerpc_srvsvc_NetShareCheck_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "dcerpc_srvsvc_NetShareCheck failed");
+ torture_assert_werr_ok(tctx, r.out.result, "NetShareCheck failed");
+
+ return true;
+}
+
+static bool test_NetShareGetInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *sharename, bool admin)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareGetInfo r;
+ union srvsvc_NetShareInfo info;
+ struct {
+ uint32_t level;
+ WERROR anon_status;
+ WERROR admin_status;
+ } levels[] = {
+ { 0, WERR_OK, WERR_OK },
+ { 1, WERR_OK, WERR_OK },
+ { 2, WERR_ACCESS_DENIED, WERR_OK },
+ { 501, WERR_OK, WERR_OK },
+ { 502, WERR_ACCESS_DENIED, WERR_OK },
+ { 1005, WERR_OK, WERR_OK },
+ };
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.share_name = sharename;
+ r.out.info = &info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ WERROR expected;
+
+ r.in.level = levels[i].level;
+ expected = levels[i].anon_status;
+ if (admin) expected = levels[i].admin_status;
+
+ torture_comment(tctx, "Testing NetShareGetInfo level %u on share '%s'\n",
+ r.in.level, r.in.share_name);
+
+ status = dcerpc_srvsvc_NetShareGetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected, "NetShareGetInfo failed");
+
+ if (r.in.level != 2) continue;
+ if (!r.out.info->info2 || !r.out.info->info2->path) continue;
+ if (!test_NetShareCheck(p, tctx, r.out.info->info2->path)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_NetShareGetInfoAdminFull(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_NetShareGetInfo(tctx, p, "IPC$", true);
+}
+
+static bool test_NetShareGetInfoAdminAnon(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_NetShareGetInfo(tctx, p, "IPC$", false);
+}
+
+static bool test_NetShareAddSetDel(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareAdd a;
+ struct srvsvc_NetShareSetInfo r;
+ struct srvsvc_NetShareGetInfo q;
+ struct srvsvc_NetShareDel d;
+ struct sec_desc_buf sd_buf;
+ union srvsvc_NetShareInfo info;
+ struct {
+ uint32_t level;
+ WERROR expected;
+ } levels[] = {
+ { 0, WERR_INVALID_LEVEL },
+ { 1, WERR_OK },
+ { 2, WERR_OK },
+ { 501, WERR_INVALID_LEVEL },
+ { 502, WERR_OK },
+ { 1004, WERR_OK },
+ { 1005, WERR_OK },
+ { 1006, WERR_OK },
+/* { 1007, WERR_OK }, */
+ { 1501, WERR_OK },
+ };
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ a.in.server_unc = r.in.server_unc = q.in.server_unc = d.in.server_unc =
+ talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.share_name = talloc_strdup(tctx, "testshare");
+
+ info.info2 = talloc(tctx, struct srvsvc_NetShareInfo2);
+ info.info2->name = r.in.share_name;
+ info.info2->type = STYPE_DISKTREE;
+ info.info2->comment = talloc_strdup(tctx, "test comment");
+ info.info2->permissions = 123434566;
+ info.info2->max_users = -1;
+ info.info2->current_users = 0;
+ info.info2->path = talloc_strdup(tctx, "C:\\");
+ info.info2->password = NULL;
+
+ a.in.info = &info;
+ a.in.level = 2;
+ a.in.parm_error = NULL;
+
+ status = dcerpc_srvsvc_NetShareAdd_r(b, tctx, &a);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareAdd level 2 on share 'testshare' failed");
+ torture_assert_werr_ok(tctx, a.out.result, "NetShareAdd level 2 on share 'testshare' failed");
+
+ r.in.parm_error = NULL;
+
+ q.in.level = 502;
+
+ for (i = 0; i < ARRAY_SIZE(levels); i++) {
+
+ r.in.level = levels[i].level;
+ ZERO_STRUCT(r.out);
+
+ torture_comment(tctx, "Testing NetShareSetInfo level %u on share '%s'\n",
+ r.in.level, r.in.share_name);
+
+ switch (levels[i].level) {
+ case 0:
+ info.info0 = talloc(tctx, struct srvsvc_NetShareInfo0);
+ info.info0->name = r.in.share_name;
+ break;
+ case 1:
+ info.info1 = talloc(tctx, struct srvsvc_NetShareInfo1);
+ info.info1->name = r.in.share_name;
+ info.info1->type = STYPE_DISKTREE;
+ info.info1->comment = talloc_strdup(tctx, "test comment 1");
+ break;
+ case 2:
+ info.info2 = talloc(tctx, struct srvsvc_NetShareInfo2);
+ info.info2->name = r.in.share_name;
+ info.info2->type = STYPE_DISKTREE;
+ info.info2->comment = talloc_strdup(tctx, "test comment 2");
+ info.info2->permissions = 0;
+ info.info2->max_users = 2;
+ info.info2->current_users = 1;
+ info.info2->path = talloc_strdup(tctx, "::BLaH::"); /* "C:\\"); */
+ info.info2->password = NULL;
+ break;
+ case 501:
+ info.info501 = talloc(tctx, struct srvsvc_NetShareInfo501);
+ info.info501->name = r.in.share_name;
+ info.info501->type = STYPE_DISKTREE;
+ info.info501->comment = talloc_strdup(tctx, "test comment 501");
+ info.info501->csc_policy = 0;
+ break;
+ case 502:
+ ZERO_STRUCT(sd_buf);
+ info.info502 = talloc(tctx, struct srvsvc_NetShareInfo502);
+ info.info502->name = r.in.share_name;
+ info.info502->type = STYPE_DISKTREE;
+ info.info502->comment = talloc_strdup(tctx, "test comment 502");
+ info.info502->permissions = 0;
+ info.info502->max_users = 502;
+ info.info502->current_users = 1;
+ info.info502->path = talloc_strdup(tctx, "C:\\");
+ info.info502->password = NULL;
+ info.info502->sd_buf = sd_buf;
+ break;
+ case 1004:
+ info.info1004 = talloc(tctx, struct srvsvc_NetShareInfo1004);
+ info.info1004->comment = talloc_strdup(tctx, "test comment 1004");
+ break;
+ case 1005:
+ info.info1005 = talloc(tctx, struct srvsvc_NetShareInfo1005);
+ info.info1005->dfs_flags = 0;
+ break;
+ case 1006:
+ info.info1006 = talloc(tctx, struct srvsvc_NetShareInfo1006);
+ info.info1006->max_users = 1006;
+ break;
+/* case 1007:
+ info.info1007 = talloc(tctx, struct srvsvc_NetShareInfo1007);
+ info.info1007->flags = 0;
+ info.info1007->alternate_directory_name = talloc_strdup(tctx, "test");
+ break;
+*/
+ case 1501:
+ info.info1501 = talloc_zero(tctx, struct sec_desc_buf);
+ break;
+ }
+
+ r.in.info = &info;
+
+ status = dcerpc_srvsvc_NetShareSetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
+ torture_assert_werr_equal(tctx, r.out.result, levels[i].expected, "NetShareSetInfo failed");
+
+ q.in.share_name = r.in.share_name;
+ q.out.info = &info;
+
+ status = dcerpc_srvsvc_NetShareGetInfo_r(b, tctx, &q);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
+ torture_assert_werr_ok(tctx, q.out.result, "NetShareGetInfo failed");
+
+ torture_assert_str_equal(tctx, q.out.info->info502->name, r.in.share_name,
+ "share name invalid");
+
+ switch (levels[i].level) {
+ case 0:
+ break;
+ case 1:
+ torture_assert_str_equal(tctx, q.out.info->info502->comment, "test comment 1", "comment");
+ break;
+ case 2:
+ torture_assert_str_equal(tctx, q.out.info->info2->comment, "test comment 2", "comment");
+ torture_assert_int_equal(tctx, q.out.info->info2->max_users, 2, "max users");
+ torture_assert_str_equal(tctx, q.out.info->info2->path, "C:\\", "path");
+ break;
+ case 501:
+ torture_assert_str_equal(tctx, q.out.info->info501->comment, "test comment 501", "comment");
+ break;
+ case 502:
+ torture_assert_str_equal(tctx, q.out.info->info502->comment, "test comment 502", "comment");
+ torture_assert_int_equal(tctx, q.out.info->info502->max_users, 502, "max users");
+ torture_assert_str_equal(tctx, q.out.info->info502->path, "C:\\", "path");
+ break;
+ case 1004:
+ torture_assert_str_equal(tctx, q.out.info->info1004->comment, "test comment 1004",
+ "comment");
+ break;
+ case 1005:
+ break;
+ case 1006:
+ torture_assert_int_equal(tctx, q.out.info->info1006->max_users, 1006, "Max users");
+ break;
+/* case 1007:
+ break;
+*/
+ case 1501:
+ break;
+ }
+ }
+
+ d.in.share_name = r.in.share_name;
+ d.in.reserved = 0;
+
+ status = dcerpc_srvsvc_NetShareDel_r(b, tctx, &d);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareDel on share 'testshare502' failed");
+ torture_assert_werr_ok(tctx, a.out.result, "NetShareDel on share 'testshare502' failed");
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetShare */
+/**************************/
+static bool test_NetShareEnumAll(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ bool admin)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareEnumAll r;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr0 c0;
+ struct srvsvc_NetShareCtr1 c1;
+ struct srvsvc_NetShareCtr2 c2;
+ struct srvsvc_NetShareCtr501 c501;
+ struct srvsvc_NetShareCtr502 c502;
+ uint32_t totalentries = 0;
+ struct {
+ uint32_t level;
+ WERROR anon_status;
+ WERROR admin_status;
+ } levels[] = {
+ { 0, WERR_OK, WERR_OK },
+ { 1, WERR_OK, WERR_OK },
+ { 2, WERR_ACCESS_DENIED, WERR_OK },
+ { 501, WERR_ACCESS_DENIED, WERR_OK },
+ { 502, WERR_ACCESS_DENIED, WERR_OK },
+ };
+ int i;
+ uint32_t resume_handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info_ctr);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = &resume_handle;
+ r.out.resume_handle = &resume_handle;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+
+ int j;
+ WERROR expected;
+
+ info_ctr.level = levels[i].level;
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ case 2:
+ ZERO_STRUCT(c2);
+ info_ctr.ctr.ctr2 = &c2;
+ break;
+ case 501:
+ ZERO_STRUCT(c501);
+ info_ctr.ctr.ctr501 = &c501;
+ break;
+ case 502:
+ ZERO_STRUCT(c502);
+ info_ctr.ctr.ctr502 = &c502;
+ break;
+ }
+
+ expected = levels[i].anon_status;
+ if (admin) expected = levels[i].admin_status;
+
+ resume_handle = 0;
+
+ torture_comment(tctx, "Testing NetShareEnumAll level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetShareEnumAll_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareEnumAll failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected, "NetShareEnumAll failed");
+
+ /* call srvsvc_NetShareGetInfo for each returned share */
+ if (info_ctr.level == 2 && r.out.info_ctr->ctr.ctr2) {
+ for (j=0;j<r.out.info_ctr->ctr.ctr2->count;j++) {
+ const char *name;
+ name = r.out.info_ctr->ctr.ctr2->array[j].name;
+ if (!test_NetShareGetInfo(tctx, p, name, admin)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_NetShareEnumAllFull(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_NetShareEnumAll(tctx, p, true);
+}
+
+static bool test_NetShareEnumAllAnon(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_NetShareEnumAll(tctx, p, false);
+}
+
+static bool test_NetShareEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p, bool admin)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareEnum r;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr0 c0;
+ struct srvsvc_NetShareCtr1 c1;
+ struct srvsvc_NetShareCtr2 c2;
+ struct srvsvc_NetShareCtr501 c501;
+ struct srvsvc_NetShareCtr502 c502;
+ uint32_t totalentries = 0;
+ struct {
+ uint32_t level;
+ WERROR anon_status;
+ WERROR admin_status;
+ } levels[] = {
+ { 0, WERR_OK, WERR_OK },
+ { 1, WERR_OK, WERR_OK },
+ { 2, WERR_ACCESS_DENIED, WERR_OK },
+ { 501, WERR_INVALID_LEVEL, WERR_INVALID_LEVEL },
+ { 502, WERR_ACCESS_DENIED, WERR_OK },
+ };
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.in.info_ctr = &info_ctr;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ WERROR expected;
+
+ info_ctr.level = levels[i].level;
+
+ switch (info_ctr.level) {
+ case 0:
+ ZERO_STRUCT(c0);
+ info_ctr.ctr.ctr0 = &c0;
+ break;
+ case 1:
+ ZERO_STRUCT(c1);
+ info_ctr.ctr.ctr1 = &c1;
+ break;
+ case 2:
+ ZERO_STRUCT(c2);
+ info_ctr.ctr.ctr2 = &c2;
+ break;
+ case 501:
+ ZERO_STRUCT(c501);
+ info_ctr.ctr.ctr501 = &c501;
+ break;
+ case 502:
+ ZERO_STRUCT(c502);
+ info_ctr.ctr.ctr502 = &c502;
+ break;
+ }
+
+ expected = levels[i].anon_status;
+ if (admin) expected = levels[i].admin_status;
+
+ torture_comment(tctx, "Testing NetShareEnum level %u\n", info_ctr.level);
+ status = dcerpc_srvsvc_NetShareEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetShareEnum failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected, "NetShareEnum failed");
+ }
+
+ return true;
+}
+
+static bool test_NetShareEnumFull(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_NetShareEnum(tctx, p, true);
+}
+
+static bool test_NetShareEnumAnon(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ return test_NetShareEnum(tctx, p, false);
+}
+
+/**************************/
+/* srvsvc_NetSrv */
+/**************************/
+static bool test_NetSrvGetInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetSrvGetInfo r;
+ union srvsvc_NetSrvInfo info;
+ uint32_t levels[] = {100, 101, 102, 502, 503};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ r.in.level = levels[i];
+ r.out.info = &info;
+ torture_comment(tctx, "Testing NetSrvGetInfo level %u\n", r.in.level);
+ status = dcerpc_srvsvc_NetSrvGetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetSrvGetInfo failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "NetSrvGetInfo failed: %s\n", win_errstr(r.out.result));
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetDisk */
+/**************************/
+static bool test_NetDiskEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetDiskEnum r;
+ struct srvsvc_NetDiskInfo info;
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0};
+ int i;
+ uint32_t resume_handle=0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info);
+ ZERO_STRUCT(r);
+
+ r.in.server_unc = NULL;
+ r.in.resume_handle = &resume_handle;
+ r.in.info = &info;
+ r.out.info = &info;
+ r.out.totalentries = &totalentries;
+ r.out.resume_handle = &resume_handle;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ ZERO_STRUCTP(r.out.info);
+ r.in.level = levels[i];
+ torture_comment(tctx, "Testing NetDiskEnum level %u\n", r.in.level);
+ status = dcerpc_srvsvc_NetDiskEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetDiskEnum failed");
+ torture_assert_werr_ok(tctx, r.out.result, "NetDiskEnum failed");
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetTransport */
+/**************************/
+static bool test_NetTransportEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetTransportEnum r;
+ struct srvsvc_NetTransportInfoCtr transports;
+ struct srvsvc_NetTransportCtr0 ctr0;
+ struct srvsvc_NetTransportCtr1 ctr1;
+
+ uint32_t totalentries = 0;
+ uint32_t levels[] = {0, 1};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(transports);
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s", dcerpc_server_name(p));
+ r.in.transports = &transports;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = NULL;
+ r.out.totalentries = &totalentries;
+ r.out.transports = &transports;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ transports.level = levels[i];
+ switch (transports.level) {
+ case 0:
+ ZERO_STRUCT(ctr0);
+ transports.ctr.ctr0 = &ctr0;
+ break;
+ case 1:
+ ZERO_STRUCT(ctr1);
+ transports.ctr.ctr1 = &ctr1;
+ break;
+ }
+ torture_comment(tctx, "Testing NetTransportEnum level %u\n", transports.level);
+ status = dcerpc_srvsvc_NetTransportEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetTransportEnum failed");
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx, "unexpected result: %s\n", win_errstr(r.out.result));
+ }
+ }
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetRemoteTOD */
+/**************************/
+static bool test_NetRemoteTOD(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetRemoteTOD r;
+ struct srvsvc_NetRemoteTODInfo *info = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx,"\\\\%s",dcerpc_server_name(p));
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing NetRemoteTOD\n");
+ status = dcerpc_srvsvc_NetRemoteTOD_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetRemoteTOD failed");
+ torture_assert_werr_ok(tctx, r.out.result, "NetRemoteTOD failed");
+
+ return true;
+}
+
+/**************************/
+/* srvsvc_NetName */
+/**************************/
+
+static bool test_NetNameValidate(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct srvsvc_NetNameValidate r;
+ char *invalidc;
+ char *name;
+ int i, n, min, max;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_unc = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.flags = 0x0;
+
+ d_printf("Testing NetNameValidate\n");
+
+ /* valid path types only between 1 and 13 */
+ for (i = 1; i < 14; i++) {
+
+again:
+ /* let's limit ourselves to a maximum of 4096 bytes */
+ r.in.name = name = talloc_array(tctx, char, 4097);
+ max = 4096;
+ min = 0;
+ n = max;
+
+ while (1) {
+
+ /* Find maximum length accepted by this type */
+ ZERO_STRUCT(r.out);
+ r.in.name_type = i;
+ memset(name, 'A', n);
+ name[n] = '\0';
+
+ status = dcerpc_srvsvc_NetNameValidate_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("NetNameValidate failed while checking maximum size (%s)\n",
+ nt_errstr(status));
+ break;
+ }
+
+ if (W_ERROR_IS_OK(r.out.result)) {
+ min = n;
+ n += (max - min + 1)/2;
+ if (n == min) {
+ /*
+ * We did not move, so
+ * do not loop forever
+ */
+ break;
+ }
+ continue;
+
+ } else {
+ if ((min + 1) >= max) break; /* found it */
+
+ max = n;
+ n -= (max - min)/2;
+ continue;
+ }
+ }
+
+ talloc_free(name);
+
+ d_printf("Maximum length for type %2d, flags %08x: %d\n", i, r.in.flags, max);
+
+ /* find invalid chars for this type check only ASCII between 0x20 and 0x7e */
+
+ invalidc = talloc_strdup(tctx, "");
+
+ for (n = 0x20; n < 0x7e; n++) {
+ r.in.name = name = talloc_asprintf(tctx, "%c", (char)n);
+
+ status = dcerpc_srvsvc_NetNameValidate_r(b, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("NetNameValidate failed while checking valid chars (%s)\n",
+ nt_errstr(status));
+ break;
+ }
+
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ invalidc = talloc_asprintf_append_buffer(invalidc, "%c", (char)n);
+ }
+
+ talloc_free(name);
+ }
+
+ d_printf(" Invalid chars for type %2d, flags %08x: \"%s\"\n", i, r.in.flags, invalidc);
+
+ /* only two values are accepted for flags: 0x0 and 0x80000000 */
+ if (r.in.flags == 0x0) {
+ r.in.flags = 0x80000000;
+ goto again;
+ }
+
+ r.in.flags = 0x0;
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_srvsvc(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "srvsvc");
+ struct torture_rpc_tcase *tcase;
+ struct torture_test *test;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "srvsvc (admin access)", &ndr_table_srvsvc);
+
+ torture_rpc_tcase_add_test(tcase, "NetCharDevEnum", test_NetCharDevEnum);
+ torture_rpc_tcase_add_test(tcase, "NetCharDevQEnum", test_NetCharDevQEnum);
+ torture_rpc_tcase_add_test(tcase, "NetConnEnum", test_NetConnEnum);
+ torture_rpc_tcase_add_test(tcase, "NetFileEnum", test_NetFileEnum);
+ torture_rpc_tcase_add_test(tcase, "NetSessEnum", test_NetSessEnum);
+ torture_rpc_tcase_add_test(tcase, "NetShareEnumAll", test_NetShareEnumAllFull);
+ torture_rpc_tcase_add_test(tcase, "NetSrvGetInfo", test_NetSrvGetInfo);
+ torture_rpc_tcase_add_test(tcase, "NetDiskEnum", test_NetDiskEnum);
+ torture_rpc_tcase_add_test(tcase, "NetTransportEnum", test_NetTransportEnum);
+ torture_rpc_tcase_add_test(tcase, "NetRemoteTOD", test_NetRemoteTOD);
+ torture_rpc_tcase_add_test(tcase, "NetShareEnum", test_NetShareEnumFull);
+ torture_rpc_tcase_add_test(tcase, "NetShareGetInfo", test_NetShareGetInfoAdminFull);
+ test = torture_rpc_tcase_add_test(tcase, "NetShareAddSetDel",
+ test_NetShareAddSetDel);
+ test->dangerous = true;
+ torture_rpc_tcase_add_test(tcase, "NetNameValidate", test_NetNameValidate);
+
+ tcase = torture_suite_add_anon_rpc_iface_tcase(suite,
+ "srvsvc anonymous access",
+ &ndr_table_srvsvc);
+
+ torture_rpc_tcase_add_test(tcase, "NetShareEnumAll",
+ test_NetShareEnumAllAnon);
+ torture_rpc_tcase_add_test(tcase, "NetShareEnum",
+ test_NetShareEnumAnon);
+ torture_rpc_tcase_add_test(tcase, "NetShareGetInfo",
+ test_NetShareGetInfoAdminAnon);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/svcctl.c b/source4/torture/rpc/svcctl.c
new file mode 100644
index 0000000..2962f15
--- /dev/null
+++ b/source4/torture/rpc/svcctl.c
@@ -0,0 +1,828 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for svcctl rpc operations
+
+ Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Guenther Deschner 2008,2009,2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_svcctl_c.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+
+#define TORTURE_DEFAULT_SERVICE "Spooler"
+
+static bool test_OpenSCManager(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *h)
+{
+ struct svcctl_OpenSCManagerW r;
+
+ r.in.MachineName = NULL;
+ r.in.DatabaseName = NULL;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = h;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_OpenSCManagerW_r(b, tctx, &r),
+ "OpenSCManager failed!");
+
+ return true;
+}
+
+static bool test_CloseServiceHandle(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *h)
+{
+ struct svcctl_CloseServiceHandle r;
+
+ r.in.handle = h;
+ r.out.handle = h;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_CloseServiceHandle_r(b, tctx, &r),
+ "CloseServiceHandle failed");
+
+ return true;
+}
+
+static bool test_OpenService(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *h,
+ const char *name,
+ struct policy_handle *s)
+{
+ struct svcctl_OpenServiceW r;
+
+ r.in.scmanager_handle = h;
+ r.in.ServiceName = name;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = s;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_OpenServiceW_r(b, tctx, &r),
+ "OpenServiceW failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "OpenServiceW failed!");
+
+ return true;
+
+}
+
+static bool test_QueryServiceStatus(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceStatus r;
+ struct policy_handle h, s;
+ struct SERVICE_STATUS service_status;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ r.in.handle = &s;
+ r.out.service_status = &service_status;
+
+ status = dcerpc_svcctl_QueryServiceStatus_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceStatus failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceStatus failed!");
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_QueryServiceStatusEx(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceStatusEx r;
+ struct policy_handle h, s;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint32_t info_level = SVC_STATUS_PROCESS_INFO;
+ uint8_t *buffer;
+ uint32_t offered = 0;
+ uint32_t needed = 0;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ buffer = talloc(tctx, uint8_t);
+
+ r.in.handle = &s;
+ r.in.info_level = info_level;
+ r.in.offered = offered;
+ r.out.buffer = buffer;
+ r.out.needed = &needed;
+
+ status = dcerpc_svcctl_QueryServiceStatusEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceStatusEx failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ r.in.offered = needed;
+ buffer = talloc_array(tctx, uint8_t, needed);
+ r.out.buffer = buffer;
+
+ status = dcerpc_svcctl_QueryServiceStatusEx_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceStatusEx failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceStatusEx failed!");
+ }
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_QueryServiceConfigW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceConfigW r;
+ struct QUERY_SERVICE_CONFIG query;
+ struct policy_handle h, s;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint32_t offered = 0;
+ uint32_t needed = 0;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ r.in.handle = &s;
+ r.in.offered = offered;
+ r.out.query = &query;
+ r.out.needed = &needed;
+
+ status = dcerpc_svcctl_QueryServiceConfigW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfigW failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ r.in.offered = needed;
+ status = dcerpc_svcctl_QueryServiceConfigW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfigW failed!");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceConfigW failed!");
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_QueryServiceConfig2W(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceConfig2W r;
+ struct policy_handle h, s;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint32_t info_level = SERVICE_CONFIG_DESCRIPTION;
+ uint8_t *buffer;
+ uint32_t offered = 0;
+ uint32_t needed = 0;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ buffer = talloc(tctx, uint8_t);
+
+ r.in.handle = &s;
+ r.in.info_level = info_level;
+ r.in.offered = offered;
+ r.out.buffer = buffer;
+ r.out.needed = &needed;
+
+ status = dcerpc_svcctl_QueryServiceConfig2W_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ r.in.offered = needed;
+ buffer = talloc_array(tctx, uint8_t, needed);
+ r.out.buffer = buffer;
+
+ status = dcerpc_svcctl_QueryServiceConfig2W_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceConfig2W failed!");
+ }
+
+ r.in.info_level = SERVICE_CONFIG_FAILURE_ACTIONS;
+ r.in.offered = offered;
+ r.out.buffer = buffer;
+ r.out.needed = &needed;
+
+ status = dcerpc_svcctl_QueryServiceConfig2W_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ r.in.offered = needed;
+ buffer = talloc_array(tctx, uint8_t, needed);
+ r.out.buffer = buffer;
+
+ status = dcerpc_svcctl_QueryServiceConfig2W_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceConfig2W failed!");
+ }
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_QueryServiceConfigEx(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceConfigEx r;
+ struct policy_handle h, s;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct SC_RPC_CONFIG_INFOW info;
+ int i;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ for (i=0; i < 16; i++) {
+
+ r.in.hService = s;
+ r.in.dwInfoLevel = i;
+ r.out.pInfo = &info;
+
+ status = dcerpc_svcctl_QueryServiceConfigEx_r(b, tctx, &r);
+ if (i == 8) {
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfigEx failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceConfigEx failed!");
+ } else {
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE, "QueryServiceConfigEx failed!");
+ }
+ }
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_QueryServiceObjectSecurity(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceObjectSecurity r;
+ struct policy_handle h, s;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint8_t *buffer = NULL;
+ uint32_t needed;
+
+ enum ndr_err_code ndr_err;
+ struct security_descriptor sd;
+ DATA_BLOB blob;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ r.in.handle = &s;
+ r.in.security_flags = 0;
+ r.in.offered = 0;
+ r.out.buffer = NULL;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_QueryServiceObjectSecurity_r(b, tctx, &r),
+ "QueryServiceObjectSecurity failed!");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "QueryServiceObjectSecurity failed!");
+
+ r.in.security_flags = SECINFO_DACL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_QueryServiceObjectSecurity_r(b, tctx, &r),
+ "QueryServiceObjectSecurity failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ r.in.offered = needed;
+ buffer = talloc_array(tctx, uint8_t, needed);
+ r.out.buffer = buffer;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_QueryServiceObjectSecurity_r(b, tctx, &r),
+ "QueryServiceObjectSecurity failed!");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "QueryServiceObjectSecurity failed!");
+
+ blob = data_blob_const(buffer, needed);
+
+ ndr_err = ndr_pull_struct_blob(&blob, tctx, &sd,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ if (DEBUGLEVEL >= 1) {
+ NDR_PRINT_DEBUG(security_descriptor, &sd);
+ }
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_SetServiceObjectSecurity(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_QueryServiceObjectSecurity q;
+ struct svcctl_SetServiceObjectSecurity r;
+ struct policy_handle h, s;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ uint8_t *buffer;
+ uint32_t needed;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ q.in.handle = &s;
+ q.in.security_flags = SECINFO_DACL;
+ q.in.offered = 0;
+ q.out.buffer = NULL;
+ q.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_QueryServiceObjectSecurity_r(b, tctx, &q),
+ "QueryServiceObjectSecurity failed!");
+
+ if (W_ERROR_EQUAL(q.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ q.in.offered = needed;
+ buffer = talloc_array(tctx, uint8_t, needed);
+ q.out.buffer = buffer;
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_QueryServiceObjectSecurity_r(b, tctx, &q),
+ "QueryServiceObjectSecurity failed!");
+ }
+
+ torture_assert_werr_ok(tctx, q.out.result,
+ "QueryServiceObjectSecurity failed!");
+
+ r.in.handle = &s;
+ r.in.security_flags = SECINFO_DACL;
+ r.in.buffer = q.out.buffer;
+ r.in.offered = *q.out.needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_SetServiceObjectSecurity_r(b, tctx, &r),
+ "SetServiceObjectSecurity failed!");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "SetServiceObjectSecurity failed!");
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_StartServiceW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_StartServiceW r;
+ struct policy_handle h, s;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ r.in.handle = &s;
+ r.in.NumArgs = 0;
+ r.in.Arguments = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_StartServiceW_r(b, tctx, &r),
+ "StartServiceW failed!");
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_SERVICE_ALREADY_RUNNING,
+ "StartServiceW failed!");
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_ControlService(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_ControlService r;
+ struct policy_handle h, s;
+ struct SERVICE_STATUS service_status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ r.in.handle = &s;
+ r.in.control = 0;
+ r.out.service_status = &service_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_ControlService_r(b, tctx, &r),
+ "ControlService failed!");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "ControlService failed!");
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_ControlServiceExW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_ControlServiceExW r;
+ struct policy_handle h, s;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ union SC_RPC_SERVICE_CONTROL_IN_PARAMSW ControlInParams;
+ union SC_RPC_SERVICE_CONTROL_OUT_PARAMSW ControlOutParams;
+ struct SERVICE_CONTROL_STATUS_REASON_OUT_PARAMS psrOutParams;
+ struct SERVICE_CONTROL_STATUS_REASON_IN_PARAMSW psrInParams;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ ZERO_STRUCT(psrInParams);
+ ZERO_STRUCT(psrOutParams);
+
+ psrInParams.dwReason = SERVICE_STOP_CUSTOM |
+ SERVICE_STOP_REASON_MAJOR_APPLICATION |
+ SERVICE_STOP_REASON_MINOR_ENVIRONMENT;
+ psrInParams.pszComment = "wurst";
+
+ ControlInParams.psrInParams = &psrInParams;
+ ControlOutParams.psrOutParams = &psrOutParams;
+
+ r.in.hService = s;
+ r.in.dwControl = SVCCTL_CONTROL_STOP;
+ r.in.dwInfoLevel = 1;
+ r.in.pControlInParams = &ControlInParams;
+ r.out.pControlOutParams = &ControlOutParams;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_ControlServiceExW_r(b, tctx, &r),
+ "ControlServiceExW failed!");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "ControlServiceExW failed!");
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_EnumServicesStatus(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct svcctl_EnumServicesStatusW r;
+ struct policy_handle h;
+ int i;
+ NTSTATUS status;
+ uint32_t resume_handle = 0;
+ struct ENUM_SERVICE_STATUSW *service = NULL;
+ uint32_t needed = 0;
+ uint32_t services_returned = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ r.in.handle = &h;
+ r.in.type = SERVICE_TYPE_WIN32;
+ r.in.state = SERVICE_STATE_ALL;
+ r.in.offered = 0;
+ r.in.resume_handle = &resume_handle;
+ r.out.service = NULL;
+ r.out.resume_handle = &resume_handle;
+ r.out.services_returned = &services_returned;
+ r.out.needed = &needed;
+
+ status = dcerpc_svcctl_EnumServicesStatusW_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumServicesStatus failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.in.offered = needed;
+ r.out.service = talloc_array(tctx, uint8_t, needed);
+
+ status = dcerpc_svcctl_EnumServicesStatusW_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumServicesStatus failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "EnumServicesStatus failed");
+ }
+
+ if (services_returned > 0) {
+
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct ndr_pull *ndr;
+
+ blob.length = r.in.offered;
+ blob.data = talloc_steal(tctx, r.out.service);
+
+ ndr = ndr_pull_init_blob(&blob, tctx);
+
+ service = talloc_array(tctx, struct ENUM_SERVICE_STATUSW, services_returned);
+ if (!service) {
+ return false;
+ }
+
+ ndr_err = ndr_pull_ENUM_SERVICE_STATUSW_array(
+ ndr, services_returned, service);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ }
+
+ for(i = 0; i < services_returned; i++) {
+
+ torture_assert(tctx, service[i].service_name,
+ "Service without name returned!");
+
+ printf("%-20s \"%s\", Type: %d, State: %d\n",
+ service[i].service_name, service[i].display_name,
+ service[i].status.type, service[i].status.state);
+ }
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_EnumDependentServicesW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_EnumDependentServicesW r;
+ struct policy_handle h, s;
+ uint32_t needed;
+ uint32_t services_returned;
+ uint32_t i;
+ uint32_t states[] = { SERVICE_STATE_ACTIVE,
+ SERVICE_STATE_INACTIVE,
+ SERVICE_STATE_ALL };
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s))
+ return false;
+
+ r.in.service = &s;
+ r.in.offered = 0;
+ r.in.state = 0;
+ r.out.service_status = NULL;
+ r.out.services_returned = &services_returned;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_EnumDependentServicesW_r(b, tctx, &r),
+ "EnumDependentServicesW failed!");
+
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "EnumDependentServicesW failed!");
+
+ for (i=0; i<ARRAY_SIZE(states); i++) {
+
+ r.in.state = states[i];
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_EnumDependentServicesW_r(b, tctx, &r),
+ "EnumDependentServicesW failed!");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ r.in.offered = needed;
+ r.out.service_status = talloc_array(tctx, uint8_t, needed);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_svcctl_EnumDependentServicesW_r(b, tctx, &r),
+ "EnumDependentServicesW failed!");
+
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "EnumDependentServicesW failed");
+ }
+
+ if (!test_CloseServiceHandle(b, tctx, &s))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_SCManager(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct policy_handle h;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenSCManager(b, tctx, &h))
+ return false;
+
+ if (!test_CloseServiceHandle(b, tctx, &h))
+ return false;
+
+ return true;
+}
+
+static bool test_ChangeServiceConfigW(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct svcctl_ChangeServiceConfigW r;
+ struct svcctl_QueryServiceConfigW q;
+ struct policy_handle h, s;
+ NTSTATUS status;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct QUERY_SERVICE_CONFIG query;
+ bool ok;
+
+ uint32_t offered = 0;
+ uint32_t needed = 0;
+
+ ok = test_OpenSCManager(b, tctx, &h);
+ if (!ok) {
+ return false;
+ }
+
+ ok = test_OpenService(b, tctx, &h, TORTURE_DEFAULT_SERVICE, &s);
+ if (!ok) {
+ return false;
+ }
+
+ q.in.handle = &s;
+ q.in.offered = offered;
+ q.out.query = &query;
+ q.out.needed = &needed;
+
+ status = dcerpc_svcctl_QueryServiceConfigW_r(b, tctx, &q);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfigW failed!");
+
+ if (W_ERROR_EQUAL(q.out.result, WERR_INSUFFICIENT_BUFFER)) {
+ q.in.offered = needed;
+ status = dcerpc_svcctl_QueryServiceConfigW_r(b, tctx, &q);
+ torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfigW failed!");
+ }
+ torture_assert_werr_ok(tctx, q.out.result, "QueryServiceConfigW failed!");
+
+ r.in.handle = &s;
+ r.in.type = query.service_type;
+ r.in.start_type = query.start_type;
+ r.in.error_control = query.error_control;
+
+ /*
+ * according to MS-SCMR 3.1.4.11 NULL params are supposed to leave the
+ * existing values intact.
+ */
+
+ r.in.binary_path = NULL;
+ r.in.load_order_group = NULL;
+ r.in.dependencies = NULL;
+ r.in.dwDependSize = 0;
+ r.in.service_start_name = NULL;
+ r.in.password = NULL;
+ r.in.dwPwSize = 0;
+ r.in.display_name = NULL;
+ r.in.tag_id = NULL;
+ r.out.tag_id = NULL;
+
+ status = dcerpc_svcctl_ChangeServiceConfigW_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "ChangeServiceConfigW failed!");
+ torture_assert_werr_ok(tctx, r.out.result, "ChangeServiceConfigW failed!");
+
+ ok = test_CloseServiceHandle(b, tctx, &s);
+ if (!ok) {
+ return false;
+ }
+
+ ok = test_CloseServiceHandle(b, tctx, &h);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_svcctl(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "svcctl");
+ struct torture_rpc_tcase *tcase;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "svcctl", &ndr_table_svcctl);
+
+ torture_rpc_tcase_add_test(tcase, "SCManager",
+ test_SCManager);
+ torture_rpc_tcase_add_test(tcase, "EnumServicesStatus",
+ test_EnumServicesStatus);
+ torture_rpc_tcase_add_test(tcase, "EnumDependentServicesW",
+ test_EnumDependentServicesW);
+ torture_rpc_tcase_add_test(tcase, "QueryServiceStatus",
+ test_QueryServiceStatus);
+ torture_rpc_tcase_add_test(tcase, "QueryServiceStatusEx",
+ test_QueryServiceStatusEx);
+ torture_rpc_tcase_add_test(tcase, "QueryServiceConfigW",
+ test_QueryServiceConfigW);
+ torture_rpc_tcase_add_test(tcase, "QueryServiceConfig2W",
+ test_QueryServiceConfig2W);
+ torture_rpc_tcase_add_test(tcase, "QueryServiceConfigEx",
+ test_QueryServiceConfigEx);
+ torture_rpc_tcase_add_test(tcase, "QueryServiceObjectSecurity",
+ test_QueryServiceObjectSecurity);
+ torture_rpc_tcase_add_test(tcase, "SetServiceObjectSecurity",
+ test_SetServiceObjectSecurity);
+ torture_rpc_tcase_add_test(tcase, "StartServiceW",
+ test_StartServiceW);
+ torture_rpc_tcase_add_test(tcase, "ControlService",
+ test_ControlService);
+ torture_rpc_tcase_add_test(tcase, "ControlServiceExW",
+ test_ControlServiceExW);
+ torture_rpc_tcase_add_test(tcase, "ChangeServiceConfigW",
+ test_ChangeServiceConfigW);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/testjoin.c b/source4/torture/rpc/testjoin.c
new file mode 100644
index 0000000..6fb5f86
--- /dev/null
+++ b/source4/torture/rpc/testjoin.c
@@ -0,0 +1,915 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ utility code to join/leave a domain
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ this code is used by other torture modules to join/leave a domain
+ as either a member, bdc or thru a trust relationship
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "libnet/libnet.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+
+#include "libcli/auth/libcli_auth.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/security/security.h"
+#include "param/param.h"
+#include "source3/rpc_client/init_samr.h"
+
+struct test_join {
+ struct dcerpc_pipe *p;
+ struct policy_handle user_handle;
+ struct policy_handle domain_handle;
+ struct libnet_JoinDomain *libnet_r;
+ struct dom_sid *dom_sid;
+ const char *dom_netbios_name;
+ const char *dom_dns_name;
+ struct dom_sid *user_sid;
+ struct GUID user_guid;
+ const char *netbios_name;
+};
+
+
+static NTSTATUS DeleteUser_byname(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *name)
+{
+ NTSTATUS status;
+ struct samr_DeleteUser d;
+ struct policy_handle user_handle;
+ uint32_t rid;
+ struct samr_LookupNames n;
+ struct samr_Ids rids, types;
+ struct lsa_String sname;
+ struct samr_OpenUser r;
+
+ sname.string = name;
+
+ n.in.domain_handle = handle;
+ n.in.num_names = 1;
+ n.in.names = &sname;
+ n.out.rids = &rids;
+ n.out.types = &types;
+
+ status = dcerpc_samr_LookupNames_r(b, mem_ctx, &n);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (NT_STATUS_IS_OK(n.out.result)) {
+ rid = n.out.rids->ids[0];
+ } else {
+ return n.out.result;
+ }
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.user_handle = &user_handle;
+
+ status = dcerpc_samr_OpenUser_r(b, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "OpenUser(%s) failed - %s\n", name, nt_errstr(status));
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "OpenUser(%s) failed - %s\n", name, nt_errstr(r.out.result));
+ return r.out.result;
+ }
+
+ d.in.user_handle = &user_handle;
+ d.out.user_handle = &user_handle;
+ status = dcerpc_samr_DeleteUser_r(b, mem_ctx, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(d.out.result)) {
+ return d.out.result;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create a test user in the domain
+ an opaque pointer is returned. Pass it to torture_leave_domain()
+ when finished
+*/
+
+struct test_join *torture_create_testuser_max_pwlen(struct torture_context *tctx,
+ const char *username,
+ const char *domain,
+ uint16_t acct_type,
+ const char **random_password,
+ int max_pw_len)
+{
+ NTSTATUS status;
+ struct samr_Connect c;
+ struct samr_CreateUser2 r;
+ struct samr_OpenDomain o;
+ struct samr_LookupDomain l;
+ struct dom_sid2 *sid = NULL;
+ struct samr_GetUserPwInfo pwp;
+ struct samr_PwInfo info;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ struct policy_handle handle;
+ uint32_t access_granted;
+ uint32_t rid;
+ DATA_BLOB session_key;
+ struct lsa_String name;
+
+ int policy_min_pw_len = 0;
+ struct test_join *join;
+ char *random_pw;
+ const char *dc_binding = torture_setting_string(tctx, "dc_binding", NULL);
+ struct dcerpc_binding_handle *b = NULL;
+ join = talloc(NULL, struct test_join);
+ if (join == NULL) {
+ return NULL;
+ }
+
+ ZERO_STRUCTP(join);
+
+ torture_comment(tctx, "Connecting to SAMR\n");
+
+ if (dc_binding) {
+ status = dcerpc_pipe_connect(join,
+ &join->p,
+ dc_binding,
+ &ndr_table_samr,
+ samba_cmdline_get_creds(),
+ NULL, tctx->lp_ctx);
+
+ } else {
+ status = torture_rpc_connection(tctx,
+ &join->p,
+ &ndr_table_samr);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ b = join->p->binding_handle;
+
+ c.in.system_name = NULL;
+ c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ c.out.connect_handle = &handle;
+
+ status = dcerpc_samr_Connect_r(b, join, &c);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ torture_comment(tctx, "samr_Connect failed - %s\n", errstr);
+ return NULL;
+ }
+ if (!NT_STATUS_IS_OK(c.out.result)) {
+ const char *errstr = nt_errstr(c.out.result);
+ torture_comment(tctx, "samr_Connect failed - %s\n", errstr);
+ return NULL;
+ }
+
+ if (domain) {
+ torture_comment(tctx, "Opening domain %s\n", domain);
+
+ name.string = domain;
+ l.in.connect_handle = &handle;
+ l.in.domain_name = &name;
+ l.out.sid = &sid;
+
+ status = dcerpc_samr_LookupDomain_r(b, join, &l);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+ if (!NT_STATUS_IS_OK(l.out.result)) {
+ torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(l.out.result));
+ goto failed;
+ }
+ } else {
+ struct samr_EnumDomains e;
+ uint32_t resume_handle = 0, num_entries;
+ struct samr_SamArray *sam;
+ int i;
+
+ e.in.connect_handle = &handle;
+ e.in.buf_size = (uint32_t)-1;
+ e.in.resume_handle = &resume_handle;
+ e.out.sam = &sam;
+ e.out.num_entries = &num_entries;
+ e.out.resume_handle = &resume_handle;
+
+ status = dcerpc_samr_EnumDomains_r(b, join, &e);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "EnumDomains failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+ if (!NT_STATUS_IS_OK(e.out.result)) {
+ torture_comment(tctx, "EnumDomains failed - %s\n", nt_errstr(e.out.result));
+ goto failed;
+ }
+ if ((num_entries != 2) || (sam && sam->count != 2)) {
+ torture_comment(tctx, "unexpected number of domains\n");
+ goto failed;
+ }
+ for (i=0; i < 2; i++) {
+ if (!strequal(sam->entries[i].name.string, "builtin")) {
+ domain = sam->entries[i].name.string;
+ break;
+ }
+ }
+ if (domain) {
+ torture_comment(tctx, "Opening domain %s\n", domain);
+
+ name.string = domain;
+ l.in.connect_handle = &handle;
+ l.in.domain_name = &name;
+ l.out.sid = &sid;
+
+ status = dcerpc_samr_LookupDomain_r(b, join, &l);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+ if (!NT_STATUS_IS_OK(l.out.result)) {
+ torture_comment(tctx, "LookupDomain failed - %s\n", nt_errstr(l.out.result));
+ goto failed;
+ }
+ } else {
+ torture_comment(tctx, "cannot proceed without domain name\n");
+ goto failed;
+ }
+ }
+
+ talloc_steal(join, *l.out.sid);
+ join->dom_sid = *l.out.sid;
+ join->dom_netbios_name = talloc_strdup(join, domain);
+ if (!join->dom_netbios_name) goto failed;
+
+ o.in.connect_handle = &handle;
+ o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ o.in.sid = *l.out.sid;
+ o.out.domain_handle = &join->domain_handle;
+
+ status = dcerpc_samr_OpenDomain_r(b, join, &o);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+ if (!NT_STATUS_IS_OK(o.out.result)) {
+ torture_comment(tctx, "OpenDomain failed - %s\n", nt_errstr(o.out.result));
+ goto failed;
+ }
+
+ torture_comment(tctx, "Creating account %s\n", username);
+
+again:
+ name.string = username;
+ r.in.domain_handle = &join->domain_handle;
+ r.in.account_name = &name;
+ r.in.acct_flags = acct_type;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.user_handle = &join->user_handle;
+ r.out.access_granted = &access_granted;
+ r.out.rid = &rid;
+
+ status = dcerpc_samr_CreateUser2_r(b, join, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "CreateUser2 failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+
+ if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_USER_EXISTS)) {
+ status = DeleteUser_byname(tctx, b, join, &join->domain_handle, name.string);
+ if (NT_STATUS_IS_OK(status)) {
+ goto again;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "CreateUser2 failed - %s\n", nt_errstr(r.out.result));
+ goto failed;
+ }
+
+ join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid);
+
+ pwp.in.user_handle = &join->user_handle;
+ pwp.out.info = &info;
+
+ status = dcerpc_samr_GetUserPwInfo_r(b, join, &pwp);
+ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(pwp.out.result)) {
+ policy_min_pw_len = pwp.out.info->min_password_length;
+ }
+
+ random_pw = generate_random_password(join, MAX(8, policy_min_pw_len), max_pw_len);
+
+ torture_comment(tctx, "Setting account password '%s'\n", random_pw);
+
+ ZERO_STRUCT(u);
+ s.in.user_handle = &join->user_handle;
+ s.in.info = &u;
+ s.in.level = 24;
+
+ u.info24.password_expired = 0;
+
+ status = dcerpc_fetch_session_key(join->p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "SetUserInfo level %u - no session key - %s\n",
+ s.in.level, nt_errstr(status));
+ torture_leave_domain(tctx, join);
+ goto failed;
+ }
+
+ status = init_samr_CryptPassword(random_pw,
+ &session_key,
+ &u.info24.password);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "init_samr_CryptPassword failed");
+
+ status = dcerpc_samr_SetUserInfo_r(b, join, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(s.out.result));
+ goto failed;
+ }
+
+ ZERO_STRUCT(u);
+ s.in.user_handle = &join->user_handle;
+ s.in.info = &u;
+ s.in.level = 21;
+
+ u.info21.acct_flags = acct_type | ACB_PWNOEXP;
+ u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
+
+ u.info21.comment.string = talloc_asprintf(join,
+ "Tortured by Samba4: %s",
+ timestring(join, time(NULL)));
+
+ u.info21.full_name.string = talloc_asprintf(join,
+ "Torture account for Samba4: %s",
+ timestring(join, time(NULL)));
+
+ u.info21.description.string = talloc_asprintf(join,
+ "Samba4 torture account created by host %s: %s",
+ lpcfg_netbios_name(tctx->lp_ctx),
+ timestring(join, time(NULL)));
+
+ torture_comment(tctx, "Resetting ACB flags, force pw change time\n");
+
+ status = dcerpc_samr_SetUserInfo_r(b, join, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(status));
+ goto failed;
+ }
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_comment(tctx, "SetUserInfo failed - %s\n", nt_errstr(s.out.result));
+ goto failed;
+ }
+
+ if (random_password) {
+ *random_password = random_pw;
+ }
+
+ return join;
+
+failed:
+ torture_leave_domain(tctx, join);
+ return NULL;
+}
+
+/*
+ * Set privileges on an account.
+ */
+
+static void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
+{
+ name->string = s;
+}
+static void init_lsa_String(struct lsa_String *name, const char *s)
+{
+ name->string = s;
+}
+
+bool torture_setup_privs(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ uint32_t num_privs,
+ const char **privs,
+ const struct dom_sid *user_sid)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct policy_handle *handle;
+ int i;
+
+ torture_assert(tctx,
+ test_lsa_OpenPolicy2(b, tctx, &handle),
+ "failed to open policy");
+
+ for (i=0; i < num_privs; i++) {
+ struct lsa_LookupPrivValue r;
+ struct lsa_LUID luid;
+ struct lsa_String name;
+
+ init_lsa_String(&name, privs[i]);
+
+ r.in.handle = handle;
+ r.in.name = &name;
+ r.out.luid = &luid;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_LookupPrivValue_r(b, tctx, &r),
+ "lsa_LookupPrivValue failed");
+ if (!NT_STATUS_IS_OK(r.out.result)) {
+ torture_comment(tctx, "lsa_LookupPrivValue failed for '%s' with %s\n",
+ privs[i], nt_errstr(r.out.result));
+ return false;
+ }
+ }
+
+ {
+ struct lsa_AddAccountRights r;
+ struct lsa_RightSet rights;
+
+ rights.count = num_privs;
+ rights.names = talloc_zero_array(tctx, struct lsa_StringLarge, rights.count);
+ for (i=0; i < rights.count; i++) {
+ init_lsa_StringLarge(&rights.names[i], privs[i]);
+ }
+
+ r.in.handle = handle;
+ r.in.sid = discard_const_p(struct dom_sid, user_sid);
+ r.in.rights = &rights;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_lsa_AddAccountRights_r(b, tctx, &r),
+ "lsa_AddAccountRights failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result,
+ "lsa_AddAccountRights failed");
+ }
+
+ test_lsa_Close(b, tctx, handle);
+
+ return true;
+}
+
+struct test_join *torture_create_testuser(struct torture_context *torture,
+ const char *username,
+ const char *domain,
+ uint16_t acct_type,
+ const char **random_password)
+{
+ return torture_create_testuser_max_pwlen(torture, username, domain, acct_type, random_password, 255);
+}
+
+NTSTATUS torture_delete_testuser(struct torture_context *torture,
+ struct test_join *join,
+ const char *username)
+{
+ NTSTATUS status;
+
+ status = DeleteUser_byname(torture,
+ join->p->binding_handle,
+ torture,
+ &join->domain_handle,
+ username);
+
+ return status;
+}
+
+_PUBLIC_ struct test_join *torture_join_domain(struct torture_context *tctx,
+ const char *machine_name,
+ uint32_t acct_flags,
+ struct cli_credentials **machine_credentials)
+{
+ NTSTATUS status;
+ struct libnet_context *libnet_ctx;
+ struct libnet_JoinDomain *libnet_r;
+ struct test_join *tj;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+ const char *binding_str = NULL;
+ struct dcerpc_binding *binding = NULL;
+ enum dcerpc_transport_t transport;
+
+ tj = talloc_zero(tctx, struct test_join);
+ if (!tj) return NULL;
+
+ binding_str = torture_setting_string(tctx, "binding", NULL);
+ if (binding_str == NULL) {
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ binding_str = talloc_asprintf(tj, "ncacn_np:%s", host);
+ }
+ status = dcerpc_parse_binding(tj, binding_str, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("dcerpc_parse_binding(%s) failed - %s\n",
+ binding_str, nt_errstr(status)));
+ talloc_free(tj);
+ return NULL;
+ }
+ transport = dcerpc_binding_get_transport(binding);
+ switch (transport) {
+ case NCALRPC:
+ case NCACN_UNIX_STREAM:
+ break;
+ default:
+ dcerpc_binding_set_transport(binding, NCACN_NP);
+ dcerpc_binding_set_flags(binding, 0, DCERPC_AUTH_OPTIONS);
+ break;
+ }
+
+ libnet_r = talloc_zero(tj, struct libnet_JoinDomain);
+ if (!libnet_r) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ libnet_ctx = libnet_context_init(tctx->ev, tctx->lp_ctx);
+ if (!libnet_ctx) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ tj->libnet_r = libnet_r;
+
+ libnet_ctx->cred = samba_cmdline_get_creds();
+ libnet_r->in.binding = dcerpc_binding_string(libnet_r, binding);
+ if (libnet_r->in.binding == NULL) {
+ talloc_free(tj);
+ return NULL;
+ }
+ libnet_r->in.level = LIBNET_JOINDOMAIN_SPECIFIED;
+ libnet_r->in.netbios_name = machine_name;
+ libnet_r->in.account_name = talloc_asprintf(libnet_r, "%s$", machine_name);
+ if (!libnet_r->in.account_name) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ libnet_r->in.acct_type = acct_flags;
+ libnet_r->in.recreate_account = true;
+
+ status = libnet_JoinDomain(libnet_ctx, libnet_r, libnet_r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (libnet_r->out.error_string) {
+ DEBUG(0, ("Domain join failed - %s\n", libnet_r->out.error_string));
+ } else {
+ DEBUG(0, ("Domain join failed - %s\n", nt_errstr(status)));
+ }
+ talloc_free(tj);
+ return NULL;
+ }
+ tj->p = libnet_r->out.samr_pipe;
+ tj->user_handle = *libnet_r->out.user_handle;
+ tj->dom_sid = libnet_r->out.domain_sid;
+ talloc_steal(tj, libnet_r->out.domain_sid);
+ tj->dom_netbios_name = libnet_r->out.domain_name;
+ talloc_steal(tj, libnet_r->out.domain_name);
+ tj->dom_dns_name = libnet_r->out.realm;
+ talloc_steal(tj, libnet_r->out.realm);
+ tj->user_guid = libnet_r->out.account_guid;
+ tj->netbios_name = talloc_strdup(tj, machine_name);
+ if (!tj->netbios_name) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ ZERO_STRUCT(u);
+ s.in.user_handle = &tj->user_handle;
+ s.in.info = &u;
+ s.in.level = 21;
+
+ u.info21.fields_present = SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
+ u.info21.comment.string = talloc_asprintf(tj,
+ "Tortured by Samba4: %s",
+ timestring(tj, time(NULL)));
+ u.info21.full_name.string = talloc_asprintf(tj,
+ "Torture account for Samba4: %s",
+ timestring(tj, time(NULL)));
+
+ u.info21.description.string = talloc_asprintf(tj,
+ "Samba4 torture account created by host %s: %s",
+ lpcfg_netbios_name(tctx->lp_ctx), timestring(tj, time(NULL)));
+
+ status = dcerpc_samr_SetUserInfo_r(tj->p->binding_handle, tj, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "SetUserInfo (non-critical) failed - %s\n", nt_errstr(status));
+ }
+ if (!NT_STATUS_IS_OK(s.out.result)) {
+ torture_comment(tctx, "SetUserInfo (non-critical) failed - %s\n", nt_errstr(s.out.result));
+ }
+
+ *machine_credentials = cli_credentials_init(tj);
+ cli_credentials_set_conf(*machine_credentials, tctx->lp_ctx);
+ cli_credentials_set_workstation(*machine_credentials, machine_name, CRED_SPECIFIED);
+ cli_credentials_set_domain(*machine_credentials, libnet_r->out.domain_name, CRED_SPECIFIED);
+ if (libnet_r->out.realm) {
+ cli_credentials_set_realm(*machine_credentials, libnet_r->out.realm, CRED_SPECIFIED);
+ }
+ cli_credentials_set_username(*machine_credentials, libnet_r->in.account_name, CRED_SPECIFIED);
+ cli_credentials_set_password(*machine_credentials, libnet_r->out.join_password, CRED_SPECIFIED);
+ cli_credentials_set_kvno(*machine_credentials, libnet_r->out.kvno);
+ if (acct_flags & ACB_SVRTRUST) {
+ cli_credentials_set_secure_channel_type(*machine_credentials,
+ SEC_CHAN_BDC);
+ } else if (acct_flags & ACB_WSTRUST) {
+ cli_credentials_set_secure_channel_type(*machine_credentials,
+ SEC_CHAN_WKSTA);
+ } else {
+ DEBUG(0, ("Invalid account type specified to torture_join_domain\n"));
+ talloc_free(*machine_credentials);
+ return NULL;
+ }
+
+ return tj;
+}
+
+struct dcerpc_pipe *torture_join_samr_pipe(struct test_join *join)
+{
+ return join->p;
+}
+
+struct policy_handle *torture_join_samr_user_policy(struct test_join *join)
+{
+ return &join->user_handle;
+}
+
+static NTSTATUS torture_leave_ads_domain(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct libnet_JoinDomain *libnet_r)
+{
+ int rtn;
+ TALLOC_CTX *tmp_ctx;
+
+ struct ldb_dn *server_dn;
+ struct ldb_context *ldb_ctx;
+
+ char *remote_ldb_url;
+
+ /* Check if we are a domain controller. If not, exit. */
+ if (!libnet_r->out.server_dn_str) {
+ return NT_STATUS_OK;
+ }
+
+ tmp_ctx = talloc_named(mem_ctx, 0, "torture_leave temporary context");
+ if (!tmp_ctx) {
+ libnet_r->out.error_string = NULL;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ldb_ctx = ldb_init(tmp_ctx, torture->ev);
+ if (!ldb_ctx) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Remove CN=Servers,... entry from the AD. */
+ server_dn = ldb_dn_new(tmp_ctx, ldb_ctx, libnet_r->out.server_dn_str);
+ if (! ldb_dn_validate(server_dn)) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s",
+ dcerpc_binding_get_string_option(libnet_r->out.samr_binding, "host"));
+ if (!remote_ldb_url) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ldb_set_opaque(ldb_ctx, "credentials", samba_cmdline_get_creds());
+ ldb_set_opaque(ldb_ctx, "loadparm", samba_cmdline_get_lp_ctx());
+
+ rtn = ldb_connect(ldb_ctx, remote_ldb_url, 0, NULL);
+ if (rtn != LDB_SUCCESS) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ rtn = ldb_delete(ldb_ctx, server_dn);
+ if (rtn != LDB_SUCCESS) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(0, ("%s removed successfully.\n", libnet_r->out.server_dn_str));
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/*
+ leave the domain, deleting the machine acct
+*/
+
+_PUBLIC_ void torture_leave_domain(struct torture_context *tctx, struct test_join *join)
+{
+ struct samr_DeleteUser d;
+ NTSTATUS status;
+
+ if (!join) {
+ return;
+ }
+ d.in.user_handle = &join->user_handle;
+ d.out.user_handle = &join->user_handle;
+
+ /* Delete machine account */
+ status = dcerpc_samr_DeleteUser_r(join->p->binding_handle, join, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "DeleteUser failed\n");
+ } else if (!NT_STATUS_IS_OK(d.out.result)) {
+ torture_comment(tctx, "Delete of machine account %s failed\n",
+ join->netbios_name);
+ } else {
+ torture_comment(tctx, "Delete of machine account %s was successful.\n",
+ join->netbios_name);
+ }
+
+ if (join->libnet_r) {
+ status = torture_leave_ads_domain(tctx, join, join->libnet_r);
+ }
+
+ talloc_free(join);
+}
+
+/*
+ return the dom sid for a test join
+*/
+_PUBLIC_ const struct dom_sid *torture_join_sid(struct test_join *join)
+{
+ return join->dom_sid;
+}
+
+const struct dom_sid *torture_join_user_sid(struct test_join *join)
+{
+ return join->user_sid;
+}
+
+const char *torture_join_netbios_name(struct test_join *join)
+{
+ return join->netbios_name;
+}
+
+const struct GUID *torture_join_user_guid(struct test_join *join)
+{
+ return &join->user_guid;
+}
+
+const char *torture_join_dom_netbios_name(struct test_join *join)
+{
+ return join->dom_netbios_name;
+}
+
+const char *torture_join_dom_dns_name(struct test_join *join)
+{
+ return join->dom_dns_name;
+}
+
+#if 0 /* Left as the documentation of the join process, but see new implementation in libnet_become_dc.c */
+struct test_join_ads_dc {
+ struct test_join *join;
+};
+
+struct test_join_ads_dc *torture_join_domain_ads_dc(const char *machine_name,
+ const char *domain,
+ struct cli_credentials **machine_credentials)
+{
+ struct test_join_ads_dc *join;
+
+ join = talloc(NULL, struct test_join_ads_dc);
+ if (join == NULL) {
+ return NULL;
+ }
+
+ join->join = torture_join_domain(machine_name,
+ ACB_SVRTRUST,
+ machine_credentials);
+
+ if (!join->join) {
+ return NULL;
+ }
+
+/* W2K: */
+ /* W2K: modify userAccountControl from 4096 to 532480 */
+
+ /* W2K: modify RDN to OU=Domain Controllers and skip the $ from server name */
+
+ /* ask objectVersion of Schema Partition */
+
+ /* ask rIDManagerReferenz of the Domain Partition */
+
+ /* ask fsMORoleOwner of the RID-Manager$ object
+ * returns CN=NTDS Settings,CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ...
+ */
+
+ /* ask for dnsHostName of CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ... */
+
+ /* ask for objectGUID of CN=NTDS Settings,CN=<DC>,CN=Servers,CN=Default-First-Site-Name, ... */
+
+ /* ask for * of CN=Default-First-Site-Name, ... */
+
+ /* search (&(|(objectClass=user)(objectClass=computer))(sAMAccountName=<machine_name>$)) in Domain Partition
+ * attributes : distinguishedName, userAccountControl
+ */
+
+ /* ask * for CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
+ * should fail with noSuchObject
+ */
+
+ /* add CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
+ *
+ * objectClass = server
+ * systemFlags = 50000000
+ * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
+ */
+
+ /* ask for * of CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
+ * should fail with noSuchObject
+ */
+
+ /* search for (ncname=<domain_nc>) in CN=Partitions,CN=Configuration,...
+ * attributes: ncName, dnsRoot
+ */
+
+ /* modify add CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
+ * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
+ * should fail with attributeOrValueExists
+ */
+
+ /* modify replace CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name,...
+ * serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
+ */
+
+ /* DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
+ *
+ */
+
+ /* replicate CN=Schema,CN=Configuration,...
+ * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
+ *
+ */
+
+ /* replicate CN=Configuration,...
+ * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
+ *
+ */
+
+ /* replicate Domain Partition
+ * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
+ *
+ */
+
+ /* call DsReplicaUpdateRefs() for all partitions like this:
+ * req1: struct drsuapi_DsReplicaUpdateRefsRequest1
+ * naming_context : *
+ * naming_context: struct drsuapi_DsReplicaObjectIdentifier
+ * __ndr_size : 0x000000ae (174)
+ * __ndr_size_sid : 0x00000000 (0)
+ * guid : 00000000-0000-0000-0000-000000000000
+ * sid : S-0-0
+ * dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
+ * dest_dsa_dns_name : *
+ * dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
+ * dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
+ * options : 0x0000001c (28)
+ * 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
+ * 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
+ * 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
+ * 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
+ * 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
+ *
+ * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
+ * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
+ */
+
+/* W2K3: see libnet/libnet_become_dc.c */
+ return join;
+}
+
+#endif
diff --git a/source4/torture/rpc/torture_rpc.h b/source4/torture/rpc/torture_rpc.h
new file mode 100644
index 0000000..9217461
--- /dev/null
+++ b/source4/torture/rpc/torture_rpc.h
@@ -0,0 +1,126 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TORTURE_RPC_H__
+#define __TORTURE_RPC_H__
+
+#include "lib/torture/torture.h"
+#include "auth/credentials/credentials.h"
+#include "torture/rpc/drsuapi.h"
+#include "libnet/libnet_join.h"
+#include "librpc/rpc/dcerpc.h"
+#include "libcli/raw/libcliraw.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "torture/rpc/proto.h"
+
+struct torture_rpc_tcase {
+ struct torture_tcase tcase;
+ const struct ndr_interface_table *table;
+ const char *machine_name;
+ bool (*setup_fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *);
+ bool (*teardown_fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *);
+};
+
+struct torture_rpc_tcase_data {
+ struct test_join *join_ctx;
+ struct dcerpc_pipe *pipe;
+ struct cli_credentials *credentials;
+};
+
+NTSTATUS torture_rpc_connection(struct torture_context *tctx,
+ struct dcerpc_pipe **p,
+ const struct ndr_interface_table *table);
+NTSTATUS torture_rpc_connection_with_binding(struct torture_context *tctx,
+ struct dcerpc_binding *binding,
+ struct dcerpc_pipe **p,
+ const struct ndr_interface_table *table);
+
+struct test_join *torture_join_domain(struct torture_context *tctx,
+ const char *machine_name,
+ uint32_t acct_flags,
+ struct cli_credentials **machine_credentials);
+const struct dom_sid *torture_join_sid(struct test_join *join);
+void torture_leave_domain(struct torture_context *tctx, struct test_join *join);
+struct torture_rpc_tcase *torture_suite_add_rpc_iface_tcase(struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table);
+struct torture_rpc_tcase *torture_suite_add_rpc_setup_tcase(
+ struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table,
+ bool (*setup_fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *),
+ bool (*teardown_fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *));
+
+struct torture_test *torture_rpc_tcase_add_test(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *));
+struct torture_rpc_tcase *torture_suite_add_anon_rpc_iface_tcase(struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table);
+
+struct torture_test *torture_rpc_tcase_add_test_join(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *,
+ struct cli_credentials *, struct test_join *));
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_setup(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn)(struct torture_context *,
+ struct dcerpc_pipe *,
+ void *),
+ void *userdata);
+struct torture_test *torture_rpc_tcase_add_test_ex(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *,
+ void *),
+ void *userdata);
+struct torture_rpc_tcase *torture_suite_add_machine_bdc_rpc_iface_tcase(
+ struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table,
+ const char *machine_name);
+struct torture_rpc_tcase *torture_suite_add_machine_workstation_rpc_iface_tcase(
+ struct torture_suite *suite,
+ const char *name,
+ const struct ndr_interface_table *table,
+ const char *machine_name);
+struct torture_test *torture_rpc_tcase_add_test_creds(
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ bool (*fn) (struct torture_context *, struct dcerpc_pipe *, struct cli_credentials *));
+bool torture_suite_init_rpc_tcase(struct torture_suite *suite,
+ struct torture_rpc_tcase *tcase,
+ const char *name,
+ const struct ndr_interface_table *table);
+
+
+
+#endif /* __TORTURE_RPC_H__ */
diff --git a/source4/torture/rpc/unixinfo.c b/source4/torture/rpc/unixinfo.c
new file mode 100644
index 0000000..227b002
--- /dev/null
+++ b/source4/torture/rpc/unixinfo.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for unixinfo rpc operations
+
+ Copyright (C) Volker Lendecke 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_unixinfo_c.h"
+#include "libcli/security/security.h"
+
+/**
+ test the SidToUid interface
+*/
+static bool test_sidtouid(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct unixinfo_SidToUid r;
+ struct dom_sid *sid;
+ uint64_t uid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1234-5432");
+ r.in.sid = *sid;
+ r.out.uid = &uid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_unixinfo_SidToUid_r(b, tctx, &r),
+ "SidToUid failed");
+ if (NT_STATUS_EQUAL(NT_STATUS_NONE_MAPPED, r.out.result)) {
+ } else torture_assert_ntstatus_ok(tctx, r.out.result, "SidToUid failed");
+
+ return true;
+}
+
+/*
+ test the UidToSid interface
+*/
+static bool test_uidtosid(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct unixinfo_UidToSid r;
+ struct dom_sid sid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.uid = 1000;
+ r.out.sid = &sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_unixinfo_UidToSid_r(b, tctx, &r),
+ "UidToSid failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "UidToSid failed");
+ return true;
+}
+
+static bool test_getpwuid(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ uint64_t uids[512];
+ uint32_t num_uids = ARRAY_SIZE(uids);
+ uint32_t i;
+ struct unixinfo_GetPWUid r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i<num_uids; i++) {
+ uids[i] = i;
+ }
+
+ r.in.count = &num_uids;
+ r.in.uids = uids;
+ r.out.count = &num_uids;
+ r.out.infos = talloc_array(tctx, struct unixinfo_GetPWUidInfo, num_uids);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_unixinfo_GetPWUid_r(b, tctx, &r),
+ "GetPWUid failed");
+
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GetPWUid failed");
+
+ return true;
+}
+
+/*
+ test the SidToGid interface
+*/
+static bool test_sidtogid(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct unixinfo_SidToGid r;
+ struct dom_sid *sid;
+ uint64_t gid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ sid = dom_sid_parse_talloc(tctx, "S-1-5-32-1234-5432");
+ r.in.sid = *sid;
+ r.out.gid = &gid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_unixinfo_SidToGid_r(b, tctx, &r),
+ "SidToGid failed");
+ if (NT_STATUS_EQUAL(NT_STATUS_NONE_MAPPED, r.out.result)) {
+ } else torture_assert_ntstatus_ok(tctx, r.out.result, "SidToGid failed");
+
+ return true;
+}
+
+/*
+ test the GidToSid interface
+*/
+static bool test_gidtosid(struct torture_context *tctx, struct dcerpc_pipe *p)
+{
+ struct unixinfo_GidToSid r;
+ struct dom_sid sid;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.gid = 1000;
+ r.out.sid = &sid;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_unixinfo_GidToSid_r(b, tctx, &r),
+ "GidToSid failed");
+ torture_assert_ntstatus_ok(tctx, r.out.result, "GidToSid failed");
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_unixinfo(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+
+ suite = torture_suite_create(mem_ctx, "unixinfo");
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "unixinfo",
+ &ndr_table_unixinfo);
+
+ torture_rpc_tcase_add_test(tcase, "sidtouid", test_sidtouid);
+ torture_rpc_tcase_add_test(tcase, "uidtosid", test_uidtosid);
+ torture_rpc_tcase_add_test(tcase, "getpwuid", test_getpwuid);
+ torture_rpc_tcase_add_test(tcase, "sidtogid", test_sidtogid);
+ torture_rpc_tcase_add_test(tcase, "gidtosid", test_gidtosid);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/winreg.c b/source4/torture/rpc/winreg.c
new file mode 100644
index 0000000..b0e153f
--- /dev/null
+++ b/source4/torture/rpc/winreg.c
@@ -0,0 +1,3335 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for winreg rpc operations
+
+ Copyright (C) Tim Potter 2003
+ Copyright (C) Jelmer Vernooij 2004-2007
+ Copyright (C) Günther Deschner 2007,2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_winreg_c.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "torture/rpc/torture_rpc.h"
+#include "param/param.h"
+#include "lib/registry/registry.h"
+
+#define TEST_KEY_BASE "winreg_torture_test"
+#define TEST_KEY1 "spottyfoot"
+#define TEST_KEY2 "with a SD (#1)"
+#define TEST_KEY3 "with a subkey"
+#define TEST_KEY4 "sd_tests"
+#define TEST_SUBKEY "subkey"
+#define TEST_SUBKEY_SD "subkey_sd"
+#define TEST_SUBSUBKEY_SD "subkey_sd\\subsubkey_sd"
+#define TEST_VALUE "torture_value_name"
+#define TEST_KEY_VOLATILE "torture_volatile_key"
+#define TEST_SUBKEY_VOLATILE "torture_volatile_subkey"
+#define TEST_KEY_SYMLINK "torture_symlink_key"
+#define TEST_KEY_SYMLINK_DEST "torture_symlink_dest"
+
+#define TEST_SID "S-1-5-21-1234567890-1234567890-1234567890-500"
+
+static void init_lsa_StringLarge(struct lsa_StringLarge *name, const char *s)
+{
+ name->string = s;
+}
+
+static void init_winreg_String(struct winreg_String *name, const char *s)
+{
+ name->name = s;
+ if (s) {
+ name->name_len = 2 * (strlen_m(s) + 1);
+ name->name_size = name->name_len;
+ } else {
+ name->name_len = 0;
+ name->name_size = 0;
+ }
+}
+
+static bool test_GetVersion(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct winreg_GetVersion r;
+ uint32_t v;
+
+ torture_comment(tctx, "Testing GetVersion\n");
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.out.version = &v;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_GetVersion_r(b, tctx, &r),
+ "GetVersion failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "GetVersion failed");
+
+ return true;
+}
+
+static bool test_NotifyChangeKeyValue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct winreg_NotifyChangeKeyValue r;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.in.watch_subtree = true;
+ r.in.notify_filter = 0;
+ r.in.unknown = r.in.unknown2 = 0;
+ init_winreg_String(&r.in.string1, NULL);
+ init_winreg_String(&r.in.string2, NULL);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_NotifyChangeKeyValue_r(b, tctx, &r),
+ "NotifyChangeKeyValue failed");
+
+ if (!W_ERROR_IS_OK(r.out.result)) {
+ torture_comment(tctx,
+ "NotifyChangeKeyValue failed - %s - not considering\n",
+ win_errstr(r.out.result));
+ return true;
+ }
+
+ return true;
+}
+
+static bool test_CreateKey_opts(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *name,
+ const char *kclass,
+ uint32_t options,
+ uint32_t access_mask,
+ struct winreg_SecBuf *secdesc,
+ WERROR expected_result,
+ enum winreg_CreateAction *action_taken_p,
+ struct policy_handle *new_handle_p)
+{
+ struct winreg_CreateKey r;
+ struct policy_handle newhandle;
+ enum winreg_CreateAction action_taken = 0;
+
+ torture_comment(tctx, "Testing CreateKey(%s)\n", name);
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ init_winreg_String(&r.in.name, name);
+ init_winreg_String(&r.in.keyclass, kclass);
+ r.in.options = options;
+ r.in.access_mask = access_mask;
+ r.in.action_taken = &action_taken;
+ r.in.secdesc = secdesc;
+ r.out.new_handle = &newhandle;
+ r.out.action_taken = &action_taken;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CreateKey_r(b, tctx, &r),
+ "CreateKey failed");
+
+ torture_assert_werr_equal(tctx, r.out.result, expected_result, "CreateKey failed");
+
+ if (new_handle_p) {
+ *new_handle_p = newhandle;
+ }
+ if (action_taken_p) {
+ *action_taken_p = *r.out.action_taken;
+ }
+
+ return true;
+}
+
+static bool test_CreateKey(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *name,
+ const char *kclass)
+{
+ return test_CreateKey_opts(tctx, b, handle, name, kclass,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL, /* secdesc */
+ WERR_OK,
+ NULL, /* action_taken */
+ NULL /* new_handle */);
+}
+
+/*
+ createkey testing with a SD
+*/
+static bool test_CreateKey_sd(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *name,
+ const char *kclass,
+ struct policy_handle *newhandle)
+{
+ struct winreg_CreateKey r;
+ enum winreg_CreateAction action_taken = 0;
+ struct security_descriptor *sd;
+ DATA_BLOB sdblob;
+ struct winreg_SecBuf secbuf;
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0,
+ NULL, NULL,
+ SID_NT_AUTHENTICATED_USERS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_ALL,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ NULL);
+
+ torture_assert_ndr_success(tctx,
+ ndr_push_struct_blob(&sdblob, tctx, sd,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor),
+ "Failed to push security_descriptor ?!\n");
+
+ secbuf.sd.data = sdblob.data;
+ secbuf.sd.len = sdblob.length;
+ secbuf.sd.size = sdblob.length;
+ secbuf.length = sdblob.length-10;
+ secbuf.inherit = 0;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.out.new_handle = newhandle;
+ init_winreg_String(&r.in.name, name);
+ init_winreg_String(&r.in.keyclass, kclass);
+ r.in.options = 0x0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.action_taken = r.out.action_taken = &action_taken;
+ r.in.secdesc = &secbuf;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CreateKey_r(b, tctx, &r),
+ "CreateKey with sd failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "CreateKey with sd failed");
+
+ return true;
+}
+
+static bool _test_GetKeySecurity(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t *sec_info_ptr,
+ WERROR get_werr,
+ struct security_descriptor **sd_out)
+{
+ struct winreg_GetKeySecurity r;
+ struct security_descriptor *sd = NULL;
+ uint32_t sec_info;
+ DATA_BLOB sdblob;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (sec_info_ptr) {
+ sec_info = *sec_info_ptr;
+ } else {
+ sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
+ }
+
+ ZERO_STRUCT(r);
+
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+ r.in.sd = r.out.sd = talloc_zero(tctx, struct KeySecurityData);
+ r.in.sd->size = 0x1000;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_GetKeySecurity_r(b, tctx, &r),
+ "GetKeySecurity failed");
+
+ torture_assert_werr_equal(tctx, r.out.result, get_werr,
+ "GetKeySecurity failed");
+
+ sdblob.data = r.out.sd->data;
+ sdblob.length = r.out.sd->len;
+
+ sd = talloc_zero(tctx, struct security_descriptor);
+
+ torture_assert_ndr_success(tctx,
+ ndr_pull_struct_blob(&sdblob, tctx, sd,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor),
+ "pull_security_descriptor failed");
+
+ if (p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ }
+
+ if (sd_out) {
+ *sd_out = sd;
+ } else {
+ talloc_free(sd);
+ }
+
+ return true;
+}
+
+static bool test_GetKeySecurity(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct security_descriptor **sd_out)
+{
+ return _test_GetKeySecurity(p, tctx, handle, NULL, WERR_OK, sd_out);
+}
+
+static bool _test_SetKeySecurity(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t *sec_info_ptr,
+ struct security_descriptor *sd,
+ WERROR werr)
+{
+ struct winreg_SetKeySecurity r;
+ struct KeySecurityData *sdata = NULL;
+ DATA_BLOB sdblob;
+ uint32_t sec_info;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+
+ if (sd && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ }
+
+ torture_assert_ndr_success(tctx,
+ ndr_push_struct_blob(&sdblob, tctx, sd,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor),
+ "push_security_descriptor failed");
+
+ sdata = talloc_zero(tctx, struct KeySecurityData);
+ sdata->data = sdblob.data;
+ sdata->size = sdblob.length;
+ sdata->len = sdblob.length;
+
+ if (sec_info_ptr) {
+ sec_info = *sec_info_ptr;
+ } else {
+ sec_info = SECINFO_UNPROTECTED_SACL |
+ SECINFO_UNPROTECTED_DACL;
+ if (sd->owner_sid) {
+ sec_info |= SECINFO_OWNER;
+ }
+ if (sd->group_sid) {
+ sec_info |= SECINFO_GROUP;
+ }
+ if (sd->sacl) {
+ sec_info |= SECINFO_SACL;
+ }
+ if (sd->dacl) {
+ sec_info |= SECINFO_DACL;
+ }
+ }
+
+ r.in.handle = handle;
+ r.in.sec_info = sec_info;
+ r.in.sd = sdata;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_SetKeySecurity_r(b, tctx, &r),
+ "SetKeySecurity failed");
+
+ torture_assert_werr_equal(tctx, r.out.result, werr,
+ "SetKeySecurity failed");
+
+ return true;
+}
+
+static bool test_SetKeySecurity(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ struct security_descriptor *sd)
+{
+ return _test_SetKeySecurity(p, tctx, handle, NULL, sd, WERR_OK);
+}
+
+static bool test_CloseKey(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct winreg_CloseKey r;
+
+ ZERO_STRUCT(r);
+ r.in.handle = r.out.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey_r(b, tctx, &r),
+ "CloseKey failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
+
+ return true;
+}
+
+static bool test_FlushKey(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ struct winreg_FlushKey r;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_FlushKey_r(b, tctx, &r),
+ "FlushKey failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "FlushKey failed");
+
+ return true;
+}
+
+static bool test_OpenKey_opts(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *hive_handle,
+ const char *keyname,
+ uint32_t options,
+ uint32_t access_mask,
+ struct policy_handle *key_handle,
+ WERROR expected_result)
+{
+ struct winreg_OpenKey r;
+
+ ZERO_STRUCT(r);
+ r.in.parent_handle = hive_handle;
+ init_winreg_String(&r.in.keyname, keyname);
+ r.in.options = options;
+ r.in.access_mask = access_mask;
+ r.out.handle = key_handle;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey_r(b, tctx, &r),
+ "OpenKey failed");
+
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "OpenKey failed");
+
+ return true;
+}
+
+static bool test_OpenKey(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *hive_handle,
+ const char *keyname, struct policy_handle *key_handle)
+{
+ return test_OpenKey_opts(tctx, b, hive_handle, keyname,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ key_handle,
+ WERR_OK);
+}
+
+static bool test_Cleanup(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *key)
+{
+ struct winreg_DeleteKey r;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+
+ init_winreg_String(&r.in.key, key);
+ dcerpc_winreg_DeleteKey_r(b, tctx, &r);
+
+ return true;
+}
+
+static bool _test_GetSetSecurityDescriptor(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ WERROR get_werr,
+ WERROR set_werr)
+{
+ struct security_descriptor *sd = NULL;
+
+ if (!_test_GetKeySecurity(p, tctx, handle, NULL, get_werr, &sd)) {
+ return false;
+ }
+
+ if (!_test_SetKeySecurity(p, tctx, handle, NULL, sd, set_werr)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_SecurityDescriptor(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "SecurityDescriptor get & set\n");
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ if (!_test_GetSetSecurityDescriptor(p, tctx, &new_handle,
+ WERR_OK, WERR_OK)) {
+ ret = false;
+ }
+
+ if (!test_CloseKey(b, tctx, &new_handle)) {
+ return false;
+ }
+
+ return ret;
+}
+
+static bool _test_SecurityDescriptor(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t access_mask,
+ const char *key,
+ WERROR open_werr,
+ WERROR get_werr,
+ WERROR set_werr)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, key,
+ REG_OPTION_NON_VOLATILE,
+ access_mask,
+ &new_handle,
+ open_werr),
+ "failed to open key");
+
+ if (!W_ERROR_IS_OK(open_werr)) {
+ return true;
+ }
+
+ if (!_test_GetSetSecurityDescriptor(p, tctx, &new_handle,
+ get_werr, set_werr)) {
+ ret = false;
+ }
+
+ if (!test_CloseKey(b, tctx, &new_handle)) {
+ return false;
+ }
+
+ return ret;
+}
+
+static bool test_dacl_trustee_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const struct dom_sid *sid)
+{
+ struct security_descriptor *sd = NULL;
+ int i;
+
+ if (!test_GetKeySecurity(p, tctx, handle, &sd)) {
+ return false;
+ }
+
+ if (!sd || !sd->dacl) {
+ return false;
+ }
+
+ for (i = 0; i < sd->dacl->num_aces; i++) {
+ if (dom_sid_equal(&sd->dacl->aces[i].trustee, sid)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool _test_dacl_trustee_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ const struct dom_sid *sid)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ ret = test_dacl_trustee_present(p, tctx, &new_handle, sid);
+
+ test_CloseKey(b, tctx, &new_handle);
+
+ return ret;
+}
+
+static bool test_sacl_trustee_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const struct dom_sid *sid)
+{
+ struct security_descriptor *sd = NULL;
+ int i;
+ uint32_t sec_info = SECINFO_SACL;
+
+ if (!_test_GetKeySecurity(p, tctx, handle, &sec_info, WERR_OK, &sd)) {
+ return false;
+ }
+
+ if (!sd || !sd->sacl) {
+ return false;
+ }
+
+ for (i = 0; i < sd->sacl->num_aces; i++) {
+ if (dom_sid_equal(&sd->sacl->aces[i].trustee, sid)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool _test_sacl_trustee_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ const struct dom_sid *sid)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, key,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_SYSTEM_SECURITY,
+ &new_handle,
+ WERR_OK),
+ "failed to open key");
+
+ ret = test_sacl_trustee_present(p, tctx, &new_handle, sid);
+
+ test_CloseKey(b, tctx, &new_handle);
+
+ return ret;
+}
+
+static bool test_owner_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const struct dom_sid *sid)
+{
+ struct security_descriptor *sd = NULL;
+ uint32_t sec_info = SECINFO_OWNER;
+
+ if (!_test_GetKeySecurity(p, tctx, handle, &sec_info, WERR_OK, &sd)) {
+ return false;
+ }
+
+ if (!sd || !sd->owner_sid) {
+ return false;
+ }
+
+ return dom_sid_equal(sd->owner_sid, sid);
+}
+
+static bool _test_owner_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ const struct dom_sid *sid)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ ret = test_owner_present(p, tctx, &new_handle, sid);
+
+ test_CloseKey(b, tctx, &new_handle);
+
+ return ret;
+}
+
+static bool test_group_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const struct dom_sid *sid)
+{
+ struct security_descriptor *sd = NULL;
+ uint32_t sec_info = SECINFO_GROUP;
+
+ if (!_test_GetKeySecurity(p, tctx, handle, &sec_info, WERR_OK, &sd)) {
+ return false;
+ }
+
+ if (!sd || !sd->group_sid) {
+ return false;
+ }
+
+ return dom_sid_equal(sd->group_sid, sid);
+}
+
+static bool _test_group_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ const struct dom_sid *sid)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ ret = test_group_present(p, tctx, &new_handle, sid);
+
+ test_CloseKey(b, tctx, &new_handle);
+
+ return ret;
+}
+
+static bool test_dacl_trustee_flags_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const struct dom_sid *sid,
+ uint8_t flags)
+{
+ struct security_descriptor *sd = NULL;
+ int i;
+
+ if (!test_GetKeySecurity(p, tctx, handle, &sd)) {
+ return false;
+ }
+
+ if (!sd || !sd->dacl) {
+ return false;
+ }
+
+ for (i = 0; i < sd->dacl->num_aces; i++) {
+ if ((dom_sid_equal(&sd->dacl->aces[i].trustee, sid)) &&
+ (sd->dacl->aces[i].flags == flags)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool test_dacl_ace_present(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const struct security_ace *ace)
+{
+ struct security_descriptor *sd = NULL;
+ int i;
+
+ if (!test_GetKeySecurity(p, tctx, handle, &sd)) {
+ return false;
+ }
+
+ if (!sd || !sd->dacl) {
+ return false;
+ }
+
+ for (i = 0; i < sd->dacl->num_aces; i++) {
+ if (security_ace_equal(&sd->dacl->aces[i], ace)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool test_RestoreSecurity(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ struct security_descriptor *sd)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ if (!test_SetKeySecurity(p, tctx, &new_handle, sd)) {
+ ret = false;
+ }
+
+ if (!test_CloseKey(b, tctx, &new_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_BackupSecurity(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ struct security_descriptor **sd)
+{
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ if (!test_GetKeySecurity(p, tctx, &new_handle, sd)) {
+ ret = false;
+ }
+
+ if (!test_CloseKey(b, tctx, &new_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_SecurityDescriptorInheritance(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key)
+{
+ /* get sd
+ add ace SEC_ACE_FLAG_CONTAINER_INHERIT
+ set sd
+ get sd
+ check ace
+ add subkey
+ get sd
+ check ace
+ add subsubkey
+ get sd
+ check ace
+ del subsubkey
+ del subkey
+ reset sd
+ */
+
+ struct security_descriptor *sd = NULL;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_ace *ace = NULL;
+ struct policy_handle new_handle;
+ bool ret = true;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *test_subkey_sd;
+ const char *test_subsubkey_sd;
+
+ torture_comment(tctx, "SecurityDescriptor inheritance\n");
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ if (!_test_GetKeySecurity(p, tctx, &new_handle, NULL, WERR_OK, &sd)) {
+ return false;
+ }
+
+ sd_orig = security_descriptor_copy(tctx, sd);
+ if (sd_orig == NULL) {
+ return false;
+ }
+
+ ace = security_ace_create(tctx,
+ TEST_SID,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_STD_REQUIRED,
+ SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+ torture_assert_ntstatus_ok(tctx,
+ security_descriptor_dacl_add(sd, ace),
+ "failed to add ace");
+
+ /* FIXME: add further tests for these flags */
+ sd->type |= SEC_DESC_DACL_AUTO_INHERIT_REQ |
+ SEC_DESC_SACL_AUTO_INHERITED;
+
+ if (!test_SetKeySecurity(p, tctx, &new_handle, sd)) {
+ return false;
+ }
+
+ torture_assert(tctx,
+ test_dacl_ace_present(p, tctx, &new_handle, ace),
+ "new ACE not present!");
+
+ if (!test_CloseKey(b, tctx, &new_handle)) {
+ return false;
+ }
+
+ test_subkey_sd = talloc_asprintf(tctx, "%s\\%s", key, TEST_SUBKEY_SD);
+
+ if (!test_CreateKey(b, tctx, handle, test_subkey_sd, NULL)) {
+ ret = false;
+ goto out;
+ }
+
+ if (!test_OpenKey(b, tctx, handle, test_subkey_sd, &new_handle)) {
+ ret = false;
+ goto out;
+ }
+
+ if (!test_dacl_ace_present(p, tctx, &new_handle, ace)) {
+ torture_comment(tctx, "inherited ACE not present!\n");
+ ret = false;
+ goto out;
+ }
+
+ test_subsubkey_sd = talloc_asprintf(tctx, "%s\\%s", key, TEST_SUBSUBKEY_SD);
+
+ test_CloseKey(b, tctx, &new_handle);
+ if (!test_CreateKey(b, tctx, handle, test_subsubkey_sd, NULL)) {
+ ret = false;
+ goto out;
+ }
+
+ if (!test_OpenKey(b, tctx, handle, test_subsubkey_sd, &new_handle)) {
+ ret = false;
+ goto out;
+ }
+
+ if (!test_dacl_ace_present(p, tctx, &new_handle, ace)) {
+ torture_comment(tctx, "inherited ACE not present!\n");
+ ret = false;
+ goto out;
+ }
+
+ out:
+ test_CloseKey(b, tctx, &new_handle);
+ test_Cleanup(b, tctx, handle, test_subkey_sd);
+ test_RestoreSecurity(p, tctx, handle, key, sd_orig);
+
+ return ret;
+}
+
+static bool test_SecurityDescriptorBlockInheritance(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key)
+{
+ /* get sd
+ add ace SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
+ set sd
+ add subkey/subkey
+ get sd
+ check ace
+ get sd from subkey
+ check ace
+ del subkey/subkey
+ del subkey
+ reset sd
+ */
+
+ struct security_descriptor *sd = NULL;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_ace *ace = NULL;
+ struct policy_handle new_handle;
+ struct dom_sid *sid = NULL;
+ bool ret = true;
+ uint8_t ace_flags = 0x0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *test_subkey_sd;
+ const char *test_subsubkey_sd;
+
+ torture_comment(tctx, "SecurityDescriptor inheritance block\n");
+
+ if (!test_OpenKey(b, tctx, handle, key, &new_handle)) {
+ return false;
+ }
+
+ if (!_test_GetKeySecurity(p, tctx, &new_handle, NULL, WERR_OK, &sd)) {
+ return false;
+ }
+
+ sd_orig = security_descriptor_copy(tctx, sd);
+ if (sd_orig == NULL) {
+ return false;
+ }
+
+ ace = security_ace_create(tctx,
+ TEST_SID,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_STD_REQUIRED,
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
+
+ torture_assert_ntstatus_ok(tctx,
+ security_descriptor_dacl_add(sd, ace),
+ "failed to add ace");
+
+ if (!_test_SetKeySecurity(p, tctx, &new_handle, NULL, sd, WERR_OK)) {
+ return false;
+ }
+
+ torture_assert(tctx,
+ test_dacl_ace_present(p, tctx, &new_handle, ace),
+ "new ACE not present!");
+
+ if (!test_CloseKey(b, tctx, &new_handle)) {
+ return false;
+ }
+
+ test_subkey_sd = talloc_asprintf(tctx, "%s\\%s", key, TEST_SUBKEY_SD);
+ test_subsubkey_sd = talloc_asprintf(tctx, "%s\\%s", key, TEST_SUBSUBKEY_SD);
+
+ if (!test_CreateKey(b, tctx, handle, test_subsubkey_sd, NULL)) {
+ return false;
+ }
+
+ if (!test_OpenKey(b, tctx, handle, test_subsubkey_sd, &new_handle)) {
+ ret = false;
+ goto out;
+ }
+
+ if (test_dacl_ace_present(p, tctx, &new_handle, ace)) {
+ torture_comment(tctx, "inherited ACE present but should not!\n");
+ ret = false;
+ goto out;
+ }
+
+ sid = dom_sid_parse_talloc(tctx, TEST_SID);
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (test_dacl_trustee_present(p, tctx, &new_handle, sid)) {
+ torture_comment(tctx, "inherited trustee SID present but should not!\n");
+ ret = false;
+ goto out;
+ }
+
+ test_CloseKey(b, tctx, &new_handle);
+
+ if (!test_OpenKey(b, tctx, handle, test_subkey_sd, &new_handle)) {
+ ret = false;
+ goto out;
+ }
+
+ if (test_dacl_ace_present(p, tctx, &new_handle, ace)) {
+ torture_comment(tctx, "inherited ACE present but should not!\n");
+ ret = false;
+ goto out;
+ }
+
+ if (!test_dacl_trustee_flags_present(p, tctx, &new_handle, sid, ace_flags)) {
+ torture_comment(tctx, "inherited trustee SID with flags 0x%02x not present!\n",
+ ace_flags);
+ ret = false;
+ goto out;
+ }
+
+ out:
+ test_CloseKey(b, tctx, &new_handle);
+ test_Cleanup(b, tctx, handle, test_subkey_sd);
+ test_RestoreSecurity(p, tctx, handle, key, sd_orig);
+
+ return ret;
+}
+
+static bool test_SecurityDescriptorsMasks(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key)
+{
+ bool ret = true;
+ int i;
+
+ struct winreg_mask_result_table {
+ uint32_t access_mask;
+ WERROR open_werr;
+ WERROR get_werr;
+ WERROR set_werr;
+ } sd_mask_tests[] = {
+ { 0,
+ WERR_ACCESS_DENIED, WERR_FILE_NOT_FOUND, WERR_FOOBAR },
+ { SEC_FLAG_MAXIMUM_ALLOWED,
+ WERR_OK, WERR_OK, WERR_OK },
+ { SEC_STD_WRITE_DAC,
+ WERR_OK, WERR_ACCESS_DENIED, WERR_FOOBAR },
+ { SEC_FLAG_SYSTEM_SECURITY,
+ WERR_OK, WERR_ACCESS_DENIED, WERR_FOOBAR }
+ };
+
+ /* FIXME: before this test can ever run successfully we need a way to
+ * correctly read a NULL security_descritpor in ndr, get the required
+ * length, requery, etc.
+ */
+
+ return true;
+
+ for (i=0; i < ARRAY_SIZE(sd_mask_tests); i++) {
+
+ torture_comment(tctx,
+ "SecurityDescriptor get & set with access_mask: 0x%08x\n",
+ sd_mask_tests[i].access_mask);
+ torture_comment(tctx,
+ "expecting: open %s, get: %s, set: %s\n",
+ win_errstr(sd_mask_tests[i].open_werr),
+ win_errstr(sd_mask_tests[i].get_werr),
+ win_errstr(sd_mask_tests[i].set_werr));
+
+ if (_test_SecurityDescriptor(p, tctx, handle,
+ sd_mask_tests[i].access_mask, key,
+ sd_mask_tests[i].open_werr,
+ sd_mask_tests[i].get_werr,
+ sd_mask_tests[i].set_werr)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+typedef bool (*secinfo_verify_fn)(struct dcerpc_pipe *,
+ struct torture_context *,
+ struct policy_handle *,
+ const char *,
+ const struct dom_sid *);
+
+static bool test_SetSecurityDescriptor_SecInfo(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ const char *test,
+ uint32_t access_mask,
+ uint32_t sec_info,
+ struct security_descriptor *sd,
+ WERROR set_werr,
+ bool expect_present,
+ bool (*fn) (struct dcerpc_pipe *,
+ struct torture_context *,
+ struct policy_handle *,
+ const char *,
+ const struct dom_sid *),
+ const struct dom_sid *sid)
+{
+ struct policy_handle new_handle;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ torture_comment(tctx, "SecurityDescriptor (%s) sets for secinfo: "
+ "0x%08x, access_mask: 0x%08x\n",
+ test, sec_info, access_mask);
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, key,
+ REG_OPTION_NON_VOLATILE,
+ access_mask,
+ &new_handle,
+ WERR_OK),
+ "failed to open key");
+
+ if (!_test_SetKeySecurity(p, tctx, &new_handle, &sec_info,
+ sd,
+ set_werr)) {
+ torture_warning(tctx,
+ "SetKeySecurity with secinfo: 0x%08x has failed\n",
+ sec_info);
+ smb_panic("");
+ test_CloseKey(b, tctx, &new_handle);
+ return false;
+ }
+
+ test_CloseKey(b, tctx, &new_handle);
+
+ if (W_ERROR_IS_OK(set_werr)) {
+ bool present;
+ present = fn(p, tctx, handle, key, sid);
+ if ((expect_present) && (!present)) {
+ torture_warning(tctx,
+ "%s sid is not present!\n",
+ test);
+ return false;
+ }
+ if ((!expect_present) && (present)) {
+ torture_warning(tctx,
+ "%s sid is present but not expected!\n",
+ test);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_SecurityDescriptorsSecInfo(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key)
+{
+ struct security_descriptor *sd_orig = NULL;
+ struct dom_sid *sid = NULL;
+ bool ret = true;
+ int i, a;
+
+ struct security_descriptor *sd_owner =
+ security_descriptor_dacl_create(tctx,
+ 0,
+ TEST_SID, NULL, NULL);
+
+ struct security_descriptor *sd_group =
+ security_descriptor_dacl_create(tctx,
+ 0,
+ NULL, TEST_SID, NULL);
+
+ struct security_descriptor *sd_dacl =
+ security_descriptor_dacl_create(tctx,
+ 0,
+ NULL, NULL,
+ TEST_SID,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_ALL,
+ 0,
+ SID_NT_AUTHENTICATED_USERS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_ALL,
+ 0,
+ NULL);
+
+ struct security_descriptor *sd_sacl =
+ security_descriptor_sacl_create(tctx,
+ 0,
+ NULL, NULL,
+ TEST_SID,
+ SEC_ACE_TYPE_SYSTEM_AUDIT,
+ SEC_GENERIC_ALL,
+ SEC_ACE_FLAG_SUCCESSFUL_ACCESS,
+ NULL);
+
+ struct winreg_secinfo_table {
+ struct security_descriptor *sd;
+ uint32_t sec_info;
+ WERROR set_werr;
+ bool sid_present;
+ secinfo_verify_fn fn;
+ };
+
+ struct winreg_secinfo_table sec_info_owner_tests[] = {
+ {
+ .sd = sd_owner,
+ .sec_info = 0,
+ .set_werr = WERR_OK,
+ .sid_present = false,
+ .fn = (secinfo_verify_fn)_test_owner_present,
+ },
+ {
+ .sd = sd_owner,
+ .sec_info = SECINFO_OWNER,
+ .set_werr = WERR_OK,
+ .sid_present = true,
+ .fn = (secinfo_verify_fn)_test_owner_present,
+ },
+ {
+ .sd = sd_owner,
+ .sec_info = SECINFO_GROUP,
+ .set_werr = WERR_INVALID_PARAMETER,
+ .sid_present = false,
+ },
+ {
+ .sd = sd_owner,
+ .sec_info = SECINFO_DACL,
+ .set_werr = WERR_OK,
+ .sid_present = true,
+ .fn = (secinfo_verify_fn)_test_owner_present,
+ },
+ {
+ .sd = sd_owner,
+ .sec_info = SECINFO_SACL,
+ .set_werr = WERR_ACCESS_DENIED,
+ .sid_present = false,
+ },
+ };
+
+ uint32_t sd_owner_good_access_masks[] = {
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ /* SEC_STD_WRITE_OWNER, */
+ };
+
+ struct winreg_secinfo_table sec_info_group_tests[] = {
+ {
+ .sd = sd_group,
+ .sec_info = 0,
+ .set_werr = WERR_OK,
+ .sid_present = false,
+ .fn = (secinfo_verify_fn)_test_group_present,
+ },
+ {
+ .sd = sd_group,
+ .sec_info = SECINFO_OWNER,
+ .set_werr = WERR_INVALID_PARAMETER,
+ .sid_present = false,
+ },
+ {
+ .sd = sd_group,
+ .sec_info = SECINFO_GROUP,
+ .set_werr = WERR_OK,
+ .sid_present = true,
+ .fn = (secinfo_verify_fn)_test_group_present,
+ },
+ {
+ .sd = sd_group,
+ .sec_info = SECINFO_DACL,
+ .set_werr = WERR_OK,
+ .sid_present = true,
+ .fn = (secinfo_verify_fn)_test_group_present,
+ },
+ {
+ .sd = sd_group,
+ .sec_info = SECINFO_SACL,
+ .set_werr = WERR_ACCESS_DENIED,
+ .sid_present = false,
+ },
+ };
+
+ uint32_t sd_group_good_access_masks[] = {
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ };
+
+ struct winreg_secinfo_table sec_info_dacl_tests[] = {
+ {
+ .sd = sd_dacl,
+ .sec_info = 0,
+ .set_werr = WERR_OK,
+ .sid_present = false,
+ .fn = (secinfo_verify_fn)_test_dacl_trustee_present,
+ },
+ {
+ .sd = sd_dacl,
+ .sec_info = SECINFO_OWNER,
+ .set_werr = WERR_INVALID_PARAMETER,
+ .sid_present = false,
+ },
+ {
+ .sd = sd_dacl,
+ .sec_info = SECINFO_GROUP,
+ .set_werr = WERR_INVALID_PARAMETER,
+ .sid_present = false,
+ },
+ {
+ .sd = sd_dacl,
+ .sec_info = SECINFO_DACL,
+ .set_werr = WERR_OK,
+ .sid_present = true,
+ .fn = (secinfo_verify_fn)_test_dacl_trustee_present
+ },
+ {
+ .sd = sd_dacl,
+ .sec_info = SECINFO_SACL,
+ .set_werr = WERR_ACCESS_DENIED,
+ .sid_present = false,
+ },
+ };
+
+ uint32_t sd_dacl_good_access_masks[] = {
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ SEC_STD_WRITE_DAC,
+ };
+
+ struct winreg_secinfo_table sec_info_sacl_tests[] = {
+ {
+ .sd = sd_sacl,
+ .sec_info = 0,
+ .set_werr = WERR_OK,
+ .sid_present = false,
+ .fn = (secinfo_verify_fn)_test_sacl_trustee_present,
+ },
+ {
+ .sd = sd_sacl,
+ .sec_info = SECINFO_OWNER,
+ .set_werr = WERR_INVALID_PARAMETER,
+ .sid_present = false,
+ },
+ {
+ .sd = sd_sacl,
+ .sec_info = SECINFO_GROUP,
+ .set_werr = WERR_INVALID_PARAMETER,
+ .sid_present = false,
+ },
+ {
+ .sd = sd_sacl,
+ .sec_info = SECINFO_DACL,
+ .set_werr = WERR_OK,
+ .sid_present = false,
+ .fn = (secinfo_verify_fn)_test_sacl_trustee_present,
+ },
+ {
+ .sd = sd_sacl,
+ .sec_info = SECINFO_SACL,
+ .set_werr = WERR_OK,
+ .sid_present = true,
+ .fn = (secinfo_verify_fn)_test_sacl_trustee_present,
+ },
+ };
+
+ uint32_t sd_sacl_good_access_masks[] = {
+ SEC_FLAG_MAXIMUM_ALLOWED | SEC_FLAG_SYSTEM_SECURITY,
+ /* SEC_FLAG_SYSTEM_SECURITY, */
+ };
+
+ sid = dom_sid_parse_talloc(tctx, TEST_SID);
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (!test_BackupSecurity(p, tctx, handle, key, &sd_orig)) {
+ return false;
+ }
+
+ /* OWNER */
+
+ for (i=0; i < ARRAY_SIZE(sec_info_owner_tests); i++) {
+
+ for (a=0; a < ARRAY_SIZE(sd_owner_good_access_masks); a++) {
+
+ if (!test_SetSecurityDescriptor_SecInfo(p, tctx, handle,
+ key,
+ "OWNER",
+ sd_owner_good_access_masks[a],
+ sec_info_owner_tests[i].sec_info,
+ sec_info_owner_tests[i].sd,
+ sec_info_owner_tests[i].set_werr,
+ sec_info_owner_tests[i].sid_present,
+ sec_info_owner_tests[i].fn,
+ sid))
+ {
+ torture_comment(tctx, "test_SetSecurityDescriptor_SecInfo failed for OWNER\n");
+ ret = false;
+ goto out;
+ }
+ }
+ }
+
+ /* GROUP */
+
+ for (i=0; i < ARRAY_SIZE(sec_info_group_tests); i++) {
+
+ for (a=0; a < ARRAY_SIZE(sd_group_good_access_masks); a++) {
+
+ if (!test_SetSecurityDescriptor_SecInfo(p, tctx, handle,
+ key,
+ "GROUP",
+ sd_group_good_access_masks[a],
+ sec_info_group_tests[i].sec_info,
+ sec_info_group_tests[i].sd,
+ sec_info_group_tests[i].set_werr,
+ sec_info_group_tests[i].sid_present,
+ sec_info_group_tests[i].fn,
+ sid))
+ {
+ torture_comment(tctx, "test_SetSecurityDescriptor_SecInfo failed for GROUP\n");
+ ret = false;
+ goto out;
+ }
+ }
+ }
+
+ /* DACL */
+
+ for (i=0; i < ARRAY_SIZE(sec_info_dacl_tests); i++) {
+
+ for (a=0; a < ARRAY_SIZE(sd_dacl_good_access_masks); a++) {
+
+ if (!test_SetSecurityDescriptor_SecInfo(p, tctx, handle,
+ key,
+ "DACL",
+ sd_dacl_good_access_masks[a],
+ sec_info_dacl_tests[i].sec_info,
+ sec_info_dacl_tests[i].sd,
+ sec_info_dacl_tests[i].set_werr,
+ sec_info_dacl_tests[i].sid_present,
+ sec_info_dacl_tests[i].fn,
+ sid))
+ {
+ torture_comment(tctx, "test_SetSecurityDescriptor_SecInfo failed for DACL\n");
+ ret = false;
+ goto out;
+ }
+ }
+ }
+
+ /* SACL */
+
+ for (i=0; i < ARRAY_SIZE(sec_info_sacl_tests); i++) {
+
+ for (a=0; a < ARRAY_SIZE(sd_sacl_good_access_masks); a++) {
+
+ if (!test_SetSecurityDescriptor_SecInfo(p, tctx, handle,
+ key,
+ "SACL",
+ sd_sacl_good_access_masks[a],
+ sec_info_sacl_tests[i].sec_info,
+ sec_info_sacl_tests[i].sd,
+ sec_info_sacl_tests[i].set_werr,
+ sec_info_sacl_tests[i].sid_present,
+ sec_info_sacl_tests[i].fn,
+ sid))
+ {
+ torture_comment(tctx, "test_SetSecurityDescriptor_SecInfo failed for SACL\n");
+ ret = false;
+ goto out;
+ }
+ }
+ }
+
+ out:
+ test_RestoreSecurity(p, tctx, handle, key, sd_orig);
+
+ return ret;
+}
+
+static bool test_SecurityDescriptors(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key)
+{
+ bool ret = true;
+
+ if (!test_SecurityDescriptor(p, tctx, handle, key)) {
+ torture_comment(tctx, "test_SecurityDescriptor failed\n");
+ ret = false;
+ }
+
+ if (!test_SecurityDescriptorInheritance(p, tctx, handle, key)) {
+ torture_comment(tctx, "test_SecurityDescriptorInheritance failed\n");
+ ret = false;
+ }
+
+ if (!test_SecurityDescriptorBlockInheritance(p, tctx, handle, key)) {
+ torture_comment(tctx, "test_SecurityDescriptorBlockInheritance failed\n");
+ ret = false;
+ }
+
+ if (!test_SecurityDescriptorsSecInfo(p, tctx, handle, key)) {
+ torture_comment(tctx, "test_SecurityDescriptorsSecInfo failed\n");
+ ret = false;
+ }
+
+ if (!test_SecurityDescriptorsMasks(p, tctx, handle, key)) {
+ torture_comment(tctx, "test_SecurityDescriptorsMasks failed\n");
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool test_DeleteKey_opts(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *key,
+ WERROR expected_result)
+{
+ struct winreg_DeleteKey r;
+
+ torture_comment(tctx, "Testing DeleteKey(%s)\n", key);
+
+ r.in.handle = handle;
+ init_winreg_String(&r.in.key, key);
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_DeleteKey_r(b, tctx, &r),
+ "Delete Key failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_result,
+ "DeleteKey failed");
+
+ return true;
+}
+
+static bool test_DeleteKey(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *key)
+{
+ return test_DeleteKey_opts(b, tctx, handle, key, WERR_OK);
+}
+
+static bool test_QueryInfoKey(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ char *kclass,
+ uint32_t *pmax_valnamelen,
+ uint32_t *pmax_valbufsize)
+{
+ struct winreg_QueryInfoKey r;
+ uint32_t num_subkeys, max_subkeylen, max_classlen,
+ num_values, max_valnamelen, max_valbufsize,
+ secdescsize;
+ NTTIME last_changed_time;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.out.num_subkeys = &num_subkeys;
+ r.out.max_subkeylen = &max_subkeylen;
+ r.out.max_classlen = &max_classlen;
+ r.out.num_values = &num_values;
+ r.out.max_valnamelen = &max_valnamelen;
+ r.out.max_valbufsize = &max_valbufsize;
+ r.out.secdescsize = &secdescsize;
+ r.out.last_changed_time = &last_changed_time;
+
+ r.out.classname = talloc(tctx, struct winreg_String);
+
+ r.in.classname = talloc(tctx, struct winreg_String);
+ init_winreg_String(r.in.classname, kclass);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryInfoKey_r(b, tctx, &r),
+ "QueryInfoKey failed");
+
+ torture_assert_werr_ok(tctx, r.out.result, "QueryInfoKey failed");
+
+ if (pmax_valnamelen) {
+ *pmax_valnamelen = max_valnamelen;
+ }
+
+ if (pmax_valbufsize) {
+ *pmax_valbufsize = max_valbufsize;
+ }
+
+ return true;
+}
+
+static bool test_SetValue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *value_name,
+ enum winreg_Type type,
+ uint8_t *data,
+ uint32_t size)
+{
+ struct winreg_SetValue r;
+ struct winreg_String name;
+
+ torture_comment(tctx, "Testing SetValue(%s), type: %s, offered: 0x%08x)\n",
+ value_name, str_regtype(type), size);
+
+ init_winreg_String(&name, value_name);
+
+ r.in.handle = handle;
+ r.in.name = name;
+ r.in.type = type;
+ r.in.data = data;
+ r.in.size = size;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_SetValue_r(b, tctx, &r),
+ "winreg_SetValue failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "winreg_SetValue failed");
+
+ return true;
+}
+
+static bool test_DeleteValue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *value_name)
+{
+ struct winreg_DeleteValue r;
+ struct winreg_String value;
+
+ torture_comment(tctx, "Testing DeleteValue(%s)\n", value_name);
+
+ init_winreg_String(&value, value_name);
+
+ r.in.handle = handle;
+ r.in.value = value;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_DeleteValue_r(b, tctx, &r),
+ "winreg_DeleteValue failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "winreg_DeleteValue failed");
+
+ return true;
+}
+
+static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, int depth,
+ bool test_security);
+
+static bool test_EnumKey(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, int depth,
+ bool test_security)
+{
+ struct winreg_EnumKey r;
+ struct winreg_StringBuf kclass, name;
+ NTSTATUS status;
+ NTTIME t = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ kclass.name = "";
+ kclass.size = 1024;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.in.enum_index = 0;
+ r.in.name = &name;
+ r.in.keyclass = &kclass;
+ r.out.name = &name;
+ r.in.last_changed_time = &t;
+
+ do {
+ name.name = NULL;
+ name.size = 1024;
+
+ status = dcerpc_winreg_EnumKey_r(b, tctx, &r);
+
+ if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
+ struct policy_handle key_handle;
+
+ torture_comment(tctx, "EnumKey: %d: %s\n",
+ r.in.enum_index,
+ r.out.name->name);
+
+ if (!test_OpenKey(b, tctx, handle, r.out.name->name,
+ &key_handle)) {
+ } else {
+ test_key(p, tctx, &key_handle,
+ depth + 1, test_security);
+ }
+ }
+
+ r.in.enum_index++;
+
+ } while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result));
+
+ torture_assert_ntstatus_ok(tctx, status, "EnumKey failed");
+
+ if (!W_ERROR_IS_OK(r.out.result) &&
+ !W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
+ torture_fail(tctx, "EnumKey failed");
+ }
+
+ return true;
+}
+
+static bool test_QueryMultipleValues(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *valuename)
+{
+ struct winreg_QueryMultipleValues r;
+ uint32_t bufsize=0;
+
+ ZERO_STRUCT(r);
+
+ r.in.key_handle = handle;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, 1);
+ r.in.values_in[0].ve_valuename = talloc(tctx, struct winreg_ValNameBuf);
+ r.in.values_in[0].ve_valuename->name = valuename;
+ /* size needs to be set manually for winreg_ValNameBuf */
+ r.in.values_in[0].ve_valuename->size = strlen_m_term(valuename)*2;
+
+ r.in.num_values = 1;
+ r.in.buffer_size = r.out.buffer_size = talloc(tctx, uint32_t);
+ *r.in.buffer_size = bufsize;
+ do {
+ *r.in.buffer_size = bufsize;
+ r.in.buffer = r.out.buffer = talloc_zero_array(tctx, uint8_t,
+ *r.in.buffer_size);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues_r(b, tctx, &r),
+ "QueryMultipleValues failed");
+
+ talloc_free(r.in.buffer);
+ bufsize += 0x20;
+ } while (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
+
+ torture_assert_werr_ok(tctx, r.out.result, "QueryMultipleValues failed");
+
+ return true;
+}
+
+static bool test_QueryMultipleValues_full(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_values,
+ const char * const *valuenames,
+ bool existing_value)
+{
+ struct winreg_QueryMultipleValues r;
+ uint32_t bufsize = 0;
+ int i;
+
+ torture_comment(tctx, "Testing QueryMultipleValues\n");
+
+ ZERO_STRUCT(r);
+
+ r.in.key_handle = handle;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, 0);
+ r.in.buffer_size = r.out.buffer_size = &bufsize;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues_r(b, tctx, &r),
+ "QueryMultipleValues failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues failed");
+
+ /* this test crashes w2k8 remote registry */
+#if 0
+ r.in.num_values = num_values;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, num_values);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues_r(b, tctx, &r),
+ "QueryMultipleValues failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues failed");
+#endif
+ r.in.num_values = num_values;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, num_values);
+ for (i=0; i < r.in.num_values; i++) {
+ r.in.values_in[i].ve_valuename = talloc_zero(tctx, struct winreg_ValNameBuf);
+ r.in.values_in[i].ve_valuename->name = talloc_strdup(tctx, valuenames[i]);
+ r.in.values_in[i].ve_valuename->size = strlen_m_term(r.in.values_in[i].ve_valuename->name)*2;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues_r(b, tctx, &r),
+ "QueryMultipleValues failed");
+ torture_assert_werr_equal(tctx, r.out.result, existing_value ? WERR_MORE_DATA : WERR_FILE_NOT_FOUND,
+ "QueryMultipleValues failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_FILE_NOT_FOUND)) {
+ return true;
+ }
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ *r.in.buffer_size = 0xff;
+ r.in.buffer = r.out.buffer = talloc_zero_array(tctx, uint8_t, *r.in.buffer_size);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues_r(b, tctx, &r),
+ "QueryMultipleValues failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues failed");
+
+ return true;
+}
+
+
+static bool test_QueryMultipleValues2_full(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ uint32_t num_values,
+ const char * const *valuenames,
+ bool existing_value)
+{
+ struct winreg_QueryMultipleValues2 r;
+ uint32_t offered = 0, needed;
+ int i;
+
+ torture_comment(tctx, "Testing QueryMultipleValues2\n");
+
+ ZERO_STRUCT(r);
+
+ r.in.key_handle = handle;
+ r.in.offered = &offered;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, 0);
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues2_r(b, tctx, &r),
+ "QueryMultipleValues2 failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues2 failed");
+
+ /* this test crashes w2k8 remote registry */
+#if 0
+ r.in.num_values = num_values;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, num_values);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues2_r(b, tctx, &r),
+ "QueryMultipleValues2 failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues2 failed");
+#endif
+ r.in.num_values = num_values;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, num_values);
+ for (i=0; i < r.in.num_values; i++) {
+ r.in.values_in[i].ve_valuename = talloc_zero(tctx, struct winreg_ValNameBuf);
+ r.in.values_in[i].ve_valuename->name = talloc_strdup(tctx, valuenames[i]);
+ r.in.values_in[i].ve_valuename->size = strlen_m_term(r.in.values_in[i].ve_valuename->name)*2;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues2_r(b, tctx, &r),
+ "QueryMultipleValues2 failed");
+ torture_assert_werr_equal(tctx, r.out.result, existing_value ? WERR_MORE_DATA : WERR_FILE_NOT_FOUND,
+ "QueryMultipleValues2 failed");
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_FILE_NOT_FOUND)) {
+ return true;
+ }
+
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ *r.in.offered = *r.out.needed;
+ r.in.buffer = r.out.buffer = talloc_zero_array(tctx, uint8_t, *r.in.offered);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues2_r(b, tctx, &r),
+ "QueryMultipleValues2 failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues2 failed");
+
+ return true;
+}
+
+static bool test_QueryMultipleValues2(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *valuename)
+{
+ struct winreg_QueryMultipleValues2 r;
+ uint32_t offered = 0, needed;
+
+ ZERO_STRUCT(r);
+
+ r.in.key_handle = handle;
+ r.in.values_in = r.out.values_out = talloc_zero_array(tctx, struct QueryMultipleValue, 1);
+ r.in.values_in[0].ve_valuename = talloc(tctx, struct winreg_ValNameBuf);
+ r.in.values_in[0].ve_valuename->name = valuename;
+ /* size needs to be set manually for winreg_ValNameBuf */
+ r.in.values_in[0].ve_valuename->size = strlen_m_term(valuename)*2;
+
+ r.in.num_values = 1;
+ r.in.offered = &offered;
+ r.out.needed = &needed;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues2_r(b, tctx, &r),
+ "QueryMultipleValues2 failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) {
+ *r.in.offered = *r.out.needed;
+ r.in.buffer = r.out.buffer = talloc_zero_array(tctx, uint8_t, *r.in.offered);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_QueryMultipleValues2_r(b, tctx, &r),
+ "QueryMultipleValues2 failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryMultipleValues2 failed");
+
+ return true;
+}
+
+static bool test_QueryValue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *valuename)
+{
+ struct winreg_QueryValue r;
+ NTSTATUS status;
+ enum winreg_Type zero_type = 0;
+ uint32_t offered = 0xfff;
+ uint32_t zero = 0;
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.in.data = NULL;
+ r.in.value_name = talloc_zero(tctx, struct winreg_String);
+ r.in.value_name->name = valuename;
+ r.in.type = &zero_type;
+ r.in.data_size = &offered;
+ r.in.data_length = &zero;
+
+ status = dcerpc_winreg_QueryValue_r(b, tctx, &r);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_fail(tctx, "QueryValue failed");
+ }
+
+ torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
+
+ return true;
+}
+
+static bool test_QueryValue_full(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ const char *valuename,
+ bool existing_value)
+{
+ struct winreg_QueryValue r;
+ struct winreg_String value_name;
+ enum winreg_Type type = REG_NONE;
+ uint32_t data_size = 0;
+ uint32_t real_data_size = 0;
+ uint32_t data_length = 0;
+ uint8_t *data = NULL;
+ WERROR expected_error = WERR_FILE_NOT_FOUND;
+ const char *errmsg_nonexisting = "expected WERR_FILE_NOT_FOUND for nonexisting value";
+
+ if (valuename == NULL) {
+ expected_error = WERR_INVALID_PARAMETER;
+ errmsg_nonexisting = "expected WERR_INVALID_PARAMETER for NULL valuename";
+ }
+
+ ZERO_STRUCT(r);
+
+ init_winreg_String(&value_name, NULL);
+
+ torture_comment(tctx, "Testing QueryValue(%s)\n", valuename);
+
+ r.in.handle = handle;
+ r.in.value_name = &value_name;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r), "QueryValue failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "expected WERR_INVALID_PARAMETER for NULL winreg_String.name");
+
+ init_winreg_String(&value_name, valuename);
+ r.in.value_name = &value_name;
+
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "expected WERR_INVALID_PARAMETER for missing type length and size");
+
+ r.in.type = &type;
+ r.out.type = &type;
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "expected WERR_INVALID_PARAMETER for missing length and size");
+
+ r.in.data_length = &data_length;
+ r.out.data_length = &data_length;
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAMETER,
+ "expected WERR_INVALID_PARAMETER for missing size");
+
+ r.in.data_size = &data_size;
+ r.out.data_size = &data_size;
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ if (existing_value) {
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryValue failed");
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ errmsg_nonexisting);
+ }
+
+ real_data_size = *r.out.data_size;
+
+ data = talloc_zero_array(tctx, uint8_t, 0);
+ r.in.data = data;
+ r.out.data = data;
+ *r.in.data_size = 0;
+ *r.out.data_size = 0;
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ if (existing_value) {
+ torture_assert_werr_equal(tctx, r.out.result, WERR_MORE_DATA,
+ "expected WERR_MORE_DATA for query with too small buffer");
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ errmsg_nonexisting);
+ }
+
+ data = talloc_zero_array(tctx, uint8_t, real_data_size);
+ r.in.data = data;
+ r.out.data = data;
+ r.in.data_size = &real_data_size;
+ r.out.data_size = &real_data_size;
+ torture_assert_ntstatus_ok(tctx, dcerpc_winreg_QueryValue_r(b, tctx, &r),
+ "QueryValue failed");
+ if (existing_value) {
+ torture_assert_werr_ok(tctx, r.out.result,
+ "QueryValue failed");
+ } else {
+ torture_assert_werr_equal(tctx, r.out.result, expected_error,
+ errmsg_nonexisting);
+ }
+
+ return true;
+}
+
+static bool test_EnumValue_one(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle,
+ int max_valnamelen)
+{
+ struct winreg_EnumValue r;
+ bool ret = true;
+ DATA_BLOB blob;
+
+ blob = data_blob_string_const("data_1");
+ torture_assert_goto(tctx,
+ test_SetValue(b, tctx, handle, "v1", REG_BINARY, blob.data, blob.length),
+ ret, done,
+ "test_SetValue failed");
+
+ blob = data_blob_string_const("data_2");
+ torture_assert_goto(tctx,
+ test_SetValue(b, tctx, handle, "v2", REG_BINARY, blob.data, blob.length),
+ ret, done,
+ "test_SetValue failed");
+
+ ZERO_STRUCT(r);
+
+ r.in.handle = handle;
+ r.in.enum_index = 0;
+
+ do {
+ enum winreg_Type type = REG_NONE;
+ uint32_t size = 0, zero = 0;
+ struct winreg_ValNameBuf name;
+ char n = '\0';
+
+ r.in.name = &name;
+ r.in.type = &type;
+ r.in.length = &zero;
+ r.in.size = &size;
+ r.out.name = &name;
+ r.out.size = &size;
+
+ name.name = &n;
+ name.size = max_valnamelen + 2;
+ name.length = 0;
+
+ r.in.value = talloc_array(tctx, uint8_t, 0);
+ torture_assert(tctx, r.in.value, "nomem");
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ dcerpc_winreg_EnumValue_r(b, tctx, &r),
+ ret, done,
+ "EnumValue failed");
+ if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
+ break;
+ }
+ torture_assert_werr_equal_goto(tctx,
+ r.out.result, WERR_MORE_DATA,
+ ret, done,
+ "unexpected return code");
+
+ *r.in.size = *r.out.size;
+ r.in.value = talloc_zero_array(tctx, uint8_t, *r.in.size);
+ torture_assert(tctx, r.in.value, "nomem");
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ dcerpc_winreg_EnumValue_r(b, tctx, &r),
+ ret, done,
+ "EnumValue failed");
+ torture_assert_werr_ok_goto(tctx, r.out.result,
+ ret, done,
+ "unexpected return code");
+
+ r.in.enum_index++;
+
+ } while (W_ERROR_IS_OK(r.out.result));
+
+ torture_assert_werr_equal_goto(tctx, r.out.result, WERR_NO_MORE_ITEMS,
+ ret, done,
+ "EnumValue failed");
+ done:
+ test_DeleteValue(b, tctx, handle, "v1");
+ test_DeleteValue(b, tctx, handle, "v2");
+
+ return ret;
+}
+
+static bool test_EnumValue(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle, int max_valnamelen,
+ int max_valbufsize)
+{
+ struct winreg_EnumValue r;
+ enum winreg_Type type = 0;
+ uint32_t size = max_valbufsize, zero = 0;
+ bool ret = true;
+ uint8_t *data = NULL;
+ struct winreg_ValNameBuf name;
+ char n = '\0';
+
+ ZERO_STRUCT(r);
+ r.in.handle = handle;
+ r.in.enum_index = 0;
+ r.in.name = &name;
+ r.out.name = &name;
+ r.in.type = &type;
+ r.in.length = &zero;
+ r.in.size = &size;
+
+ do {
+ name.name = &n;
+ name.size = max_valnamelen + 2;
+ name.length = 0;
+
+ data = NULL;
+ if (size) {
+ data = talloc_array(tctx, uint8_t, size);
+ }
+ r.in.value = data;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_EnumValue_r(b, tctx, &r),
+ "EnumValue failed");
+
+ if (W_ERROR_IS_OK(r.out.result)) {
+ ret &= test_QueryValue(b, tctx, handle,
+ r.out.name->name);
+ ret &= test_QueryMultipleValues(b, tctx, handle,
+ r.out.name->name);
+ ret &= test_QueryMultipleValues2(b, tctx, handle,
+ r.out.name->name);
+ }
+
+ talloc_free(data);
+
+ r.in.enum_index++;
+ } while (W_ERROR_IS_OK(r.out.result));
+
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NO_MORE_ITEMS,
+ "EnumValue failed");
+
+ return ret;
+}
+
+static bool test_AbortSystemShutdown(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx)
+{
+ struct winreg_AbortSystemShutdown r;
+ uint16_t server = 0x0;
+
+ ZERO_STRUCT(r);
+ r.in.server = &server;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_AbortSystemShutdown_r(b, tctx, &r),
+ "AbortSystemShutdown failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "AbortSystemShutdown failed");
+
+ return true;
+}
+
+static bool test_InitiateSystemShutdown(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct winreg_InitiateSystemShutdown r;
+ uint16_t hostname = 0x0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+ r.in.hostname = &hostname;
+ r.in.message = talloc(tctx, struct lsa_StringLarge);
+ init_lsa_StringLarge(r.in.message, "spottyfood");
+ r.in.force_apps = 1;
+ r.in.timeout = 30;
+ r.in.do_reboot = 1;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_InitiateSystemShutdown_r(b, tctx, &r),
+ "InitiateSystemShutdown failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "InitiateSystemShutdown failed");
+
+ return test_AbortSystemShutdown(b, tctx);
+}
+
+
+static bool test_InitiateSystemShutdownEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ struct winreg_InitiateSystemShutdownEx r;
+ uint16_t hostname = 0x0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+ r.in.hostname = &hostname;
+ r.in.message = talloc(tctx, struct lsa_StringLarge);
+ init_lsa_StringLarge(r.in.message, "spottyfood");
+ r.in.force_apps = 1;
+ r.in.timeout = 30;
+ r.in.do_reboot = 1;
+ r.in.reason = 0;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_InitiateSystemShutdownEx_r(b, tctx, &r),
+ "InitiateSystemShutdownEx failed");
+
+ torture_assert_werr_ok(tctx, r.out.result,
+ "InitiateSystemShutdownEx failed");
+
+ return test_AbortSystemShutdown(b, tctx);
+}
+#define MAX_DEPTH 2 /* Only go this far down the tree */
+
+static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *handle, int depth,
+ bool test_security)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ uint32_t max_valnamelen = 0;
+ uint32_t max_valbufsize = 0;
+
+ if (depth == MAX_DEPTH)
+ return true;
+
+ if (!test_QueryInfoKey(b, tctx, handle, NULL,
+ &max_valnamelen, &max_valbufsize)) {
+ }
+
+ if (!test_NotifyChangeKeyValue(b, tctx, handle)) {
+ }
+
+ if (test_security && !test_GetKeySecurity(p, tctx, handle, NULL)) {
+ }
+
+ if (!test_EnumKey(p, tctx, handle, depth, test_security)) {
+ }
+
+ if (!test_EnumValue(b, tctx, handle, max_valnamelen, max_valbufsize)) {
+ }
+
+ if (!test_EnumValue(b, tctx, handle, max_valnamelen, 0xFFFF)) {
+ }
+
+ if (!test_EnumValue_one(b, tctx, handle, 0xff)) {
+ return false;
+ }
+
+ test_CloseKey(b, tctx, handle);
+
+ return true;
+}
+
+static bool test_SetValue_simple(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ const char *value_name = TEST_VALUE;
+ uint32_t value = 0x12345678;
+ uint64_t value2 = 0x12345678;
+ const char *string = "torture";
+ const char *array[2];
+ DATA_BLOB blob;
+ enum winreg_Type types[] = {
+ REG_DWORD,
+ REG_DWORD_BIG_ENDIAN,
+ REG_QWORD,
+ REG_BINARY,
+ REG_SZ,
+ REG_MULTI_SZ
+ };
+ int t;
+
+ array[0] = "array0";
+ array[1] = NULL;
+
+ torture_comment(tctx, "Testing SetValue (standard formats)\n");
+
+ for (t=0; t < ARRAY_SIZE(types); t++) {
+
+ enum winreg_Type w_type;
+ uint32_t w_size, w_length;
+ uint8_t *w_data;
+
+ switch (types[t]) {
+ case REG_DWORD:
+ case REG_DWORD_BIG_ENDIAN:
+ blob = data_blob_talloc_zero(tctx, 4);
+ SIVAL(blob.data, 0, value);
+ break;
+ case REG_QWORD:
+ blob = data_blob_talloc_zero(tctx, 8);
+ SBVAL(blob.data, 0, value2);
+ break;
+ case REG_BINARY:
+ blob = data_blob_string_const("binary_blob");
+ break;
+ case REG_SZ:
+ torture_assert(tctx, push_reg_sz(tctx, &blob, string), "failed to push REG_SZ");
+ break;
+ case REG_MULTI_SZ:
+ torture_assert(tctx, push_reg_multi_sz(tctx, &blob, array), "failed to push REG_MULTI_SZ");
+ break;
+ default:
+ break;
+ }
+
+ torture_assert(tctx,
+ test_SetValue(b, tctx, handle, value_name, types[t], blob.data, blob.length),
+ "test_SetValue failed");
+ torture_assert(tctx,
+ test_QueryValue_full(b, tctx, handle, value_name, true),
+ talloc_asprintf(tctx, "test_QueryValue_full for %s value failed", value_name));
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, handle, value_name, &w_type, &w_size, &w_length, &w_data),
+ "test_winreg_QueryValue failed");
+ torture_assert(tctx,
+ test_DeleteValue(b, tctx, handle, value_name),
+ "test_DeleteValue failed");
+
+ torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
+ torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
+ torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
+ torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
+ }
+
+ torture_comment(tctx, "Testing SetValue (standard formats) succeeded\n");
+
+ return true;
+}
+
+static bool test_SetValue_values(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ DATA_BLOB blob;
+ const char *values[] = {
+ "torture_value",
+ "torture value",
+ "torture,value",
+ "torture;value",
+ "torture/value",
+ "torture\\value",
+ "torture_value_name",
+ "torture value name",
+ "torture,value,name",
+ "torture;value;name",
+ "torture/value/name",
+ "torture\\value\\name",
+ };
+ int i;
+
+ torture_comment(tctx, "Testing SetValue (values)\n");
+
+ for (i=0; i < ARRAY_SIZE(values); i++) {
+
+ enum winreg_Type w_type;
+ uint32_t w_size, w_length;
+ uint8_t *w_data;
+
+ blob = data_blob_talloc(tctx, NULL, 32);
+
+ generate_random_buffer(blob.data, 32);
+
+ torture_assert(tctx,
+ test_SetValue(b, tctx, handle, values[i], REG_BINARY, blob.data, blob.length),
+ "test_SetValue failed");
+ torture_assert(tctx,
+ test_QueryValue_full(b, tctx, handle, values[i], true),
+ talloc_asprintf(tctx, "test_QueryValue_full for %s value failed", values[i]));
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, handle, values[i], &w_type, &w_size, &w_length, &w_data),
+ "test_winreg_QueryValue failed");
+ torture_assert(tctx,
+ test_DeleteValue(b, tctx, handle, values[i]),
+ "test_DeleteValue failed");
+
+ torture_assert_int_equal(tctx, w_type, REG_BINARY, "winreg type mismatch");
+ torture_assert_int_equal(tctx, w_size, blob.length, "winreg size mismatch");
+ torture_assert_int_equal(tctx, w_length, blob.length, "winreg length mismatch");
+ torture_assert_mem_equal(tctx, w_data, blob.data, blob.length, "winreg buffer mismatch");
+ }
+
+ torture_comment(tctx, "Testing SetValue (values) succeeded\n");
+
+ return true;
+}
+
+typedef NTSTATUS (*winreg_open_fn)(struct dcerpc_binding_handle *, TALLOC_CTX *, void *);
+
+static bool test_SetValue_extended(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ const char *value_name = TEST_VALUE;
+ enum winreg_Type types[] = {
+ REG_NONE,
+ REG_SZ,
+ REG_EXPAND_SZ,
+ REG_BINARY,
+ REG_DWORD,
+ REG_DWORD_BIG_ENDIAN,
+ REG_LINK,
+ REG_MULTI_SZ,
+ REG_RESOURCE_LIST,
+ REG_FULL_RESOURCE_DESCRIPTOR,
+ REG_RESOURCE_REQUIREMENTS_LIST,
+ REG_QWORD,
+ 12,
+ 13,
+ 14,
+ 55,
+ 123456,
+ 653210,
+ __LINE__
+ };
+ int t, l;
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "skipping extended SetValue test against Samba4");
+ }
+
+ torture_comment(tctx, "Testing SetValue (extended formats)\n");
+
+ for (t=0; t < ARRAY_SIZE(types); t++) {
+ for (l=0; l < 16; l++) {
+
+ enum winreg_Type w_type;
+ uint32_t w_size, w_length;
+ uint8_t *w_data;
+
+ uint32_t size;
+ uint8_t *data;
+
+ size = l;
+ data = talloc_array(tctx, uint8_t, size);
+
+ generate_random_buffer(data, size);
+
+ torture_assert(tctx,
+ test_SetValue(b, tctx, handle, value_name, types[t], data, size),
+ "test_SetValue failed");
+
+ torture_assert(tctx,
+ test_winreg_QueryValue(tctx, b, handle, value_name, &w_type, &w_size, &w_length, &w_data),
+ "test_winreg_QueryValue failed");
+
+ torture_assert(tctx,
+ test_DeleteValue(b, tctx, handle, value_name),
+ "test_DeleteValue failed");
+
+ torture_assert_int_equal(tctx, w_type, types[t], "winreg type mismatch");
+ torture_assert_int_equal(tctx, w_size, size, "winreg size mismatch");
+ torture_assert_int_equal(tctx, w_length, size, "winreg length mismatch");
+ torture_assert_mem_equal(tctx, w_data, data, size, "winreg buffer mismatch");
+ }
+ }
+
+ torture_comment(tctx, "Testing SetValue (extended formats) succeeded\n");
+
+ return true;
+}
+
+static bool test_create_keynames(struct dcerpc_binding_handle *b,
+ struct torture_context *tctx,
+ struct policy_handle *handle)
+{
+ const char *keys[] = {
+ "torture_key",
+ "torture key",
+ "torture,key",
+ "torture/key",
+ "torture\\key",
+ };
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(keys); i++) {
+
+ enum winreg_CreateAction action_taken;
+ struct policy_handle new_handle;
+ char *q, *tmp;
+
+ torture_assert(tctx,
+ test_CreateKey_opts(tctx, b, handle, keys[i], NULL,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL,
+ WERR_OK,
+ &action_taken,
+ &new_handle),
+ talloc_asprintf(tctx, "failed to create '%s' key", keys[i]));
+
+ torture_assert_int_equal(tctx, action_taken, REG_CREATED_NEW_KEY, "unexpected action");
+
+ torture_assert(tctx,
+ test_DeleteKey_opts(b, tctx, handle, keys[i], WERR_OK),
+ "failed to delete key");
+
+ torture_assert(tctx,
+ test_DeleteKey_opts(b, tctx, handle, keys[i], WERR_FILE_NOT_FOUND),
+ "failed 2nd delete key");
+
+ tmp = talloc_strdup(tctx, keys[i]);
+
+ q = strchr(tmp, '\\');
+ if (q != NULL) {
+ *q = '\0';
+ q++;
+
+ torture_assert(tctx,
+ test_DeleteKey_opts(b, tctx, handle, tmp, WERR_OK),
+ "failed to delete key");
+
+ torture_assert(tctx,
+ test_DeleteKey_opts(b, tctx, handle, tmp, WERR_FILE_NOT_FOUND),
+ "failed 2nd delete key");
+ }
+ }
+
+ return true;
+}
+
+#define KEY_CURRENT_VERSION "SOFTWARE\\MICROSOFT\\WINDOWS NT\\CURRENTVERSION"
+#define VALUE_CURRENT_VERSION "CurrentVersion"
+#define VALUE_SYSTEM_ROOT "SystemRoot"
+
+static const struct {
+ const char *values[3];
+ uint32_t num_values;
+ bool existing_value;
+ const char *error_message;
+} multiple_values_tests[] = {
+ {
+ .values = { VALUE_CURRENT_VERSION, NULL, NULL },
+ .num_values = 1,
+ .existing_value = true,
+ .error_message = NULL
+ },{
+ .values = { VALUE_SYSTEM_ROOT, NULL, NULL },
+ .num_values = 1,
+ .existing_value = true,
+ .error_message = NULL
+ },{
+ .values = { VALUE_CURRENT_VERSION, VALUE_SYSTEM_ROOT, NULL },
+ .num_values = 2,
+ .existing_value = true,
+ .error_message = NULL
+ },{
+ .values = { VALUE_CURRENT_VERSION, VALUE_SYSTEM_ROOT,
+ VALUE_CURRENT_VERSION },
+ .num_values = 3,
+ .existing_value = true,
+ .error_message = NULL
+ },{
+ .values = { VALUE_CURRENT_VERSION, NULL, VALUE_SYSTEM_ROOT },
+ .num_values = 3,
+ .existing_value = false,
+ .error_message = NULL
+ },{
+ .values = { VALUE_CURRENT_VERSION, "", VALUE_SYSTEM_ROOT },
+ .num_values = 3,
+ .existing_value = false,
+ .error_message = NULL
+ },{
+ .values = { "IDoNotExist", NULL, NULL },
+ .num_values = 1,
+ .existing_value = false,
+ .error_message = NULL
+ },{
+ .values = { "IDoNotExist", VALUE_CURRENT_VERSION, NULL },
+ .num_values = 2,
+ .existing_value = false,
+ .error_message = NULL
+ },{
+ .values = { VALUE_CURRENT_VERSION, "IDoNotExist", NULL },
+ .num_values = 2,
+ .existing_value = false,
+ .error_message = NULL
+ }
+};
+
+static bool test_HKLM_wellknown(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle)
+{
+ struct policy_handle newhandle;
+ int i;
+
+ /* FIXME: s3 does not support SEC_FLAG_MAXIMUM_ALLOWED yet */
+ if (torture_setting_bool(tctx, "samba3", false)) {
+ torture_assert(tctx, test_OpenKey_opts(tctx, b, handle,
+ KEY_CURRENT_VERSION,
+ REG_OPTION_NON_VOLATILE,
+ KEY_QUERY_VALUE,
+ &newhandle,
+ WERR_OK),
+ "failed to open current version key");
+ } else {
+ torture_assert(tctx, test_OpenKey(b, tctx, handle, KEY_CURRENT_VERSION, &newhandle),
+ "failed to open current version key");
+ }
+
+ torture_assert(tctx, test_QueryValue_full(b, tctx, &newhandle, VALUE_CURRENT_VERSION, true),
+ "failed to query current version");
+ torture_assert(tctx, test_QueryValue_full(b, tctx, &newhandle, "IDoNotExist", false),
+ "succeeded to query nonexistent value");
+ torture_assert(tctx, test_QueryValue_full(b, tctx, &newhandle, NULL, false),
+ "succeeded to query value with NULL name");
+ torture_assert(tctx, test_QueryValue_full(b, tctx, &newhandle, "", false),
+ "succeeded to query nonexistent default value (\"\")");
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping QueryMultipleValues{2} tests against Samba4\n");
+ goto close_key;
+ }
+
+ for (i=0; i < ARRAY_SIZE(multiple_values_tests); i++) {
+ const char *msg;
+ msg = talloc_asprintf(tctx,
+ "failed to query %d %sexisting values\n",
+ multiple_values_tests[i].num_values,
+ multiple_values_tests[i].existing_value ? "":"non");
+
+ torture_assert(tctx,
+ test_QueryMultipleValues_full(b, tctx, &newhandle,
+ multiple_values_tests[i].num_values,
+ multiple_values_tests[i].values,
+ multiple_values_tests[i].existing_value),
+ msg);
+ torture_assert(tctx,
+ test_QueryMultipleValues2_full(b, tctx, &newhandle,
+ multiple_values_tests[i].num_values,
+ multiple_values_tests[i].values,
+ multiple_values_tests[i].existing_value),
+ msg);
+ }
+
+ close_key:
+ torture_assert(tctx, test_CloseKey(b, tctx, &newhandle),
+ "failed to close current version key");
+
+ return true;
+}
+
+static bool test_OpenHive(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ int hkey)
+{
+ struct winreg_OpenHKLM r;
+
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = handle;
+
+ switch (hkey) {
+ case HKEY_LOCAL_MACHINE:
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_OpenHKLM_r(b, tctx, &r),
+ "failed to open HKLM");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to open HKLM");
+ break;
+ case HKEY_CURRENT_USER:
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_OpenHKCU_r(b, tctx, (struct winreg_OpenHKCU *)(void *)&r),
+ "failed to open HKCU");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to open HKCU");
+ break;
+ case HKEY_USERS:
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_OpenHKU_r(b, tctx, (struct winreg_OpenHKU *)(void *)&r),
+ "failed to open HKU");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to open HKU");
+ break;
+ case HKEY_CLASSES_ROOT:
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_winreg_OpenHKCR_r(b, tctx, (struct winreg_OpenHKCR *)(void *)&r),
+ "failed to open HKCR");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "failed to open HKCR");
+ break;
+ default:
+ torture_warning(tctx, "unsupported hkey: 0x%08x\n", hkey);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_volatile_keys(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ int hkey)
+{
+ struct policy_handle new_handle, hive_handle;
+ enum winreg_CreateAction action_taken = REG_ACTION_NONE;
+
+ ZERO_STRUCT(new_handle);
+ ZERO_STRUCT(hive_handle);
+
+ torture_comment(tctx, "Testing VOLATILE key\n");
+
+ test_DeleteKey(b, tctx, handle, TEST_KEY_VOLATILE);
+
+ torture_assert(tctx,
+ test_CreateKey_opts(tctx, b, handle, TEST_KEY_VOLATILE, NULL,
+ REG_OPTION_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL,
+ WERR_OK,
+ &action_taken,
+ &new_handle),
+ "failed to create REG_OPTION_VOLATILE type key");
+
+ torture_assert_int_equal(tctx, action_taken, REG_CREATED_NEW_KEY, "unexpected action");
+
+ torture_assert(tctx,
+ test_CreateKey_opts(tctx, b, &new_handle, TEST_SUBKEY_VOLATILE, NULL,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL,
+ WERR_CHILD_MUST_BE_VOLATILE,
+ NULL,
+ NULL),
+ "failed to fail create REG_OPTION_VOLATILE type key");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, TEST_KEY_VOLATILE,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &new_handle,
+ WERR_OK),
+ "failed to open volatile key");
+
+ torture_assert(tctx,
+ test_DeleteKey(b, tctx, handle, TEST_KEY_VOLATILE),
+ "failed to delete key");
+
+ torture_assert(tctx,
+ test_CreateKey_opts(tctx, b, handle, TEST_KEY_VOLATILE, NULL,
+ REG_OPTION_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL,
+ WERR_OK,
+ &action_taken,
+ &new_handle),
+ "failed to create REG_OPTION_VOLATILE type key");
+
+ torture_assert_int_equal(tctx, action_taken, REG_CREATED_NEW_KEY, "unexpected action");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, TEST_KEY_VOLATILE,
+ REG_OPTION_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &new_handle,
+ WERR_OK),
+ "failed to open volatile key");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ torture_assert(tctx,
+ test_OpenHive(tctx, b, &hive_handle, hkey),
+ "failed top open hive");
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, &hive_handle, TEST_KEY_VOLATILE,
+ REG_OPTION_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &new_handle,
+ WERR_FILE_NOT_FOUND),
+ "failed to open volatile key");
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, &hive_handle, TEST_KEY_VOLATILE,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &new_handle,
+ WERR_FILE_NOT_FOUND),
+ "failed to open volatile key");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &hive_handle),
+ "failed to close");
+
+ torture_assert(tctx,
+ test_DeleteKey(b, tctx, handle, TEST_KEY_VOLATILE),
+ "failed to delete key");
+
+
+ torture_comment(tctx, "Testing VOLATILE key succeeded\n");
+
+ return true;
+}
+
+static const char *kernel_mode_registry_path(struct torture_context *tctx,
+ int hkey,
+ const char *sid_string,
+ const char *path)
+{
+ switch (hkey) {
+ case HKEY_LOCAL_MACHINE:
+ return talloc_asprintf(tctx, "\\Registry\\MACHINE\\%s", path);
+ case HKEY_CURRENT_USER:
+ return talloc_asprintf(tctx, "\\Registry\\USER\\%s\\%s", sid_string, path);
+ case HKEY_USERS:
+ return talloc_asprintf(tctx, "\\Registry\\USER\\%s", path);
+ case HKEY_CLASSES_ROOT:
+ return talloc_asprintf(tctx, "\\Registry\\MACHINE\\Software\\Classes\\%s", path);
+ default:
+ torture_warning(tctx, "unsupported hkey: 0x%08x\n", hkey);
+ return NULL;
+ }
+}
+
+static bool test_symlink_keys(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key,
+ int hkey)
+{
+ struct policy_handle new_handle;
+ enum winreg_CreateAction action_taken;
+ DATA_BLOB blob;
+ uint32_t value = 42;
+ const char *test_key_symlink_dest;
+ const char *test_key_symlink;
+ const char *kernel_mode_path;
+
+ /* disable until we know how to delete a symbolic link */
+ torture_skip(tctx, "symlink test disabled");
+
+ torture_comment(tctx, "Testing REG_OPTION_CREATE_LINK key\n");
+
+ /* create destination key with testvalue */
+ test_key_symlink = talloc_asprintf(tctx, "%s\\%s",
+ key, TEST_KEY_SYMLINK);
+ test_key_symlink_dest = talloc_asprintf(tctx, "%s\\%s",
+ key, TEST_KEY_SYMLINK_DEST);
+
+ test_DeleteKey(b, tctx, handle, test_key_symlink);
+
+ torture_assert(tctx,
+ test_CreateKey_opts(tctx, b, handle, test_key_symlink_dest, NULL,
+ 0,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL,
+ WERR_OK,
+ &action_taken,
+ &new_handle),
+ "failed to create symlink destination");
+
+ blob = data_blob_talloc_zero(tctx, 4);
+ SIVAL(blob.data, 0, value);
+
+ torture_assert(tctx,
+ test_SetValue(b, tctx, &new_handle, "TestValue", REG_DWORD, blob.data, blob.length),
+ "failed to create TestValue");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ /* create symlink */
+
+ torture_assert(tctx,
+ test_CreateKey_opts(tctx, b, handle, test_key_symlink, NULL,
+ REG_OPTION_CREATE_LINK | REG_OPTION_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ NULL,
+ WERR_OK,
+ &action_taken,
+ &new_handle),
+ "failed to create REG_OPTION_CREATE_LINK type key");
+
+ torture_assert_int_equal(tctx, action_taken, REG_CREATED_NEW_KEY, "unexpected action");
+
+ kernel_mode_path = kernel_mode_registry_path(tctx, hkey, NULL, test_key_symlink_dest);
+
+ torture_assert(tctx,
+ convert_string_talloc(tctx, CH_UNIX, CH_UTF16,
+ kernel_mode_path,
+ strlen(kernel_mode_path), /* not NULL terminated */
+ &blob.data, &blob.length),
+ "failed to convert");
+
+ torture_assert(tctx,
+ test_SetValue(b, tctx, &new_handle, "SymbolicLinkValue", REG_LINK, blob.data, blob.length),
+ "failed to create SymbolicLinkValue value");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ /* test follow symlink */
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, test_key_symlink,
+ 0,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &new_handle,
+ WERR_OK),
+ "failed to follow symlink key");
+
+ torture_assert(tctx,
+ test_QueryValue(b, tctx, &new_handle, "TestValue"),
+ "failed to query value");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ /* delete link */
+
+ torture_assert(tctx,
+ test_OpenKey_opts(tctx, b, handle, test_key_symlink,
+ REG_OPTION_OPEN_LINK | REG_OPTION_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &new_handle,
+ WERR_OK),
+ "failed to open symlink key");
+
+ torture_assert(tctx,
+ test_DeleteValue(b, tctx, &new_handle, "SymbolicLinkValue"),
+ "failed to delete value SymbolicLinkValue");
+
+ torture_assert(tctx,
+ test_CloseKey(b, tctx, &new_handle),
+ "failed to close");
+
+ torture_assert(tctx,
+ test_DeleteKey(b, tctx, handle, test_key_symlink),
+ "failed to delete key");
+
+ /* delete destination */
+
+ torture_assert(tctx,
+ test_DeleteKey(b, tctx, handle, test_key_symlink_dest),
+ "failed to delete key");
+
+ return true;
+}
+
+static bool test_CreateKey_keytypes(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *key,
+ int hkey)
+{
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "skipping CreateKey keytypes test against Samba");
+ }
+
+ torture_assert(tctx,
+ test_volatile_keys(tctx, b, handle, hkey),
+ "failed to test volatile keys");
+
+ torture_assert(tctx,
+ test_symlink_keys(tctx, b, handle, key, hkey),
+ "failed to test symlink keys");
+
+ return true;
+}
+
+static bool test_key_base(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ struct policy_handle *handle,
+ const char *base_key,
+ int hkey)
+{
+ struct policy_handle newhandle;
+ bool ret = true, created = false, deleted = false;
+ bool created3 = false;
+ const char *test_key1;
+ const char *test_key3;
+ const char *test_subkey;
+
+ test_Cleanup(b, tctx, handle, base_key);
+
+ if (!test_CreateKey(b, tctx, handle, base_key, NULL)) {
+ torture_comment(tctx,
+ "CreateKey(%s) failed\n", base_key);
+ }
+
+ test_key1 = talloc_asprintf(tctx, "%s\\%s", base_key, TEST_KEY1);
+
+ if (!test_CreateKey(b, tctx, handle, test_key1, NULL)) {
+ torture_comment(tctx,
+ "CreateKey failed - not considering a failure\n");
+ } else {
+ created = true;
+ }
+
+ if (created) {
+ if (!test_FlushKey(b, tctx, handle)) {
+ torture_comment(tctx, "FlushKey failed\n");
+ ret = false;
+ }
+
+ if (!test_OpenKey(b, tctx, handle, test_key1, &newhandle)) {
+ torture_fail(tctx,
+ "CreateKey failed (OpenKey after Create didn't work)\n");
+ }
+
+ if (hkey == HKEY_CURRENT_USER) {
+ torture_assert(tctx, test_SetValue_simple(b, tctx, &newhandle),
+ "simple SetValue test failed");
+ torture_assert(tctx, test_SetValue_values(b, tctx, &newhandle),
+ "values SetValue test failed");
+ torture_assert(tctx, test_SetValue_extended(b, tctx, &newhandle),
+ "extended SetValue test failed");
+ torture_assert(tctx, test_create_keynames(b, tctx, &newhandle),
+ "keyname CreateKey test failed");
+ } else {
+ torture_assert(tctx, test_CreateKey_keytypes(tctx, b, &newhandle, test_key1, hkey),
+ "keytype test failed");
+ torture_assert(tctx, test_EnumValue_one(b, tctx, &newhandle, 0xff),
+ "simple EnumValue test failed");
+ }
+
+ if (!test_CloseKey(b, tctx, &newhandle)) {
+ torture_fail(tctx,
+ "CreateKey failed (CloseKey after Open didn't work)\n");
+ }
+
+ if (!test_DeleteKey(b, tctx, handle, test_key1)) {
+ torture_comment(tctx, "DeleteKey(%s) failed\n",
+ test_key1);
+ ret = false;
+ } else {
+ deleted = true;
+ }
+
+ if (!test_FlushKey(b, tctx, handle)) {
+ torture_comment(tctx, "FlushKey failed\n");
+ ret = false;
+ }
+
+ if (deleted) {
+ if (!test_OpenKey_opts(tctx, b, handle, test_key1,
+ REG_OPTION_NON_VOLATILE,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &newhandle,
+ WERR_FILE_NOT_FOUND)) {
+ torture_comment(tctx,
+ "DeleteKey failed (OpenKey after Delete "
+ "did not return WERR_FILE_NOT_FOUND)\n");
+ ret = false;
+ }
+ }
+
+ test_key3 = talloc_asprintf(tctx, "%s\\%s", base_key, TEST_KEY3);
+
+ if (test_CreateKey(b, tctx, handle, test_key3, NULL)) {
+ created3 = true;
+ }
+
+ test_subkey = talloc_asprintf(tctx, "%s\\%s", test_key3, TEST_SUBKEY);
+
+ if (created3) {
+ if (test_CreateKey(b, tctx, handle, test_subkey, NULL)) {
+ if (!test_DeleteKey(b, tctx, handle, test_subkey)) {
+ torture_comment(tctx, "DeleteKey(%s) failed\n", test_subkey);
+ ret = false;
+ }
+ }
+
+ if (!test_DeleteKey(b, tctx, handle, test_key3)) {
+ torture_comment(tctx, "DeleteKey(%s) failed\n", test_key3);
+ ret = false;
+ }
+ }
+ }
+
+ test_Cleanup(b, tctx, handle, base_key);
+
+ return ret;
+}
+
+static bool test_key_base_sd(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *handle,
+ const char *base_key)
+{
+ struct policy_handle newhandle;
+ bool ret = true, created2 = false, created4 = false;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *test_key2;
+ const char *test_key4;
+
+ torture_skip(tctx, "security descriptor test disabled\n");
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "skipping security descriptor tests against Samba");
+ }
+
+ test_Cleanup(b, tctx, handle, base_key);
+
+ if (!test_CreateKey(b, tctx, handle, base_key, NULL)) {
+ torture_comment(tctx,
+ "CreateKey(%s) failed\n", base_key);
+ }
+
+ test_key2 = talloc_asprintf(tctx, "%s\\%s", base_key, TEST_KEY2);
+
+ if (test_CreateKey_sd(b, tctx, handle, test_key2,
+ NULL, &newhandle)) {
+ created2 = true;
+ }
+
+ if (created2 && !test_CloseKey(b, tctx, &newhandle)) {
+ torture_comment(tctx, "CloseKey failed\n");
+ ret = false;
+ }
+
+ test_key4 = talloc_asprintf(tctx, "%s\\%s", base_key, TEST_KEY4);
+
+ if (test_CreateKey_sd(b, tctx, handle, test_key4, NULL, &newhandle)) {
+ created4 = true;
+ }
+
+ if (created4 && !test_CloseKey(b, tctx, &newhandle)) {
+ torture_comment(tctx, "CloseKey failed\n");
+ ret = false;
+ }
+
+ if (created4 && !test_SecurityDescriptors(p, tctx, handle, test_key4)) {
+ ret = false;
+ }
+
+ if (created4 && !test_DeleteKey(b, tctx, handle, test_key4)) {
+ torture_comment(tctx, "DeleteKey(%s) failed\n", test_key4);
+ ret = false;
+ }
+
+ if (created2 && !test_DeleteKey(b, tctx, handle, test_key4)) {
+ torture_comment(tctx, "DeleteKey(%s) failed\n", test_key4);
+ ret = false;
+ }
+
+ test_Cleanup(b, tctx, handle, base_key);
+
+ return ret;
+}
+
+static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p,
+ void *userdata)
+{
+ struct policy_handle handle;
+ bool ret = true;
+ struct winreg_OpenHKLM r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ const char *torture_base_key;
+ int hkey = 0;
+
+ winreg_open_fn open_fn = (winreg_open_fn)userdata;
+
+ r.in.system_name = 0;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.handle = &handle;
+
+ torture_assert_ntstatus_ok(tctx, open_fn(b, tctx, &r),
+ "open");
+
+ if (!test_GetVersion(b, tctx, &handle)) {
+ torture_comment(tctx, "GetVersion failed\n");
+ ret = false;
+ }
+
+ if (open_fn == (winreg_open_fn)dcerpc_winreg_OpenHKLM_r) {
+ hkey = HKEY_LOCAL_MACHINE;
+ torture_base_key = "SOFTWARE\\Samba\\" TEST_KEY_BASE;
+ } else if (open_fn == (winreg_open_fn)dcerpc_winreg_OpenHKU_r) {
+ hkey = HKEY_USERS;
+ torture_base_key = TEST_KEY_BASE;
+ } else if (open_fn == (winreg_open_fn)dcerpc_winreg_OpenHKCR_r) {
+ hkey = HKEY_CLASSES_ROOT;
+ torture_base_key = TEST_KEY_BASE;
+ } else if (open_fn == (winreg_open_fn)dcerpc_winreg_OpenHKCU_r) {
+ hkey = HKEY_CURRENT_USER;
+ torture_base_key = TEST_KEY_BASE;
+ } else {
+ torture_fail(tctx, "unsupported hkey");
+ }
+
+ if (hkey == HKEY_LOCAL_MACHINE) {
+ torture_assert(tctx,
+ test_HKLM_wellknown(tctx, b, &handle),
+ "failed to test HKLM wellknown keys");
+ }
+
+ if (!test_key_base(tctx, b, &handle, torture_base_key, hkey)) {
+ torture_warning(tctx, "failed to test TEST_KEY_BASE(%s)",
+ torture_base_key);
+ ret = false;
+ }
+
+ if (!test_key_base_sd(tctx, p, &handle, torture_base_key)) {
+ torture_warning(tctx, "failed to test TEST_KEY_BASE(%s) sd",
+ torture_base_key);
+ ret = false;
+ }
+
+ /* The HKCR hive has a very large fanout */
+ if (hkey == HKEY_CLASSES_ROOT) {
+ if(!test_key(p, tctx, &handle, MAX_DEPTH - 1, false)) {
+ ret = false;
+ }
+ } else if (hkey == HKEY_LOCAL_MACHINE) {
+ /* FIXME we are not allowed to enum values in the HKLM root */
+ } else {
+ if (!test_key(p, tctx, &handle, 0, false)) {
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+struct torture_suite *torture_rpc_winreg(TALLOC_CTX *mem_ctx)
+{
+ struct torture_rpc_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "winreg");
+ struct torture_test *test;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "winreg",
+ &ndr_table_winreg);
+
+ test = torture_rpc_tcase_add_test(tcase, "InitiateSystemShutdown",
+ test_InitiateSystemShutdown);
+ test->dangerous = true;
+
+ test = torture_rpc_tcase_add_test(tcase, "InitiateSystemShutdownEx",
+ test_InitiateSystemShutdownEx);
+ test->dangerous = true;
+
+ torture_rpc_tcase_add_test_ex(tcase, "HKLM",
+ test_Open,
+ (void *)dcerpc_winreg_OpenHKLM_r);
+ torture_rpc_tcase_add_test_ex(tcase, "HKU",
+ test_Open,
+ (void *)dcerpc_winreg_OpenHKU_r);
+ torture_rpc_tcase_add_test_ex(tcase, "HKCR",
+ test_Open,
+ (void *)dcerpc_winreg_OpenHKCR_r);
+ torture_rpc_tcase_add_test_ex(tcase, "HKCU",
+ test_Open,
+ (void *)dcerpc_winreg_OpenHKCU_r);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/witness.c b/source4/torture/rpc/witness.c
new file mode 100644
index 0000000..602e8ca
--- /dev/null
+++ b/source4/torture/rpc/witness.c
@@ -0,0 +1,911 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for rpc witness operations
+
+ Copyright (C) Guenther Deschner 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "torture/rpc/torture_rpc.h"
+#include "librpc/gen_ndr/ndr_witness_c.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "librpc/gen_ndr/ndr_clusapi_c.h"
+#include "param/param.h"
+#include <tevent.h>
+#include "lib/cmdline/cmdline.h"
+
+struct torture_test_clusapi_state {
+ struct dcerpc_pipe *p;
+};
+
+struct torture_test_witness_state {
+ const char *net_name;
+ const char *share_name;
+ struct witness_interfaceList *list;
+ struct policy_handle context_handle;
+ struct torture_test_clusapi_state clusapi;
+};
+
+static bool test_witness_GetInterfaceList(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct witness_GetInterfaceList r;
+ struct witness_interfaceList *l;
+ struct torture_test_witness_state *state =
+ (struct torture_test_witness_state *)data;
+
+ r.out.interface_list = &l;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_GetInterfaceList_r(b, tctx, &r),
+ "GetInterfaceList failed");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetInterfaceList failed");
+
+ state->list = l;
+
+ return true;
+}
+
+static bool find_sofs_share(struct torture_context *tctx,
+ const char **sofs_sharename)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding_handle *b;
+ struct srvsvc_NetShareEnumAll r;
+ struct srvsvc_NetShareInfoCtr info_ctr;
+ struct srvsvc_NetShareCtr1 ctr1;
+ uint32_t resume_handle = 0;
+ uint32_t totalentries = 0;
+ int i;
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_connection_transport(tctx, &p, &ndr_table_srvsvc,
+ NCACN_NP, 0, 0),
+ "failed to setup srvsvc connection");
+
+ b = p->binding_handle;
+
+ ZERO_STRUCT(ctr1);
+
+ info_ctr.level = 1;
+ info_ctr.ctr.ctr1 = &ctr1;
+
+ r.in.server_unc = dcerpc_server_name(p);
+ r.in.max_buffer = -1;
+ r.in.info_ctr = &info_ctr;
+ r.in.resume_handle = &resume_handle;
+ r.out.totalentries = &totalentries;
+ r.out.info_ctr = &info_ctr;
+ r.out.resume_handle = &resume_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_srvsvc_NetShareEnumAll_r(b, tctx, &r),
+ "failed to call srvsvc_NetShareEnumAll");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "failed to call srvsvc_NetShareEnumAll");
+
+ for (i=0; i < r.out.info_ctr->ctr.ctr1->count; i++) {
+
+ if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_CLUSTER_SOFS) {
+ *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
+ if (*sofs_sharename == NULL) {
+ return false;
+ }
+ torture_comment(tctx, "using SOFS share: %s\n", *sofs_sharename);
+ return true;
+ }
+ if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_DISKTREE) {
+ *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
+ if (*sofs_sharename == NULL) {
+ return false;
+ }
+ torture_comment(tctx, "assuming SOFS share: %s\n", *sofs_sharename);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool init_witness_test_state(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct torture_test_witness_state *state)
+{
+ if (state->net_name == NULL) {
+ state->net_name = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "net_name");
+ }
+
+ if (state->list == NULL) {
+ torture_assert(tctx,
+ test_witness_GetInterfaceList(tctx, p, state),
+ "failed to retrieve GetInterfaceList");
+ }
+
+ if (state->share_name == NULL) {
+ find_sofs_share(tctx, &state->share_name);
+ }
+
+ return true;
+}
+
+static bool test_witness_UnRegister_with_handle(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *context_handle)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct witness_UnRegister r;
+
+ r.in.context_handle = *context_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_UnRegister_r(b, tctx, &r),
+ "UnRegister failed");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "UnRegister failed");
+
+ /* make sure we are not able/allowed to reuse context handles after they
+ * have been unregistered */
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_UnRegister_r(b, tctx, &r),
+ "UnRegister failed");
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_PARAMETER,
+ "UnRegister failed");
+
+ return true;
+}
+
+static bool test_witness_UnRegister(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ /* acquire handle and free afterwards */
+ return true;
+}
+
+static bool get_ip_address_from_interface(struct torture_context *tctx,
+ struct witness_interfaceInfo *i,
+ const char **ip_address)
+{
+ if (i->flags & WITNESS_INFO_IPv4_VALID) {
+ *ip_address = talloc_strdup(tctx, i->ipv4);
+ torture_assert(tctx, *ip_address, "talloc_strdup failed");
+ return true;
+ }
+
+ if (i->flags & WITNESS_INFO_IPv6_VALID) {
+ *ip_address = talloc_strdup(tctx, i->ipv6);
+ torture_assert(tctx, *ip_address, "talloc_strdup failed");
+ return true;
+ }
+
+ return false;
+}
+
+static bool check_valid_interface(struct torture_context *tctx,
+ struct witness_interfaceInfo *i)
+{
+ /* continue looking for an interface that allows witness
+ * registration */
+ if (!(i->flags & WITNESS_INFO_WITNESS_IF)) {
+ return false;
+ }
+
+ /* witness should be available of course */
+ if (i->state != WITNESS_STATE_AVAILABLE) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_witness_Register(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct witness_Register r;
+ struct policy_handle context_handle;
+ struct torture_test_witness_state *state =
+ (struct torture_test_witness_state *)data;
+ int i;
+
+ struct {
+ enum witness_version version;
+ const char *net_name;
+ const char *ip_address;
+ const char *client_computer_name;
+ NTSTATUS expected_status;
+ WERROR expected_result;
+ } tests[] = {
+ {
+ .version = 0,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = 1,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = 123456,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = -1,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = WITNESS_V2,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = WITNESS_V1,
+ .net_name = "",
+ .ip_address = "",
+ .client_computer_name = "",
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_INVALID_PARAMETER
+ },{
+ .version = WITNESS_V1,
+ .net_name = NULL,
+ .ip_address = NULL,
+ .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_INVALID_PARAMETER
+ },{
+ .version = WITNESS_V2,
+ .net_name = NULL,
+ .ip_address = NULL,
+ .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = WITNESS_V1,
+ .net_name = dcerpc_server_name(p),
+ .ip_address = NULL,
+ .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_INVALID_PARAMETER
+ }
+
+ };
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+
+ ZERO_STRUCT(r);
+
+ r.out.context_handle = &context_handle;
+
+ r.in.version = tests[i].version;
+ r.in.net_name = tests[i].net_name;
+ r.in.ip_address = tests[i].ip_address;
+ r.in.client_computer_name = tests[i].client_computer_name;
+
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_witness_Register_r(b, tctx, &r),
+ tests[i].expected_status,
+ "Register failed");
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ tests[i].expected_result,
+ "Register failed");
+
+ if (W_ERROR_IS_OK(r.out.result)) {
+
+ /* we have a handle, make sure to unregister it */
+ torture_assert(tctx,
+ test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
+ "Failed to unregister");
+ }
+ }
+
+ init_witness_test_state(tctx, p, state);
+
+ for (i=0; state->list && i < state->list->num_interfaces; i++) {
+
+ const char *ip_address;
+ struct witness_interfaceInfo interface = state->list->interfaces[i];
+
+ if (!check_valid_interface(tctx, &interface)) {
+ continue;
+ }
+
+ torture_assert(tctx,
+ get_ip_address_from_interface(tctx, &interface, &ip_address),
+ "failed to get ip_address from interface");
+
+ r.in.version = WITNESS_V1;
+ r.in.net_name = state->net_name;
+ r.in.ip_address = ip_address;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_Register_r(b, tctx, &r),
+ "Register failed");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "Register failed");
+
+ torture_assert(tctx,
+ test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
+ "Failed to unregister");
+ }
+
+ return true;
+}
+
+static bool test_witness_RegisterEx(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct witness_RegisterEx r;
+ struct policy_handle context_handle;
+ struct torture_test_witness_state *state =
+ (struct torture_test_witness_state *)data;
+ int i;
+
+ struct {
+ enum witness_version version;
+ const char *net_name;
+ const char *ip_address;
+ const char *client_computer_name;
+ NTSTATUS expected_status;
+ WERROR expected_result;
+ } tests[] = {
+ {
+ .version = 0,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = 1,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = 123456,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = -1,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = WITNESS_V1,
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = WITNESS_V2,
+ .net_name = "",
+ .ip_address = "",
+ .client_computer_name = "",
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_INVALID_PARAMETER
+ },{
+ .version = WITNESS_V2,
+ .net_name = NULL,
+ .ip_address = NULL,
+ .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_INVALID_PARAMETER
+ },{
+ .version = WITNESS_V1,
+ .net_name = NULL,
+ .ip_address = NULL,
+ .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_REVISION_MISMATCH
+ },{
+ .version = WITNESS_V2,
+ .net_name = dcerpc_server_name(p),
+ .ip_address = NULL,
+ .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
+ .expected_status = NT_STATUS_OK,
+ .expected_result = WERR_INVALID_PARAMETER
+ }
+
+ };
+
+ for (i=0; i < ARRAY_SIZE(tests); i++) {
+
+ ZERO_STRUCT(r);
+
+ r.out.context_handle = &context_handle;
+
+ r.in.version = tests[i].version;
+ r.in.net_name = tests[i].net_name;
+ r.in.ip_address = tests[i].ip_address;
+ r.in.client_computer_name = tests[i].client_computer_name;
+
+ torture_assert_ntstatus_equal(tctx,
+ dcerpc_witness_RegisterEx_r(b, tctx, &r),
+ tests[i].expected_status,
+ "RegisterEx failed");
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ tests[i].expected_result,
+ "RegisterEx failed");
+
+ if (W_ERROR_IS_OK(r.out.result)) {
+
+ /* we have a handle, make sure to unregister it */
+ torture_assert(tctx,
+ test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
+ "Failed to unregister");
+ }
+ }
+
+ init_witness_test_state(tctx, p, state);
+
+ for (i=0; state->list && i < state->list->num_interfaces; i++) {
+
+ const char *ip_address;
+ struct witness_interfaceInfo interface = state->list->interfaces[i];
+
+ if (!check_valid_interface(tctx, &interface)) {
+ continue;
+ }
+
+ torture_assert(tctx,
+ get_ip_address_from_interface(tctx, &interface, &ip_address),
+ "failed to get ip_address from interface");
+
+ r.in.version = WITNESS_V2;
+ r.in.net_name = state->net_name;
+ r.in.ip_address = ip_address;
+
+ /*
+ * a valid request with an invalid sharename fails with
+ * WERR_INVALID_STATE
+ */
+ r.in.share_name = "any_invalid_share_name";
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_RegisterEx_r(b, tctx, &r),
+ "RegisterEx failed");
+
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_INVALID_STATE,
+ "RegisterEx failed");
+
+ r.in.share_name = NULL;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_RegisterEx_r(b, tctx, &r),
+ "RegisterEx failed");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "RegisterEx failed");
+
+ torture_assert(tctx,
+ test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
+ "Failed to unregister");
+ }
+
+ return true;
+}
+
+static bool setup_clusapi_connection(struct torture_context *tctx,
+ struct torture_test_witness_state *s)
+{
+ struct dcerpc_binding *binding;
+
+ if (s->clusapi.p) {
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "failed to retrieve torture binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_transport(binding, NCACN_IP_TCP),
+ "failed to set transport");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_binding_set_flags(binding, DCERPC_SEAL, 0),
+ "failed to set dcerpc flags");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx, &s->clusapi.p, binding,
+ &ndr_table_clusapi,
+ samba_cmdline_get_creds(),
+ tctx->ev, tctx->lp_ctx),
+ "failed to connect dcerpc pipe");
+
+ return true;
+}
+
+#if 0
+static bool cluster_get_nodes(struct torture_context *tctx,
+ struct torture_test_witness_state *s)
+{
+ struct clusapi_CreateEnum r;
+ struct ENUM_LIST *ReturnEnum;
+ WERROR rpc_status;
+ struct dcerpc_binding_handle *b;
+
+ torture_assert(tctx,
+ setup_clusapi_connection(tctx, s),
+ "failed to setup clusapi connection");
+
+ b = s->clusapi.p->binding_handle;
+
+ r.in.dwType = CLUSTER_ENUM_NODE;
+ r.out.ReturnEnum = &ReturnEnum;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
+ "failed to enumerate nodes");
+
+ return true;
+}
+#endif
+
+static bool test_GetResourceState_int(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ struct policy_handle *hResource,
+ enum clusapi_ClusterResourceState *State)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct clusapi_GetResourceState r;
+ const char *NodeName;
+ const char *GroupName;
+ WERROR rpc_status;
+
+ r.in.hResource = *hResource;
+ r.out.State = State;
+ r.out.NodeName = &NodeName;
+ r.out.GroupName = &GroupName;
+ r.out.rpc_status = &rpc_status;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_clusapi_GetResourceState_r(b, tctx, &r),
+ "GetResourceState failed");
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "GetResourceState failed");
+
+ return true;
+}
+
+static bool toggle_cluster_resource_state(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *resource_name,
+ enum clusapi_ClusterResourceState *old_state,
+ enum clusapi_ClusterResourceState *new_state)
+{
+ struct policy_handle hResource;
+ enum clusapi_ClusterResourceState State;
+
+ torture_assert(tctx,
+ test_OpenResource_int(tctx, p, resource_name, &hResource),
+ "failed to open resource");
+ torture_assert(tctx,
+ test_GetResourceState_int(tctx, p, &hResource, &State),
+ "failed to query resource state");
+
+ if (old_state) {
+ *old_state = State;
+ }
+
+ switch (State) {
+ case ClusterResourceOffline:
+ if (!test_OnlineResource_int(tctx, p, &hResource)) {
+ test_CloseResource_int(tctx, p, &hResource);
+ torture_warning(tctx, "failed to set resource online");
+ return false;
+ }
+ break;
+ case ClusterResourceOnline:
+ if (!test_OfflineResource_int(tctx, p, &hResource)) {
+ test_CloseResource_int(tctx, p, &hResource);
+ torture_warning(tctx, "failed to set resource offline");
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ torture_assert(tctx,
+ test_GetResourceState_int(tctx, p, &hResource, &State),
+ "failed to query resource state");
+
+ if (new_state) {
+ *new_state = State;
+ }
+
+ test_CloseResource_int(tctx, p, &hResource);
+
+ return true;
+}
+
+static bool test_witness_AsyncNotify(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct witness_AsyncNotify r;
+ struct witness_notifyResponse *response;
+ struct torture_test_witness_state *state =
+ (struct torture_test_witness_state *)data;
+ int i;
+
+ init_witness_test_state(tctx, p, state);
+
+ setup_clusapi_connection(tctx, state);
+
+ for (i=0; state->list && i < state->list->num_interfaces; i++) {
+
+ const char *ip_address;
+ struct witness_interfaceInfo interface = state->list->interfaces[i];
+ struct witness_Register reg;
+ struct tevent_req *req;
+ enum clusapi_ClusterResourceState old_state, new_state;
+
+ if (!check_valid_interface(tctx, &interface)) {
+ continue;
+ }
+
+ torture_assert(tctx,
+ get_ip_address_from_interface(tctx, &interface, &ip_address),
+ "failed to get ip_address from interface");
+
+ reg.in.version = WITNESS_V1;
+ reg.in.net_name = state->net_name;
+ reg.in.ip_address = ip_address;
+ reg.in.client_computer_name = lpcfg_netbios_name(tctx->lp_ctx);
+ reg.out.context_handle = &state->context_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_Register_r(b, tctx, &reg),
+ "Register failed");
+
+ torture_assert_werr_ok(tctx,
+ reg.out.result,
+ "Register failed");
+
+ r.in.context_handle = state->context_handle;
+ r.out.response = &response;
+
+ req = dcerpc_witness_AsyncNotify_r_send(tctx, tctx->ev, b, &r);
+ torture_assert(tctx, req, "failed to create request");
+
+ torture_assert(tctx,
+ toggle_cluster_resource_state(tctx, state->clusapi.p, state->net_name, &old_state, &new_state),
+ "failed to toggle cluster resource state");
+ torture_assert(tctx, old_state != new_state, "failed to change cluster resource state");
+
+ torture_assert(tctx,
+ tevent_req_poll(req, tctx->ev),
+ "failed to call event loop");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_AsyncNotify_r_recv(req, tctx),
+ "failed to receive reply");
+
+ torture_assert_int_equal(tctx, response->num, 1, "num");
+ torture_assert_int_equal(tctx, response->type, WITNESS_NOTIFY_RESOURCE_CHANGE, "type");
+
+ /*
+ * TODO: find out how ClusterResourceOfflinePending and
+ * ClusterResourceOnlinePending are represented as witness
+ * types.
+ */
+
+ if (new_state == ClusterResourceOffline) {
+ torture_assert_int_equal(tctx, response->messages[0].resource_change.type, WITNESS_RESOURCE_STATE_UNAVAILABLE, "resource_change.type");
+ }
+ if (new_state == ClusterResourceOnline) {
+ torture_assert_int_equal(tctx, response->messages[0].resource_change.type, WITNESS_RESOURCE_STATE_AVAILABLE, "resource_change.type");
+ }
+ torture_assert(tctx,
+ test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
+ "Failed to unregister");
+
+ ZERO_STRUCT(state->context_handle);
+
+ torture_assert(tctx,
+ toggle_cluster_resource_state(tctx, state->clusapi.p, state->net_name, &old_state, &new_state),
+ "failed to toggle cluster resource state");
+ torture_assert(tctx, old_state != new_state, "failed to change cluster resource state");
+ }
+
+ return true;
+}
+
+static bool test_do_witness_RegisterEx(struct torture_context *tctx,
+ struct dcerpc_binding_handle *b,
+ uint32_t version,
+ const char *net_name,
+ const char *share_name,
+ const char *ip_address,
+ const char *client_computer_name,
+ uint32_t flags,
+ uint32_t timeout,
+ struct policy_handle *context_handle)
+{
+ struct witness_RegisterEx r;
+
+ r.in.version = version;
+ r.in.net_name = net_name;
+ r.in.share_name = NULL;
+ r.in.ip_address = ip_address;
+ r.in.client_computer_name = client_computer_name;
+ r.in.flags = flags;
+ r.in.timeout = timeout;
+ r.out.context_handle = context_handle;
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_RegisterEx_r(b, tctx, &r),
+ "RegisterEx failed");
+
+ torture_assert_werr_ok(tctx,
+ r.out.result,
+ "RegisterEx failed");
+
+ return true;
+}
+
+static void torture_subunit_report_time(struct torture_context *tctx)
+{
+ struct timespec tp;
+ struct tm *tmp;
+ char timestr[200];
+
+ if (clock_gettime(CLOCK_REALTIME, &tp) != 0) {
+ torture_comment(tctx, "failed to call clock_gettime");
+ return;
+ }
+
+ tmp = gmtime(&tp.tv_sec);
+ if (!tmp) {
+ torture_comment(tctx, "failed to call gmtime");
+ return;
+ }
+
+ if (strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tmp) <= 0) {
+ torture_comment(tctx, "failed to call strftime");
+ return;
+ }
+
+ torture_comment(tctx, "time: %s.%06ld\n", timestr, tp.tv_nsec / 1000);
+}
+
+static bool test_witness_AsyncNotify_timeouts(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ void *data)
+{
+ struct dcerpc_binding_handle *b = p->binding_handle;
+ struct witness_AsyncNotify r;
+ struct witness_notifyResponse *response;
+ struct torture_test_witness_state *state =
+ (struct torture_test_witness_state *)data;
+ int i;
+
+ init_witness_test_state(tctx, p, state);
+
+ setup_clusapi_connection(tctx, state);
+
+ for (i=0; state->list && i < state->list->num_interfaces; i++) {
+
+ const char *ip_address;
+ struct witness_interfaceInfo interface = state->list->interfaces[i];
+ uint32_t timeouts[] = {
+ 0, 1, 10, 100, 120
+ };
+ int t;
+ uint32_t old_timeout;
+
+ if (!check_valid_interface(tctx, &interface)) {
+ continue;
+ }
+
+ torture_assert(tctx,
+ get_ip_address_from_interface(tctx, &interface, &ip_address),
+ "failed to get ip_address from interface");
+
+ for (t=0; t < ARRAY_SIZE(timeouts); t++) {
+
+ torture_comment(tctx, "Testing Async Notify with timeout of %d milliseconds", timeouts[t]);
+
+ torture_assert(tctx,
+ test_do_witness_RegisterEx(tctx, b,
+ WITNESS_V2,
+ state->net_name,
+ NULL,
+ ip_address,
+ lpcfg_netbios_name(tctx->lp_ctx),
+ 0,
+ timeouts[t],
+ &state->context_handle),
+ "failed to RegisterEx");
+
+ r.in.context_handle = state->context_handle;
+ r.out.response = &response;
+
+ old_timeout = dcerpc_binding_handle_set_timeout(b, UINT_MAX);
+
+ torture_subunit_report_time(tctx);
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_witness_AsyncNotify_r(b, tctx, &r),
+ "AsyncNotify failed");
+ torture_assert_werr_equal(tctx,
+ r.out.result,
+ WERR_TIMEOUT,
+ "AsyncNotify failed");
+
+ torture_subunit_report_time(tctx);
+
+ dcerpc_binding_handle_set_timeout(b, old_timeout);
+
+ torture_assert(tctx,
+ test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
+ "Failed to unregister");
+
+ ZERO_STRUCT(state->context_handle);
+ }
+ }
+
+ return true;
+}
+
+struct torture_suite *torture_rpc_witness(TALLOC_CTX *mem_ctx)
+{
+ struct torture_rpc_tcase *tcase;
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "witness");
+ struct torture_test_witness_state *state;
+
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "witness",
+ &ndr_table_witness);
+
+ state = talloc_zero(tcase, struct torture_test_witness_state);
+
+ torture_rpc_tcase_add_test_ex(tcase, "GetInterfaceList",
+ test_witness_GetInterfaceList, state);
+ torture_rpc_tcase_add_test_ex(tcase, "Register",
+ test_witness_Register, state);
+ torture_rpc_tcase_add_test_ex(tcase, "UnRegister",
+ test_witness_UnRegister, state);
+ torture_rpc_tcase_add_test_ex(tcase, "RegisterEx",
+ test_witness_RegisterEx, state);
+ torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify",
+ test_witness_AsyncNotify, state);
+ torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify_timeouts",
+ test_witness_AsyncNotify_timeouts, state);
+
+ return suite;
+}
diff --git a/source4/torture/rpc/wkssvc.c b/source4/torture/rpc/wkssvc.c
new file mode 100644
index 0000000..c43e16f
--- /dev/null
+++ b/source4/torture/rpc/wkssvc.c
@@ -0,0 +1,1458 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for wkssvc rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Günther Deschner 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/ndr_wkssvc_c.h"
+#include "torture/rpc/torture_rpc.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+#include "libcli/auth/libcli_auth.h"
+
+#define SMBTORTURE_MACHINE_NAME "smbtrt_name"
+#define SMBTORTURE_ALTERNATE_NAME "smbtrt_altname"
+#define SMBTORTURE_TRANSPORT_NAME "\\Device\\smbtrt_transport_name"
+#define SMBTORTURE_USE_NAME "S:"
+#define SMBTORTURE_MESSAGE "You are currently tortured by Samba"
+
+static bool test_NetWkstaGetInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetWkstaGetInfo r;
+ union wkssvc_NetWkstaInfo info;
+ uint16_t levels[] = {100, 101, 102, 502};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.out.info = &info;
+
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ r.in.level = levels[i];
+ torture_comment(tctx, "Testing NetWkstaGetInfo level %u\n",
+ r.in.level);
+ status = dcerpc_wkssvc_NetWkstaGetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "NetWkstaGetInfo level %u failed",
+ r.in.level));
+ torture_assert_werr_ok(tctx, r.out.result,
+ talloc_asprintf(tctx, "NetWkstaGetInfo level %u failed",
+ r.in.level));
+ }
+
+ return true;
+}
+
+static bool test_NetWkstaTransportEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetWkstaTransportEnum r;
+ uint32_t resume_handle = 0;
+ struct wkssvc_NetWkstaTransportInfo info;
+ union wkssvc_NetWkstaTransportCtr ctr;
+ struct wkssvc_NetWkstaTransportCtr0 ctr0;
+ uint32_t total_entries = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(ctr0);
+ ctr.ctr0 = &ctr0;
+
+ info.level = 0;
+ info.ctr = ctr;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.info = &info;
+ r.in.max_buffer = (uint32_t)-1;
+ r.in.resume_handle = &resume_handle;
+ r.out.total_entries = &total_entries;
+ r.out.info = &info;
+ r.out.resume_handle = &resume_handle;
+
+ torture_comment(tctx, "Testing NetWkstaTransportEnum level 0\n");
+
+ status = dcerpc_wkssvc_NetWkstaTransportEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetWkstaTransportEnum failed");
+ torture_assert_werr_ok(tctx, r.out.result, talloc_asprintf(tctx,
+ "NetWkstaTransportEnum level %u failed",
+ info.level));
+
+ return true;
+}
+
+static bool test_NetrWkstaTransportAdd(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrWkstaTransportAdd r;
+ struct wkssvc_NetWkstaTransportInfo0 info0;
+ uint32_t parm_err = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info0);
+
+ info0.quality_of_service = 0xffff;
+ info0.vc_count = 0;
+ info0.name = SMBTORTURE_TRANSPORT_NAME;
+ info0.address = "000000000000";
+ info0.wan_link = 0x400;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.level = 0;
+ r.in.info0 = &info0;
+ r.in.parm_err = r.out.parm_err = &parm_err;
+
+ torture_comment(tctx, "Testing NetrWkstaTransportAdd level 0\n");
+
+ status = dcerpc_wkssvc_NetrWkstaTransportAdd_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrWkstaTransportAdd failed");
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_INVALID_PARAMETER,
+ "NetrWkstaTransportAdd level 0 failed");
+
+ return true;
+}
+
+static bool test_NetrWkstaTransportDel(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrWkstaTransportDel r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.transport_name = SMBTORTURE_TRANSPORT_NAME;
+ r.in.unknown3 = 0;
+
+ torture_comment(tctx, "Testing NetrWkstaTransportDel\n");
+
+ status = dcerpc_wkssvc_NetrWkstaTransportDel_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrWkstaTransportDel failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrWkstaTransportDel");
+
+ return true;
+}
+
+static bool test_NetWkstaEnumUsers(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetWkstaEnumUsers r;
+ uint32_t handle = 0;
+ uint32_t entries_read = 0;
+ struct wkssvc_NetWkstaEnumUsersInfo info;
+ struct wkssvc_NetWkstaEnumUsersCtr0 *user0;
+ struct wkssvc_NetWkstaEnumUsersCtr1 *user1;
+ uint32_t levels[] = { 0, 1 };
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ ZERO_STRUCT(info);
+
+ info.level = levels[i];
+ switch (info.level) {
+ case 0:
+ user0 = talloc_zero(tctx,
+ struct wkssvc_NetWkstaEnumUsersCtr0);
+ info.ctr.user0 = user0;
+ break;
+ case 1:
+ user1 = talloc_zero(tctx,
+ struct wkssvc_NetWkstaEnumUsersCtr1);
+ info.ctr.user1 = user1;
+ break;
+ default:
+ break;
+ }
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.prefmaxlen = (uint32_t)-1;
+ r.in.info = r.out.info = &info;
+ r.in.resume_handle = r.out.resume_handle = &handle;
+
+ r.out.entries_read = &entries_read;
+
+ torture_comment(tctx, "Testing NetWkstaEnumUsers level %u\n",
+ levels[i]);
+
+ status = dcerpc_wkssvc_NetWkstaEnumUsers_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetWkstaEnumUsers failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetWkstaEnumUsers failed");
+ }
+
+ return true;
+}
+
+static bool test_NetrWkstaUserGetInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrWkstaUserGetInfo r;
+ union wkssvc_NetrWkstaUserInfo info;
+ const char *dom = lpcfg_workgroup(tctx->lp_ctx);
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+ const char *user = cli_credentials_get_username(creds);
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ const struct {
+ const char *unknown;
+ uint32_t level;
+ WERROR result;
+ } tests[] = {
+ { NULL, 0, WERR_NO_SUCH_LOGON_SESSION },
+ { NULL, 1, WERR_NO_SUCH_LOGON_SESSION },
+ { NULL, 1101, WERR_OK },
+ { dom, 0, WERR_INVALID_PARAMETER },
+ { dom, 1, WERR_INVALID_PARAMETER },
+ { dom, 1101, WERR_INVALID_PARAMETER },
+ { user, 0, WERR_INVALID_PARAMETER },
+ { user, 1, WERR_INVALID_PARAMETER },
+ { user, 1101, WERR_INVALID_PARAMETER },
+ };
+
+ for (i=0; i<ARRAY_SIZE(tests); i++) {
+ r.in.unknown = tests[i].unknown;
+ r.in.level = tests[i].level;
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing NetrWkstaUserGetInfo level %u\n",
+ r.in.level);
+
+ status = dcerpc_wkssvc_NetrWkstaUserGetInfo_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrWkstaUserGetInfo failed");
+ torture_assert_werr_equal(tctx, r.out.result,
+ tests[i].result,
+ "NetrWkstaUserGetInfo failed");
+ }
+
+ return true;
+}
+
+static bool test_NetrUseEnum(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUseEnum r;
+ uint32_t handle = 0;
+ uint32_t entries_read = 0;
+ struct wkssvc_NetrUseEnumInfo info;
+ struct wkssvc_NetrUseEnumCtr0 *use0;
+ struct wkssvc_NetrUseEnumCtr1 *use1;
+ struct wkssvc_NetrUseEnumCtr2 *use2;
+ uint32_t levels[] = { 0, 1, 2 };
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ ZERO_STRUCT(info);
+
+ info.level = levels[i];
+ switch (info.level) {
+ case 0:
+ use0 = talloc_zero(tctx, struct wkssvc_NetrUseEnumCtr0);
+ info.ctr.ctr0 = use0;
+ break;
+ case 1:
+ use1 = talloc_zero(tctx, struct wkssvc_NetrUseEnumCtr1);
+ info.ctr.ctr1 = use1;
+ break;
+ case 2:
+ use2 = talloc_zero(tctx, struct wkssvc_NetrUseEnumCtr2);
+ info.ctr.ctr2 = use2;
+ break;
+ default:
+ break;
+ }
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.prefmaxlen = (uint32_t)-1;
+ r.in.info = r.out.info = &info;
+ r.in.resume_handle = r.out.resume_handle = &handle;
+
+ r.out.entries_read = &entries_read;
+
+ torture_comment(tctx, "Testing NetrUseEnum level %u\n",
+ levels[i]);
+
+ status = dcerpc_wkssvc_NetrUseEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUseEnum failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrUseEnum failed");
+ }
+
+ return true;
+}
+
+static bool test_NetrUseAdd(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUseAdd r;
+ struct wkssvc_NetrUseInfo0 info0;
+ struct wkssvc_NetrUseInfo1 info1;
+ union wkssvc_NetrUseGetInfoCtr *ctr;
+ uint32_t parm_err = 0;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ctr = talloc(tctx, union wkssvc_NetrUseGetInfoCtr);
+
+ ZERO_STRUCT(info0);
+
+ info0.local = SMBTORTURE_USE_NAME;
+ info0.remote = "\\\\localhost\\c$";
+
+ ctr->info0 = &info0;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.level = 0;
+ r.in.ctr = ctr;
+ r.in.parm_err = r.out.parm_err = &parm_err;
+
+ torture_comment(tctx, "Testing NetrUseAdd level %u\n",
+ r.in.level);
+
+ status = dcerpc_wkssvc_NetrUseAdd_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUseAdd failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_LEVEL,
+ "NetrUseAdd failed");
+
+ ZERO_STRUCT(r);
+ ZERO_STRUCT(info1);
+
+ info1.local = SMBTORTURE_USE_NAME;
+ info1.remote = "\\\\localhost\\sysvol";
+ info1.password = NULL;
+
+ ctr->info1 = &info1;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.level = 1;
+ r.in.ctr = ctr;
+ r.in.parm_err = r.out.parm_err = &parm_err;
+
+ torture_comment(tctx, "Testing NetrUseAdd level %u\n",
+ r.in.level);
+
+ status = dcerpc_wkssvc_NetrUseAdd_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUseAdd failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrUseAdd failed");
+
+ return true;
+}
+
+static bool test_NetrUseDel(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUseDel r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.use_name = SMBTORTURE_USE_NAME;
+ r.in.force_cond = 0;
+
+ torture_comment(tctx, "Testing NetrUseDel\n");
+
+ status = dcerpc_wkssvc_NetrUseDel_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUseDel failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrUseDel failed");
+ return true;
+}
+
+static bool test_NetrUseGetInfo_level(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *use_name,
+ uint32_t level,
+ WERROR werr)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUseGetInfo r;
+ union wkssvc_NetrUseGetInfoCtr ctr;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(ctr);
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.use_name = use_name;
+ r.in.level = level;
+ r.out.ctr = &ctr;
+ status = dcerpc_wkssvc_NetrUseGetInfo_r(b, tctx, &r);
+
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUseGetInfo failed");
+ torture_assert_werr_equal(tctx, r.out.result, werr,
+ "NetrUseGetInfo failed");
+ return true;
+}
+
+static bool test_NetrUseGetInfo(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUseEnum r;
+ uint32_t handle = 0;
+ uint32_t entries_read = 0;
+ struct wkssvc_NetrUseEnumInfo info;
+ struct wkssvc_NetrUseEnumCtr0 *use0;
+ uint32_t levels[] = { 0, 1, 2 };
+ const char *use_name = NULL;
+ int i, k;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(info);
+
+ info.level = 0;
+ use0 = talloc_zero(tctx, struct wkssvc_NetrUseEnumCtr0);
+ info.ctr.ctr0 = use0;
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.prefmaxlen = (uint32_t)-1;
+ r.in.info = r.out.info = &info;
+ r.in.resume_handle = r.out.resume_handle = &handle;
+ r.out.entries_read = &entries_read;
+
+ status = dcerpc_wkssvc_NetrUseEnum_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUseEnum failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrUseEnum failed");
+
+ for (k=0; k < r.out.info->ctr.ctr0->count; k++) {
+
+ use_name = r.out.info->ctr.ctr0->array[k].local;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ if (!test_NetrUseGetInfo_level(tctx, p, use_name,
+ levels[i],
+ WERR_OK))
+ {
+ if (levels[i] != 0) {
+ return false;
+ }
+ }
+ }
+
+ use_name = r.out.info->ctr.ctr0->array[k].remote;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ if (!test_NetrUseGetInfo_level(tctx, p, use_name,
+ levels[i],
+ WERR_NERR_USENOTFOUND))
+ {
+ if (levels[i] != 0) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_NetrLogonDomainNameAdd(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrLogonDomainNameAdd r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+
+ torture_comment(tctx, "Testing NetrLogonDomainNameAdd\n");
+
+ status = dcerpc_wkssvc_NetrLogonDomainNameAdd_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrLogonDomainNameAdd failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "NetrLogonDomainNameAdd failed");
+ return true;
+}
+
+static bool test_NetrLogonDomainNameDel(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrLogonDomainNameDel r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+
+ torture_comment(tctx, "Testing NetrLogonDomainNameDel\n");
+
+ status = dcerpc_wkssvc_NetrLogonDomainNameDel_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrLogonDomainNameDel failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "NetrLogonDomainNameDel failed");
+ return true;
+}
+
+static bool test_NetrEnumerateComputerNames_level(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ uint16_t level,
+ const char ***names,
+ size_t *num_names)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrEnumerateComputerNames r;
+ struct wkssvc_ComputerNamesCtr *ctr;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ctr = talloc_zero(tctx, struct wkssvc_ComputerNamesCtr);
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.name_type = level;
+ r.in.Reserved = 0;
+ r.out.ctr = &ctr;
+
+ torture_comment(tctx, "Testing NetrEnumerateComputerNames level %u\n",
+ r.in.name_type);
+
+ status = dcerpc_wkssvc_NetrEnumerateComputerNames_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrEnumerateComputerNames failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrEnumerateComputerNames failed");
+
+ if ((level == NetPrimaryComputerName) && ctr->count != 1) {
+ torture_comment(tctx,
+ "NetrEnumerateComputerNames did not return one "
+ "name but %u\n", ctr->count);
+ return false;
+ }
+
+ if (names && num_names) {
+ *num_names = 0;
+ *names = NULL;
+ for (i=0; i<ctr->count; i++) {
+ if (!add_string_to_array(tctx,
+ ctr->computer_name[i].string,
+ names,
+ num_names))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool test_NetrEnumerateComputerNames(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ uint16_t levels[] = {0,1,2};
+ int i;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ if (!test_NetrEnumerateComputerNames_level(tctx,
+ p,
+ levels[i],
+ NULL, NULL))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_NetrValidateName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrValidateName r;
+ uint16_t levels[] = {0,1,2,3,4,5};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.Account = NULL;
+ r.in.Password = NULL;
+ r.in.name_type = levels[i];
+
+ torture_comment(tctx, "Testing NetrValidateName level %u\n",
+ r.in.name_type);
+
+ status = dcerpc_wkssvc_NetrValidateName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrValidateName failed");
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_NOT_SUPPORTED,
+ "NetrValidateName failed");
+ }
+
+ return true;
+}
+
+static bool test_NetrValidateName2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrValidateName2 r;
+ uint16_t levels[] = {0,1,2,3,4,5};
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.Account = NULL;
+ r.in.EncryptedPassword = NULL;
+ r.in.name_type = levels[i];
+
+ torture_comment(tctx, "Testing NetrValidateName2 level %u\n",
+ r.in.name_type);
+
+ status = dcerpc_wkssvc_NetrValidateName2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrValidateName2 failed");
+ torture_assert_werr_equal(tctx, r.out.result,
+ W_ERROR(HRES_ERROR_V(HRES_RPC_E_REMOTE_DISABLED)),
+ "NetrValidateName2 failed");
+ }
+
+ return true;
+}
+
+static bool test_NetrAddAlternateComputerName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrAddAlternateComputerName r;
+ const char **names = NULL;
+ size_t num_names = 0;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.NewAlternateMachineName = SMBTORTURE_ALTERNATE_NAME;
+ r.in.Account = NULL;
+ r.in.EncryptedPassword = NULL;
+ r.in.Reserved = 0;
+
+ torture_comment(tctx, "Testing NetrAddAlternateComputerName\n");
+
+ status = dcerpc_wkssvc_NetrAddAlternateComputerName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrAddAlternateComputerName failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrAddAlternateComputerName failed");
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetAlternateComputerNames,
+ &names, &num_names))
+ {
+ return false;
+ }
+
+ for (i=0; i<num_names; i++) {
+ if (strequal(names[i], SMBTORTURE_ALTERNATE_NAME)) {
+ return true;
+ }
+ }
+
+ torture_comment(tctx, "new alternate name not set\n");
+
+ return false;
+}
+
+static bool test_NetrRemoveAlternateComputerName(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrRemoveAlternateComputerName r;
+ const char **names = NULL;
+ size_t num_names = 0;
+ int i;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.AlternateMachineNameToRemove = SMBTORTURE_ALTERNATE_NAME;
+ r.in.Account = NULL;
+ r.in.EncryptedPassword = NULL;
+ r.in.Reserved = 0;
+
+ torture_comment(tctx, "Testing NetrRemoveAlternateComputerName\n");
+
+ status = dcerpc_wkssvc_NetrRemoveAlternateComputerName_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrRemoveAlternateComputerName failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrRemoveAlternateComputerName failed");
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetAlternateComputerNames,
+ &names, &num_names))
+ {
+ return false;
+ }
+
+ for (i=0; i<num_names; i++) {
+ if (strequal(names[i], SMBTORTURE_ALTERNATE_NAME)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_NetrSetPrimaryComputername_name(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *name)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrSetPrimaryComputername r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.primary_name = name;
+ r.in.Account = NULL;
+ r.in.EncryptedPassword = NULL;
+ r.in.Reserved = 0;
+
+ status = dcerpc_wkssvc_NetrSetPrimaryComputername_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrSetPrimaryComputername failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrSetPrimaryComputername failed");
+ return true;
+}
+
+
+static bool test_NetrSetPrimaryComputername(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ /*
+ add alternate,
+ check if there
+ store old primary
+ set new primary (alternate)
+ check if there
+ later: check if del is possible
+ set primary back to origin
+ check if there
+ del alternate
+ */
+
+ const char **names_o = NULL, **names = NULL;
+ size_t num_names_o = 0, num_names = 0;
+
+ torture_comment(tctx, "Testing NetrSetPrimaryComputername\n");
+
+ if (!test_NetrAddAlternateComputerName(tctx, p)) {
+ return false;
+ }
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetPrimaryComputerName,
+ &names_o, &num_names_o))
+ {
+ return false;
+ }
+
+ if (num_names_o != 1) {
+ return false;
+ }
+
+ if (!test_NetrSetPrimaryComputername_name(tctx, p,
+ SMBTORTURE_ALTERNATE_NAME))
+ {
+ return false;
+ }
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetPrimaryComputerName,
+ &names, &num_names))
+ {
+ return false;
+ }
+
+ if (num_names != 1) {
+ return false;
+ }
+
+ if (!strequal(names[0], SMBTORTURE_ALTERNATE_NAME)) {
+ torture_comment(tctx,
+ "name mismatch (%s != %s) after NetrSetPrimaryComputername!\n",
+ names[0], SMBTORTURE_ALTERNATE_NAME);
+ /*return false */;
+ }
+
+ if (!test_NetrSetPrimaryComputername_name(tctx, p,
+ names_o[0]))
+ {
+ return false;
+ }
+
+ if (!test_NetrRemoveAlternateComputerName(tctx, p)) {
+ return false;
+ }
+
+
+ return true;
+}
+
+static bool test_NetrRenameMachineInDomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrRenameMachineInDomain r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.NewMachineName = SMBTORTURE_MACHINE_NAME;
+ r.in.Account = NULL;
+ r.in.password = NULL;
+ r.in.RenameOptions = 0;
+
+ torture_comment(tctx, "Testing NetrRenameMachineInDomain\n");
+
+ status = dcerpc_wkssvc_NetrRenameMachineInDomain_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrRenameMachineInDomain failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "NetrRenameMachineInDomain failed");
+ return true;
+}
+
+static bool test_NetrRenameMachineInDomain2_name(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ const char *new_name)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrRenameMachineInDomain2 r;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.NewMachineName = new_name;
+ r.in.Account = NULL;
+ r.in.EncryptedPassword = NULL;
+ r.in.RenameOptions = 0;
+
+ status = dcerpc_wkssvc_NetrRenameMachineInDomain2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrRenameMachineInDomain2 failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrRenameMachineInDomain2 failed");
+ return true;
+}
+
+static bool test_NetrRenameMachineInDomain2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ const char **names_o = NULL, **names = NULL;
+ size_t num_names_o = 0, num_names = 0;
+
+ torture_comment(tctx, "Testing NetrRenameMachineInDomain2\n");
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetPrimaryComputerName,
+ &names_o, &num_names_o))
+ {
+ return false;
+ }
+
+ if (num_names_o != 1) {
+ return false;
+ }
+
+ if (!test_NetrRenameMachineInDomain2_name(tctx, p,
+ SMBTORTURE_MACHINE_NAME))
+ {
+ return false;
+ }
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetPrimaryComputerName,
+ &names, &num_names))
+ {
+ return false;
+ }
+
+ if (num_names != 1) {
+ return false;
+ }
+
+ if (strequal(names[0], names_o[0])) {
+ test_NetrRenameMachineInDomain2_name(tctx, p, names_o[0]);
+ return false;
+ }
+
+ if (!strequal(names[0], SMBTORTURE_MACHINE_NAME)) {
+ test_NetrRenameMachineInDomain2_name(tctx, p, names_o[0]);
+ return false;
+ }
+
+ if (!test_NetrRenameMachineInDomain2_name(tctx, p, names_o[0]))
+ {
+ return false;
+ }
+
+ if (!test_NetrEnumerateComputerNames_level(tctx, p,
+ NetPrimaryComputerName,
+ &names, &num_names))
+ {
+ return false;
+ }
+
+ if (num_names != 1) {
+ return false;
+ }
+
+ if (!strequal(names[0], names_o[0])) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_NetrWorkstationStatisticsGet(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrWorkstationStatisticsGet r;
+ struct wkssvc_NetrWorkstationStatistics *info;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ ZERO_STRUCT(r);
+
+ info = talloc_zero(tctx, struct wkssvc_NetrWorkstationStatistics);
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.out.info = &info;
+
+ torture_comment(tctx, "Testing NetrWorkstationStatisticsGet\n");
+
+ status = dcerpc_wkssvc_NetrWorkstationStatisticsGet_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrWorkstationStatisticsGet failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrWorkstationStatisticsGet failed");
+ return true;
+}
+
+/* only succeeds as long as the local messenger service is running - Guenther */
+
+static bool test_NetrMessageBufferSend(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrMessageBufferSend r;
+ const char *message = SMBTORTURE_MESSAGE;
+ size_t size;
+ uint16_t *msg;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ if (!push_ucs2_talloc(tctx, &msg, message, &size)) {
+ return false;
+ }
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.message_name = dcerpc_server_name(p);
+ r.in.message_sender_name = dcerpc_server_name(p);
+ r.in.message_buffer = (uint8_t *)msg;
+ r.in.message_size = size;
+
+ torture_comment(tctx, "Testing NetrMessageBufferSend\n");
+
+ status = dcerpc_wkssvc_NetrMessageBufferSend_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrMessageBufferSend failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrMessageBufferSend failed");
+ return true;
+}
+
+static bool test_NetrGetJoinInformation(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrGetJoinInformation r;
+ enum wkssvc_NetJoinStatus join_status;
+ const char *name_buffer = "";
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.name_buffer = r.out.name_buffer = &name_buffer;
+ r.out.name_type = &join_status;
+
+ torture_comment(tctx, "Testing NetrGetJoinInformation\n");
+
+ status = dcerpc_wkssvc_NetrGetJoinInformation_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrGetJoinInformation failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrGetJoinInformation failed");
+ return true;
+}
+
+static bool test_GetJoinInformation(struct torture_context *tctx,
+ struct dcerpc_pipe *p,
+ enum wkssvc_NetJoinStatus *join_status_p,
+ const char **name)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrGetJoinInformation r;
+ enum wkssvc_NetJoinStatus join_status;
+ const char *name_buffer = "";
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.name_buffer = r.out.name_buffer = &name_buffer;
+ r.out.name_type = &join_status;
+
+ status = dcerpc_wkssvc_NetrGetJoinInformation_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrGetJoinInformation failed");
+ torture_assert_werr_ok(tctx, r.out.result,
+ "NetrGetJoinInformation failed");
+
+ if (join_status_p) {
+ *join_status_p = join_status;
+ }
+
+ if (*name) {
+ *name = talloc_strdup(tctx, name_buffer);
+ }
+
+ return true;
+
+}
+
+static bool test_NetrGetJoinableOus(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrGetJoinableOus r;
+ uint32_t num_ous = 0;
+ const char **ous = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.Account = NULL;
+ r.in.unknown = NULL;
+ r.in.num_ous = r.out.num_ous = &num_ous;
+ r.out.ous = &ous;
+
+ torture_comment(tctx, "Testing NetrGetJoinableOus\n");
+
+ status = dcerpc_wkssvc_NetrGetJoinableOus_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetrGetJoinableOus failed");
+ torture_assert_werr_equal(tctx, r.out.result,
+ WERR_NOT_SUPPORTED,
+ "NetrGetJoinableOus failed");
+
+ return true;
+}
+
+static bool test_NetrGetJoinableOus2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrGetJoinableOus2 r;
+ uint32_t num_ous = 0;
+ const char **ous = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.domain_name = lpcfg_workgroup(tctx->lp_ctx);
+ r.in.Account = NULL;
+ r.in.EncryptedPassword = NULL;
+ r.in.num_ous = r.out.num_ous = &num_ous;
+ r.out.ous = &ous;
+
+ torture_comment(tctx, "Testing NetrGetJoinableOus2\n");
+
+ status = dcerpc_wkssvc_NetrGetJoinableOus2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "NetrGetJoinableOus2 failed");
+ torture_assert_werr_equal(tctx, r.out.result,
+ W_ERROR(HRES_ERROR_V(HRES_RPC_E_REMOTE_DISABLED)),
+ "NetrGetJoinableOus2 failed");
+
+ return true;
+}
+
+static bool test_NetrUnjoinDomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUnjoinDomain r;
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+ const char *user = cli_credentials_get_username(creds);
+ const char *admin_account = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ admin_account = talloc_asprintf(tctx, "%s\\%s",
+ lpcfg_workgroup(tctx->lp_ctx),
+ user);
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.Account = admin_account;
+ r.in.password = NULL;
+ r.in.unjoin_flags = 0;
+
+ torture_comment(tctx, "Testing NetrUnjoinDomain\n");
+
+ status = dcerpc_wkssvc_NetrUnjoinDomain_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUnjoinDomain failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "NetrUnjoinDomain failed");
+ return true;
+}
+
+static bool test_NetrJoinDomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrJoinDomain r;
+ struct cli_credentials *creds = samba_cmdline_get_creds();
+ const char *user = cli_credentials_get_username(creds);
+ const char *admin_account = NULL;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ admin_account = talloc_asprintf(tctx, "%s\\%s",
+ lpcfg_workgroup(tctx->lp_ctx),
+ user);
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.domain_name = lpcfg_dnsdomain(tctx->lp_ctx);
+ r.in.account_ou = NULL;
+ r.in.Account = admin_account;
+ r.in.password = NULL;
+ r.in.join_flags = 0;
+
+ torture_comment(tctx, "Testing NetrJoinDomain\n");
+
+ status = dcerpc_wkssvc_NetrJoinDomain_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrJoinDomain failed");
+ torture_assert_werr_equal(tctx, r.out.result, WERR_NOT_SUPPORTED,
+ "NetrJoinDomain failed");
+ return true;
+}
+
+/*
+ * prerequisites for remotely joining an unjoined XP SP2 workstation:
+ * - firewall needs to be disabled (or open for ncacn_np access)
+ * - HKLM\System\CurrentControlSet\Control\Lsa\forceguest needs to 0
+ * see also:
+ * http://support.microsoft.com/kb/294355/EN-US/ and
+ * http://support.microsoft.com/kb/290403/EN-US/
+ */
+
+static bool test_NetrJoinDomain2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrJoinDomain2 r;
+ const char *domain_admin_account = NULL;
+ const char *domain_admin_password = NULL;
+ const char *domain_name = NULL;
+ struct wkssvc_PasswordBuffer *pwd_buf;
+ enum wkssvc_NetJoinStatus join_status;
+ const char *join_name = NULL;
+ WERROR expected_err;
+ WERROR werr;
+ DATA_BLOB session_key;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ /* FIXME: this test assumes to join workstations / servers and does not
+ * handle DCs (WERR_NERR_SETUPDOMAINCONTROLLER) */
+
+ if (!test_GetJoinInformation(tctx, p, &join_status, &join_name))
+ {
+ return false;
+ }
+
+ switch (join_status) {
+ case NET_SETUP_DOMAIN_NAME:
+ expected_err = WERR_NERR_SETUPALREADYJOINED;
+ break;
+ case NET_SETUP_UNKNOWN_STATUS:
+ case NET_SETUP_UNJOINED:
+ case NET_SETUP_WORKGROUP_NAME:
+ default:
+ expected_err = WERR_OK;
+ break;
+ }
+
+ domain_admin_account = torture_setting_string(tctx, "domain_admin_account", NULL);
+
+ domain_admin_password = torture_setting_string(tctx, "domain_admin_password", NULL);
+
+ domain_name = torture_setting_string(tctx, "domain_name", NULL);
+
+ if ((domain_admin_account == NULL) ||
+ (domain_admin_password == NULL) ||
+ (domain_name == NULL)) {
+ torture_comment(tctx, "not enough input parameter\n");
+ return false;
+ }
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ werr = encode_wkssvc_join_password_buffer(tctx,
+ domain_admin_password,
+ &session_key,
+ &pwd_buf);
+ if (!W_ERROR_IS_OK(werr)) {
+ return false;
+ }
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.domain_name = domain_name;
+ r.in.account_ou = NULL;
+ r.in.admin_account = domain_admin_account;
+ r.in.encrypted_password = pwd_buf;
+ r.in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
+
+ torture_comment(tctx, "Testing NetrJoinDomain2 (assuming non-DC)\n");
+
+ status = dcerpc_wkssvc_NetrJoinDomain2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrJoinDomain2 failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_err,
+ "NetrJoinDomain2 failed");
+
+ if (!test_GetJoinInformation(tctx, p, &join_status, &join_name))
+ {
+ return false;
+ }
+
+ if (join_status != NET_SETUP_DOMAIN_NAME) {
+ torture_comment(tctx,
+ "Join verify failed: got %d\n", join_status);
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_NetrUnjoinDomain2(struct torture_context *tctx,
+ struct dcerpc_pipe *p)
+{
+ NTSTATUS status;
+ struct wkssvc_NetrUnjoinDomain2 r;
+ const char *domain_admin_account = NULL;
+ const char *domain_admin_password = NULL;
+ struct wkssvc_PasswordBuffer *pwd_buf;
+ enum wkssvc_NetJoinStatus join_status;
+ const char *join_name = NULL;
+ WERROR expected_err;
+ WERROR werr;
+ DATA_BLOB session_key;
+ struct dcerpc_binding_handle *b = p->binding_handle;
+
+ /* FIXME: this test assumes to join workstations / servers and does not
+ * handle DCs (WERR_NERR_SETUPDOMAINCONTROLLER) */
+
+ if (!test_GetJoinInformation(tctx, p, &join_status, &join_name))
+ {
+ return false;
+ }
+
+ switch (join_status) {
+ case NET_SETUP_UNJOINED:
+ expected_err = WERR_NERR_SETUPNOTJOINED;
+ break;
+ case NET_SETUP_DOMAIN_NAME:
+ case NET_SETUP_UNKNOWN_STATUS:
+ case NET_SETUP_WORKGROUP_NAME:
+ default:
+ expected_err = WERR_OK;
+ break;
+ }
+
+ domain_admin_account = torture_setting_string(tctx, "domain_admin_account", NULL);
+
+ domain_admin_password = torture_setting_string(tctx, "domain_admin_password", NULL);
+
+ if ((domain_admin_account == NULL) ||
+ (domain_admin_password == NULL)) {
+ torture_comment(tctx, "not enough input parameter\n");
+ return false;
+ }
+
+ status = dcerpc_fetch_session_key(p, &session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ werr = encode_wkssvc_join_password_buffer(tctx,
+ domain_admin_password,
+ &session_key,
+ &pwd_buf);
+ if (!W_ERROR_IS_OK(werr)) {
+ return false;
+ }
+
+ r.in.server_name = dcerpc_server_name(p);
+ r.in.account = domain_admin_account;
+ r.in.encrypted_password = pwd_buf;
+ r.in.unjoin_flags = 0;
+
+ torture_comment(tctx, "Testing NetrUnjoinDomain2 (assuming non-DC)\n");
+
+ status = dcerpc_wkssvc_NetrUnjoinDomain2_r(b, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "NetrUnjoinDomain2 failed");
+ torture_assert_werr_equal(tctx, r.out.result, expected_err,
+ "NetrUnjoinDomain2 failed");
+
+ if (!test_GetJoinInformation(tctx, p, &join_status, &join_name))
+ {
+ return false;
+ }
+
+ switch (join_status) {
+ case NET_SETUP_UNJOINED:
+ case NET_SETUP_WORKGROUP_NAME:
+ break;
+ case NET_SETUP_UNKNOWN_STATUS:
+ case NET_SETUP_DOMAIN_NAME:
+ default:
+ torture_comment(tctx,
+ "Unjoin verify failed: got %d\n", join_status);
+ return false;
+ }
+
+ return true;
+}
+
+
+struct torture_suite *torture_rpc_wkssvc(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+ struct torture_rpc_tcase *tcase;
+ struct torture_test *test;
+
+ suite = torture_suite_create(mem_ctx, "wkssvc");
+ tcase = torture_suite_add_rpc_iface_tcase(suite, "wkssvc",
+ &ndr_table_wkssvc);
+
+ torture_rpc_tcase_add_test(tcase, "NetWkstaGetInfo",
+ test_NetWkstaGetInfo);
+
+ torture_rpc_tcase_add_test(tcase, "NetWkstaTransportEnum",
+ test_NetWkstaTransportEnum);
+ torture_rpc_tcase_add_test(tcase, "NetrWkstaTransportDel",
+ test_NetrWkstaTransportDel);
+ torture_rpc_tcase_add_test(tcase, "NetrWkstaTransportAdd",
+ test_NetrWkstaTransportAdd);
+
+ torture_rpc_tcase_add_test(tcase, "NetWkstaEnumUsers",
+ test_NetWkstaEnumUsers);
+ torture_rpc_tcase_add_test(tcase, "NetrWkstaUserGetInfo",
+ test_NetrWkstaUserGetInfo);
+
+ torture_rpc_tcase_add_test(tcase, "NetrUseDel",
+ test_NetrUseDel);
+ torture_rpc_tcase_add_test(tcase, "NetrUseGetInfo",
+ test_NetrUseGetInfo);
+ torture_rpc_tcase_add_test(tcase, "NetrUseEnum",
+ test_NetrUseEnum);
+ torture_rpc_tcase_add_test(tcase, "NetrUseAdd",
+ test_NetrUseAdd);
+
+ torture_rpc_tcase_add_test(tcase, "NetrValidateName",
+ test_NetrValidateName);
+ torture_rpc_tcase_add_test(tcase, "NetrValidateName2",
+ test_NetrValidateName2);
+ torture_rpc_tcase_add_test(tcase, "NetrLogonDomainNameDel",
+ test_NetrLogonDomainNameDel);
+ torture_rpc_tcase_add_test(tcase, "NetrLogonDomainNameAdd",
+ test_NetrLogonDomainNameAdd);
+ torture_rpc_tcase_add_test(tcase, "NetrRemoveAlternateComputerName",
+ test_NetrRemoveAlternateComputerName);
+ torture_rpc_tcase_add_test(tcase, "NetrAddAlternateComputerName",
+ test_NetrAddAlternateComputerName);
+ test = torture_rpc_tcase_add_test(tcase, "NetrSetPrimaryComputername",
+ test_NetrSetPrimaryComputername);
+ test->dangerous = true;
+ test = torture_rpc_tcase_add_test(tcase, "NetrRenameMachineInDomain",
+ test_NetrRenameMachineInDomain);
+ test->dangerous = true;
+ test = torture_rpc_tcase_add_test(tcase, "NetrRenameMachineInDomain2",
+ test_NetrRenameMachineInDomain2);
+ test->dangerous = true;
+ torture_rpc_tcase_add_test(tcase, "NetrEnumerateComputerNames",
+ test_NetrEnumerateComputerNames);
+
+ test = torture_rpc_tcase_add_test(tcase, "NetrJoinDomain2",
+ test_NetrJoinDomain2);
+ test->dangerous = true;
+ test = torture_rpc_tcase_add_test(tcase, "NetrUnjoinDomain2",
+ test_NetrUnjoinDomain2);
+ test->dangerous = true;
+
+ torture_rpc_tcase_add_test(tcase, "NetrJoinDomain",
+ test_NetrJoinDomain);
+ test->dangerous = true;
+ torture_rpc_tcase_add_test(tcase, "NetrUnjoinDomain",
+ test_NetrUnjoinDomain);
+ test->dangerous = true;
+ torture_rpc_tcase_add_test(tcase, "NetrGetJoinInformation",
+ test_NetrGetJoinInformation);
+ torture_rpc_tcase_add_test(tcase, "NetrGetJoinableOus",
+ test_NetrGetJoinableOus);
+ torture_rpc_tcase_add_test(tcase, "NetrGetJoinableOus2",
+ test_NetrGetJoinableOus2);
+
+ torture_rpc_tcase_add_test(tcase, "NetrWorkstationStatisticsGet",
+ test_NetrWorkstationStatisticsGet);
+ torture_rpc_tcase_add_test(tcase, "NetrMessageBufferSend",
+ test_NetrMessageBufferSend);
+
+ return suite;
+}
diff --git a/source4/torture/shell.c b/source4/torture/shell.c
new file mode 100644
index 0000000..d34267d
--- /dev/null
+++ b/source4/torture/shell.c
@@ -0,0 +1,326 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006-2008
+ Copyright (C) James Peach 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/readline.h"
+#include "../libcli/smbreadline/smbreadline.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/credentials/credentials.h"
+#include "torture/smbtorture.h"
+#include "param/param.h"
+
+struct shell_command;
+
+typedef void (*shell_function)(const struct shell_command *,
+ struct torture_context *, int, const char **);
+
+static void shell_quit(const struct shell_command *,
+ struct torture_context *, int, const char **);
+static void shell_help(const struct shell_command *,
+ struct torture_context *, int, const char **);
+static void shell_set(const struct shell_command *,
+ struct torture_context *, int, const char **);
+static void shell_run(const struct shell_command *,
+ struct torture_context *, int, const char **);
+static void shell_list(const struct shell_command *,
+ struct torture_context *, int, const char **);
+static void shell_auth(const struct shell_command *,
+ struct torture_context *, int, const char **);
+static void shell_target(const struct shell_command *,
+ struct torture_context *, int, const char **);
+
+static void shell_usage(const struct shell_command *);
+static bool match_command(const char *, const struct shell_command *);
+
+struct shell_command
+{
+ shell_function handler;
+ const char * name;
+ const char * usage;
+ const char * help;
+} shell_command;
+
+static const struct shell_command commands[] =
+{
+ {
+ shell_auth, "auth",
+ "[[username | principal | domain | realm | password] STRING]",
+ "set authentication parameters"
+ },
+
+ {
+ shell_help, "help", NULL,
+ "print this help message"
+ },
+
+ {
+ shell_list, "list", NULL,
+ "list the available tests"
+ },
+
+ {
+ shell_quit, "quit", NULL,
+ "exit smbtorture"
+ },
+
+ {
+ shell_run, "run", "[TESTNAME]",
+ "run the specified test"
+ },
+
+ {
+ shell_set, "set", "[NAME VALUE]",
+ "print or set test configuration parameters"
+ },
+
+ {
+ shell_target, "target", "[TARGET]",
+ "print or set the test target"
+ }
+
+};
+
+void torture_shell(struct torture_context *tctx)
+{
+ char *cline;
+ int argc;
+ const char **argv;
+ int ret;
+ int i;
+
+ /* If we don't have a specified password, specify it as empty. This
+ * stops the credentials system prompting when we use the "auth"
+ * command to display the current auth parameters.
+ */
+ cli_credentials_set_password(samba_cmdline_get_creds(),
+ "", CRED_GUESS_ENV);
+
+ while (1) {
+ cline = smb_readline("torture> ", NULL, NULL);
+
+ if (cline == NULL)
+ return;
+
+#ifdef HAVE_ADD_HISTORY
+ add_history(cline);
+#endif
+
+ ret = poptParseArgvString(cline, &argc, &argv);
+ if (ret != 0) {
+ fprintf(stderr, "Error parsing line\n");
+ continue;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (match_command(argv[0], &commands[i])) {
+ argc--;
+ argv++;
+ commands[i].handler(&commands[i],
+ tctx, argc, argv);
+ break;
+ }
+ }
+
+ free(cline);
+ }
+}
+
+static void shell_quit(const struct shell_command * command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+ exit(0);
+}
+
+static void shell_help(const struct shell_command * command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+ int i;
+
+ if (argc == 1) {
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (match_command(argv[0], &commands[i])) {
+ shell_usage(&commands[i]);
+ return;
+ }
+ }
+ } else {
+ fprintf(stdout, "Available commands:\n");
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ fprintf(stdout, "\t%s - %s\n",
+ commands[i].name, commands[i].help);
+ }
+ }
+}
+
+static void shell_set(const struct shell_command *command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+ switch (argc) {
+ case 0:
+ lpcfg_dump(tctx->lp_ctx, stdout,
+ false /* show_defaults */,
+ 0 /* skip services */);
+ break;
+
+ case 2:
+ /* We want to allow users to set any config option. Top level
+ * options will get checked against their static definition, but
+ * parametric options can't be checked and will just get stashed
+ * as they are provided.
+ */
+ lpcfg_set_cmdline(tctx->lp_ctx, argv[0], argv[1]);
+ break;
+
+ default:
+ shell_usage(command);
+ }
+}
+
+static void shell_run(const struct shell_command * command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+ if (argc != 1) {
+ shell_usage(command);
+ return;
+ }
+
+ torture_run_named_tests(tctx, argv[0], NULL /* restricted */);
+}
+
+static void shell_list(const struct shell_command * command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+ if (argc != 0) {
+ shell_usage(command);
+ return;
+ }
+
+ torture_print_testsuites(true);
+}
+
+static void shell_auth(const struct shell_command * command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+
+ if (argc == 0) {
+ const char * username;
+ const char * domain;
+ const char * realm;
+ const char * password;
+ const char * principal;
+
+ username = cli_credentials_get_username(
+ samba_cmdline_get_creds());
+ principal = cli_credentials_get_principal(
+ samba_cmdline_get_creds(), tctx);
+ domain = cli_credentials_get_domain(samba_cmdline_get_creds());
+ realm = cli_credentials_get_realm(samba_cmdline_get_creds());
+ password = cli_credentials_get_password(
+ samba_cmdline_get_creds());
+
+ printf("Username: %s\n", username ? username : "");
+ printf("User Principal: %s\n", principal ? principal : "");
+ printf("Domain: %s\n", domain ? domain : "");
+ printf("Realm: %s\n", realm ? realm : "");
+ printf("Password: %s\n", password ? password : "");
+ } else if (argc == 2) {
+ bool result;
+
+ if (!strcmp(argv[0], "username")) {
+ result = cli_credentials_set_username(
+ samba_cmdline_get_creds(),
+ argv[1], CRED_SPECIFIED);
+ } else if (!strcmp(argv[0], "principal")) {
+ result = cli_credentials_set_principal(
+ samba_cmdline_get_creds(),
+ argv[1], CRED_SPECIFIED);
+ } else if (!strcmp(argv[0], "domain")) {
+ result = cli_credentials_set_domain(
+ samba_cmdline_get_creds(),
+ argv[1], CRED_SPECIFIED);
+ } else if (!strcmp(argv[0], "realm")) {
+ result = cli_credentials_set_realm(
+ samba_cmdline_get_creds(),
+ argv[1], CRED_SPECIFIED);
+ } else if (!strcmp(argv[0], "password")) {
+ result = cli_credentials_set_password(
+ samba_cmdline_get_creds(),
+ argv[1], CRED_SPECIFIED);
+ } else {
+ shell_usage(command);
+ return;
+ }
+
+ if (!result) {
+ printf("failed to set %s\n", argv[0]);
+ }
+ } else {
+ shell_usage(command);
+ }
+
+}
+
+static void shell_target(const struct shell_command *command,
+ struct torture_context *tctx, int argc, const char **argv)
+{
+ if (argc == 0) {
+ const char * host;
+ const char * share;
+ const char * binding;
+
+ host = torture_setting_string(tctx, "host", NULL);
+ share = torture_setting_string(tctx, "share", NULL);
+ binding = torture_setting_string(tctx, "binding", NULL);
+
+ printf("Target host: %s\n", host ? host : "");
+ printf("Target share: %s\n", share ? share : "");
+ printf("Target binding: %s\n", binding ? binding : "");
+ } else if (argc == 1) {
+ torture_parse_target(tctx, tctx->lp_ctx, argv[0]);
+ } else {
+ shell_usage(command);
+ }
+}
+
+static void shell_usage(const struct shell_command * command)
+{
+ if (command->usage) {
+ fprintf(stderr, "Usage: %s %s\n",
+ command->name, command->usage);
+ } else {
+ fprintf(stderr, "Usage: %s\n",
+ command->name);
+ }
+}
+
+static bool match_command(const char * name,
+ const struct shell_command * command)
+{
+ if (!strcmp(name, command->name)) {
+ return true;
+ }
+
+ if (name[0] == command->name[0] && name[1] == '\0') {
+ return true;
+ }
+
+ return false;
+}
diff --git a/source4/torture/smb2/acls.c b/source4/torture/smb2/acls.c
new file mode 100644
index 0000000..019886e
--- /dev/null
+++ b/source4/torture/smb2/acls.c
@@ -0,0 +1,3340 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test security descriptor operations for SMB2
+
+ Copyright (C) Zack Kirsch 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/param/param.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define BASEDIR "smb2-testsd"
+
+#define CHECK_ACCESS_IGNORE SEC_STD_SYNCHRONIZE
+
+#define CHECK_ACCESS_FLAGS(_fh, flags) do { \
+ union smb_fileinfo _q; \
+ _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
+ _q.access_information.in.file.handle = (_fh); \
+ status = smb2_getinfo_file(tree, tctx, &_q); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ /* Handle a Vista bug where SEC_STD_SYNCHRONIZE doesn't come back. */ \
+ if ((((flags) & CHECK_ACCESS_IGNORE) == CHECK_ACCESS_IGNORE) && \
+ ((_q.access_information.out.access_flags & CHECK_ACCESS_IGNORE) != CHECK_ACCESS_IGNORE)) { \
+ torture_comment(tctx, "SKIPPING (Vista bug): (%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
+ __location__, _q.access_information.out.access_flags, (flags)); \
+ } \
+ if ((_q.access_information.out.access_flags & ~CHECK_ACCESS_IGNORE) != \
+ (((flags) & ~CHECK_ACCESS_IGNORE))) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
+ __location__, _q.access_information.out.access_flags, (flags)); \
+ ret = false; \
+ goto done; \
+ } \
+} while (0)
+
+#define FAIL_UNLESS(__cond) \
+ do { \
+ if (__cond) {} else { \
+ torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
+ __location__, #__cond); \
+ ret = false; goto done; \
+ } \
+ } while(0)
+
+#define CHECK_SECURITY_DESCRIPTOR(_sd1, _sd2) do { \
+ if (!security_descriptor_equal(_sd1, _sd2)) { \
+ torture_warning(tctx, "security descriptors don't match!\n"); \
+ torture_warning(tctx, "got:\n"); \
+ NDR_PRINT_DEBUG(security_descriptor, _sd1); \
+ torture_warning(tctx, "expected:\n"); \
+ NDR_PRINT_DEBUG(security_descriptor, _sd2); \
+ torture_result(tctx, TORTURE_FAIL, \
+ "%s: security descriptors don't match!\n", \
+ __location__); \
+ ret = false; \
+ } \
+} while (0)
+
+/*
+ test the behaviour of the well known SID_CREATOR_OWNER sid, and some generic
+ mapping bits
+ Note: This test was copied from raw/acls.c.
+*/
+static bool test_creator_sid(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *fname = BASEDIR "\\creator.txt";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig, *sd2;
+ const char *owner_sid;
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING SID_CREATOR_OWNER\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "try open for write\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read\n");
+ io.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.in.desired_access = SEC_GENERIC_WRITE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.in.desired_access = SEC_GENERIC_READ;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "set a sec desc allowing no write by owner\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "check that sd has been mapped correctly\n");
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ torture_comment(tctx, "try open for write\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read\n");
+ io.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_FILE_READ_DATA);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.in.desired_access = SEC_GENERIC_WRITE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.in.desired_access = SEC_GENERIC_READ;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_RIGHTS_FILE_READ);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "set a sec desc allowing generic read by owner\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "check that generic read has been mapped correctly\n");
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ torture_comment(tctx, "try open for write\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for read\n");
+ io.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_FILE_READ_DATA);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.in.desired_access = SEC_GENERIC_WRITE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.in.desired_access = SEC_GENERIC_READ;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle, SEC_RIGHTS_FILE_READ);
+ smb2_util_close(tree, io.out.file.handle);
+
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+
+/*
+ test the mapping of the SEC_GENERIC_xx bits to SEC_STD_xx and
+ SEC_FILE_xx bits
+ Note: This test was copied from raw/acls.c.
+*/
+static bool test_generic_bits(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *fname = BASEDIR "\\generic.txt";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ int i;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig, *sd2;
+ const char *owner_sid;
+ const struct {
+ uint32_t gen_bits;
+ uint32_t specific_bits;
+ } file_mappings[] = {
+ { 0, 0 },
+ { SEC_GENERIC_READ, SEC_RIGHTS_FILE_READ },
+ { SEC_GENERIC_WRITE, SEC_RIGHTS_FILE_WRITE },
+ { SEC_GENERIC_EXECUTE, SEC_RIGHTS_FILE_EXECUTE },
+ { SEC_GENERIC_ALL, SEC_RIGHTS_FILE_ALL },
+ { SEC_FILE_READ_DATA, SEC_FILE_READ_DATA },
+ { SEC_FILE_READ_ATTRIBUTE, SEC_FILE_READ_ATTRIBUTE }
+ };
+ const struct {
+ uint32_t gen_bits;
+ uint32_t specific_bits;
+ } dir_mappings[] = {
+ { 0, 0 },
+ { SEC_GENERIC_READ, SEC_RIGHTS_DIR_READ },
+ { SEC_GENERIC_WRITE, SEC_RIGHTS_DIR_WRITE },
+ { SEC_GENERIC_EXECUTE, SEC_RIGHTS_DIR_EXECUTE },
+ { SEC_GENERIC_ALL, SEC_RIGHTS_DIR_ALL }
+ };
+ bool has_restore_privilege = false;
+ bool has_take_ownership_privilege = false;
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING FILE GENERIC BITS\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+/*
+ * XXX: The smblsa calls use SMB as their transport - need to get rid of
+ * dependency.
+ */
+/*
+ status = smblsa_sid_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smblsa_sid_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_RESTORE - %s\n", has_restore_privilege?"Yes":"No");
+
+ status = smblsa_sid_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_TAKE_OWNERSHIP));
+ has_take_ownership_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smblsa_sid_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_TAKE_OWNERSHIP - %s\n", has_take_ownership_privilege?"Yes":"No");
+*/
+
+ for (i=0;i<ARRAY_SIZE(file_mappings);i++) {
+ uint32_t expected_mask =
+ SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_STD_DELETE;
+ uint32_t expected_mask_anon = SEC_FILE_READ_ATTRIBUTE;
+
+ if (has_restore_privilege) {
+ expected_mask_anon |= SEC_STD_DELETE;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ expected_mask | file_mappings[i].specific_bits);
+ smb2_util_close(tree, io.out.file.handle);
+
+ if (!has_take_ownership_privilege) {
+ continue;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x (anonymous)\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ expected_mask_anon | file_mappings[i].specific_bits);
+ smb2_util_close(tree, io.out.file.handle);
+ }
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+
+
+ torture_comment(tctx, "TESTING DIR GENERIC BITS\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+/*
+ * XXX: The smblsa calls use SMB as their transport - need to get rid of
+ * dependency.
+ */
+/*
+ status = smblsa_sid_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smblsa_sid_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_RESTORE - %s\n", has_restore_privilege?"Yes":"No");
+
+ status = smblsa_sid_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_TAKE_OWNERSHIP));
+ has_take_ownership_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smblsa_sid_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_TAKE_OWNERSHIP - %s\n", has_take_ownership_privilege?"Yes":"No");
+
+*/
+ for (i=0;i<ARRAY_SIZE(dir_mappings);i++) {
+ uint32_t expected_mask =
+ SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_STD_DELETE;
+ uint32_t expected_mask_anon = SEC_FILE_READ_ATTRIBUTE;
+
+ if (has_restore_privilege) {
+ expected_mask_anon |= SEC_STD_DELETE;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ dir_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ dir_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ expected_mask | dir_mappings[i].specific_bits);
+ smb2_util_close(tree, io.out.file.handle);
+
+ if (!has_take_ownership_privilege) {
+ continue;
+ }
+
+ torture_comment(tctx, "Testing generic bits 0x%08x (anonymous)\n",
+ file_mappings[i].gen_bits);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].gen_bits,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ file_mappings[i].specific_bits,
+ 0,
+ NULL);
+
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ expected_mask_anon | dir_mappings[i].specific_bits);
+ smb2_util_close(tree, io.out.file.handle);
+ }
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+
+/*
+ see what access bits the owner of a file always gets
+ Note: This test was copied from raw/acls.c.
+*/
+static bool test_owner_bits(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *fname = BASEDIR "\\test_owner_bits.txt";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ int i;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig;
+ const char *owner_sid;
+ uint32_t expected_bits;
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING FILE OWNER BITS\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+/*
+ * XXX: The smblsa calls use SMB as their transport - need to get rid of
+ * dependency.
+ */
+/*
+ status = smblsa_sid_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smblsa_sid_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_RESTORE - %s\n", has_restore_privilege?"Yes":"No");
+
+ status = smblsa_sid_check_privilege(cli,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_TAKE_OWNERSHIP));
+ has_take_ownership_privilege = NT_STATUS_IS_OK(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "smblsa_sid_check_privilege - %s\n", nt_errstr(status));
+ }
+ torture_comment(tctx, "SEC_PRIV_TAKE_OWNERSHIP - %s\n", has_take_ownership_privilege?"Yes":"No");
+*/
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ expected_bits = SEC_FILE_WRITE_DATA | SEC_FILE_READ_ATTRIBUTE;
+
+ for (i=0;i<16;i++) {
+ uint32_t bit = (1<<i);
+ io.in.desired_access = bit;
+ status = smb2_create(tree, tctx, &io);
+ if (expected_bits & bit) {
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "failed with access mask 0x%08x of expected 0x%08x\n",
+ bit, expected_bits);
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle, bit);
+ smb2_util_close(tree, io.out.file.handle);
+ } else {
+ if (NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "open succeeded with access mask 0x%08x of "
+ "expected 0x%08x - should fail\n",
+ bit, expected_bits);
+ }
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+
+
+/*
+ test the inheritance of ACL flags onto new files and directories
+ Note: This test was copied from raw/acls.c.
+*/
+static bool test_inheritance(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *dname = BASEDIR "\\inheritance";
+ const char *fname1 = BASEDIR "\\inheritance\\testfile";
+ const char *fname2 = BASEDIR "\\inheritance\\testdir";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle handle2 = {{0}};
+ int i;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd2, *sd_orig=NULL, *sd_def1, *sd_def2;
+ const char *owner_sid;
+ const struct dom_sid *creator_owner;
+ const struct {
+ uint32_t parent_flags;
+ uint32_t file_flags;
+ uint32_t dir_flags;
+ } test_flags[] = {
+ {
+ 0,
+ 0,
+ 0
+ },
+ {
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY,
+ },
+ {
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT,
+ 0,
+ 0,
+ },
+ {
+ SEC_ACE_FLAG_INHERIT_ONLY |
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ 0,
+ 0,
+ }
+ };
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACL INHERITANCE\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access = 0;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = dname;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+
+ /*
+ * The Windows Default ACL for a new file, when there is no ACL to be
+ * inherited: FullControl for the owner and SYSTEM.
+ */
+ sd_def1 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ SID_NT_SYSTEM,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ NULL);
+
+ /*
+ * Use this in the case the system being tested does not add an ACE for
+ * the SYSTEM SID.
+ */
+ sd_def2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0,
+ NULL);
+
+ creator_owner = dom_sid_parse_talloc(tctx, SID_CREATOR_OWNER);
+
+ for (i=0;i<ARRAY_SIZE(test_flags);i++) {
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ test_flags[i].parent_flags,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.fname = fname1;
+ io.in.create_options = 0;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+
+ q.query_secdesc.in.file.handle = handle2;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, handle2);
+ smb2_util_unlink(tree, fname1);
+
+ if (!(test_flags[i].parent_flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ if (!security_descriptor_equal(q.query_secdesc.out.sd, sd_def1) &&
+ !security_descriptor_equal(q.query_secdesc.out.sd, sd_def2)) {
+ torture_warning(tctx, "Expected default sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd_def1);
+ torture_warning(tctx, "at %d - got:\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ }
+ goto check_dir;
+ }
+
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 1 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ sd_orig->owner_sid)) {
+ torture_warning(tctx, "Bad sd in child file at %d\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ ret = false;
+ goto check_dir;
+ }
+
+ if (q.query_secdesc.out.sd->dacl->aces[0].flags !=
+ test_flags[i].file_flags) {
+ torture_warning(tctx, "incorrect file_flags 0x%x - expected 0x%x for parent 0x%x with (i=%d)\n",
+ q.query_secdesc.out.sd->dacl->aces[0].flags,
+ test_flags[i].file_flags,
+ test_flags[i].parent_flags,
+ i);
+ ret = false;
+ }
+
+ check_dir:
+ io.in.fname = fname2;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+
+ q.query_secdesc.in.file.handle = handle2;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, handle2);
+ smb2_util_rmdir(tree, fname2);
+
+ if (!(test_flags[i].parent_flags & SEC_ACE_FLAG_CONTAINER_INHERIT) &&
+ (!(test_flags[i].parent_flags & SEC_ACE_FLAG_OBJECT_INHERIT) ||
+ (test_flags[i].parent_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT))) {
+ if (!security_descriptor_equal(q.query_secdesc.out.sd, sd_def1) &&
+ !security_descriptor_equal(q.query_secdesc.out.sd, sd_def2)) {
+ torture_warning(tctx, "Expected default sd for dir at %d:\n", i);
+ NDR_PRINT_DEBUG(security_descriptor, sd_def1);
+ torture_warning(tctx, "got:\n");
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ }
+ continue;
+ }
+
+ if ((test_flags[i].parent_flags & SEC_ACE_FLAG_CONTAINER_INHERIT) &&
+ (test_flags[i].parent_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 1 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ sd_orig->owner_sid) ||
+ q.query_secdesc.out.sd->dacl->aces[0].flags != test_flags[i].dir_flags) {
+ torture_warning(tctx, "(CI & NP) Bad sd in child dir - expected 0x%x for parent 0x%x (i=%d)\n",
+ test_flags[i].dir_flags,
+ test_flags[i].parent_flags, i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ torture_warning(tctx, "FYI, here is the parent sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ continue;
+ }
+ } else if (test_flags[i].parent_flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 2 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ sd_orig->owner_sid) ||
+ q.query_secdesc.out.sd->dacl->aces[1].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[1].trustee,
+ creator_owner) ||
+ q.query_secdesc.out.sd->dacl->aces[0].flags != 0 ||
+ q.query_secdesc.out.sd->dacl->aces[1].flags !=
+ (test_flags[i].dir_flags | SEC_ACE_FLAG_INHERIT_ONLY)) {
+ torture_warning(tctx, "(CI) Bad sd in child dir - expected 0x%x for parent 0x%x (i=%d)\n",
+ test_flags[i].dir_flags,
+ test_flags[i].parent_flags, i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ torture_warning(tctx, "FYI, here is the parent sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ continue;
+ }
+ } else {
+ if (q.query_secdesc.out.sd->dacl == NULL ||
+ q.query_secdesc.out.sd->dacl->num_aces != 1 ||
+ q.query_secdesc.out.sd->dacl->aces[0].access_mask != SEC_FILE_WRITE_DATA ||
+ !dom_sid_equal(&q.query_secdesc.out.sd->dacl->aces[0].trustee,
+ creator_owner) ||
+ q.query_secdesc.out.sd->dacl->aces[0].flags != test_flags[i].dir_flags) {
+ torture_warning(tctx, "(0) Bad sd in child dir - expected 0x%x for parent 0x%x (i=%d)\n",
+ test_flags[i].dir_flags,
+ test_flags[i].parent_flags, i);
+ NDR_PRINT_DEBUG(security_descriptor, q.query_secdesc.out.sd);
+ torture_warning(tctx, "FYI, here is the parent sd:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ continue;
+ }
+ }
+ }
+
+ torture_comment(tctx, "Testing access checks on inherited create with %s\n", fname1);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Check DACL we just set. */
+ torture_comment(tctx, "checking new sd\n");
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ io.in.fname = fname1;
+ io.in.create_options = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ CHECK_ACCESS_FLAGS(handle2, SEC_RIGHTS_FILE_ALL);
+
+ q.query_secdesc.in.file.handle = handle2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, handle2);
+
+ sd2 = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ 0,
+ NULL);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ status = smb2_create(tree, tctx, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "failed: w2k3 ACL bug (allowed open when ACL should deny)\n");
+ ret = false;
+ handle2 = io.out.file.handle;
+ CHECK_ACCESS_FLAGS(handle2, SEC_RIGHTS_FILE_ALL);
+ smb2_util_close(tree, handle2);
+ } else {
+ if (torture_setting_bool(tctx, "hide_on_access_denied",
+ false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ torture_comment(tctx, "trying without execute\n");
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL & ~SEC_FILE_EXECUTE;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "and with full permissions again\n");
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ CHECK_ACCESS_FLAGS(handle2, SEC_FILE_WRITE_DATA);
+ smb2_util_close(tree, handle2);
+
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, handle);
+
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ CHECK_ACCESS_FLAGS(handle2, SEC_FILE_WRITE_DATA);
+ smb2_util_close(tree, handle2);
+
+ smb2_util_unlink(tree, fname1);
+ smb2_util_rmdir(tree, dname);
+
+done:
+ if (sd_orig != NULL) {
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+ }
+
+ smb2_util_close(tree, handle);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_inheritance_flags(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *dname = BASEDIR "\\inheritance";
+ const char *fname1 = BASEDIR "\\inheritance\\testfile";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle handle2 = {{0}};
+ int i, j;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd2, *sd_orig=NULL;
+ const char *owner_sid;
+ struct {
+ uint32_t parent_set_sd_type; /* 3 options */
+ uint32_t parent_set_ace_inherit; /* 1 option */
+ uint32_t parent_get_sd_type;
+ uint32_t parent_get_ace_inherit;
+ uint32_t child_get_sd_type;
+ uint32_t child_get_ace_inherit;
+ } tflags[16] = {{0}}; /* 2^4 */
+
+ for (i = 0; i < 15; i++) {
+ torture_comment(tctx, "i=%d:", i);
+
+ if (i & 1) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ torture_comment(tctx, "AUTO_INHERITED, ");
+ }
+ if (i & 2) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERIT_REQ;
+ torture_comment(tctx, "AUTO_INHERIT_REQ, ");
+ }
+ if (i & 4) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_PROTECTED;
+ torture_comment(tctx, "PROTECTED, ");
+ tflags[i].parent_get_sd_type |=
+ SEC_DESC_DACL_PROTECTED;
+ }
+ if (i & 8) {
+ tflags[i].parent_set_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, "INHERITED, ");
+ tflags[i].parent_get_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ }
+
+ if ((tflags[i].parent_set_sd_type &
+ (SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ)) ==
+ (SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ)) {
+ tflags[i].parent_get_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ tflags[i].child_get_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ tflags[i].child_get_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, " ... parent is AUTO INHERITED");
+ }
+
+ if (tflags[i].parent_set_ace_inherit &
+ SEC_ACE_FLAG_INHERITED_ACE) {
+ tflags[i].parent_get_ace_inherit =
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, " ... parent ACE is INHERITED");
+ }
+
+ torture_comment(tctx, "\n");
+ }
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACL INHERITANCE FLAGS\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = dname;
+
+ torture_comment(tctx, "creating initial directory %s\n", dname);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "getting original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+
+ for (i=0; i < ARRAY_SIZE(tflags); i++) {
+ torture_comment(tctx, "setting a new sd on directory, pass #%d\n", i);
+
+ sd = security_descriptor_dacl_create(tctx,
+ tflags[i].parent_set_sd_type,
+ NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ tflags[i].parent_set_ace_inherit,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Check DACL we just set, except change the bits to what they
+ * should be.
+ */
+ torture_comment(tctx, " checking new sd\n");
+
+ /* REQ bit should always be false. */
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ if ((tflags[i].parent_get_sd_type & SEC_DESC_DACL_AUTO_INHERITED) == 0)
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ /* Create file. */
+ torture_comment(tctx, " creating file %s\n", fname1);
+ io.in.fname = fname1;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ CHECK_ACCESS_FLAGS(handle2, SEC_RIGHTS_FILE_ALL);
+
+ q.query_secdesc.in.file.handle = handle2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, " checking sd on file %s\n", fname1);
+ sd2 = security_descriptor_dacl_create(tctx,
+ tflags[i].child_get_sd_type,
+ owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ tflags[i].child_get_ace_inherit,
+ NULL);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ /*
+ * Set new sd on file ... prove that the bits have nothing to
+ * do with the parents bits when manually setting an ACL. The
+ * _AUTO_INHERITED bit comes directly from the ACL set.
+ */
+ for (j = 0; j < ARRAY_SIZE(tflags); j++) {
+ torture_comment(tctx, " setting new file sd, pass #%d\n", j);
+
+ /* Change sd type. */
+ sd2->type &= ~(SEC_DESC_DACL_AUTO_INHERITED |
+ SEC_DESC_DACL_AUTO_INHERIT_REQ |
+ SEC_DESC_DACL_PROTECTED);
+ sd2->type |= tflags[j].parent_set_sd_type;
+
+ sd2->dacl->aces[0].flags &=
+ ~SEC_ACE_FLAG_INHERITED_ACE;
+ sd2->dacl->aces[0].flags |=
+ tflags[j].parent_set_ace_inherit;
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle2;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd2;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Check DACL we just set. */
+ sd2->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
+ if ((tflags[j].parent_get_sd_type & SEC_DESC_DACL_AUTO_INHERITED) == 0)
+ sd2->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ q.query_secdesc.in.file.handle = handle2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+ }
+
+ smb2_util_close(tree, handle2);
+ smb2_util_unlink(tree, fname1);
+ }
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+/*
+ * This is basically a copy of test_inheritance_flags() with an additional twist
+ * to change the owner of the testfile, verifying that the security descriptor
+ * flags are not altered.
+ */
+static bool test_sd_flags_vs_chown(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *dname = BASEDIR "\\inheritance";
+ const char *fname1 = BASEDIR "\\inheritance\\testfile";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle handle2 = {{0}};
+ int i, j;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd2, *sd_orig=NULL;
+ struct security_descriptor *owner_sd = NULL;
+ const char *owner_sid_string = NULL;
+ struct dom_sid *owner_sid = NULL;
+ struct dom_sid world_sid = global_sid_World;
+ struct {
+ uint32_t parent_set_sd_type; /* 3 options */
+ uint32_t parent_set_ace_inherit; /* 1 option */
+ uint32_t parent_get_sd_type;
+ uint32_t parent_get_ace_inherit;
+ uint32_t child_get_sd_type;
+ uint32_t child_get_ace_inherit;
+ } tflags[16] = {{0}}; /* 2^4 */
+
+ owner_sd = security_descriptor_dacl_create(tctx,
+ 0,
+ SID_WORLD,
+ NULL,
+ NULL);
+ torture_assert_not_null_goto(tctx, owner_sd, ret, done,
+ "security_descriptor_dacl_create failed\n");
+
+ for (i = 0; i < 15; i++) {
+ torture_comment(tctx, "i=%d:", i);
+
+ if (i & 1) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ torture_comment(tctx, "AUTO_INHERITED, ");
+ }
+ if (i & 2) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERIT_REQ;
+ torture_comment(tctx, "AUTO_INHERIT_REQ, ");
+ }
+ if (i & 4) {
+ tflags[i].parent_set_sd_type |=
+ SEC_DESC_DACL_PROTECTED;
+ torture_comment(tctx, "PROTECTED, ");
+ tflags[i].parent_get_sd_type |=
+ SEC_DESC_DACL_PROTECTED;
+ }
+ if (i & 8) {
+ tflags[i].parent_set_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, "INHERITED, ");
+ tflags[i].parent_get_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ }
+
+ if ((tflags[i].parent_set_sd_type &
+ (SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ)) ==
+ (SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ)) {
+ tflags[i].parent_get_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ tflags[i].child_get_sd_type |=
+ SEC_DESC_DACL_AUTO_INHERITED;
+ tflags[i].child_get_ace_inherit |=
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, " ... parent is AUTO INHERITED");
+ }
+
+ if (tflags[i].parent_set_ace_inherit &
+ SEC_ACE_FLAG_INHERITED_ACE) {
+ tflags[i].parent_get_ace_inherit =
+ SEC_ACE_FLAG_INHERITED_ACE;
+ torture_comment(tctx, " ... parent ACE is INHERITED");
+ }
+
+ torture_comment(tctx, "\n");
+ }
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACL INHERITANCE FLAGS\n");
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = dname;
+
+ torture_comment(tctx, "creating initial directory %s\n", dname);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "getting original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = sd_orig->owner_sid;
+ owner_sid_string = dom_sid_string(tctx, sd_orig->owner_sid);
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid_string);
+
+ for (i=0; i < ARRAY_SIZE(tflags); i++) {
+ torture_comment(tctx, "setting a new sd on directory, pass #%d\n", i);
+
+ sd = security_descriptor_dacl_create(tctx,
+ tflags[i].parent_set_sd_type,
+ NULL, NULL,
+ owner_sid_string,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ tflags[i].parent_set_ace_inherit,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL | SEC_STD_ALL,
+ 0,
+ NULL);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Check DACL we just set, except change the bits to what they
+ * should be.
+ */
+ torture_comment(tctx, " checking new sd\n");
+
+ /* REQ bit should always be false. */
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ if ((tflags[i].parent_get_sd_type & SEC_DESC_DACL_AUTO_INHERITED) == 0)
+ sd->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd);
+
+ /* Create file. */
+ torture_comment(tctx, " creating file %s\n", fname1);
+ io.in.fname = fname1;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ CHECK_ACCESS_FLAGS(handle2, SEC_RIGHTS_FILE_ALL);
+
+ q.query_secdesc.in.file.handle = handle2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, " checking sd on file %s\n", fname1);
+ sd2 = security_descriptor_dacl_create(tctx,
+ tflags[i].child_get_sd_type,
+ owner_sid_string, NULL,
+ owner_sid_string,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_WRITE_DAC,
+ tflags[i].child_get_ace_inherit,
+ NULL);
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ /*
+ * Set new sd on file ... prove that the bits have nothing to
+ * do with the parents bits when manually setting an ACL. The
+ * _AUTO_INHERITED bit comes directly from the ACL set.
+ */
+ for (j = 0; j < ARRAY_SIZE(tflags); j++) {
+ torture_comment(tctx, " setting new file sd, pass #%d\n", j);
+
+ /* Change sd type. */
+ sd2->type &= ~(SEC_DESC_DACL_AUTO_INHERITED |
+ SEC_DESC_DACL_AUTO_INHERIT_REQ |
+ SEC_DESC_DACL_PROTECTED);
+ sd2->type |= tflags[j].parent_set_sd_type;
+
+ sd2->dacl->aces[0].flags &=
+ ~SEC_ACE_FLAG_INHERITED_ACE;
+ sd2->dacl->aces[0].flags |=
+ tflags[j].parent_set_ace_inherit;
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle2;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd2;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Check DACL we just set. */
+ sd2->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
+ if ((tflags[j].parent_get_sd_type & SEC_DESC_DACL_AUTO_INHERITED) == 0)
+ sd2->type &= ~SEC_DESC_DACL_AUTO_INHERITED;
+
+ q.query_secdesc.in.file.handle = handle2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+
+ /*
+ * Check that changing owner doesn't affect SD flags.
+ *
+ * Do this by first changing owner to world and then
+ * back to the original owner. Afterwards compare SD,
+ * should be the same.
+ */
+ owner_sd->owner_sid = &world_sid;
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle2;
+ set.set_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ set.set_secdesc.in.sd = owner_sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ owner_sd->owner_sid = owner_sid;
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle2;
+ set.set_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ set.set_secdesc.in.sd = owner_sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ q.query_secdesc.in.file.handle = handle2;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_SECURITY_DESCRIPTOR(q.query_secdesc.out.sd, sd2);
+ torture_assert_goto(tctx, ret, ret, done, "CHECK_SECURITY_DESCRIPTOR failed\n");
+ }
+
+ smb2_util_close(tree, handle2);
+ smb2_util_unlink(tree, fname1);
+ }
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+/*
+ test dynamic acl inheritance
+ Note: This test was copied from raw/acls.c.
+*/
+static bool test_inheritance_dynamic(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *dname = BASEDIR "\\inheritance";
+ const char *fname1 = BASEDIR "\\inheritance\\testfile";
+ bool ret = true;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle handle2 = {{0}};
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig=NULL;
+ const char *owner_sid;
+
+ torture_comment(tctx, "TESTING DYNAMIC ACL INHERITANCE\n");
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access = 0;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = dname;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_DELETE | SEC_FILE_READ_ATTRIBUTE,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+ sd->type |= SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "create a file with an inherited acl\n");
+ io.in.fname = fname1;
+ io.in.create_options = 0;
+ io.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ smb2_util_close(tree, handle2);
+
+ torture_comment(tctx, "try and access file with base rights - should be OK\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ smb2_util_close(tree, handle2);
+
+ torture_comment(tctx, "try and access file with extra rights - should be denied\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA | SEC_FILE_EXECUTE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(tctx, "update parent sd\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA | SEC_STD_DELETE | SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+ sd->type |= SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_DACL_AUTO_INHERIT_REQ;
+
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "try and access file with base rights - should be OK\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle2 = io.out.file.handle;
+ smb2_util_close(tree, handle2);
+
+
+ torture_comment(tctx, "try and access now - should be OK if dynamic inheritance works\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA | SEC_FILE_EXECUTE;
+ status = smb2_create(tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx, "Server does not have dynamic inheritance\n");
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Server does have dynamic inheritance\n");
+ }
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ smb2_util_unlink(tree, fname1);
+
+done:
+ torture_comment(tctx, "put back original sd\n");
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+ status = smb2_setinfo_file(tree, &set);
+
+ smb2_util_close(tree, handle);
+ smb2_util_rmdir(tree, dname);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+
+ return ret;
+}
+
+#define CHECK_STATUS_FOR_BIT_ACTION(status, bits, action) do { \
+ if (!(bits & desired_64)) {\
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); \
+ action; \
+ } else { \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ } \
+} while (0)
+
+#define CHECK_STATUS_FOR_BIT(status, bits, access) do { \
+ if (NT_STATUS_IS_OK(status)) { \
+ if (!(granted & access)) {\
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s but flags 0x%08X are not granted! granted[0x%08X] desired[0x%08X]\n", \
+ __location__, nt_errstr(status), access, granted, desired); \
+ goto done; \
+ } \
+ } else { \
+ if (granted & access) {\
+ ret = false; \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s but flags 0x%08X are granted! granted[0x%08X] desired[0x%08X]\n", \
+ __location__, nt_errstr(status), access, granted, desired); \
+ goto done; \
+ } \
+ } \
+ CHECK_STATUS_FOR_BIT_ACTION(status, bits, do {} while (0)); \
+} while (0)
+
+#if 0
+/* test what access mask is needed for getting and setting security_descriptors */
+/* Note: This test was copied from raw/acls.c. */
+static bool test_sd_get_set(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create io;
+ union smb_fileinfo fi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd;
+ struct security_descriptor *sd_owner = NULL;
+ struct security_descriptor *sd_group = NULL;
+ struct security_descriptor *sd_dacl = NULL;
+ struct security_descriptor *sd_sacl = NULL;
+ struct smb2_handle handle;
+ const char *fname = BASEDIR "\\sd_get_set.txt";
+ uint64_t desired_64;
+ uint32_t desired = 0, granted;
+ int i = 0;
+#define NO_BITS_HACK (((uint64_t)1)<<32)
+ uint64_t open_bits =
+ SEC_MASK_GENERIC |
+ SEC_FLAG_SYSTEM_SECURITY |
+ SEC_FLAG_MAXIMUM_ALLOWED |
+ SEC_STD_ALL |
+ SEC_FILE_ALL |
+ NO_BITS_HACK;
+ uint64_t get_owner_bits = SEC_MASK_GENERIC | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_READ_CONTROL;
+ uint64_t set_owner_bits = SEC_GENERIC_ALL | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_WRITE_OWNER;
+ uint64_t get_group_bits = SEC_MASK_GENERIC | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_READ_CONTROL;
+ uint64_t set_group_bits = SEC_GENERIC_ALL | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_WRITE_OWNER;
+ uint64_t get_dacl_bits = SEC_MASK_GENERIC | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_READ_CONTROL;
+ uint64_t set_dacl_bits = SEC_GENERIC_ALL | SEC_FLAG_MAXIMUM_ALLOWED | SEC_STD_WRITE_DAC;
+ uint64_t get_sacl_bits = SEC_FLAG_SYSTEM_SECURITY;
+ uint64_t set_sacl_bits = SEC_FLAG_SYSTEM_SECURITY;
+
+ if (!smb2_util_setup_dir(tctx, tree, BASEDIR))
+ return false;
+
+ torture_comment(tctx, "TESTING ACCESS MASKS FOR SD GET/SET\n");
+
+ /* first create a file with full access for everyone */
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_NT_ANONYMOUS, SID_BUILTIN_USERS,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_GENERIC_ALL,
+ 0,
+ NULL);
+ sd->type |= SEC_DESC_SACL_PRESENT;
+ sd->sacl = NULL;
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_GENERIC_ALL;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+ io.in.sec_desc = sd;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ status = smb2_util_close(tree, handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * now try each access_mask bit and no bit at all in a loop
+ * and see what's allowed
+ * NOTE: if i == 32 it means access_mask = 0 (see NO_BITS_HACK above)
+ */
+ for (i=0; i <= 32; i++) {
+ desired_64 = ((uint64_t)1) << i;
+ desired = (uint32_t)desired_64;
+
+ /* first open the file with the desired access */
+ io.level = RAW_OPEN_SMB2;
+ io.in.desired_access = desired;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS_FOR_BIT_ACTION(status, open_bits, goto next);
+ handle = io.out.file.handle;
+
+ /* then check what access was granted */
+ fi.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ fi.access_information.in.file.handle = handle;
+ status = smb2_getinfo_file(tree, tctx, &fi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ granted = fi.access_information.out.access_flags;
+
+ /* test the owner */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.handle = handle;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_owner_bits, SEC_STD_READ_CONTROL);
+ if (fi.query_secdesc.out.sd) {
+ sd_owner = fi.query_secdesc.out.sd;
+ } else if (!sd_owner) {
+ sd_owner = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.handle = handle;
+ si.set_secdesc.in.secinfo_flags = SECINFO_OWNER;
+ si.set_secdesc.in.sd = sd_owner;
+ status = smb2_setinfo_file(tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_owner_bits, SEC_STD_WRITE_OWNER);
+
+ /* test the group */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.handle = handle;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_GROUP;
+ status = smb2_getinfo_file(tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_group_bits, SEC_STD_READ_CONTROL);
+ if (fi.query_secdesc.out.sd) {
+ sd_group = fi.query_secdesc.out.sd;
+ } else if (!sd_group) {
+ sd_group = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.handle = handle;
+ si.set_secdesc.in.secinfo_flags = SECINFO_GROUP;
+ si.set_secdesc.in.sd = sd_group;
+ status = smb2_setinfo_file(tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_group_bits, SEC_STD_WRITE_OWNER);
+
+ /* test the DACL */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.handle = handle;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_dacl_bits, SEC_STD_READ_CONTROL);
+ if (fi.query_secdesc.out.sd) {
+ sd_dacl = fi.query_secdesc.out.sd;
+ } else if (!sd_dacl) {
+ sd_dacl = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.handle = handle;
+ si.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ si.set_secdesc.in.sd = sd_dacl;
+ status = smb2_setinfo_file(tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_dacl_bits, SEC_STD_WRITE_DAC);
+
+ /* test the SACL */
+ ZERO_STRUCT(fi);
+ fi.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ fi.query_secdesc.in.file.handle = handle;
+ fi.query_secdesc.in.secinfo_flags = SECINFO_SACL;
+ status = smb2_getinfo_file(tree, tctx, &fi);
+ CHECK_STATUS_FOR_BIT(status, get_sacl_bits, SEC_FLAG_SYSTEM_SECURITY);
+ if (fi.query_secdesc.out.sd) {
+ sd_sacl = fi.query_secdesc.out.sd;
+ } else if (!sd_sacl) {
+ sd_sacl = sd;
+ }
+ si.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ si.set_secdesc.in.file.handle = handle;
+ si.set_secdesc.in.secinfo_flags = SECINFO_SACL;
+ si.set_secdesc.in.sd = sd_sacl;
+ status = smb2_setinfo_file(tree, &si);
+ CHECK_STATUS_FOR_BIT(status, set_sacl_bits, SEC_FLAG_SYSTEM_SECURITY);
+
+ /* close the handle */
+ status = smb2_util_close(tree, handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+next:
+ continue;
+ }
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+
+ return ret;
+}
+#endif
+
+static bool test_access_based(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_tree *tree1 = NULL;
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *fname = BASEDIR "\\testfile";
+ bool ret = true;
+ struct smb2_handle fhandle, dhandle;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig=NULL;
+ const char *owner_sid;
+ uint32_t flags = 0;
+ /*
+ * Can't test without SEC_STD_READ_CONTROL as we
+ * own the file and implicitly have SEC_STD_READ_CONTROL.
+ */
+ uint32_t access_masks[] = {
+ /* Full READ access. */
+ SEC_STD_READ_CONTROL|FILE_READ_DATA|
+ FILE_READ_ATTRIBUTES|FILE_READ_EA,
+
+ /* Missing FILE_READ_EA. */
+ SEC_STD_READ_CONTROL|FILE_READ_DATA|
+ FILE_READ_ATTRIBUTES,
+
+ /* Missing FILE_READ_ATTRIBUTES. */
+ SEC_STD_READ_CONTROL|FILE_READ_DATA|
+ FILE_READ_EA,
+
+ /* Missing FILE_READ_DATA. */
+ SEC_STD_READ_CONTROL|
+ FILE_READ_ATTRIBUTES|FILE_READ_EA,
+ };
+ unsigned int i;
+ unsigned int count;
+ struct smb2_find f;
+ union smb_search_data *d;
+
+ ZERO_STRUCT(fhandle);
+ ZERO_STRUCT(dhandle);
+
+ if (!torture_smb2_con_share(tctx, "hideunread", &tree1)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) Unable to connect "
+ "to share 'hideunread'\n",
+ __location__);
+ ret = false;
+ goto done;
+ }
+
+ flags = smb2cli_tcon_flags(tree1->smbXcli);
+
+ smb2_util_unlink(tree1, fname);
+ smb2_deltree(tree1, BASEDIR);
+
+ torture_comment(tctx, "TESTING ACCESS BASED ENUMERATION\n");
+
+ if ((flags & SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM)==0) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) No access enumeration "
+ "on share 'hideunread'\n",
+ __location__);
+ ret = false;
+ goto done;
+ }
+
+ if (!smb2_util_setup_dir(tctx, tree1, BASEDIR)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) Unable to setup %s\n",
+ __location__, BASEDIR);
+ ret = false;
+ goto done;
+ }
+
+ /* Get a handle to the BASEDIR directory. */
+ status = torture_smb2_testdir(tree1, BASEDIR, &dhandle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, dhandle);
+ ZERO_STRUCT(dhandle);
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access = 0;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+
+ status = smb2_create(tree1, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fhandle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = fhandle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree1, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ torture_comment(tctx, "owner_sid is %s\n", owner_sid);
+
+ /* Setup for the search. */
+ ZERO_STRUCT(f);
+ f.in.pattern = "*";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_REOPEN;
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_DIRECTORY_INFO;
+
+ for (i = 0; i < ARRAY_SIZE(access_masks); i++) {
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ access_masks[i]|SEC_STD_SYNCHRONIZE,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = fhandle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree1, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Now see if we can see the file in a directory listing. */
+
+ /* Re-open dhandle. */
+ status = torture_smb2_testdir(tree1, BASEDIR, &dhandle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ f.in.file.handle = dhandle;
+
+ count = 0;
+ d = NULL;
+ status = smb2_find_level(tree1, tree1, &f, &count, &d);
+ TALLOC_FREE(d);
+
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree1, dhandle);
+ ZERO_STRUCT(dhandle);
+
+ if (i == 0) {
+ /* We should see the first sd. */
+ if (count != 3) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Normal SD - Unable "
+ "to see file %s\n",
+ __location__,
+ BASEDIR);
+ ret = false;
+ goto done;
+ }
+ } else {
+ /* But no others. */
+ if (count != 2) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) SD 0x%x - can "
+ "see file %s\n",
+ __location__,
+ access_masks[i],
+ BASEDIR);
+ ret = false;
+ goto done;
+ }
+ }
+ }
+
+done:
+
+ if (tree1) {
+ smb2_util_close(tree1, fhandle);
+ smb2_util_close(tree1, dhandle);
+ smb2_util_unlink(tree1, fname);
+ smb2_deltree(tree1, BASEDIR);
+ smb2_tdis(tree1);
+ smb2_logoff(tree1->session);
+ }
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+/*
+ * test Owner Rights, S-1-3-4
+ */
+static bool test_owner_rights(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\owner_right.txt";
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_descriptor *sd = NULL;
+ const char *owner_sid = NULL;
+ NTSTATUS mxac_status;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done,
+ "smb2_util_setup_dir failed\n");
+
+ torture_comment(tctx, "TESTING OWNER RIGHTS\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |SEC_STD_WRITE_OWNER,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL|SECINFO_OWNER,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ /*
+ * Add a 2 element ACL
+ * SEC_RIGHTS_FILE_READ for the owner,
+ * SEC_FILE_WRITE_DATA for SID_OWNER_RIGHTS.
+ *
+ * Proves that the owner and SID_OWNER_RIGHTS
+ * ACE entries are additive.
+ */
+ sd = security_descriptor_dacl_create(tctx, 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ,
+ 0,
+ SID_OWNER_RIGHTS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = handle,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.query_maximal_access = true,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+ handle = cr.out.file.handle;
+
+ mxac_status = NT_STATUS(cr.out.maximal_access_status);
+ torture_assert_ntstatus_ok_goto(tctx, mxac_status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ /*
+ * For some reasons Windows 2016 doesn't set SEC_STD_DELETE but we
+ * do. Mask it out so the test passes against Samba and Windows.
+ */
+ torture_assert_int_equal_goto(tctx,
+ cr.out.maximal_access & ~SEC_STD_DELETE,
+ SEC_RIGHTS_FILE_READ |
+ SEC_FILE_WRITE_DATA,
+ ret, done,
+ "Wrong maximum access\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * test Owner Rights with a leading DENY ACE, S-1-3-4
+ */
+static bool test_owner_rights_deny(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\owner_right_deny.txt";
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_descriptor *sd = NULL;
+ const char *owner_sid = NULL;
+ NTSTATUS mxac_status;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done,
+ "smb2_util_setup_dir failed\n");
+
+ torture_comment(tctx, "TESTING OWNER RIGHTS DENY\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |SEC_STD_WRITE_OWNER,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL|SECINFO_OWNER,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ /*
+ * Add a 2 element ACL
+ * DENY SEC_FILE_DATA_READ for SID_OWNER_RIGHTS
+ * SEC_FILE_READ_DATA for the owner.
+ *
+ * Proves that the owner and SID_OWNER_RIGHTS
+ * ACE entries are additive.
+ */
+ sd = security_descriptor_dacl_create(tctx, 0, NULL, NULL,
+ SID_OWNER_RIGHTS,
+ SEC_ACE_TYPE_ACCESS_DENIED,
+ SEC_FILE_READ_DATA,
+ 0,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = handle,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.query_maximal_access = true,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+ handle = cr.out.file.handle;
+
+ mxac_status = NT_STATUS(cr.out.maximal_access_status);
+ torture_assert_ntstatus_ok_goto(tctx, mxac_status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ /*
+ * For some reasons Windows 2016 doesn't set SEC_STD_DELETE but we
+ * do. Mask it out so the test passes against Samba and Windows.
+ */
+ torture_assert_int_equal_goto(tctx,
+ cr.out.maximal_access & ~SEC_STD_DELETE,
+ SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA,
+ ret, done,
+ "Wrong maximum access\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * test Owner Rights with a trailing DENY ACE, S-1-3-4
+ */
+static bool test_owner_rights_deny1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\owner_right_deny1.txt";
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_descriptor *sd = NULL;
+ const char *owner_sid = NULL;
+ NTSTATUS mxac_status;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done,
+ "smb2_util_setup_dir failed\n");
+
+ torture_comment(tctx, "TESTING OWNER RIGHTS DENY1\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |SEC_STD_WRITE_OWNER,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL|SECINFO_OWNER,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ /*
+ * Add a 3 element ACL
+ *
+ * SEC_RIGHTS_FILE_READ allow for owner.
+ * SEC_FILE_WRITE_DATA allow for SID-OWNER-RIGHTS.
+ * SEC_FILE_WRITE_DATA|SEC_FILE_READ_DATA) deny for SID-OWNER-RIGHTS.
+ *
+ * Shows on Windows that trailing DENY entries don't
+ * override granted permissions in max access calculations.
+ */
+ sd = security_descriptor_dacl_create(tctx, 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ,
+ 0,
+ SID_OWNER_RIGHTS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ 0,
+ SID_OWNER_RIGHTS,
+ SEC_ACE_TYPE_ACCESS_DENIED,
+ (SEC_FILE_WRITE_DATA|
+ SEC_FILE_READ_DATA),
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = handle,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.query_maximal_access = true,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+ handle = cr.out.file.handle;
+
+ mxac_status = NT_STATUS(cr.out.maximal_access_status);
+ torture_assert_ntstatus_ok_goto(tctx, mxac_status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ /*
+ * For some reasons Windows 2016 doesn't set SEC_STD_DELETE but we
+ * do. Mask it out so the test passes against Samba and Windows.
+ */
+ torture_assert_int_equal_goto(tctx,
+ cr.out.maximal_access & ~SEC_STD_DELETE,
+ SEC_RIGHTS_FILE_READ | SEC_FILE_WRITE_DATA,
+ ret, done,
+ "Wrong maximum access\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * test that shows that a DENY ACE doesn't remove rights granted
+ * by a previous ALLOW ACE.
+ */
+static bool test_deny1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\test_deny1.txt";
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_descriptor *sd = NULL;
+ const char *owner_sid = NULL;
+ NTSTATUS mxac_status;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done,
+ "smb2_util_setup_dir failed\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |SEC_STD_WRITE_OWNER,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL|SECINFO_OWNER,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ /*
+ * Add a 2 element ACL
+ *
+ * SEC_RIGHTS_FILE_READ|SEC_FILE_WRITE_DATA allow for owner.
+ * SEC_FILE_WRITE_DATA deny for owner
+ *
+ * Shows on Windows that trailing DENY entries don't
+ * override granted permissions.
+ */
+ sd = security_descriptor_dacl_create(tctx, 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ|SEC_FILE_WRITE_DATA,
+ 0,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_DENIED,
+ SEC_FILE_WRITE_DATA,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = handle,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_WRITE_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.query_maximal_access = true,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ mxac_status = NT_STATUS(cr.out.maximal_access_status);
+ torture_assert_ntstatus_ok_goto(tctx, mxac_status, ret, done,
+ "Wrong maximum access status\n");
+
+ /*
+ * For some reasons Windows 2016 doesn't set SEC_STD_DELETE but we
+ * do. Mask it out so the test passes against Samba and Windows.
+ * SEC_STD_WRITE_DAC comes from being the owner.
+ */
+ torture_assert_int_equal_goto(tctx,
+ cr.out.maximal_access & ~SEC_STD_DELETE,
+ SEC_RIGHTS_FILE_READ |
+ SEC_FILE_WRITE_DATA |
+ SEC_STD_WRITE_DAC,
+ ret, done,
+ "Wrong maximum access\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * test SEC_FLAG_MAXIMUM_ALLOWED with not-granted access
+ *
+ * When access_mask contains SEC_FLAG_MAXIMUM_ALLOWED, the server must still
+ * process other bits from access_mask. Eg if access_mask contains a right that
+ * the requester doesn't have, the function must validate that against the
+ * effective permissions.
+ */
+static bool test_mxac_not_granted(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\test_mxac_not_granted.txt";
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_descriptor *sd = NULL;
+ const char *owner_sid = NULL;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done,
+ "smb2_util_setup_dir failed\n");
+
+ torture_comment(tctx, "TESTING OWNER RIGHTS DENY\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |SEC_STD_WRITE_OWNER,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL|SECINFO_OWNER,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ sd = security_descriptor_dacl_create(tctx, 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_READ_DATA,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = handle,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED |
+ SEC_FILE_WRITE_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "Wrong smb2_create result\n");
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_overwrite_read_only_file(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create c;
+ const char *fname = BASEDIR "\\test_overwrite_read_only_file.txt";
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd = NULL, *sd_orig = NULL;
+ const char *owner_sid = NULL;
+ int i;
+ bool ret = true;
+
+ struct tcase {
+ int disposition;
+ const char *disposition_string;
+ NTSTATUS expected_status;
+ } tcases[] = {
+#define TCASE(d, s) { \
+ .disposition = d, \
+ .disposition_string = #d, \
+ .expected_status = s, \
+ }
+ TCASE(NTCREATEX_DISP_OPEN, NT_STATUS_OK),
+ TCASE(NTCREATEX_DISP_SUPERSEDE, NT_STATUS_ACCESS_DENIED),
+ TCASE(NTCREATEX_DISP_OVERWRITE, NT_STATUS_ACCESS_DENIED),
+ TCASE(NTCREATEX_DISP_OVERWRITE_IF, NT_STATUS_ACCESS_DENIED),
+ };
+#undef TCASE
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done, "smb2_util_setup_dir not ok");
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = c.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ ZERO_STRUCT(q);
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+
+ status = smb2_getinfo_file(tree, tctx, &q);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_READ_DATA,
+ 0,
+ NULL);
+
+ ZERO_STRUCT(set);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ smb2_util_close(tree, handle);
+ ZERO_STRUCT(handle);
+
+ for (i = 0; i < ARRAY_SIZE(tcases); i++) {
+ torture_comment(tctx, "Verify open with %s disposition\n",
+ tcases[i].disposition_string);
+
+ c = (struct smb2_create) {
+ .in.create_disposition = tcases[i].disposition,
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ smb2_util_close(tree, c.out.file.handle);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, tcases[i].expected_status, ret, done,
+ "smb2_create failed\n");
+ };
+
+ torture_comment(tctx, "put back original sd\n");
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_STD_WRITE_DAC,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = c.out.file.handle;
+
+ ZERO_STRUCT(set);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd_orig;
+
+ status = smb2_setinfo_file(tree, &set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ smb2_util_close(tree, handle);
+ ZERO_STRUCT(handle);
+
+done:
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of SMB2 ACLs
+*/
+struct torture_suite *torture_smb2_acls_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "acls");
+
+ torture_suite_add_1smb2_test(suite, "CREATOR", test_creator_sid);
+ torture_suite_add_1smb2_test(suite, "GENERIC", test_generic_bits);
+ torture_suite_add_1smb2_test(suite, "OWNER", test_owner_bits);
+ torture_suite_add_1smb2_test(suite, "INHERITANCE", test_inheritance);
+ torture_suite_add_1smb2_test(suite, "INHERITFLAGS", test_inheritance_flags);
+ torture_suite_add_1smb2_test(suite, "SDFLAGSVSCHOWN", test_sd_flags_vs_chown);
+ torture_suite_add_1smb2_test(suite, "DYNAMIC", test_inheritance_dynamic);
+#if 0
+ /* XXX This test does not work against XP or Vista. */
+ torture_suite_add_1smb2_test(suite, "GETSET", test_sd_get_set);
+#endif
+ torture_suite_add_1smb2_test(suite, "ACCESSBASED", test_access_based);
+ torture_suite_add_1smb2_test(suite, "OWNER-RIGHTS", test_owner_rights);
+ torture_suite_add_1smb2_test(suite, "OWNER-RIGHTS-DENY",
+ test_owner_rights_deny);
+ torture_suite_add_1smb2_test(suite, "OWNER-RIGHTS-DENY1",
+ test_owner_rights_deny1);
+ torture_suite_add_1smb2_test(suite, "DENY1",
+ test_deny1);
+ torture_suite_add_1smb2_test(suite, "MXAC-NOT-GRANTED",
+ test_mxac_not_granted);
+ torture_suite_add_1smb2_test(suite, "OVERWRITE_READ_ONLY_FILE", test_overwrite_read_only_file);
+
+ suite->description = talloc_strdup(suite, "SMB2-ACLS tests");
+
+ return suite;
+}
+
+static bool test_acls_non_canonical_flags(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\test_acls_non_canonical_flags.txt";
+ struct smb2_create cr;
+ struct smb2_handle testdirh = {{0}};
+ struct smb2_handle handle = {{0}};
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct security_descriptor *sd_orig = NULL;
+ struct security_descriptor *sd = NULL;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ SEC_DESC_DACL_AUTO_INHERITED
+ | SEC_DESC_DACL_AUTO_INHERIT_REQ,
+ NULL,
+ NULL,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_DIR_ALL,
+ SEC_ACE_FLAG_OBJECT_INHERIT
+ | SEC_ACE_FLAG_CONTAINER_INHERIT,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = testdirh,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = testdirh,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+
+ torture_assert_goto(tctx, sd_orig->type & SEC_DESC_DACL_AUTO_INHERITED,
+ ret, done, "Missing SEC_DESC_DACL_AUTO_INHERITED\n");
+
+ /*
+ * SD with SEC_DESC_DACL_AUTO_INHERITED but without
+ * SEC_DESC_DACL_AUTO_INHERITED_REQ, so the resulting SD should not have
+ * SEC_DESC_DACL_AUTO_INHERITED on a Windows box.
+ *
+ * But as we're testing against a share with
+ *
+ * "acl flag inherited canonicalization = no"
+ *
+ * the resulting SD should have acl flag inherited canonicalization set.
+ */
+ sd = security_descriptor_dacl_create(tctx,
+ SEC_DESC_DACL_AUTO_INHERITED,
+ NULL,
+ NULL,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "SD create failed\n");
+
+ si = (union smb_setfileinfo) {
+ .set_secdesc.level = RAW_SFILEINFO_SEC_DESC,
+ .set_secdesc.in.file.handle = handle,
+ .set_secdesc.in.secinfo_flags = SECINFO_DACL,
+ .set_secdesc.in.sd = sd,
+ };
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED ,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ gi = (union smb_fileinfo) {
+ .query_secdesc.level = RAW_FILEINFO_SEC_DESC,
+ .query_secdesc.in.file.handle = handle,
+ .query_secdesc.in.secinfo_flags = SECINFO_DACL,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ sd_orig = gi.query_secdesc.out.sd;
+ torture_assert_goto(tctx, sd_orig->type & SEC_DESC_DACL_AUTO_INHERITED,
+ ret, done, "Missing SEC_DESC_DACL_AUTO_INHERITED\n");
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, testdirh);
+ }
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_acls_non_canonical_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "acls_non_canonical");
+
+ torture_suite_add_1smb2_test(suite, "flags", test_acls_non_canonical_flags);
+ return suite;
+}
diff --git a/source4/torture/smb2/attr.c b/source4/torture/smb2/attr.c
new file mode 100644
index 0000000..bc474d2
--- /dev/null
+++ b/source4/torture/smb2/attr.c
@@ -0,0 +1,710 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ openattr tester
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) David Mulder 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "libcli/security/security_descriptor.h"
+#include "torture/smb2/proto.h"
+
+static const uint32_t open_attrs_table[] = {
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_ATTRIBUTE_ARCHIVE,
+ FILE_ATTRIBUTE_READONLY,
+ FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_SYSTEM,
+
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+ FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_SYSTEM,
+};
+
+struct trunc_open_results {
+ unsigned int num;
+ uint32_t init_attr;
+ uint32_t trunc_attr;
+ uint32_t result_attr;
+};
+
+static const struct trunc_open_results attr_results[] = {
+ { 0, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
+ { 1, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
+ { 2, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
+ { 16, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_ARCHIVE },
+ { 17, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE },
+ { 18, FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY },
+ { 51, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 54, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 56, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 68, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 71, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 73, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
+ { 99, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN,FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 102, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 104, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 116, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 119, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 121, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM },
+ { 170, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN },
+ { 173, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM },
+ { 227, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 230, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN },
+ { 232, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN },
+ { 244, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 247, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SYSTEM },
+ { 249, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM }
+};
+
+static NTSTATUS smb2_setatr(struct smb2_tree *tree, const char *name,
+ uint32_t attrib)
+{
+ NTSTATUS status;
+ struct smb2_create create_io = {0};
+ union smb_setfileinfo io;
+
+ create_io.in.desired_access = SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ create_io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create_io.in.fname = name;
+ status = smb2_create(tree, tree, &create_io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ZERO_STRUCT(io);
+ io.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ io.basic_info.in.file.handle = create_io.out.file.handle;
+ io.basic_info.in.attrib = attrib;
+ status = smb2_setinfo_file(tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return status;
+}
+
+bool torture_smb2_openattrtest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ const char *fname = "openattr.file";
+ uint16_t attr;
+ unsigned int i, j, k, l;
+ int ret = true;
+
+ for (k = 0, i = 0; i < sizeof(open_attrs_table)/sizeof(uint32_t); i++) {
+ struct smb2_create create_io = {0};
+ smb2_setatr(tree, fname, FILE_ATTRIBUTE_NORMAL);
+ smb2_util_unlink(tree, fname);
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_FILE_WRITE_DATA;
+ create_io.in.file_attributes = open_attrs_table[i];
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = fname;
+ status = smb2_create(tree, tctx, &create_io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "open %d (1) of %s failed (%s)",
+ i, fname, nt_errstr(status)));
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "close %d (1) of %s failed (%s)",
+ i, fname, nt_errstr(status)));
+
+ for (j = 0; j < ARRAY_SIZE(open_attrs_table); j++) {
+ create_io = (struct smb2_create){0};
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_FILE_READ_DATA|
+ SEC_FILE_WRITE_DATA;
+ create_io.in.file_attributes = open_attrs_table[j];
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = fname;
+ status = smb2_create(tree, tctx, &create_io);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ for (l = 0; l < ARRAY_SIZE(attr_results); l++) {
+ torture_assert_goto(tctx,
+ attr_results[l].num != k,
+ ret, error_exit,
+ talloc_asprintf(tctx,
+ "[%d] trunc open 0x%x "
+ "-> 0x%x of %s failed "
+ "- should have "
+ "succeeded !(%s)",
+ k, open_attrs_table[i],
+ open_attrs_table[j],
+ fname,
+ nt_errstr(status)));
+ }
+ torture_assert_ntstatus_equal_goto(tctx,
+ status, NT_STATUS_ACCESS_DENIED,
+ ret, error_exit,
+ talloc_asprintf(tctx,
+ "[%d] trunc open 0x%x "
+ "-> 0x%x failed with "
+ "wrong error code %s",
+ k, open_attrs_table[i],
+ open_attrs_table[j],
+ nt_errstr(status)));
+ k++;
+ continue;
+ }
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ error_exit, talloc_asprintf(tctx,
+ "close %d (2) of %s failed (%s)", j,
+ fname, nt_errstr(status)));
+
+ status = smb2_util_getatr(tree, fname, &attr, NULL, NULL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ error_exit, talloc_asprintf(tctx,
+ "getatr(2) failed (%s)",
+ nt_errstr(status)));
+
+ for (l = 0; l < ARRAY_SIZE(attr_results); l++) {
+ if (attr_results[l].num == k) {
+ if (attr != attr_results[l].result_attr ||
+ open_attrs_table[i] != attr_results[l].init_attr ||
+ open_attrs_table[j] != attr_results[l].trunc_attr) {
+ ret = false;
+ torture_fail_goto(tctx, error_exit,
+ talloc_asprintf(tctx,
+ "[%d] getatr check "
+ "failed. [0x%x] trunc "
+ "[0x%x] got attr 0x%x,"
+ " should be 0x%x",
+ k, open_attrs_table[i],
+ open_attrs_table[j],
+ (unsigned int)attr,
+ attr_results[l].result_attr));
+ }
+ break;
+ }
+ }
+ k++;
+ }
+ }
+error_exit:
+ smb2_setatr(tree, fname, FILE_ATTRIBUTE_NORMAL);
+ smb2_util_unlink(tree, fname);
+
+
+ return ret;
+}
+
+bool torture_smb2_winattrtest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "winattr1.file";
+ const char *dname = "winattr1.dir";
+ uint16_t attr;
+ uint16_t j;
+ uint32_t aceno;
+ bool ret = true;
+ union smb_fileinfo query, query_org;
+ NTSTATUS status;
+ struct security_descriptor *sd1 = NULL, *sd2 = NULL;
+ struct smb2_create create_io = {0};
+ ZERO_STRUCT(query);
+ ZERO_STRUCT(query_org);
+
+ /* Test winattrs for file */
+ smb2_util_unlink(tree, fname);
+
+ /* Open a file*/
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA |
+ SEC_STD_READ_CONTROL;
+ create_io.in.file_attributes = 0;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = FILE_SUPERSEDE;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = fname;
+ status = smb2_create(tree, tctx, &create_io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "open(1) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+
+ /* Get security descriptor and store it*/
+ query_org.generic.level = RAW_FILEINFO_SEC_DESC;
+ query_org.generic.in.file.handle = create_io.out.file.handle;
+ query_org.query_secdesc.in.secinfo_flags = SECINFO_OWNER|
+ SECINFO_GROUP|
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &query_org);
+ if(!NT_STATUS_IS_OK(status)){
+ NTSTATUS s = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, s, ret, error_exit,
+ talloc_asprintf(tctx,
+ "close(1) of %s failed (%s)\n",
+ fname, nt_errstr(s)));
+ ret = false;
+ torture_fail_goto(tctx, error_exit, talloc_asprintf(tctx,
+ "smb2_getinfo_file(1) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+ }
+ sd1 = query_org.query_secdesc.out.sd;
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "close(1) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+
+ /*Set and get attributes*/
+ for (j = 0; j < ARRAY_SIZE(open_attrs_table); j++) {
+ status = smb2_setatr(tree, fname, open_attrs_table[j]);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ error_exit,
+ talloc_asprintf(tctx, "setatr(2) failed (%s)",
+ nt_errstr(status)));
+
+ status = smb2_util_getatr(tree, fname, &attr, NULL, NULL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ error_exit,
+ talloc_asprintf(tctx, "getatr(2) failed (%s)",
+ nt_errstr(status)));
+
+ /* Check the result */
+ torture_assert_goto(tctx, attr == open_attrs_table[j], ret,
+ error_exit, talloc_asprintf(tctx,
+ "getatr check failed. \
+ Attr applied [0x%x],got attr 0x%x, \
+ should be 0x%x ", open_attrs_table[j],
+ (uint16_t)attr, open_attrs_table[j]));
+
+ create_io = (struct smb2_create){0};
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_FILE_READ_ATTRIBUTE|
+ SEC_STD_READ_CONTROL;
+ create_io.in.file_attributes = 0;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = FILE_OPEN_IF;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = fname;
+ status = smb2_create(tree, tctx, &create_io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ error_exit,
+ talloc_asprintf(tctx, "open(2) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+ /*Get security descriptor */
+ query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ query.query_secdesc.in.file.handle = create_io.out.file.handle;
+ query.query_secdesc.in.secinfo_flags = SECINFO_OWNER|
+ SECINFO_GROUP|
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &query);
+ if(!NT_STATUS_IS_OK(status)){
+ NTSTATUS s = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, s, ret,
+ error_exit,
+ talloc_asprintf(tctx,
+ "close(2) of %s failed (%s)\n",
+ fname, nt_errstr(s)));
+ ret = false;
+ torture_fail_goto(tctx, error_exit,
+ talloc_asprintf(tctx,
+ "smb2_getinfo_file(2) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+ }
+ sd2 = query.query_secdesc.out.sd;
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "close(2) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+
+ /*Compare security descriptors -- Must be same*/
+ for (aceno=0;(sd1->dacl&&aceno < sd1->dacl->num_aces);aceno++){
+ struct security_ace *ace1 = &sd1->dacl->aces[aceno];
+ struct security_ace *ace2 = &sd2->dacl->aces[aceno];
+
+ torture_assert_goto(tctx, security_ace_equal(ace1, ace2),
+ ret, error_exit,
+ "ACLs changed! Not expected!\n");
+ }
+
+ torture_comment(tctx, "[%d] setattr = [0x%x] got attr 0x%x\n",
+ j, open_attrs_table[j], attr );
+
+ }
+
+
+/* Check for Directory. */
+
+ smb2_deltree(tree, dname);
+ smb2_util_rmdir(tree, dname);
+
+ /* Open a directory */
+ create_io = (struct smb2_create){0};
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create_io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create_io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = dname;
+ status = smb2_create(tree, tctx, &create_io);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx,
+ "open (1) of %s failed (%s)",
+ dname, nt_errstr(status)));
+
+
+ /* Get Security Descriptor */
+ query_org.generic.level = RAW_FILEINFO_SEC_DESC;
+ query_org.generic.in.file.handle = create_io.out.file.handle;
+ status = smb2_getinfo_file(tree, tctx, &query_org);
+ if(!NT_STATUS_IS_OK(status)){
+ NTSTATUS s = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, s, ret, error_exit,
+ talloc_asprintf(tctx,
+ "close(1) of %s failed (%s)\n",
+ dname, nt_errstr(s)));
+ ret = false;
+ torture_fail_goto(tctx, error_exit, talloc_asprintf(tctx,
+ "smb2_getinfo_file(1) of %s failed (%s)\n", dname,
+ nt_errstr(status)));
+ }
+ sd1 = query_org.query_secdesc.out.sd;
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx,
+ "close (1) of %s failed (%s)", dname,
+ nt_errstr(status)));
+
+ /* Set and get win attributes*/
+ for (j = 1; j < ARRAY_SIZE(open_attrs_table); j++) {
+
+ status = smb2_setatr(tree, dname, open_attrs_table[j]);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "setatr(2) failed (%s)",
+ nt_errstr(status)));
+
+ status = smb2_util_getatr(tree, dname, &attr, NULL, NULL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "getatr(2) failed (%s)",
+ nt_errstr(status)));
+
+ torture_comment(tctx, "[%d] setatt = [0x%x] got attr 0x%x\n",
+ j, open_attrs_table[j], attr );
+
+ /* Check the result */
+ torture_assert_goto(tctx,
+ attr == (open_attrs_table[j]|FILE_ATTRIBUTE_DIRECTORY),
+ ret, error_exit, talloc_asprintf(tctx,
+ "getatr check failed. set attr "
+ "[0x%x], got attr 0x%x, should be 0x%x\n",
+ open_attrs_table[j], (uint16_t)attr,
+ (unsigned int)(open_attrs_table[j]|FILE_ATTRIBUTE_DIRECTORY)));
+
+ create_io = (struct smb2_create){0};
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_RIGHTS_DIR_READ;
+ create_io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = dname;
+ status = smb2_create(tree, tctx, &create_io);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx,
+ "open (2) of %s failed (%s)",
+ dname, nt_errstr(status)));
+ /* Get security descriptor */
+ query.generic.level = RAW_FILEINFO_SEC_DESC;
+ query.generic.in.file.handle = create_io.out.file.handle;
+ status = smb2_getinfo_file(tree, tctx, &query);
+ if(!NT_STATUS_IS_OK(status)){
+ NTSTATUS s = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, s, ret, error_exit,
+ talloc_asprintf(tctx,
+ "close (2) of %s failed (%s)", dname,
+ nt_errstr(s)));
+ ret = false;
+ torture_fail_goto(tctx, error_exit,
+ talloc_asprintf(tctx,
+ "smb2_getinfo_file(2) of %s failed(%s)\n",
+ dname, nt_errstr(status)));
+ }
+ sd2 = query.query_secdesc.out.sd;
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx,
+ "close (2) of %s failed (%s)", dname,
+ nt_errstr(status)));
+
+ /* Security descriptor must be same*/
+ for (aceno=0;(sd1->dacl&&aceno < sd1->dacl->num_aces);aceno++){
+ struct security_ace *ace1 = &sd1->dacl->aces[aceno];
+ struct security_ace *ace2 = &sd2->dacl->aces[aceno];
+
+ torture_assert_goto(tctx, security_ace_equal(ace1, ace2),
+ ret, error_exit,
+ "ACLs changed! Not expected!\n");
+ }
+
+ }
+
+error_exit:
+ smb2_setatr(tree, fname, FILE_ATTRIBUTE_NORMAL);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, dname);
+ smb2_util_rmdir(tree, dname);
+
+ return ret;
+}
+
+bool torture_smb2_winattr2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "winattr2.file";
+ struct smb2_create c = {0};
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ /* Create a file with FILE_ATTRIBUTE_ARCHIVE */
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_ARCHIVE,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ status = smb2_util_close(tree, c.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+
+ /* Reopen file with different attributes */
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_ARCHIVE |
+ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_READONLY,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ status = smb2_util_close(tree, c.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+
+ torture_assert_int_equal_goto(tctx,
+ c.out.file_attr,
+ FILE_ATTRIBUTE_ARCHIVE,
+ ret, done,
+ "Wrong attributes\n");
+
+done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+bool torture_smb2_sdreadtest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "sdread.file";
+ bool ret = true;
+ union smb_fileinfo query;
+ NTSTATUS status;
+ struct security_descriptor *sd = NULL;
+ struct smb2_create create_io = {0};
+ uint32_t sd_bits[] = { SECINFO_OWNER,
+ SECINFO_GROUP,
+ SECINFO_DACL };
+ size_t i;
+
+ ZERO_STRUCT(query);
+
+ smb2_util_unlink(tree, fname);
+
+ /* Create then close a file*/
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ create_io.in.file_attributes = 0;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = FILE_SUPERSEDE;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = fname;
+ status = smb2_create(tree, tctx, &create_io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "open(1) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, error_exit,
+ talloc_asprintf(tctx, "close(1) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+
+ /*
+ * Open the file with READ_ATTRIBUTES *only*,
+ * no READ_CONTROL.
+ *
+ * This should deny access for any attempt to
+ * get a security descriptor if we ask for
+ * any of OWNER|GROUP|DACL, but if
+ * we ask for *NO* info but still ask for
+ * the security descriptor, then Windows
+ * returns an ACL but with zero entries
+ * for OWNER|GROUP|DACL.
+ */
+
+ create_io = (struct smb2_create){0};
+ create_io.in.create_flags = 0;
+ create_io.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create_io.in.file_attributes = 0;
+ create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create_io.in.create_disposition = FILE_OPEN;
+ create_io.in.create_options = 0;
+ create_io.in.security_flags = 0;
+ create_io.in.fname = fname;
+ status = smb2_create(tree, tctx, &create_io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ error_exit,
+ talloc_asprintf(tctx, "open(2) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+
+ /* Check asking for SD fails ACCESS_DENIED with actual bits set. */
+ for (i = 0; i < ARRAY_SIZE(sd_bits); i++) {
+ query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ query.query_secdesc.in.file.handle = create_io.out.file.handle;
+ query.query_secdesc.in.secinfo_flags = sd_bits[i];
+
+ status = smb2_getinfo_file(tree, tctx, &query);
+
+ /* Must return ACESS_DENIED. */
+ if(!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)){
+ NTSTATUS s = smb2_util_close(tree,
+ create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, s, ret,
+ error_exit,
+ talloc_asprintf(tctx,
+ "close(2) of %s failed (%s)\n",
+ fname, nt_errstr(s)));
+ ret = false;
+ torture_fail_goto(tctx, error_exit,
+ talloc_asprintf(tctx,
+ "smb2_getinfo_file(2) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+ }
+ }
+
+ /*
+ * Get security descriptor whilst asking for *NO* bits.
+ * This succeeds even though we don't have READ_CONTROL
+ * access but returns an SD with zero data.
+ */
+ query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ query.query_secdesc.in.file.handle = create_io.out.file.handle;
+ query.query_secdesc.in.secinfo_flags = 0;
+
+ status = smb2_getinfo_file(tree, tctx, &query);
+ if(!NT_STATUS_IS_OK(status)){
+ NTSTATUS s = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, s, ret, error_exit,
+ talloc_asprintf(tctx,
+ "close(3) of %s failed (%s)\n",
+ fname, nt_errstr(s)));
+ ret = false;
+ torture_fail_goto(tctx, error_exit, talloc_asprintf(tctx,
+ "smb2_getinfo_file(3) of %s failed (%s)\n",
+ fname, nt_errstr(status)));
+ }
+
+ sd = query.query_secdesc.out.sd;
+
+ /* Check it's empty. */
+ torture_assert_goto(tctx,
+ (sd->owner_sid == NULL),
+ ret,
+ error_exit,
+ "sd->owner_sid != NULL\n");
+
+ torture_assert_goto(tctx,
+ (sd->group_sid == NULL),
+ ret,
+ error_exit,
+ "sd->group_sid != NULL\n");
+
+ torture_assert_goto(tctx,
+ (sd->dacl == NULL),
+ ret,
+ error_exit,
+ "sd->dacl != NULL\n");
+
+ status = smb2_util_close(tree, create_io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx,
+ status,
+ ret,
+ error_exit,
+ talloc_asprintf(tctx, "close(4) of %s failed (%s)\n",
+ fname,
+ nt_errstr(status)));
+
+error_exit:
+
+ smb2_setatr(tree, fname, FILE_ATTRIBUTE_NORMAL);
+ smb2_util_unlink(tree, fname);
+
+ return ret;
+}
diff --git a/source4/torture/smb2/bench.c b/source4/torture/smb2/bench.c
new file mode 100644
index 0000000..a91ca6c
--- /dev/null
+++ b/source4/torture/smb2/bench.c
@@ -0,0 +1,1376 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 bench test suite
+
+ Copyright (C) Stefan Metzmacher 2022
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+
+#include "system/filesys.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/security.h"
+#include "lib/events/events.h"
+
+#define FNAME "test_create.dat"
+#define DNAME "smb2_open"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ return false; \
+ }} while (0)
+
+#define CHECK_EQUAL(v, correct) do { \
+ if (v != correct) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value for %s 0x%08llx - " \
+ "should be 0x%08llx\n", \
+ __location__, #v, \
+ (unsigned long long)v, \
+ (unsigned long long)correct); \
+ return false; \
+ }} while (0)
+
+#define CHECK_TIME(t, field) do { \
+ time_t t1, t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo.all_info.in.file.handle = h1; \
+ status = smb2_getinfo_file(tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t1 = t & ~1; \
+ t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
+ if (abs(t1-t2) > 2) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong time for field %s %s - %s\n", \
+ __location__, #field, \
+ timestring(tctx, t1), \
+ timestring(tctx, t2)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_NTTIME(t, field) do { \
+ NTTIME t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo.all_info.in.file.handle = h1; \
+ status = smb2_getinfo_file(tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t2 = finfo.all_info.out.field; \
+ if (llabs((int64_t)(t-t2)) > 20000) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong time for field %s %s - %s\n", \
+ __location__, #field, \
+ nt_time_string(tctx, t), \
+ nt_time_string(tctx, t2)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_ALL_INFO(v, field) do { \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo.all_info.in.file.handle = h1; \
+ status = smb2_getinfo_file(tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if ((v) != (finfo.all_info.out.field)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for field %s 0x%x - 0x%x\n", \
+ __location__, #field, (int)v,\
+ (int)(finfo.all_info.out.field)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)(v), (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define SET_ATTRIB(sattrib) do { \
+ union smb_setfileinfo sfinfo; \
+ ZERO_STRUCT(sfinfo.basic_info.in); \
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
+ sfinfo.basic_info.in.file.handle = h1; \
+ sfinfo.basic_info.in.attrib = sattrib; \
+ status = smb2_setinfo_file(tree, &sfinfo); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_comment(tctx, \
+ "(%s) Failed to set attrib 0x%x on %s\n", \
+ __location__, (unsigned int)(sattrib), fname); \
+ }} while (0)
+
+/*
+ stress testing keepalive iops
+ */
+
+struct test_smb2_bench_echo_conn;
+struct test_smb2_bench_echo_loop;
+
+struct test_smb2_bench_echo_state {
+ struct torture_context *tctx;
+ size_t num_conns;
+ struct test_smb2_bench_echo_conn *conns;
+ size_t num_loops;
+ struct test_smb2_bench_echo_loop *loops;
+ size_t pending_loops;
+ struct timeval starttime;
+ int timecount;
+ int timelimit;
+ uint64_t num_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ bool ok;
+ bool stop;
+};
+
+struct test_smb2_bench_echo_conn {
+ struct test_smb2_bench_echo_state *state;
+ int idx;
+ struct smb2_tree *tree;
+};
+
+struct test_smb2_bench_echo_loop {
+ struct test_smb2_bench_echo_state *state;
+ struct test_smb2_bench_echo_conn *conn;
+ int idx;
+ struct tevent_immediate *im;
+ struct tevent_req *req;
+ struct timeval starttime;
+ uint64_t num_started;
+ uint64_t num_finished;
+ uint64_t total_finished;
+ uint64_t max_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ NTSTATUS error;
+};
+
+static void test_smb2_bench_echo_loop_do(
+ struct test_smb2_bench_echo_loop *loop);
+
+static void test_smb2_bench_echo_loop_start(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_smb2_bench_echo_loop *loop =
+ (struct test_smb2_bench_echo_loop *)
+ private_data;
+
+ test_smb2_bench_echo_loop_do(loop);
+}
+
+static void test_smb2_bench_echo_loop_done(struct tevent_req *req);
+
+static void test_smb2_bench_echo_loop_do(
+ struct test_smb2_bench_echo_loop *loop)
+{
+ struct test_smb2_bench_echo_state *state = loop->state;
+
+ loop->num_started += 1;
+ loop->starttime = timeval_current();
+ loop->req = smb2cli_echo_send(state->loops,
+ state->tctx->ev,
+ loop->conn->tree->session->transport->conn,
+ 1000);
+ torture_assert_goto(state->tctx, loop->req != NULL,
+ state->ok, asserted, "smb2cli_echo_send");
+
+ tevent_req_set_callback(loop->req,
+ test_smb2_bench_echo_loop_done,
+ loop);
+ return;
+asserted:
+ state->stop = true;
+}
+
+static void test_smb2_bench_echo_loop_done(struct tevent_req *req)
+{
+ struct test_smb2_bench_echo_loop *loop =
+ (struct test_smb2_bench_echo_loop *)
+ _tevent_req_callback_data(req);
+ struct test_smb2_bench_echo_state *state = loop->state;
+ double latency = timeval_elapsed(&loop->starttime);
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ torture_assert_goto(state->tctx, loop->req == req,
+ state->ok, asserted, __location__);
+ loop->error = smb2cli_echo_recv(req);
+ torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
+ state->ok, asserted, __location__);
+ SMB_ASSERT(latency >= 0.000001);
+
+ if (loop->num_finished == 0) {
+ /* first round */
+ loop->min_latency = latency;
+ loop->max_latency = latency;
+ }
+
+ loop->num_finished += 1;
+ loop->total_finished += 1;
+ loop->total_latency += latency;
+
+ if (latency < loop->min_latency) {
+ loop->min_latency = latency;
+ }
+
+ if (latency > loop->max_latency) {
+ loop->max_latency = latency;
+ }
+
+ if (loop->total_finished >= loop->max_finished) {
+ if (state->pending_loops > 0) {
+ state->pending_loops -= 1;
+ }
+ if (state->pending_loops == 0) {
+ goto asserted;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ test_smb2_bench_echo_loop_do(loop);
+ return;
+asserted:
+ state->stop = true;
+ TALLOC_FREE(frame);
+}
+
+static void test_smb2_bench_echo_progress(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct test_smb2_bench_echo_state *state =
+ (struct test_smb2_bench_echo_state *)private_data;
+ uint64_t num_echos = 0;
+ double total_echo_latency = 0;
+ double min_echo_latency = 0;
+ double max_echo_latency = 0;
+ double avs_echo_latency = 0;
+ size_t i;
+
+ state->timecount += 1;
+
+ for (i=0;i<state->num_loops;i++) {
+ struct test_smb2_bench_echo_loop *loop =
+ &state->loops[i];
+
+ num_echos += loop->num_finished;
+ total_echo_latency += loop->total_latency;
+ if (min_echo_latency == 0.0 && loop->min_latency != 0.0) {
+ min_echo_latency = loop->min_latency;
+ }
+ if (loop->min_latency < min_echo_latency) {
+ min_echo_latency = loop->min_latency;
+ }
+ if (max_echo_latency == 0.0) {
+ max_echo_latency = loop->max_latency;
+ }
+ if (loop->max_latency > max_echo_latency) {
+ max_echo_latency = loop->max_latency;
+ }
+ loop->num_finished = 0;
+ loop->total_latency = 0.0;
+ }
+
+ state->num_finished += num_echos;
+ state->total_latency += total_echo_latency;
+ if (state->min_latency == 0.0 && min_echo_latency != 0.0) {
+ state->min_latency = min_echo_latency;
+ }
+ if (min_echo_latency < state->min_latency) {
+ state->min_latency = min_echo_latency;
+ }
+ if (state->max_latency == 0.0) {
+ state->max_latency = max_echo_latency;
+ }
+ if (max_echo_latency > state->max_latency) {
+ state->max_latency = max_echo_latency;
+ }
+
+ if (state->timecount < state->timelimit) {
+ te = tevent_add_timer(state->tctx->ev,
+ state,
+ timeval_current_ofs(1, 0),
+ test_smb2_bench_echo_progress,
+ state);
+ torture_assert_goto(state->tctx, te != NULL,
+ state->ok, asserted, "tevent_add_timer");
+
+ if (!torture_setting_bool(state->tctx, "progress", true)) {
+ return;
+ }
+
+ avs_echo_latency = total_echo_latency / num_echos;
+
+ torture_comment(state->tctx,
+ "%.2f second: "
+ "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
+ timeval_elapsed(&state->starttime),
+ (unsigned long long)num_echos,
+ avs_echo_latency,
+ min_echo_latency,
+ max_echo_latency);
+ return;
+ }
+
+ avs_echo_latency = state->total_latency / state->num_finished;
+ num_echos = state->num_finished / state->timelimit;
+
+ torture_comment(state->tctx,
+ "%.2f second: "
+ "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
+ timeval_elapsed(&state->starttime),
+ (unsigned long long)num_echos,
+ avs_echo_latency,
+ state->min_latency,
+ state->max_latency);
+
+asserted:
+ state->stop = true;
+}
+
+static bool test_smb2_bench_echo(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct test_smb2_bench_echo_state *state = NULL;
+ bool ret = true;
+ int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+ int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
+ size_t i;
+ size_t li = 0;
+ int looplimit = torture_setting_int(tctx, "looplimit", -1);
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ struct tevent_timer *te = NULL;
+ uint32_t timeout_msec;
+
+ state = talloc_zero(tctx, struct test_smb2_bench_echo_state);
+ torture_assert(tctx, state != NULL, __location__);
+ state->tctx = tctx;
+ state->num_conns = torture_nprocs;
+ state->conns = talloc_zero_array(state,
+ struct test_smb2_bench_echo_conn,
+ state->num_conns);
+ torture_assert(tctx, state->conns != NULL, __location__);
+ state->num_loops = torture_nprocs * torture_qdepth;
+ state->loops = talloc_zero_array(state,
+ struct test_smb2_bench_echo_loop,
+ state->num_loops);
+ torture_assert(tctx, state->loops != NULL, __location__);
+ state->ok = true;
+ state->timelimit = MAX(timelimit, 1);
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
+
+ for (i=0;i<state->num_conns;i++) {
+ struct smb2_tree *ct = NULL;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ size_t pcli;
+
+ state->conns[i].state = state;
+ state->conns[i].idx = i;
+
+ if (!torture_smb2_connection(tctx, &ct)) {
+ torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
+ return false;
+ }
+ state->conns[i].tree = talloc_steal(state->conns, ct);
+
+ smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
+ smb2cli_ioctl(ct->session->transport->conn,
+ timeout_msec,
+ ct->session->smbXcli,
+ ct->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ UINT32_MAX,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ ct,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert(tctx,
+ smbXcli_conn_is_connected(ct->session->transport->conn),
+ "smbXcli_conn_is_connected");
+
+ for (pcli = 0; pcli < torture_qdepth; pcli++) {
+ struct test_smb2_bench_echo_loop *loop = &state->loops[li];
+
+ loop->idx = li++;
+ if (looplimit != -1) {
+ loop->max_finished = looplimit;
+ } else {
+ loop->max_finished = UINT64_MAX;
+ }
+ loop->state = state;
+ loop->conn = &state->conns[i];
+ loop->im = tevent_create_immediate(state->loops);
+ torture_assert(tctx, loop->im != NULL, __location__);
+
+ tevent_schedule_immediate(loop->im,
+ tctx->ev,
+ test_smb2_bench_echo_loop_start,
+ loop);
+ }
+ }
+
+ torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
+ state->num_conns, torture_qdepth, state->num_loops);
+
+ torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
+
+ state->starttime = timeval_current();
+ state->pending_loops = state->num_loops;
+
+ te = tevent_add_timer(tctx->ev,
+ state,
+ timeval_current_ofs(1, 0),
+ test_smb2_bench_echo_progress,
+ state);
+ torture_assert(tctx, te != NULL, __location__);
+
+ while (!state->stop) {
+ int rc = tevent_loop_once(tctx->ev);
+ torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
+ }
+
+ torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
+ TALLOC_FREE(state);
+ return ret;
+}
+
+/*
+ stress testing path base operations
+ e.g. contention on lockting.tdb records
+ */
+
+struct test_smb2_bench_path_contention_shared_conn;
+struct test_smb2_bench_path_contention_shared_loop;
+
+struct test_smb2_bench_path_contention_shared_state {
+ struct torture_context *tctx;
+ size_t num_conns;
+ struct test_smb2_bench_path_contention_shared_conn *conns;
+ size_t num_loops;
+ struct test_smb2_bench_path_contention_shared_loop *loops;
+ struct timeval starttime;
+ int timecount;
+ int timelimit;
+ struct {
+ uint64_t num_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ } opens;
+ struct {
+ uint64_t num_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ } closes;
+ bool ok;
+ bool stop;
+};
+
+struct test_smb2_bench_path_contention_shared_conn {
+ struct test_smb2_bench_path_contention_shared_state *state;
+ int idx;
+ struct smb2_tree *tree;
+};
+
+struct test_smb2_bench_path_contention_shared_loop {
+ struct test_smb2_bench_path_contention_shared_state *state;
+ struct test_smb2_bench_path_contention_shared_conn *conn;
+ int idx;
+ struct tevent_immediate *im;
+ struct {
+ struct smb2_create io;
+ struct smb2_request *req;
+ struct timeval starttime;
+ uint64_t num_started;
+ uint64_t num_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ } opens;
+ struct {
+ struct smb2_close io;
+ struct smb2_request *req;
+ struct timeval starttime;
+ uint64_t num_started;
+ uint64_t num_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ } closes;
+ NTSTATUS error;
+};
+
+static void test_smb2_bench_path_contention_loop_open(
+ struct test_smb2_bench_path_contention_shared_loop *loop);
+
+static void test_smb2_bench_path_contention_loop_start(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_smb2_bench_path_contention_shared_loop *loop =
+ (struct test_smb2_bench_path_contention_shared_loop *)
+ private_data;
+
+ test_smb2_bench_path_contention_loop_open(loop);
+}
+
+static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req);
+
+static void test_smb2_bench_path_contention_loop_open(
+ struct test_smb2_bench_path_contention_shared_loop *loop)
+{
+ struct test_smb2_bench_path_contention_shared_state *state = loop->state;
+
+ loop->opens.num_started += 1;
+ loop->opens.starttime = timeval_current();
+ loop->opens.req = smb2_create_send(loop->conn->tree, &loop->opens.io);
+ torture_assert_goto(state->tctx, loop->opens.req != NULL,
+ state->ok, asserted, "smb2_create_send");
+
+ loop->opens.req->async.fn = test_smb2_bench_path_contention_loop_opened;
+ loop->opens.req->async.private_data = loop;
+ return;
+asserted:
+ state->stop = true;
+}
+
+static void test_smb2_bench_path_contention_loop_close(
+ struct test_smb2_bench_path_contention_shared_loop *loop);
+
+static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req)
+{
+ struct test_smb2_bench_path_contention_shared_loop *loop =
+ (struct test_smb2_bench_path_contention_shared_loop *)
+ req->async.private_data;
+ struct test_smb2_bench_path_contention_shared_state *state = loop->state;
+ double latency = timeval_elapsed(&loop->opens.starttime);
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ torture_assert_goto(state->tctx, loop->opens.req == req,
+ state->ok, asserted, __location__);
+ loop->error = smb2_create_recv(req, frame, &loop->opens.io);
+ torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
+ state->ok, asserted, __location__);
+ ZERO_STRUCT(loop->opens.io.out.blobs);
+ SMB_ASSERT(latency >= 0.000001);
+
+ if (loop->opens.num_finished == 0) {
+ /* first round */
+ loop->opens.min_latency = latency;
+ loop->opens.max_latency = latency;
+ }
+
+ loop->opens.num_finished += 1;
+ loop->opens.total_latency += latency;
+
+ if (latency < loop->opens.min_latency) {
+ loop->opens.min_latency = latency;
+ }
+
+ if (latency > loop->opens.max_latency) {
+ loop->opens.max_latency = latency;
+ }
+
+ TALLOC_FREE(frame);
+ test_smb2_bench_path_contention_loop_close(loop);
+ return;
+asserted:
+ state->stop = true;
+ TALLOC_FREE(frame);
+}
+
+static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req);
+
+static void test_smb2_bench_path_contention_loop_close(
+ struct test_smb2_bench_path_contention_shared_loop *loop)
+{
+ struct test_smb2_bench_path_contention_shared_state *state = loop->state;
+
+ loop->closes.num_started += 1;
+ loop->closes.starttime = timeval_current();
+ loop->closes.io.in.file = loop->opens.io.out.file;
+ loop->closes.req = smb2_close_send(loop->conn->tree, &loop->closes.io);
+ torture_assert_goto(state->tctx, loop->closes.req != NULL,
+ state->ok, asserted, "smb2_close_send");
+
+ loop->closes.req->async.fn = test_smb2_bench_path_contention_loop_closed;
+ loop->closes.req->async.private_data = loop;
+ return;
+asserted:
+ state->stop = true;
+}
+
+static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req)
+{
+ struct test_smb2_bench_path_contention_shared_loop *loop =
+ (struct test_smb2_bench_path_contention_shared_loop *)
+ req->async.private_data;
+ struct test_smb2_bench_path_contention_shared_state *state = loop->state;
+ double latency = timeval_elapsed(&loop->closes.starttime);
+
+ torture_assert_goto(state->tctx, loop->closes.req == req,
+ state->ok, asserted, __location__);
+ loop->error = smb2_close_recv(req, &loop->closes.io);
+ torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
+ state->ok, asserted, __location__);
+ SMB_ASSERT(latency >= 0.000001);
+ if (loop->closes.num_finished == 0) {
+ /* first round */
+ loop->closes.min_latency = latency;
+ loop->closes.max_latency = latency;
+ }
+ loop->closes.num_finished += 1;
+
+ loop->closes.total_latency += latency;
+
+ if (latency < loop->closes.min_latency) {
+ loop->closes.min_latency = latency;
+ }
+
+ if (latency > loop->closes.max_latency) {
+ loop->closes.max_latency = latency;
+ }
+
+ test_smb2_bench_path_contention_loop_open(loop);
+ return;
+asserted:
+ state->stop = true;
+}
+
+static void test_smb2_bench_path_contention_progress(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct test_smb2_bench_path_contention_shared_state *state =
+ (struct test_smb2_bench_path_contention_shared_state *)private_data;
+ uint64_t num_opens = 0;
+ double total_open_latency = 0;
+ double min_open_latency = 0;
+ double max_open_latency = 0;
+ double avs_open_latency = 0;
+ uint64_t num_closes = 0;
+ double total_close_latency = 0;
+ double min_close_latency = 0;
+ double max_close_latency = 0;
+ double avs_close_latency = 0;
+ size_t i;
+
+ state->timecount += 1;
+
+ for (i=0;i<state->num_loops;i++) {
+ struct test_smb2_bench_path_contention_shared_loop *loop =
+ &state->loops[i];
+
+ num_opens += loop->opens.num_finished;
+ total_open_latency += loop->opens.total_latency;
+ if (min_open_latency == 0.0 && loop->opens.min_latency != 0.0) {
+ min_open_latency = loop->opens.min_latency;
+ }
+ if (loop->opens.min_latency < min_open_latency) {
+ min_open_latency = loop->opens.min_latency;
+ }
+ if (max_open_latency == 0.0) {
+ max_open_latency = loop->opens.max_latency;
+ }
+ if (loop->opens.max_latency > max_open_latency) {
+ max_open_latency = loop->opens.max_latency;
+ }
+ loop->opens.num_finished = 0;
+ loop->opens.total_latency = 0.0;
+
+ num_closes += loop->closes.num_finished;
+ total_close_latency += loop->closes.total_latency;
+ if (min_close_latency == 0.0 && loop->closes.min_latency != 0.0) {
+ min_close_latency = loop->closes.min_latency;
+ }
+ if (loop->closes.min_latency < min_close_latency) {
+ min_close_latency = loop->closes.min_latency;
+ }
+ if (max_close_latency == 0.0) {
+ max_close_latency = loop->closes.max_latency;
+ }
+ if (loop->closes.max_latency > max_close_latency) {
+ max_close_latency = loop->closes.max_latency;
+ }
+ loop->closes.num_finished = 0;
+ loop->closes.total_latency = 0.0;
+ }
+
+ state->opens.num_finished += num_opens;
+ state->opens.total_latency += total_open_latency;
+ if (state->opens.min_latency == 0.0 && min_open_latency != 0.0) {
+ state->opens.min_latency = min_open_latency;
+ }
+ if (min_open_latency < state->opens.min_latency) {
+ state->opens.min_latency = min_open_latency;
+ }
+ if (state->opens.max_latency == 0.0) {
+ state->opens.max_latency = max_open_latency;
+ }
+ if (max_open_latency > state->opens.max_latency) {
+ state->opens.max_latency = max_open_latency;
+ }
+
+ state->closes.num_finished += num_closes;
+ state->closes.total_latency += total_close_latency;
+ if (state->closes.min_latency == 0.0 && min_close_latency != 0.0) {
+ state->closes.min_latency = min_close_latency;
+ }
+ if (min_close_latency < state->closes.min_latency) {
+ state->closes.min_latency = min_close_latency;
+ }
+ if (state->closes.max_latency == 0.0) {
+ state->closes.max_latency = max_close_latency;
+ }
+ if (max_close_latency > state->closes.max_latency) {
+ state->closes.max_latency = max_close_latency;
+ }
+
+ if (state->timecount < state->timelimit) {
+ te = tevent_add_timer(state->tctx->ev,
+ state,
+ timeval_current_ofs(1, 0),
+ test_smb2_bench_path_contention_progress,
+ state);
+ torture_assert_goto(state->tctx, te != NULL,
+ state->ok, asserted, "tevent_add_timer");
+
+ if (!torture_setting_bool(state->tctx, "progress", true)) {
+ return;
+ }
+
+ avs_open_latency = total_open_latency / num_opens;
+ avs_close_latency = total_close_latency / num_closes;
+
+ torture_comment(state->tctx,
+ "%.2f second: "
+ "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
+ "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
+ timeval_elapsed(&state->starttime),
+ (unsigned long long)num_opens,
+ avs_open_latency,
+ min_open_latency,
+ max_open_latency,
+ (unsigned long long)num_closes,
+ avs_close_latency,
+ min_close_latency,
+ max_close_latency);
+ return;
+ }
+
+ avs_open_latency = state->opens.total_latency / state->opens.num_finished;
+ avs_close_latency = state->closes.total_latency / state->closes.num_finished;
+ num_opens = state->opens.num_finished / state->timelimit;
+ num_closes = state->closes.num_finished / state->timelimit;
+
+ torture_comment(state->tctx,
+ "%.2f second: "
+ "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
+ "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
+ timeval_elapsed(&state->starttime),
+ (unsigned long long)num_opens,
+ avs_open_latency,
+ state->opens.min_latency,
+ state->opens.max_latency,
+ (unsigned long long)num_closes,
+ avs_close_latency,
+ state->closes.min_latency,
+ state->closes.max_latency);
+
+asserted:
+ state->stop = true;
+}
+
+bool test_smb2_bench_path_contention_shared(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct test_smb2_bench_path_contention_shared_state *state = NULL;
+ bool ret = true;
+ int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+ int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
+ size_t i;
+ size_t li = 0;
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ const char *path = torture_setting_string(tctx, "bench_path", "");
+ struct smb2_create open_io = { .level = RAW_OPEN_SMB2, };
+ struct smb2_close close_io = { .level = RAW_CLOSE_SMB2, };
+ struct tevent_timer *te = NULL;
+ uint32_t timeout_msec;
+
+ state = talloc_zero(tctx, struct test_smb2_bench_path_contention_shared_state);
+ torture_assert(tctx, state != NULL, __location__);
+ state->tctx = tctx;
+ state->num_conns = torture_nprocs;
+ state->conns = talloc_zero_array(state,
+ struct test_smb2_bench_path_contention_shared_conn,
+ state->num_conns);
+ torture_assert(tctx, state->conns != NULL, __location__);
+ state->num_loops = torture_nprocs * torture_qdepth;
+ state->loops = talloc_zero_array(state,
+ struct test_smb2_bench_path_contention_shared_loop,
+ state->num_loops);
+ torture_assert(tctx, state->loops != NULL, __location__);
+ state->ok = true;
+ state->timelimit = MAX(timelimit, 1);
+
+ open_io.in.desired_access = SEC_DIR_READ_ATTRIBUTE;
+ open_io.in.alloc_size = 0;
+ open_io.in.file_attributes = 0;
+ open_io.in.share_access = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
+ open_io.in.create_disposition = FILE_OPEN;
+ open_io.in.create_options = FILE_OPEN_REPARSE_POINT;
+ open_io.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ open_io.in.security_flags = 0;
+ open_io.in.fname = path;
+ open_io.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ open_io.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ torture_comment(tctx, "Opening %zd connections\n", state->num_conns);
+
+ for (i=0;i<state->num_conns;i++) {
+ struct smb2_tree *ct = NULL;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ size_t pcli;
+
+ state->conns[i].state = state;
+ state->conns[i].idx = i;
+
+ if (!torture_smb2_connection(tctx, &ct)) {
+ torture_comment(tctx, "Failed opening %zd/%zd connections\n", i, state->num_conns);
+ return false;
+ }
+ state->conns[i].tree = talloc_steal(state->conns, ct);
+
+ smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
+ smb2cli_ioctl(ct->session->transport->conn,
+ timeout_msec,
+ ct->session->smbXcli,
+ ct->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ UINT32_MAX,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ ct,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert(tctx,
+ smbXcli_conn_is_connected(ct->session->transport->conn),
+ "smbXcli_conn_is_connected");
+ for (pcli = 0; pcli < torture_qdepth; pcli++) {
+ struct test_smb2_bench_path_contention_shared_loop *loop = &state->loops[li];
+
+ loop->idx = li++;
+ loop->state = state;
+ loop->conn = &state->conns[i];
+ loop->im = tevent_create_immediate(state->loops);
+ torture_assert(tctx, loop->im != NULL, __location__);
+ loop->opens.io = open_io;
+ loop->closes.io = close_io;
+
+ tevent_schedule_immediate(loop->im,
+ tctx->ev,
+ test_smb2_bench_path_contention_loop_start,
+ loop);
+ }
+ }
+
+ torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
+ state->num_conns, torture_qdepth, state->num_loops);
+
+ torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
+
+ state->starttime = timeval_current();
+
+ te = tevent_add_timer(tctx->ev,
+ state,
+ timeval_current_ofs(1, 0),
+ test_smb2_bench_path_contention_progress,
+ state);
+ torture_assert(tctx, te != NULL, __location__);
+
+ while (!state->stop) {
+ int rc = tevent_loop_once(tctx->ev);
+ torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
+ }
+
+ torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
+ TALLOC_FREE(state);
+ return ret;
+}
+
+/*
+ stress testing read iops
+ */
+
+struct test_smb2_bench_read_conn;
+struct test_smb2_bench_read_loop;
+
+struct test_smb2_bench_read_state {
+ struct torture_context *tctx;
+ size_t num_conns;
+ struct test_smb2_bench_read_conn *conns;
+ size_t num_loops;
+ struct test_smb2_bench_read_loop *loops;
+ size_t pending_loops;
+ uint32_t io_size;
+ struct timeval starttime;
+ int timecount;
+ int timelimit;
+ uint64_t num_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ bool ok;
+ bool stop;
+};
+
+struct test_smb2_bench_read_conn {
+ struct test_smb2_bench_read_state *state;
+ int idx;
+ struct smb2_tree *tree;
+};
+
+struct test_smb2_bench_read_loop {
+ struct test_smb2_bench_read_state *state;
+ struct test_smb2_bench_read_conn *conn;
+ int idx;
+ struct tevent_immediate *im;
+ char *fname;
+ struct smb2_handle handle;
+ struct tevent_req *req;
+ struct timeval starttime;
+ uint64_t num_started;
+ uint64_t num_finished;
+ uint64_t total_finished;
+ uint64_t max_finished;
+ double total_latency;
+ double min_latency;
+ double max_latency;
+ NTSTATUS error;
+};
+
+static void test_smb2_bench_read_loop_do(
+ struct test_smb2_bench_read_loop *loop);
+
+static void test_smb2_bench_read_loop_start(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_smb2_bench_read_loop *loop =
+ (struct test_smb2_bench_read_loop *)
+ private_data;
+
+ test_smb2_bench_read_loop_do(loop);
+}
+
+static void test_smb2_bench_read_loop_done(struct tevent_req *req);
+
+static void test_smb2_bench_read_loop_do(
+ struct test_smb2_bench_read_loop *loop)
+{
+ struct test_smb2_bench_read_state *state = loop->state;
+ uint32_t timeout_msec;
+
+ timeout_msec = loop->conn->tree->session->transport->options.request_timeout * 1000;
+
+ loop->num_started += 1;
+ loop->starttime = timeval_current();
+ loop->req = smb2cli_read_send(state->loops,
+ state->tctx->ev,
+ loop->conn->tree->session->transport->conn,
+ timeout_msec,
+ loop->conn->tree->session->smbXcli,
+ loop->conn->tree->smbXcli,
+ state->io_size, /* length */
+ 0, /* offset */
+ loop->handle.data[0],/* fid_persistent */
+ loop->handle.data[1],/* fid_volatile */
+ state->io_size, /* minimum_count */
+ 0); /* remaining_bytes */
+ torture_assert_goto(state->tctx, loop->req != NULL,
+ state->ok, asserted, "smb2cli_read_send");
+
+ tevent_req_set_callback(loop->req,
+ test_smb2_bench_read_loop_done,
+ loop);
+ return;
+asserted:
+ state->stop = true;
+}
+
+static void test_smb2_bench_read_loop_done(struct tevent_req *req)
+{
+ struct test_smb2_bench_read_loop *loop =
+ (struct test_smb2_bench_read_loop *)
+ _tevent_req_callback_data(req);
+ struct test_smb2_bench_read_state *state = loop->state;
+ double latency = timeval_elapsed(&loop->starttime);
+ TALLOC_CTX *frame = talloc_stackframe();
+ uint8_t *data = NULL;
+ uint32_t data_length = 0;
+
+ torture_assert_goto(state->tctx, loop->req == req,
+ state->ok, asserted, __location__);
+ loop->error = smb2cli_read_recv(req, frame, &data, &data_length);
+ torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
+ state->ok, asserted, __location__);
+ torture_assert_u32_equal_goto(state->tctx, data_length, state->io_size,
+ state->ok, asserted, __location__);
+ SMB_ASSERT(latency >= 0.000001);
+
+ if (loop->num_finished == 0) {
+ /* first round */
+ loop->min_latency = latency;
+ loop->max_latency = latency;
+ }
+
+ loop->num_finished += 1;
+ loop->total_finished += 1;
+ loop->total_latency += latency;
+
+ if (latency < loop->min_latency) {
+ loop->min_latency = latency;
+ }
+
+ if (latency > loop->max_latency) {
+ loop->max_latency = latency;
+ }
+
+ if (loop->total_finished >= loop->max_finished) {
+ if (state->pending_loops > 0) {
+ state->pending_loops -= 1;
+ }
+ if (state->pending_loops == 0) {
+ goto asserted;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ test_smb2_bench_read_loop_do(loop);
+ return;
+asserted:
+ state->stop = true;
+ TALLOC_FREE(frame);
+}
+
+static void test_smb2_bench_read_progress(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct test_smb2_bench_read_state *state =
+ (struct test_smb2_bench_read_state *)private_data;
+ uint64_t num_reads = 0;
+ double total_read_latency = 0;
+ double min_read_latency = 0;
+ double max_read_latency = 0;
+ double avs_read_latency = 0;
+ size_t i;
+
+ state->timecount += 1;
+
+ for (i=0;i<state->num_loops;i++) {
+ struct test_smb2_bench_read_loop *loop =
+ &state->loops[i];
+
+ num_reads += loop->num_finished;
+ total_read_latency += loop->total_latency;
+ if (min_read_latency == 0.0 && loop->min_latency != 0.0) {
+ min_read_latency = loop->min_latency;
+ }
+ if (loop->min_latency < min_read_latency) {
+ min_read_latency = loop->min_latency;
+ }
+ if (max_read_latency == 0.0) {
+ max_read_latency = loop->max_latency;
+ }
+ if (loop->max_latency > max_read_latency) {
+ max_read_latency = loop->max_latency;
+ }
+ loop->num_finished = 0;
+ loop->total_latency = 0.0;
+ }
+
+ state->num_finished += num_reads;
+ state->total_latency += total_read_latency;
+ if (state->min_latency == 0.0 && min_read_latency != 0.0) {
+ state->min_latency = min_read_latency;
+ }
+ if (min_read_latency < state->min_latency) {
+ state->min_latency = min_read_latency;
+ }
+ if (state->max_latency == 0.0) {
+ state->max_latency = max_read_latency;
+ }
+ if (max_read_latency > state->max_latency) {
+ state->max_latency = max_read_latency;
+ }
+
+ if (state->timecount < state->timelimit) {
+ te = tevent_add_timer(state->tctx->ev,
+ state,
+ timeval_current_ofs(1, 0),
+ test_smb2_bench_read_progress,
+ state);
+ torture_assert_goto(state->tctx, te != NULL,
+ state->ok, asserted, "tevent_add_timer");
+
+ if (!torture_setting_bool(state->tctx, "progress", true)) {
+ return;
+ }
+
+ avs_read_latency = total_read_latency / num_reads;
+
+ torture_comment(state->tctx,
+ "%.2f second: "
+ "read[num/s=%llu,bytes/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
+ timeval_elapsed(&state->starttime),
+ (unsigned long long)num_reads,
+ (unsigned long long)num_reads*state->io_size,
+ avs_read_latency,
+ min_read_latency,
+ max_read_latency);
+ return;
+ }
+
+ avs_read_latency = state->total_latency / state->num_finished;
+ num_reads = state->num_finished / state->timelimit;
+
+ torture_comment(state->tctx,
+ "%.2f second: "
+ "read[num/s=%llu,bytes/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
+ timeval_elapsed(&state->starttime),
+ (unsigned long long)num_reads,
+ (unsigned long long)num_reads*state->io_size,
+ avs_read_latency,
+ state->min_latency,
+ state->max_latency);
+
+asserted:
+ state->stop = true;
+}
+
+static bool test_smb2_bench_read(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct test_smb2_bench_read_state *state = NULL;
+ bool ret = true;
+ int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+ int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
+ int torture_io_size = torture_setting_int(tctx, "io_size", 4096);
+ size_t i;
+ size_t li = 0;
+ int looplimit = torture_setting_int(tctx, "looplimit", -1);
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ struct tevent_timer *te = NULL;
+ uint32_t timeout_msec;
+ const char *dname = "bench_read_dir";
+ const char *unique = generate_random_str(tctx, 8);
+ struct smb2_handle dh;
+ NTSTATUS status;
+
+ smb2_deltree(tree, dname);
+
+ status = torture_smb2_testdir(tree, dname, &dh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_close(tree, dh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ state = talloc_zero(tctx, struct test_smb2_bench_read_state);
+ torture_assert(tctx, state != NULL, __location__);
+ state->tctx = tctx;
+ state->num_conns = torture_nprocs;
+ state->conns = talloc_zero_array(state,
+ struct test_smb2_bench_read_conn,
+ state->num_conns);
+ torture_assert(tctx, state->conns != NULL, __location__);
+ state->num_loops = torture_nprocs * torture_qdepth;
+ state->loops = talloc_zero_array(state,
+ struct test_smb2_bench_read_loop,
+ state->num_loops);
+ torture_assert(tctx, state->loops != NULL, __location__);
+ state->ok = true;
+ state->timelimit = MAX(timelimit, 1);
+ state->io_size = MAX(torture_io_size, 1);
+ state->io_size = MIN(state->io_size, 16*1024*1024);
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
+
+ for (i=0;i<state->num_conns;i++) {
+ struct smb2_tree *ct = NULL;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ size_t pcli;
+
+ state->conns[i].state = state;
+ state->conns[i].idx = i;
+
+ if (!torture_smb2_connection(tctx, &ct)) {
+ torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
+ return false;
+ }
+ state->conns[i].tree = talloc_steal(state->conns, ct);
+
+ smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
+ smb2cli_ioctl(ct->session->transport->conn,
+ timeout_msec,
+ ct->session->smbXcli,
+ ct->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ UINT32_MAX,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ ct,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert(tctx,
+ smbXcli_conn_is_connected(ct->session->transport->conn),
+ "smbXcli_conn_is_connected");
+
+ for (pcli = 0; pcli < torture_qdepth; pcli++) {
+ struct test_smb2_bench_read_loop *loop = &state->loops[li];
+ struct smb2_create cr;
+ union smb_setfileinfo sfinfo;
+
+ loop->idx = li++;
+ if (looplimit != -1) {
+ loop->max_finished = looplimit;
+ } else {
+ loop->max_finished = UINT64_MAX;
+ }
+ loop->state = state;
+ loop->conn = &state->conns[i];
+ loop->im = tevent_create_immediate(state->loops);
+ torture_assert(tctx, loop->im != NULL, __location__);
+
+ loop->fname = talloc_asprintf(state->loops,
+ "%s\\%s_loop_%zu_conn_%zu_loop_%zu.dat",
+ dname, unique, li, i, pcli);
+ torture_assert(tctx, loop->fname != NULL, __location__);
+
+ /* reasonable default parameters */
+ ZERO_STRUCT(cr);
+ cr.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ cr.in.alloc_size = state->io_size;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+ cr.in.create_options =
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ cr.in.security_flags = 0;
+ cr.in.fname = loop->fname;
+ status = smb2_create(state->conns[i].tree, tctx, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ loop->handle = cr.out.file.handle;
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.end_of_file_info.in.file.handle = loop->handle;
+ sfinfo.end_of_file_info.in.size = state->io_size;
+ status = smb2_setinfo_file(state->conns[i].tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ tevent_schedule_immediate(loop->im,
+ tctx->ev,
+ test_smb2_bench_read_loop_start,
+ loop);
+ }
+ }
+
+ torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
+ state->num_conns, torture_qdepth, state->num_loops);
+
+ torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
+
+ state->starttime = timeval_current();
+ state->pending_loops = state->num_loops;
+
+ te = tevent_add_timer(tctx->ev,
+ state,
+ timeval_current_ofs(1, 0),
+ test_smb2_bench_read_progress,
+ state);
+ torture_assert(tctx, te != NULL, __location__);
+
+ while (!state->stop) {
+ int rc = tevent_loop_once(tctx->ev);
+ torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
+ }
+
+ torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
+ TALLOC_FREE(state);
+ smb2_deltree(tree, dname);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_bench_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "bench");
+
+ torture_suite_add_1smb2_test(suite, "oplock1", test_smb2_bench_oplock);
+ torture_suite_add_1smb2_test(suite, "echo", test_smb2_bench_echo);
+ torture_suite_add_1smb2_test(suite, "path-contention-shared", test_smb2_bench_path_contention_shared);
+ torture_suite_add_1smb2_test(suite, "read", test_smb2_bench_read);
+
+ suite->description = talloc_strdup(suite, "SMB2-BENCH tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/block.c b/source4/torture/smb2/block.c
new file mode 100644
index 0000000..b9982b0
--- /dev/null
+++ b/source4/torture/smb2/block.c
@@ -0,0 +1,446 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * block SMB2 transports using iptables
+ *
+ * Copyright (C) Guenther Deschner, 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "system/network.h"
+#include "lib/util/util_net.h"
+#include "torture/smb2/block.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "oplock_break_handler.h"
+#include "lease_break_handler.h"
+
+/*
+ * OUTPUT
+ * |
+ * -----> SMBTORTURE_OUTPUT
+ * |
+ * -----> SMBTORTURE_transportname1
+ * -----> SMBTORTURE_transportname2
+ */
+
+
+static bool run_cmd(const char *cmd)
+{
+ int ret;
+
+ DEBUG(10, ("%s will call '%s'\n", __location__, cmd));
+
+ ret = system(cmd);
+ if (ret) {
+ DEBUG(1, ("%s failed to execute system call: %s: %d\n",
+ __location__, cmd, ret));
+ return false;
+ }
+
+ return true;
+}
+
+static const char *iptables_command(struct torture_context *tctx)
+{
+ return torture_setting_string(tctx, "iptables_command",
+ "/usr/sbin/iptables");
+}
+
+char *escape_shell_string(const char *src);
+
+/*
+ * iptables v1.6.1: chain name `SMBTORTURE_INPUT_tree1->session->transport'
+ * too long (must be under 29 chars)
+ *
+ * maybe truncate chainname ?
+ */
+static const char *samba_chain_name(struct torture_context *tctx,
+ const char *name,
+ const char *prefix)
+{
+ const char *s;
+ char *sm;
+
+ s = talloc_asprintf(tctx, "%s_%s", prefix, name);
+ if (s == NULL) {
+ return NULL;
+ }
+
+ sm = escape_shell_string(s);
+ if (sm == NULL) {
+ return NULL;
+ }
+
+ s = talloc_strdup(tctx, sm);
+ free(sm);
+
+ return s;
+}
+
+static bool iptables_setup_chain(struct torture_context *tctx,
+ const char *parent_chain,
+ const char *chain,
+ bool unblock)
+{
+ const char *ipt = iptables_command(tctx);
+ const char *cmd;
+
+ if (unblock) {
+ cmd = talloc_asprintf(tctx,
+ "%s -L %s > /dev/null 2>&1 && "
+ "("
+ "%s -F %s;"
+ "%s -D %s -j %s > /dev/null 2>&1 || true;"
+ "%s -X %s;"
+ ");"
+ "%s -L %s > /dev/null 2>&1 || true;",
+ ipt, chain,
+ ipt, chain,
+ ipt, parent_chain, chain,
+ ipt, chain,
+ ipt, chain);
+ } else {
+ cmd = talloc_asprintf(tctx,
+ "%s -L %s > /dev/null 2>&1 || "
+ "("
+ "%s -N %s && "
+ "%s -I %s -j %s;"
+ ");"
+ "%s -F %s;",
+ ipt, chain,
+ ipt, chain,
+ ipt, parent_chain, chain,
+ ipt, chain);
+ }
+
+ if (cmd == NULL) {
+ return false;
+ }
+
+ if (!run_cmd(cmd)) {
+ return false;
+ }
+
+ return true;
+}
+
+uint16_t torture_get_local_port_from_transport(struct smb2_transport *t)
+{
+ const struct sockaddr_storage *local_ss;
+
+ local_ss = smbXcli_conn_local_sockaddr(t->conn);
+
+ return get_sockaddr_port(local_ss);
+}
+
+static bool torture_block_tcp_output_port_internal(
+ struct torture_context *tctx,
+ const char *name,
+ uint16_t port,
+ bool unblock)
+{
+ const char *ipt = iptables_command(tctx);
+ const char *chain_out = NULL;
+ char *cmd_out = NULL;
+
+ chain_out = samba_chain_name(tctx, name, "SMBTORTURE");
+ if (chain_out == NULL) {
+ return false;
+ }
+
+ torture_comment(tctx, "%sblocking %s dport %d\n",
+ unblock ? "un" : "", name, port);
+
+ if (!unblock) {
+ bool ok;
+
+ iptables_setup_chain(tctx,
+ "SMBTORTURE_OUTPUT",
+ chain_out,
+ true);
+ ok = iptables_setup_chain(tctx,
+ "SMBTORTURE_OUTPUT",
+ chain_out,
+ false);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ cmd_out = talloc_asprintf(tctx,
+ "%s %s %s -p tcp --sport %d -j DROP",
+ ipt, unblock ? "-D" : "-I", chain_out, port);
+ if (cmd_out == NULL) {
+ return false;
+ }
+
+ if (!run_cmd(cmd_out)) {
+ return false;
+ }
+
+ if (unblock) {
+ bool ok;
+
+ ok = iptables_setup_chain(tctx,
+ "SMBTORTURE_OUTPUT",
+ chain_out,
+ true);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool torture_block_tcp_output_port(struct torture_context *tctx,
+ const char *name,
+ uint16_t port)
+{
+ return torture_block_tcp_output_port_internal(tctx, name, port, false);
+}
+
+bool torture_unblock_tcp_output_port(struct torture_context *tctx,
+ const char *name,
+ uint16_t port)
+{
+ return torture_block_tcp_output_port_internal(tctx, name, port, true);
+}
+
+bool torture_block_tcp_output_setup(struct torture_context *tctx)
+{
+ return iptables_setup_chain(tctx, "OUTPUT", "SMBTORTURE_OUTPUT", false);
+}
+
+bool torture_unblock_tcp_output_cleanup(struct torture_context *tctx)
+{
+ return iptables_setup_chain(tctx, "OUTPUT", "SMBTORTURE_OUTPUT", true);
+}
+
+/*
+ * Use iptables to block channels
+ */
+static bool test_block_smb2_transport_iptables(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name)
+{
+ uint16_t local_port;
+ bool ret;
+
+ local_port = torture_get_local_port_from_transport(transport);
+ torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port);
+ ret = torture_block_tcp_output_port(tctx, name, local_port);
+ torture_assert(tctx, ret, "we could not block tcp transport");
+
+ return ret;
+}
+
+static bool test_unblock_smb2_transport_iptables(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name)
+{
+ uint16_t local_port;
+ bool ret;
+
+ local_port = torture_get_local_port_from_transport(transport);
+ torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port);
+ ret = torture_unblock_tcp_output_port(tctx, name, local_port);
+ torture_assert(tctx, ret, "we could not block tcp transport");
+
+ return ret;
+}
+
+static bool torture_blocked_lease_handler(struct smb2_transport *transport,
+ const struct smb2_lease_break *lb,
+ void *private_data)
+{
+ struct smb2_transport *transport_copy =
+ talloc_get_type_abort(private_data,
+ struct smb2_transport);
+ bool lease_skip_ack = lease_break_info.lease_skip_ack;
+ bool ok;
+
+ lease_break_info.lease_skip_ack = true;
+ ok = transport_copy->lease.handler(transport,
+ lb,
+ transport_copy->lease.private_data);
+ lease_break_info.lease_skip_ack = lease_skip_ack;
+
+ if (!ok) {
+ return false;
+ }
+
+ if (lease_break_info.lease_skip_ack) {
+ return true;
+ }
+
+ if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
+ lease_break_info.failures++;
+ }
+
+ return true;
+}
+
+static bool torture_blocked_oplock_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_transport *transport_copy =
+ talloc_get_type_abort(private_data,
+ struct smb2_transport);
+ bool oplock_skip_ack = break_info.oplock_skip_ack;
+ bool ok;
+
+ break_info.oplock_skip_ack = true;
+ ok = transport_copy->oplock.handler(transport,
+ handle,
+ level,
+ transport_copy->oplock.private_data);
+ break_info.oplock_skip_ack = oplock_skip_ack;
+
+ if (!ok) {
+ return false;
+ }
+
+ if (break_info.oplock_skip_ack) {
+ return true;
+ }
+
+ break_info.failures++;
+ break_info.failure_status = NT_STATUS_CONNECTION_DISCONNECTED;
+
+ return true;
+}
+
+static bool test_block_smb2_transport_fsctl_smbtorture(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name)
+{
+ struct smb2_transport *transport_copy = NULL;
+ DATA_BLOB in_input_buffer = data_blob_null;
+ DATA_BLOB in_output_buffer = data_blob_null;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ struct tevent_req *req = NULL;
+ uint16_t local_port;
+ NTSTATUS status;
+ bool ok;
+
+ transport_copy = talloc_zero(transport, struct smb2_transport);
+ torture_assert(tctx, transport_copy, "talloc transport_copy");
+ transport_copy->lease = transport->lease;
+ transport_copy->oplock = transport->oplock;
+
+ local_port = torture_get_local_port_from_transport(transport);
+ torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port);
+ req = smb2cli_ioctl_send(tctx,
+ tctx->ev,
+ transport->conn,
+ 1000, /* timeout_msec */
+ NULL, /* session */
+ NULL, /* tcon */
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT,
+ 0, /* in_max_input_length */
+ &in_input_buffer,
+ 0, /* in_max_output_length */
+ &in_output_buffer,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ torture_assert(tctx, req != NULL, "smb2cli_ioctl_send() failed");
+ ok = tevent_req_poll_ntstatus(req, tctx->ev, &status);
+ if (ok) {
+ status = NT_STATUS_OK;
+ }
+ torture_assert_ntstatus_ok(tctx, status, "tevent_req_poll_ntstatus() failed");
+ status = smb2cli_ioctl_recv(req, tctx,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT failed\n\n"
+ "On a Samba server 'smbd:FSCTL_SMBTORTURE = yes' is needed!\n\n"
+ "Otherwise you may need to use iptables like this:\n"
+ "--option='torture:use_iptables=yes'\n"
+ "And maybe something like this in addition:\n"
+ "--option='torture:iptables_command=sudo /sbin/iptables'\n\n");
+ TALLOC_FREE(req);
+
+ if (transport->lease.handler != NULL) {
+ transport->lease.handler = torture_blocked_lease_handler;
+ transport->lease.private_data = transport_copy;
+ }
+ if (transport->oplock.handler != NULL) {
+ transport->oplock.handler = torture_blocked_oplock_handler;
+ transport->oplock.private_data = transport_copy;
+ }
+
+ return true;
+}
+
+bool _test_block_smb2_transport(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name)
+{
+ bool use_iptables = torture_setting_bool(tctx,
+ "use_iptables", false);
+
+ if (use_iptables) {
+ return test_block_smb2_transport_iptables(tctx, transport, name);
+ } else {
+ return test_block_smb2_transport_fsctl_smbtorture(tctx, transport, name);
+ }
+}
+
+bool _test_unblock_smb2_transport(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name)
+{
+ bool use_iptables = torture_setting_bool(tctx,
+ "use_iptables", false);
+
+ if (use_iptables) {
+ return test_unblock_smb2_transport_iptables(tctx, transport, name);
+ } else {
+ return true;
+ }
+}
+
+bool test_setup_blocked_transports(struct torture_context *tctx)
+{
+ bool use_iptables = torture_setting_bool(tctx,
+ "use_iptables", false);
+
+ if (use_iptables) {
+ return torture_block_tcp_output_setup(tctx);
+ }
+
+ return true;
+}
+
+void test_cleanup_blocked_transports(struct torture_context *tctx)
+{
+ bool use_iptables = torture_setting_bool(tctx,
+ "use_iptables", false);
+
+ if (use_iptables) {
+ torture_unblock_tcp_output_cleanup(tctx);
+ }
+}
diff --git a/source4/torture/smb2/block.h b/source4/torture/smb2/block.h
new file mode 100644
index 0000000..6a6370a
--- /dev/null
+++ b/source4/torture/smb2/block.h
@@ -0,0 +1,43 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * block SMB2 transports using iptables
+ *
+ * Copyright (C) Guenther Deschner, 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+uint16_t torture_get_local_port_from_transport(struct smb2_transport *t);
+
+bool torture_block_tcp_output_port(struct torture_context *tctx,
+ const char *name,
+ uint16_t port);
+bool torture_unblock_tcp_output_port(struct torture_context *tctx,
+ const char *name,
+ uint16_t port);
+bool torture_block_tcp_output_setup(struct torture_context *tctx);
+bool torture_unblock_tcp_output_cleanup(struct torture_context *tctx);
+
+bool test_setup_blocked_transports(struct torture_context *tctx);
+void test_cleanup_blocked_transports(struct torture_context *tctx);
+
+#define test_block_smb2_transport(_tctx, _t) _test_block_smb2_transport(_tctx, _t, #_t)
+bool _test_block_smb2_transport(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name);
+#define test_unblock_smb2_transport(_tctx, _t) _test_unblock_smb2_transport(_tctx, _t, #_t)
+bool _test_unblock_smb2_transport(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ const char *name);
diff --git a/source4/torture/smb2/charset.c b/source4/torture/smb2/charset.c
new file mode 100644
index 0000000..a385266
--- /dev/null
+++ b/source4/torture/smb2/charset.c
@@ -0,0 +1,235 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB torture tester - charset test routines
+
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "param/param.h"
+
+#define BASEDIR "chartest"
+
+/*
+ open a file using a set of unicode code points for the name
+
+ the prefix BASEDIR is added before the name
+*/
+static NTSTATUS unicode_open(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ uint32_t create_disposition,
+ const uint32_t *u_name,
+ size_t u_name_len)
+{
+ struct smb2_create io = {0};
+ char *fname = NULL;
+ char *fname2 = NULL;
+ char *ucs_name = NULL;
+ size_t i;
+ NTSTATUS status;
+
+ ucs_name = talloc_size(mem_ctx, (1+u_name_len)*2);
+ if (!ucs_name) {
+ torture_comment(tctx, "Failed to create UCS2 Name - talloc() failure\n");
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<u_name_len;i++) {
+ SSVAL(ucs_name, i*2, u_name[i]);
+ }
+ SSVAL(ucs_name, i*2, 0);
+
+ if (!convert_string_talloc_handle(ucs_name, lpcfg_iconv_handle(tctx->lp_ctx), CH_UTF16, CH_UNIX, ucs_name, (1+u_name_len)*2, (void **)&fname, &i)) {
+ torture_comment(tctx, "Failed to convert UCS2 Name into unix - convert_string_talloc() failure\n");
+ talloc_free(ucs_name);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fname2 = talloc_asprintf(ucs_name, "%s\\%s", BASEDIR, fname);
+ if (!fname2) {
+ talloc_free(ucs_name);
+ torture_comment(tctx, "Failed to create fname - talloc() failure\n");
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ io.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.in.create_options = 0;
+ io.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname2;
+ io.in.create_disposition = create_disposition;
+
+ status = smb2_create(tree, tctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(ucs_name);
+ return status;
+ }
+
+ smb2_util_close(tree, io.out.file.handle);
+ talloc_free(ucs_name);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ see if the server recognises composed characters
+*/
+static bool test_composed(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const uint32_t name1[] = {0x61, 0x308};
+ const uint32_t name2[] = {0xe4};
+ NTSTATUS status;
+ bool ret = true;
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done, "setting up basedir");
+
+ status = unicode_open(tctx, tree, tctx,
+ NTCREATEX_DISP_CREATE, name1, 2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create composed name");
+
+ status = unicode_open(tctx, tree, tctx,
+ NTCREATEX_DISP_CREATE, name2, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create accented character");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ see if the server recognises a naked diacritical
+*/
+static bool test_diacritical(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const uint32_t name1[] = {0x308};
+ const uint32_t name2[] = {0x308, 0x308};
+ NTSTATUS status;
+ bool ret = true;
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done, "setting up basedir");
+
+ status = unicode_open(tctx, tree, tctx,
+ NTCREATEX_DISP_CREATE, name1, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create naked diacritical");
+
+ /* try a double diacritical */
+ status = unicode_open(tctx, tree, tctx,
+ NTCREATEX_DISP_CREATE, name2, 2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create double "
+ "naked diacritical");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ see if the server recognises a partial surrogate pair
+*/
+static bool test_surrogate(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const uint32_t name1[] = {0xd800};
+ const uint32_t name2[] = {0xdc00};
+ const uint32_t name3[] = {0xd800, 0xdc00};
+ NTSTATUS status;
+ bool ret = true;
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done, "setting up basedir");
+
+ status = unicode_open(tctx, tree, tctx, NTCREATEX_DISP_CREATE, name1, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create partial surrogate 1");
+
+ status = unicode_open(tctx, tree, tctx, NTCREATEX_DISP_CREATE, name2, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create partial surrogate 2");
+
+ status = unicode_open(tctx, tree, tctx, NTCREATEX_DISP_CREATE, name3, 2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create full surrogate");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ return true;
+}
+
+/*
+ see if the server recognises wide-a characters
+*/
+static bool test_widea(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const uint32_t name1[] = {'a'};
+ const uint32_t name2[] = {0xff41};
+ const uint32_t name3[] = {0xff21};
+ NTSTATUS status;
+ bool ret = true;
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ret, ret, done, "setting up basedir");
+
+ status = unicode_open(tctx, tree, tctx, NTCREATEX_DISP_CREATE, name1, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create 'a'");
+
+ status = unicode_open(tctx, tree, tctx, NTCREATEX_DISP_CREATE, name2, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to create wide-a");
+
+ status = unicode_open(tctx, tree, tctx, NTCREATEX_DISP_CREATE, name3, 1);
+ torture_assert_ntstatus_equal_goto(tctx,
+ status,
+ NT_STATUS_OBJECT_NAME_COLLISION,
+ ret, done,
+ "Failed to create wide-A");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_charset(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "charset");
+
+ torture_suite_add_1smb2_test(suite, "Testing composite character (a umlaut)", test_composed);
+ torture_suite_add_1smb2_test(suite, "Testing naked diacritical (umlaut)", test_diacritical);
+ torture_suite_add_1smb2_test(suite, "Testing partial surrogate", test_surrogate);
+ torture_suite_add_1smb2_test(suite, "Testing wide-a", test_widea);
+
+ return suite;
+}
diff --git a/source4/torture/smb2/compound.c b/source4/torture/smb2/compound.c
new file mode 100644
index 0000000..175069d
--- /dev/null
+++ b/source4/torture/smb2/compound.c
@@ -0,0 +1,2595 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 compounded requests
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "tevent.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value %s=%d - should be %d\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define WAIT_FOR_ASYNC_RESPONSE(req) \
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
+ if (tevent_loop_once(tctx->ev) != 0) { \
+ break; \
+ } \
+ }
+
+static struct {
+ struct smb2_handle handle;
+ uint8_t level;
+ struct smb2_break br;
+ int count;
+ int failures;
+ NTSTATUS failure_status;
+} break_info;
+
+static void torture_oplock_break_callback(struct smb2_request *req)
+{
+ NTSTATUS status;
+ struct smb2_break br;
+
+ ZERO_STRUCT(br);
+ status = smb2_break_recv(req, &break_info.br);
+ if (!NT_STATUS_IS_OK(status)) {
+ break_info.failures++;
+ break_info.failure_status = status;
+ }
+
+ return;
+}
+
+/* A general oplock break notification handler. This should be used when a
+ * test expects to break from batch or exclusive to a lower level. */
+static bool torture_oplock_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ const char *name;
+ struct smb2_request *req;
+ ZERO_STRUCT(break_info.br);
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ switch (level) {
+ case SMB2_OPLOCK_LEVEL_II:
+ name = "level II";
+ break;
+ case SMB2_OPLOCK_LEVEL_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break_info.failures++;
+ }
+ printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
+
+ break_info.br.in.file.handle = *handle;
+ break_info.br.in.oplock_level = level;
+ break_info.br.in.reserved = 0;
+ break_info.br.in.reserved2 = 0;
+
+ req = smb2_break_send(tree, &break_info.br);
+ req->async.fn = torture_oplock_break_callback;
+ req->async.private_data = NULL;
+ return true;
+}
+
+static bool test_compound_break(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname1 = "some-file.pptx";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io1;
+ struct smb2_create io2;
+ struct smb2_getinfo gf;
+ struct smb2_request *req[2];
+ struct smb2_handle h1;
+ struct smb2_handle h;
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ ZERO_STRUCT(break_info);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io1.smb2);
+ io1.generic.level = RAW_OPEN_SMB2;
+ io1.smb2.in.desired_access = (SEC_STD_SYNCHRONIZE|
+ SEC_STD_READ_CONTROL|
+ SEC_FILE_READ_ATTRIBUTE|
+ SEC_FILE_READ_EA|
+ SEC_FILE_READ_DATA);
+ io1.smb2.in.alloc_size = 0;
+ io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io1.smb2.in.create_options = 0;
+ io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io1.smb2.in.security_flags = 0;
+ io1.smb2.in.fname = fname1;
+
+ torture_comment(tctx, "TEST2: open a file with an batch "
+ "oplock (share mode: all)\n");
+ io1.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree, tctx, &(io1.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+
+ h1 = io1.smb2.out.file.handle;
+
+ torture_comment(tctx, "TEST2: Opening second time with compound\n");
+
+ ZERO_STRUCT(io2);
+
+ io2.in.desired_access = (SEC_STD_SYNCHRONIZE|
+ SEC_FILE_READ_ATTRIBUTE|
+ SEC_FILE_READ_EA);
+ io2.in.alloc_size = 0;
+ io2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io2.in.create_options = 0;
+ io2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io2.in.security_flags = 0;
+ io2.in.fname = fname1;
+ io2.in.oplock_level = 0;
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ req[0] = smb2_create_send(tree, &io2);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ h.data[0] = UINT64_MAX;
+ h.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(gf);
+ gf.in.file.handle = h;
+ gf.in.info_type = SMB2_0_INFO_FILE;
+ gf.in.info_class = 0x16;
+ gf.in.output_buffer_length = 0x1000;
+ gf.in.input_buffer = data_blob_null;
+
+ req[1] = smb2_getinfo_send(tree, &gf);
+
+ status = smb2_create_recv(req[0], tree, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_getinfo_recv(req[1], tree, &gf);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname1);
+ return ret;
+}
+
+static bool test_compound_related1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status;
+ const char *fname = "compound_related1.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ struct smb2_request *req[2];
+ struct smbXcli_tcon *saved_tcon = tree->smbXcli;
+ struct smbXcli_session *saved_session = tree->session->smbXcli;
+
+ smb2_transport_credits_ask_num(tree->session->transport, 2);
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ tree->smbXcli = smbXcli_tcon_create(tree);
+ smb2cli_tcon_set_values(tree->smbXcli,
+ NULL, /* session */
+ 0xFFFFFFFF, /* tcon_id */
+ 0, /* type */
+ 0, /* flags */
+ 0, /* capabilities */
+ 0 /* maximal_access */);
+
+ tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
+ tree->session->smbXcli);
+ smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
+
+ req[1] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[1], &cl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ TALLOC_FREE(tree->smbXcli);
+ tree->smbXcli = saved_tcon;
+ TALLOC_FREE(tree->session->smbXcli);
+ tree->session->smbXcli = saved_session;
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+static bool test_compound_related2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status;
+ const char *fname = "compound_related2.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ struct smb2_request *req[5];
+ struct smbXcli_tcon *saved_tcon = tree->smbXcli;
+ struct smbXcli_session *saved_session = tree->session->smbXcli;
+
+ smb2_transport_credits_ask_num(tree->session->transport, 5);
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 5);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ tree->smbXcli = smbXcli_tcon_create(tree);
+ smb2cli_tcon_set_values(tree->smbXcli,
+ NULL, /* session */
+ 0xFFFFFFFF, /* tcon_id */
+ 0, /* type */
+ 0, /* flags */
+ 0, /* capabilities */
+ 0 /* maximal_access */);
+
+ tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
+ tree->session->smbXcli);
+ smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
+
+ req[1] = smb2_close_send(tree, &cl);
+ req[2] = smb2_close_send(tree, &cl);
+ req[3] = smb2_close_send(tree, &cl);
+ req[4] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[1], &cl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[2], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[3], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[4], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+
+ TALLOC_FREE(tree->smbXcli);
+ tree->smbXcli = saved_tcon;
+ TALLOC_FREE(tree->session->smbXcli);
+ tree->session->smbXcli = saved_session;
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+static bool test_compound_related3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_ioctl io;
+ struct smb2_create cr;
+ struct smb2_close cl;
+ const char *fname = "compound_related3.dat";
+ struct smb2_request *req[3];
+ NTSTATUS status;
+ bool ret = false;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 3);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(io);
+ io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
+ io.in.file.handle = hd;
+ io.in.reserved2 = 0;
+ io.in.max_output_response = 64;
+ io.in.flags = 1;
+
+ req[1] = smb2_ioctl_send(tree, &io);
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[2] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_ioctl_recv(req[1], tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[2], &cl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret = true;
+done:
+ return ret;
+}
+
+static bool test_compound_related4(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "compound_related4.dat";
+ struct security_descriptor *sd = NULL;
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ union smb_setfileinfo set;
+ struct smb2_ioctl io;
+ struct smb2_close cl;
+ struct smb2_request *req[4];
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.level = RAW_OPEN_SMB2;
+ cr.in.create_flags = 0;
+ cr.in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ cr.in.create_options = 0;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ cr.in.alloc_size = 0;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ cr.in.security_flags = 0;
+ cr.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
+
+ hd = cr.out.file.handle;
+ torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "security_descriptor_dacl_create failed\n");
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = hd;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ torture_comment(tctx, "try open for write\n");
+ cr.in.desired_access = SEC_FILE_WRITE_DATA;
+ smb2_transport_compound_start(tree->session->transport, 4);
+
+ req[0] = smb2_create_send(tree, &cr);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_create_send failed\n");
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+ ZERO_STRUCT(io);
+ io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
+ io.in.file.handle = hd;
+ io.in.flags = 1;
+
+ req[1] = smb2_ioctl_send(tree, &io);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_ioctl_send failed\n");
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[2] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[2], ret, done,
+ "smb2_create_send failed\n");
+
+ set.set_secdesc.in.file.handle = hd;
+
+ req[3] = smb2_setinfo_file_send(tree, &set);
+ torture_assert_not_null_goto(tctx, req[3], ret, done,
+ "smb2_create_send failed\n");
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_create_recv failed\n");
+
+ status = smb2_ioctl_recv(req[1], tree, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_ioctl_recv failed\n");
+
+ status = smb2_close_recv(req[2], &cl);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_close_recv failed\n");
+
+ status = smb2_setinfo_recv(req[3]);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_setinfo_recv failed\n");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_compound_related5(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_ioctl io;
+ struct smb2_close cl;
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool ret = false;
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(io);
+ io.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID;
+ io.in.file.handle = hd;
+ io.in.flags = 1;
+
+ req[0] = smb2_ioctl_send(tree, &io);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_ioctl_send failed\n");
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[1] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_create_send failed\n");
+
+ status = smb2_ioctl_recv(req[0], tree, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_FILE_CLOSED,
+ ret, done,
+ "smb2_ioctl_recv failed\n");
+
+ status = smb2_close_recv(req[1], &cl);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_FILE_CLOSED,
+ ret, done,
+ "smb2_close_recv failed\n");
+
+ ret = true;
+
+done:
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_compound_related6(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ struct smb2_read rd;
+ struct smb2_write wr;
+ struct smb2_close cl;
+ NTSTATUS status;
+ const char *fname = "compound_related6.dat";
+ struct smb2_request *req[5];
+ uint8_t buf[64];
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.level = RAW_OPEN_SMB2;
+ cr.in.create_flags = 0;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.create_options = 0;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ cr.in.alloc_size = 0;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ cr.in.security_flags = 0;
+ cr.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ hd = cr.out.file.handle;
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, hd, buf, 0, ARRAY_SIZE(buf));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ torture_comment(tctx, "try open for read\n");
+ cr.in.desired_access = SEC_FILE_READ_DATA;
+ smb2_transport_compound_start(tree->session->transport, 5);
+
+ req[0] = smb2_create_send(tree, &cr);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_create_send failed\n");
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = hd;
+ rd.in.length = 1;
+ rd.in.offset = 0;
+
+ req[1] = smb2_read_send(tree, &rd);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_read_send failed\n");
+
+ ZERO_STRUCT(wr);
+ wr.in.file.handle = hd;
+ wr.in.offset = 0;
+ wr.in.data = data_blob_talloc(tctx, NULL, 64);
+
+ req[2] = smb2_write_send(tree, &wr);
+ torture_assert_not_null_goto(tctx, req[2], ret, done,
+ "smb2_write_send failed\n");
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = hd;
+ rd.in.length = 1;
+ rd.in.offset = 0;
+
+ req[3] = smb2_read_send(tree, &rd);
+ torture_assert_not_null_goto(tctx, req[3], ret, done,
+ "smb2_read_send failed\n");
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[4] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[4], ret, done,
+ "smb2_close_send failed\n");
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create_recv failed\n");
+
+ status = smb2_read_recv(req[1], tree, &rd);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_read_recv failed\n");
+
+ status = smb2_write_recv(req[2], &wr);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_write_recv failed\n");
+
+ status = smb2_read_recv(req[3], tree, &rd);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_read_recv failed\n");
+
+ status = smb2_close_recv(req[4], &cl);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_close_recv failed\n");
+
+ done:
+ smb2_util_unlink(tree, fname);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_compound_related7(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "compound_related4.dat";
+ struct security_descriptor *sd = NULL;
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ union smb_setfileinfo set;
+ struct smb2_notify nt;
+ struct smb2_close cl;
+ NTSTATUS status;
+ struct smb2_request *req[4];
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.level = RAW_OPEN_SMB2;
+ cr.in.create_flags = 0;
+ cr.in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ cr.in.create_options = 0;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ cr.in.alloc_size = 0;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ cr.in.security_flags = 0;
+ cr.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ hd = cr.out.file.handle;
+ torture_comment(tctx, "set a sec desc allowing no write by CREATOR_OWNER\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "security_descriptor_dacl_create failed\n");
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = hd;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ torture_comment(tctx, "try open for write\n");
+ cr.in.desired_access = SEC_FILE_WRITE_DATA;
+ smb2_transport_compound_start(tree->session->transport, 4);
+
+ req[0] = smb2_create_send(tree, &cr);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_create_send failed\n");
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(nt);
+ nt.in.recursive = true;
+ nt.in.buffer_size = 0x1000;
+ nt.in.file.handle = hd;
+ nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ nt.in.unknown = 0x00000000;
+
+ req[1] = smb2_notify_send(tree, &nt);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_notify_send failed\n");
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[2] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[2], ret, done,
+ "smb2_close_send failed\n");
+
+ set.set_secdesc.in.file.handle = hd;
+
+ req[3] = smb2_setinfo_file_send(tree, &set);
+ torture_assert_not_null_goto(tctx, req[3], ret, done,
+ "smb2_setinfo_file_send failed\n");
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_create_recv failed\n");
+
+ status = smb2_notify_recv(req[1], tree, &nt);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_notify_recv failed\n");
+
+ status = smb2_close_recv(req[2], &cl);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_close_recv failed\n");
+
+ status = smb2_setinfo_recv(req[3]);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,
+ "smb2_setinfo_recv failed\n");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_compound_related8(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "compound_related8.dat";
+ const char *fname_nonexisting = "compound_related8.dat.void";
+ struct security_descriptor *sd = NULL;
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ union smb_setfileinfo set;
+ struct smb2_notify nt;
+ struct smb2_close cl;
+ NTSTATUS status;
+ struct smb2_request *req[4];
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.level = RAW_OPEN_SMB2;
+ cr.in.create_flags = 0;
+ cr.in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ cr.in.create_options = 0;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ cr.in.alloc_size = 0;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ cr.in.security_flags = 0;
+ cr.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ hd = cr.out.file.handle;
+
+ smb2_transport_compound_start(tree->session->transport, 4);
+
+ torture_comment(tctx, "try open for write\n");
+ cr.in.fname = fname_nonexisting;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ req[0] = smb2_create_send(tree, &cr);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_create_send failed\n");
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(nt);
+ nt.in.recursive = true;
+ nt.in.buffer_size = 0x1000;
+ nt.in.file.handle = hd;
+ nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ nt.in.unknown = 0x00000000;
+
+ req[1] = smb2_notify_send(tree, &nt);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_notify_send failed\n");
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[2] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[2], ret, done,
+ "smb2_close_send failed\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "security_descriptor_dacl_create failed\n");
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = hd;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ req[3] = smb2_setinfo_file_send(tree, &set);
+ torture_assert_not_null_goto(tctx, req[3], ret, done,
+ "smb2_setinfo_file_send failed\n");
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_create_recv failed\n");
+
+ status = smb2_notify_recv(req[1], tree, &nt);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_notify_recv failed\n");
+
+ status = smb2_close_recv(req[2], &cl);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_close_recv failed\n");
+
+ status = smb2_setinfo_recv(req[3]);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done,
+ "smb2_setinfo_recv failed\n");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_compound_related9(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "compound_related9.dat";
+ struct security_descriptor *sd = NULL;
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ union smb_setfileinfo set;
+ struct smb2_notify nt;
+ struct smb2_close cl;
+ NTSTATUS status;
+ struct smb2_request *req[3];
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.level = RAW_OPEN_SMB2;
+ cr.in.create_flags = 0;
+ cr.in.desired_access = SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ cr.in.create_options = 0;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ cr.in.alloc_size = 0;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ cr.in.security_flags = 0;
+ cr.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ hd = cr.out.file.handle;
+
+ smb2_transport_compound_start(tree->session->transport, 3);
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(nt);
+ nt.in.recursive = true;
+ nt.in.buffer_size = 0x1000;
+ nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+
+ req[0] = smb2_notify_send(tree, &nt);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_notify_send failed\n");
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ req[1] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_close_send failed\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ SID_CREATOR_OWNER,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+ torture_assert_not_null_goto(tctx, sd, ret, done,
+ "security_descriptor_dacl_create failed\n");
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = hd;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+
+ req[2] = smb2_setinfo_file_send(tree, &set);
+ torture_assert_not_null_goto(tctx, req[2], ret, done,
+ "smb2_setinfo_file_send failed\n");
+
+ status = smb2_notify_recv(req[0], tree, &nt);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
+ ret, done,
+ "smb2_notify_recv failed\n");
+
+ status = smb2_close_recv(req[1], &cl);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
+ ret, done,
+ "smb2_close_recv failed\n");
+
+ status = smb2_setinfo_recv(req[2]);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_INVALID_PARAMETER,
+ ret, done,
+ "smb2_setinfo_recv failed\n");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+static bool test_compound_padding(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle h;
+ struct smb2_create cr;
+ struct smb2_read r;
+ struct smb2_read r2;
+ const char *fname = "compound_read.dat";
+ const char *sname = "compound_read.dat:foo";
+ struct smb2_request *req[3];
+ NTSTATUS status;
+ bool ret = false;
+
+ smb2_util_unlink(tree, fname);
+
+ /* Write file */
+ ZERO_STRUCT(cr);
+ cr.in.desired_access = SEC_FILE_WRITE_DATA;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+ cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ cr.in.fname = fname;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree, tctx, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = cr.out.file.handle;
+
+ status = smb2_util_write(tree, h, "123", 0, 3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h);
+
+ /* Write stream */
+ ZERO_STRUCT(cr);
+ cr.in.desired_access = SEC_FILE_WRITE_DATA;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+ cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ cr.in.fname = sname;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree, tctx, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = cr.out.file.handle;
+
+ status = smb2_util_write(tree, h, "456", 0, 3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h);
+
+ /* Check compound read from basefile */
+ smb2_transport_compound_start(tree->session->transport, 3);
+
+ ZERO_STRUCT(cr);
+ cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ cr.in.desired_access = SEC_FILE_READ_DATA;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN;
+ cr.in.fname = fname;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ req[0] = smb2_create_send(tree, &cr);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ /*
+ * We send 2 reads in the compound here as the protocol
+ * allows the last read to be split off and possibly
+ * go async. Check the padding on the first read returned,
+ * not the second as the second may not be part of the
+ * returned compound.
+ */
+
+ ZERO_STRUCT(r);
+ h.data[0] = UINT64_MAX;
+ h.data[1] = UINT64_MAX;
+ r.in.file.handle = h;
+ r.in.length = 3;
+ r.in.offset = 0;
+ r.in.min_count = 1;
+ req[1] = smb2_read_send(tree, &r);
+
+ ZERO_STRUCT(r2);
+ h.data[0] = UINT64_MAX;
+ h.data[1] = UINT64_MAX;
+ r2.in.file.handle = h;
+ r2.in.length = 3;
+ r2.in.offset = 0;
+ r2.in.min_count = 1;
+ req[2] = smb2_read_send(tree, &r2);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * We must do a manual smb2_request_receive() in order to be
+ * able to check the transport layer info, as smb2_read_recv()
+ * will destroy the req. smb2_read_recv() will call
+ * smb2_request_receive() again, but that's ok.
+ */
+ if (!smb2_request_receive(req[1]) ||
+ !smb2_request_is_ok(req[1])) {
+ torture_fail(tctx, "failed to receive read request");
+ }
+
+ /*
+ * size must be 24: 16 byte read response header plus 3
+ * requested bytes padded to an 8 byte boundary.
+ */
+ CHECK_VALUE(req[1]->in.body_size, 24);
+
+ status = smb2_read_recv(req[1], tree, &r);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Pick up the second, possibly async, read. */
+ status = smb2_read_recv(req[2], tree, &r2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, cr.out.file.handle);
+
+ /* Check compound read from stream */
+ smb2_transport_compound_start(tree->session->transport, 3);
+
+ ZERO_STRUCT(cr);
+ cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ cr.in.desired_access = SEC_FILE_READ_DATA;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN;
+ cr.in.fname = sname;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ req[0] = smb2_create_send(tree, &cr);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ /*
+ * We send 2 reads in the compound here as the protocol
+ * allows the last read to be split off and possibly
+ * go async. Check the padding on the first read returned,
+ * not the second as the second may not be part of the
+ * returned compound.
+ */
+
+ ZERO_STRUCT(r);
+ h.data[0] = UINT64_MAX;
+ h.data[1] = UINT64_MAX;
+ r.in.file.handle = h;
+ r.in.length = 3;
+ r.in.offset = 0;
+ r.in.min_count = 1;
+ req[1] = smb2_read_send(tree, &r);
+
+ ZERO_STRUCT(r2);
+ h.data[0] = UINT64_MAX;
+ h.data[1] = UINT64_MAX;
+ r2.in.file.handle = h;
+ r2.in.length = 3;
+ r2.in.offset = 0;
+ r2.in.min_count = 1;
+ req[2] = smb2_read_send(tree, &r2);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * We must do a manual smb2_request_receive() in order to be
+ * able to check the transport layer info, as smb2_read_recv()
+ * will destroy the req. smb2_read_recv() will call
+ * smb2_request_receive() again, but that's ok.
+ */
+ if (!smb2_request_receive(req[1]) ||
+ !smb2_request_is_ok(req[1])) {
+ torture_fail(tctx, "failed to receive read request");
+ }
+
+ /*
+ * size must be 24: 16 byte read response header plus 3
+ * requested bytes padded to an 8 byte boundary.
+ */
+ CHECK_VALUE(req[1]->in.body_size, 24);
+
+ status = smb2_read_recv(req[1], tree, &r);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Pick up the second, possibly async, read. */
+ status = smb2_read_recv(req[2], tree, &r2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ h = cr.out.file.handle;
+
+ /* Check 2 compound (unrelateated) reads from existing stream handle */
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = h;
+ r.in.length = 3;
+ r.in.offset = 0;
+ r.in.min_count = 1;
+ req[0] = smb2_read_send(tree, &r);
+ req[1] = smb2_read_send(tree, &r);
+
+ /*
+ * We must do a manual smb2_request_receive() in order to be
+ * able to check the transport layer info, as smb2_read_recv()
+ * will destroy the req. smb2_read_recv() will call
+ * smb2_request_receive() again, but that's ok.
+ */
+ if (!smb2_request_receive(req[0]) ||
+ !smb2_request_is_ok(req[0])) {
+ torture_fail(tctx, "failed to receive read request");
+ }
+ if (!smb2_request_receive(req[1]) ||
+ !smb2_request_is_ok(req[1])) {
+ torture_fail(tctx, "failed to receive read request");
+ }
+
+ /*
+ * size must be 24: 16 byte read response header plus 3
+ * requested bytes padded to an 8 byte boundary.
+ */
+ CHECK_VALUE(req[0]->in.body_size, 24);
+ CHECK_VALUE(req[1]->in.body_size, 24);
+
+ status = smb2_read_recv(req[0], tree, &r);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_read_recv(req[1], tree, &r);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * now try a single read from the stream and verify there's no padding
+ */
+ ZERO_STRUCT(r);
+ r.in.file.handle = h;
+ r.in.length = 3;
+ r.in.offset = 0;
+ r.in.min_count = 1;
+ req[0] = smb2_read_send(tree, &r);
+
+ /*
+ * We must do a manual smb2_request_receive() in order to be
+ * able to check the transport layer info, as smb2_read_recv()
+ * will destroy the req. smb2_read_recv() will call
+ * smb2_request_receive() again, but that's ok.
+ */
+ if (!smb2_request_receive(req[0]) ||
+ !smb2_request_is_ok(req[0])) {
+ torture_fail(tctx, "failed to receive read request");
+ }
+
+ /*
+ * size must be 19: 16 byte read response header plus 3
+ * requested bytes without padding.
+ */
+ CHECK_VALUE(req[0]->in.body_size, 19);
+
+ status = smb2_read_recv(req[0], tree, &r);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h);
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret = true;
+done:
+ return ret;
+}
+
+static bool test_compound_create_write_close(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle handle = { .data = { UINT64_MAX, UINT64_MAX } };
+ struct smb2_create create;
+ struct smb2_write write;
+ struct smb2_close close;
+ const char *fname = "compound_create_write_close.dat";
+ struct smb2_request *req[3];
+ NTSTATUS status;
+ bool ret = false;
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(create);
+ create.in.security_flags = 0x00;
+ create.in.oplock_level = 0;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ create.in.create_flags = 0x00000000;
+ create.in.reserved = 0x00000000;
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ create.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 3);
+
+ req[0] = smb2_create_send(tree, &create);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(write);
+ write.in.file.handle = handle;
+ write.in.offset = 0;
+ write.in.data = data_blob_talloc(tctx, NULL, 1024);
+
+ req[1] = smb2_write_send(tree, &write);
+
+ ZERO_STRUCT(close);
+ close.in.file.handle = handle;
+
+ req[2] = smb2_close_send(tree, &close);
+
+ status = smb2_create_recv(req[0], tree, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE failed.");
+
+ status = smb2_write_recv(req[1], &write);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "WRITE failed.");
+
+ status = smb2_close_recv(req[2], &close);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE failed.");
+
+ status = smb2_util_unlink(tree, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "File deletion failed.");
+
+ ret = true;
+done:
+ return ret;
+}
+
+static bool test_compound_unrelated1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status;
+ const char *fname = "compound_unrelated1.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ struct smb2_request *req[5];
+
+ smb2_transport_credits_ask_num(tree->session->transport, 5);
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 5);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+ req[1] = smb2_close_send(tree, &cl);
+ req[2] = smb2_close_send(tree, &cl);
+ req[3] = smb2_close_send(tree, &cl);
+ req[4] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[1], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[2], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[3], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[4], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+static bool test_compound_invalid1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status;
+ const char *fname = "compound_invalid1.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ struct smb2_request *req[3];
+
+ smb2_transport_credits_ask_num(tree->session->transport, 3);
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 3);
+
+ /* passing the first request with the related flag is invalid */
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+ req[1] = smb2_close_send(tree, &cl);
+
+ smb2_transport_compound_set_related(tree->session->transport, false);
+ req[2] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ /* TODO: check why this fails with --signing=required */
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ status = smb2_close_recv(req[1], &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ status = smb2_close_recv(req[2], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+static bool test_compound_invalid2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status;
+ const char *fname = "compound_invalid2.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ struct smb2_request *req[5];
+ struct smbXcli_tcon *saved_tcon = tree->smbXcli;
+ struct smbXcli_session *saved_session = tree->session->smbXcli;
+
+ smb2_transport_credits_ask_num(tree->session->transport, 5);
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 5);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+
+ tree->smbXcli = smbXcli_tcon_create(tree);
+ smb2cli_tcon_set_values(tree->smbXcli,
+ NULL, /* session */
+ 0xFFFFFFFF, /* tcon_id */
+ 0, /* type */
+ 0, /* flags */
+ 0, /* capabilities */
+ 0 /* maximal_access */);
+
+ tree->session->smbXcli = smbXcli_session_shallow_copy(tree->session,
+ tree->session->smbXcli);
+ smb2cli_session_set_id_and_flags(tree->session->smbXcli, UINT64_MAX, 0);
+
+ req[1] = smb2_close_send(tree, &cl);
+ /* strange that this is not generating invalid parameter */
+ smb2_transport_compound_set_related(tree->session->transport, false);
+ req[2] = smb2_close_send(tree, &cl);
+ req[3] = smb2_close_send(tree, &cl);
+ smb2_transport_compound_set_related(tree->session->transport, true);
+ req[4] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[1], &cl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[2], &cl);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+ status = smb2_close_recv(req[3], &cl);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+ status = smb2_close_recv(req[4], &cl);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ TALLOC_FREE(tree->smbXcli);
+ tree->smbXcli = saved_tcon;
+ TALLOC_FREE(tree->session->smbXcli);
+ tree->session->smbXcli = saved_session;
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+static bool test_compound_invalid3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status;
+ const char *fname = "compound_invalid3.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ struct smb2_request *req[5];
+
+ smb2_transport_credits_ask_num(tree->session->transport, 5);
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ smb2_transport_compound_start(tree->session->transport, 5);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = hd;
+ req[1] = smb2_close_send(tree, &cl);
+ req[2] = smb2_close_send(tree, &cl);
+ /* flipping the related flag is invalid */
+ smb2_transport_compound_set_related(tree->session->transport, true);
+ req[3] = smb2_close_send(tree, &cl);
+ req[4] = smb2_close_send(tree, &cl);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_close_recv(req[1], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[2], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[3], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ status = smb2_close_recv(req[4], &cl);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+static bool test_compound_invalid4(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create cr;
+ struct smb2_read rd;
+ NTSTATUS status;
+ const char *fname = "compound_invalid4.dat";
+ struct smb2_close cl;
+ bool ret = true;
+ bool ok;
+ struct smb2_request *req[2];
+
+ smb2_transport_credits_ask_num(tree->session->transport, 2);
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(cr);
+ cr.in.security_flags = 0x00;
+ cr.in.oplock_level = 0;
+ cr.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ cr.in.create_flags = 0x00000000;
+ cr.in.reserved = 0x00000000;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ cr.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = cr.out.file.handle;
+ rd.in.length = 1;
+ rd.in.offset = 0;
+ req[0] = smb2_read_send(tree, &rd);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ /*
+ * Send a completely bogus request as second compound
+ * element. This triggers smbd_smb2_request_error() in in
+ * smbd_smb2_request_dispatch() before calling
+ * smbd_smb2_request_dispatch_update_counts().
+ */
+
+ req[1] = smb2_request_init_tree(tree, 0xff, 0x04, false, 0);
+ smb2_transport_send(req[1]);
+
+ status = smb2_read_recv(req[0], tctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ ok = smb2_request_receive(req[1]);
+ torture_assert(tctx, ok, "Invalid request failed\n");
+ CHECK_STATUS(req[1]->status, NT_STATUS_INVALID_PARAMETER);
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = cr.out.file.handle;
+
+ status = smb2_close(tree, &cl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_unlink(tree, fname);
+done:
+ return ret;
+}
+
+/* Send a compound request where we expect the last request (Create, Notify)
+ * to go asynchronous. This works against a Win7 server and the reply is
+ * sent in two different packets. */
+static bool test_compound_interim1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status = NT_STATUS_OK;
+ const char *dname = "compound_interim_dir";
+ struct smb2_notify nt;
+ bool ret = true;
+ struct smb2_request *req[2];
+
+ /* Win7 compound request implementation deviates substantially from the
+ * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
+ * verifies the Windows behavior, not the general spec behavior. */
+
+ smb2_transport_credits_ask_num(tree->session->transport, 5);
+
+ smb2_deltree(tree, dname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ cr.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+ cr.in.fname = dname;
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(nt);
+ nt.in.recursive = true;
+ nt.in.buffer_size = 0x1000;
+ nt.in.file.handle = hd;
+ nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ nt.in.unknown = 0x00000000;
+
+ req[1] = smb2_notify_send(tree, &nt);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_cancel(req[1]);
+ status = smb2_notify_recv(req[1], tree, &nt);
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ smb2_util_close(tree, cr.out.file.handle);
+
+ smb2_deltree(tree, dname);
+done:
+ return ret;
+}
+
+/* Send a compound request where we expect the middle request (Create, Notify,
+ * GetInfo) to go asynchronous. Against Win7 the sync request succeed while
+ * the async fails. All are returned in the same compound response. */
+static bool test_compound_interim2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle hd;
+ struct smb2_create cr;
+ NTSTATUS status = NT_STATUS_OK;
+ const char *dname = "compound_interim_dir";
+ struct smb2_getinfo gf;
+ struct smb2_notify nt;
+ bool ret = true;
+ struct smb2_request *req[3];
+
+ /* Win7 compound request implementation deviates substantially from the
+ * SMB2 spec as noted in MS-SMB2 <159>, <162>. This, test currently
+ * verifies the Windows behavior, not the general spec behavior. */
+
+ smb2_transport_credits_ask_num(tree->session->transport, 5);
+
+ smb2_deltree(tree, dname);
+
+ smb2_transport_credits_ask_num(tree->session->transport, 1);
+
+ ZERO_STRUCT(cr);
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ cr.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ cr.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ cr.in.create_disposition = NTCREATEX_DISP_CREATE;
+ cr.in.fname = dname;
+
+ smb2_transport_compound_start(tree->session->transport, 3);
+
+ req[0] = smb2_create_send(tree, &cr);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ hd.data[0] = UINT64_MAX;
+ hd.data[1] = UINT64_MAX;
+
+ ZERO_STRUCT(nt);
+ nt.in.recursive = true;
+ nt.in.buffer_size = 0x1000;
+ nt.in.file.handle = hd;
+ nt.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ nt.in.unknown = 0x00000000;
+
+ req[1] = smb2_notify_send(tree, &nt);
+
+ ZERO_STRUCT(gf);
+ gf.in.file.handle = hd;
+ gf.in.info_type = SMB2_0_INFO_FILE;
+ gf.in.info_class = 0x04; /* FILE_BASIC_INFORMATION */
+ gf.in.output_buffer_length = 0x1000;
+ gf.in.input_buffer = data_blob_null;
+
+ req[2] = smb2_getinfo_send(tree, &gf);
+
+ status = smb2_create_recv(req[0], tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req[1], tree, &nt);
+ CHECK_STATUS(status, NT_STATUS_INTERNAL_ERROR);
+
+ status = smb2_getinfo_recv(req[2], tree, &gf);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, cr.out.file.handle);
+
+ smb2_deltree(tree, dname);
+done:
+ return ret;
+}
+
+/* Test compound related finds */
+static bool test_compound_find_related(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *dname = "compound_find_dir";
+ struct smb2_create create;
+ struct smb2_find f;
+ struct smb2_handle h;
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, dname);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = dname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ h = create.out.file.handle;
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.max_response_size = 0x100;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ req[0] = smb2_find_send(tree, &f);
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ req[1] = smb2_find_send(tree, &f);
+
+ status = smb2_find_recv(req[0], mem_ctx, &f);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
+
+ status = smb2_find_recv(req[1], mem_ctx, &f);
+ torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, dname);
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/* Test compound related finds */
+static bool test_compound_find_close(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *dname = "compound_find_dir";
+ struct smb2_create create;
+ struct smb2_find f;
+ struct smb2_handle h;
+ struct smb2_request *req = NULL;
+ const int num_files = 5000;
+ int i;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, dname);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = dname;
+
+ smb2cli_conn_set_max_credits(tree->session->transport->conn, 256);
+
+ status = smb2_create(tree, mem_ctx, &create);
+ h = create.out.file.handle;
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ for (i = 0; i < num_files; i++) {
+ create.in.fname = talloc_asprintf(mem_ctx, "%s\\file%d",
+ dname, i);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ smb2_util_close(tree, create.out.file.handle);
+ }
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.max_response_size = 8*1024*1024;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ req = smb2_find_send(tree, &f);
+
+ status = smb2_util_close(tree, h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed\n");
+
+ status = smb2_find_recv(req, mem_ctx, &f);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, dname);
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+/* Test compound unrelated finds */
+static bool test_compound_find_unrelated(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *dname = "compound_find_dir";
+ struct smb2_create create;
+ struct smb2_find f;
+ struct smb2_handle h;
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, dname);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = dname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ h = create.out.file.handle;
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.max_response_size = 0x100;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ req[0] = smb2_find_send(tree, &f);
+ req[1] = smb2_find_send(tree, &f);
+
+ status = smb2_find_recv(req[0], mem_ctx, &f);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_recv failed\n");
+
+ status = smb2_find_recv(req[1], mem_ctx, &f);
+ torture_assert_ntstatus_equal_goto(tctx, status, STATUS_NO_MORE_FILES, ret, done, "smb2_find_recv failed\n");
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, dname);
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool test_compound_async_flush_close(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fhandle = { .data = { 0, 0 } };
+ struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
+ struct smb2_close cl;
+ struct smb2_flush fl;
+ const char *fname = "compound_async_flush_close";
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool ret = false;
+
+ /* Start clean. */
+ smb2_util_unlink(tree, fname);
+
+ /* Create a file. */
+ status = torture_smb2_testfile_access(tree,
+ fname,
+ &fhandle,
+ SEC_RIGHTS_FILE_ALL);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Now do a compound flush + close handle. */
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(fl);
+ fl.in.file.handle = fhandle;
+
+ req[0] = smb2_flush_send(tree, &fl);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_flush_send failed\n");
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = relhandle;
+ req[1] = smb2_close_send(tree, &cl);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_close_send failed\n");
+
+ status = smb2_flush_recv(req[0], &fl);
+ /*
+ * On Windows, this flush will usually
+ * succeed as we have nothing to flush,
+ * so allow NT_STATUS_OK. Once bug #15172
+ * is fixed Samba will do the flush synchronously
+ * so allow NT_STATUS_OK.
+ */
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * If we didn't get NT_STATUS_OK, we *must*
+ * get NT_STATUS_INTERNAL_ERROR if the flush
+ * goes async.
+ *
+ * For pre-bugfix #15172 Samba, the flush goes async and
+ * we should get NT_STATUS_INTERNAL_ERROR.
+ */
+ torture_assert_ntstatus_equal_goto(tctx,
+ status,
+ NT_STATUS_INTERNAL_ERROR,
+ ret,
+ done,
+ "smb2_flush_recv didn't return "
+ "NT_STATUS_INTERNAL_ERROR.\n");
+ }
+ status = smb2_close_recv(req[1], &cl);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_close_recv failed.");
+
+ ZERO_STRUCT(fhandle);
+
+ /*
+ * Do several more operations on the tree, spaced
+ * out by 1 sec sleeps to make sure the server didn't
+ * crash on the close. The sleeps are required to
+ * make test test for a crash reliable, as we ensure
+ * the pthread fsync internally finishes and accesses
+ * freed memory. Without them the test occasionally
+ * passes as we disconnect before the pthread fsync
+ * finishes.
+ */
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sleep(1);
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ sleep(1);
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ret = true;
+
+ done:
+
+ if (fhandle.data[0] != 0) {
+ smb2_util_close(tree, fhandle);
+ }
+
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+static bool test_compound_async_flush_flush(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fhandle = { .data = { 0, 0 } };
+ struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
+ struct smb2_flush fl1;
+ struct smb2_flush fl2;
+ const char *fname = "compound_async_flush_flush";
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool ret = false;
+
+ /* Start clean. */
+ smb2_util_unlink(tree, fname);
+
+ /* Create a file. */
+ status = torture_smb2_testfile_access(tree,
+ fname,
+ &fhandle,
+ SEC_RIGHTS_FILE_ALL);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Now do a compound flush + flush handle. */
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(fl1);
+ fl1.in.file.handle = fhandle;
+
+ req[0] = smb2_flush_send(tree, &fl1);
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_flush_send (1) failed\n");
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(fl2);
+ fl2.in.file.handle = relhandle;
+
+ req[1] = smb2_flush_send(tree, &fl2);
+ torture_assert_not_null_goto(tctx, req[1], ret, done,
+ "smb2_flush_send (2) failed\n");
+
+ status = smb2_flush_recv(req[0], &fl1);
+ /*
+ * On Windows, this flush will usually
+ * succeed as we have nothing to flush,
+ * so allow NT_STATUS_OK. Once bug #15172
+ * is fixed Samba will do the flush synchronously
+ * so allow NT_STATUS_OK.
+ */
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * If we didn't get NT_STATUS_OK, we *must*
+ * get NT_STATUS_INTERNAL_ERROR if the flush
+ * goes async.
+ *
+ * For pre-bugfix #15172 Samba, the flush goes async and
+ * we should get NT_STATUS_INTERNAL_ERROR.
+ */
+ torture_assert_ntstatus_equal_goto(tctx,
+ status,
+ NT_STATUS_INTERNAL_ERROR,
+ ret,
+ done,
+ "smb2_flush_recv (1) didn't return "
+ "NT_STATUS_INTERNAL_ERROR.\n");
+ }
+
+ /*
+ * If the flush is the last entry in a compound,
+ * it should always succeed even if it goes async.
+ */
+ status = smb2_flush_recv(req[1], &fl2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_flush_recv (2) failed.");
+
+ status = smb2_util_close(tree, fhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed.");
+ ZERO_STRUCT(fhandle);
+
+ /*
+ * Do several more operations on the tree, spaced
+ * out by 1 sec sleeps to make sure the server didn't
+ * crash on the close. The sleeps are required to
+ * make test test for a crash reliable, as we ensure
+ * the pthread fsync internally finishes and accesses
+ * freed memory. Without them the test occasionally
+ * passes as we disconnect before the pthread fsync
+ * finishes.
+ */
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sleep(1);
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ sleep(1);
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ret = true;
+
+ done:
+
+ if (fhandle.data[0] != 0) {
+ smb2_util_close(tree, fhandle);
+ }
+
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/*
+ * For Samba/smbd this test must be run against the aio_delay_inject share
+ * as we need to ensure the last write in the compound takes longer than
+ * 500 us, which is the threshold for going async in smbd SMB2 writes.
+ */
+
+static bool test_compound_async_write_write(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fhandle = { .data = { 0, 0 } };
+ struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
+ struct smb2_write w1;
+ struct smb2_write w2;
+ const char *fname = "compound_async_write_write";
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool is_smbd = torture_setting_bool(tctx, "smbd", true);
+ bool ret = false;
+
+ /* Start clean. */
+ smb2_util_unlink(tree, fname);
+
+ /* Create a file. */
+ status = torture_smb2_testfile_access(tree,
+ fname,
+ &fhandle,
+ SEC_RIGHTS_FILE_ALL);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Now do a compound write + write handle. */
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(w1);
+ w1.in.file.handle = fhandle;
+ w1.in.offset = 0;
+ w1.in.data = data_blob_talloc_zero(tctx, 64);
+ req[0] = smb2_write_send(tree, &w1);
+
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_write_send (1) failed\n");
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(w2);
+ w2.in.file.handle = relhandle;
+ w2.in.offset = 64;
+ w2.in.data = data_blob_talloc_zero(tctx, 64);
+ req[1] = smb2_write_send(tree, &w2);
+
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_write_send (2) failed\n");
+
+ status = smb2_write_recv(req[0], &w1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_write_recv (1) failed.");
+
+ if (!is_smbd) {
+ /*
+ * Windows and other servers don't go async.
+ */
+ status = smb2_write_recv(req[1], &w2);
+ } else {
+ /*
+ * For smbd, the second write should go async
+ * as it's the last element of a compound.
+ */
+ WAIT_FOR_ASYNC_RESPONSE(req[1]);
+ CHECK_VALUE(req[1]->cancel.can_cancel, true);
+ /*
+ * Now pick up the real return.
+ */
+ status = smb2_write_recv(req[1], &w2);
+ }
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_write_recv (2) failed.");
+
+ status = smb2_util_close(tree, fhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed.");
+ ZERO_STRUCT(fhandle);
+
+ ret = true;
+
+ done:
+
+ if (fhandle.data[0] != 0) {
+ smb2_util_close(tree, fhandle);
+ }
+
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/*
+ * For Samba/smbd this test must be run against the aio_delay_inject share
+ * as we need to ensure the last read in the compound takes longer than
+ * 500 us, which is the threshold for going async in smbd SMB2 reads.
+ */
+
+static bool test_compound_async_read_read(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fhandle = { .data = { 0, 0 } };
+ struct smb2_handle relhandle = { .data = { UINT64_MAX, UINT64_MAX } };
+ struct smb2_write w;
+ struct smb2_read r1;
+ struct smb2_read r2;
+ const char *fname = "compound_async_read_read";
+ struct smb2_request *req[2];
+ NTSTATUS status;
+ bool is_smbd = torture_setting_bool(tctx, "smbd", true);
+ bool ret = false;
+
+ /* Start clean. */
+ smb2_util_unlink(tree, fname);
+
+ /* Create a file. */
+ status = torture_smb2_testfile_access(tree,
+ fname,
+ &fhandle,
+ SEC_RIGHTS_FILE_ALL);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Write 128 bytes. */
+ ZERO_STRUCT(w);
+ w.in.file.handle = fhandle;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc_zero(tctx, 128);
+ status = smb2_write(tree, &w);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_write_recv (1) failed.");
+
+ /* Now do a compound read + read handle. */
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ ZERO_STRUCT(r1);
+ r1.in.file.handle = fhandle;
+ r1.in.length = 64;
+ r1.in.offset = 0;
+ req[0] = smb2_read_send(tree, &r1);
+
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_read_send (1) failed\n");
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(r2);
+ r2.in.file.handle = relhandle;
+ r2.in.length = 64;
+ r2.in.offset = 64;
+ req[1] = smb2_read_send(tree, &r2);
+
+ torture_assert_not_null_goto(tctx, req[0], ret, done,
+ "smb2_read_send (2) failed\n");
+
+ status = smb2_read_recv(req[0], tree, &r1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_read_recv (1) failed.");
+
+ if (!is_smbd) {
+ /*
+ * Windows and other servers don't go async.
+ */
+ status = smb2_read_recv(req[1], tree, &r2);
+ } else {
+ /*
+ * For smbd, the second write should go async
+ * as it's the last element of a compound.
+ */
+ WAIT_FOR_ASYNC_RESPONSE(req[1]);
+ CHECK_VALUE(req[1]->cancel.can_cancel, true);
+ /*
+ * Now pick up the real return.
+ */
+ status = smb2_read_recv(req[1], tree, &r2);
+ }
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_read_recv (2) failed.");
+
+ status = smb2_util_close(tree, fhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed.");
+ ZERO_STRUCT(fhandle);
+
+ ret = true;
+
+ done:
+
+ if (fhandle.data[0] != 0) {
+ smb2_util_close(tree, fhandle);
+ }
+
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+
+struct torture_suite *torture_smb2_compound_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "compound");
+
+ torture_suite_add_1smb2_test(suite, "related1", test_compound_related1);
+ torture_suite_add_1smb2_test(suite, "related2", test_compound_related2);
+ torture_suite_add_1smb2_test(suite, "related3",
+ test_compound_related3);
+ torture_suite_add_1smb2_test(suite, "related4",
+ test_compound_related4);
+ torture_suite_add_1smb2_test(suite, "related5",
+ test_compound_related5);
+ torture_suite_add_1smb2_test(suite, "related6",
+ test_compound_related6);
+ torture_suite_add_1smb2_test(suite, "related7",
+ test_compound_related7);
+ torture_suite_add_1smb2_test(suite, "related8",
+ test_compound_related8);
+ torture_suite_add_1smb2_test(suite, "related9",
+ test_compound_related9);
+ torture_suite_add_1smb2_test(suite, "unrelated1", test_compound_unrelated1);
+ torture_suite_add_1smb2_test(suite, "invalid1", test_compound_invalid1);
+ torture_suite_add_1smb2_test(suite, "invalid2", test_compound_invalid2);
+ torture_suite_add_1smb2_test(suite, "invalid3", test_compound_invalid3);
+ torture_suite_add_1smb2_test(
+ suite, "invalid4", test_compound_invalid4);
+ torture_suite_add_1smb2_test(suite, "interim1", test_compound_interim1);
+ torture_suite_add_1smb2_test(suite, "interim2", test_compound_interim2);
+ torture_suite_add_1smb2_test(suite, "compound-break", test_compound_break);
+ torture_suite_add_1smb2_test(suite, "compound-padding", test_compound_padding);
+ torture_suite_add_1smb2_test(suite, "create-write-close",
+ test_compound_create_write_close);
+
+ suite->description = talloc_strdup(suite, "SMB2-COMPOUND tests");
+
+ return suite;
+}
+
+struct torture_suite *torture_smb2_compound_find_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "compound_find");
+
+ torture_suite_add_1smb2_test(suite, "compound_find_related", test_compound_find_related);
+ torture_suite_add_1smb2_test(suite, "compound_find_unrelated", test_compound_find_unrelated);
+ torture_suite_add_1smb2_test(suite, "compound_find_close", test_compound_find_close);
+
+ suite->description = talloc_strdup(suite, "SMB2-COMPOUND-FIND tests");
+
+ return suite;
+}
+
+struct torture_suite *torture_smb2_compound_async_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx,
+ "compound_async");
+
+ torture_suite_add_1smb2_test(suite, "flush_close",
+ test_compound_async_flush_close);
+ torture_suite_add_1smb2_test(suite, "flush_flush",
+ test_compound_async_flush_flush);
+ torture_suite_add_1smb2_test(suite, "write_write",
+ test_compound_async_write_write);
+ torture_suite_add_1smb2_test(suite, "read_read",
+ test_compound_async_read_read);
+
+ suite->description = talloc_strdup(suite, "SMB2-COMPOUND-ASYNC tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c
new file mode 100644
index 0000000..5a2b48b
--- /dev/null
+++ b/source4/torture/smb2/connect.c
@@ -0,0 +1,257 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 connection operations
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+/*
+ send a close
+*/
+static NTSTATUS torture_smb2_close(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_handle handle)
+{
+ struct smb2_close io;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ ZERO_STRUCT(io);
+ io.in.file.handle = handle;
+ io.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
+ status = smb2_close(tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "close failed - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ if (DEBUGLVL(1)) {
+ torture_comment(tctx, "Close gave:\n");
+ torture_comment(tctx, "create_time = %s\n", nt_time_string(tmp_ctx, io.out.create_time));
+ torture_comment(tctx, "access_time = %s\n", nt_time_string(tmp_ctx, io.out.access_time));
+ torture_comment(tctx, "write_time = %s\n", nt_time_string(tmp_ctx, io.out.write_time));
+ torture_comment(tctx, "change_time = %s\n", nt_time_string(tmp_ctx, io.out.change_time));
+ torture_comment(tctx, "alloc_size = %lld\n", (long long)io.out.alloc_size);
+ torture_comment(tctx, "size = %lld\n", (long long)io.out.size);
+ torture_comment(tctx, "file_attr = 0x%x\n", io.out.file_attr);
+ }
+
+ talloc_free(tmp_ctx);
+
+ return status;
+}
+
+
+/*
+ test writing
+*/
+static NTSTATUS torture_smb2_write(struct torture_context *tctx, struct smb2_tree *tree, struct smb2_handle handle)
+{
+ struct smb2_write w;
+ struct smb2_read r;
+ struct smb2_flush f;
+ NTSTATUS status;
+ DATA_BLOB data;
+ int i;
+ uint32_t size = torture_setting_int(tctx, "smb2maxwrite", 64*1024);
+
+ data = data_blob_talloc(tree, NULL, size);
+ if (size != data.length) {
+ torture_comment(tctx, "data_blob_talloc(%u) failed\n", (unsigned int)size);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<data.length;i++) {
+ data.data[i] = i;
+ }
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = handle;
+ w.in.offset = 0;
+ w.in.data = data;
+
+ status = smb2_write(tree, &w);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "write 1 failed - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ torture_smb2_all_info(tctx, tree, handle);
+
+ status = smb2_write(tree, &w);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "write 2 failed - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ torture_smb2_all_info(tctx, tree, handle);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = handle;
+
+ status = smb2_flush(tree, &f);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "flush failed - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = handle;
+ r.in.length = data.length;
+ r.in.offset = 0;
+
+ status = smb2_read(tree, tree, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "read failed - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ if (data.length != r.out.data.length ||
+ memcmp(data.data, r.out.data.data, data.length) != 0) {
+ torture_comment(tctx, "read data mismatch\n");
+ return NT_STATUS_NET_WRITE_FAULT;
+ }
+
+ return status;
+}
+
+
+/*
+ send a create
+*/
+NTSTATUS torture_smb2_createfile(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ struct smb2_handle *handle)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = NTCREATEX_OPTIONS_WRITE_THROUGH;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tmp_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(tmp_ctx);
+ torture_comment(tctx, "create1 failed - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ if (DEBUGLVL(1)) {
+ torture_comment(tctx, "Open gave:\n");
+ torture_comment(tctx, "oplock_flags = 0x%x\n", io.out.oplock_level);
+ torture_comment(tctx, "create_action = 0x%x\n", io.out.create_action);
+ torture_comment(tctx, "create_time = %s\n", nt_time_string(tmp_ctx, io.out.create_time));
+ torture_comment(tctx, "access_time = %s\n", nt_time_string(tmp_ctx, io.out.access_time));
+ torture_comment(tctx, "write_time = %s\n", nt_time_string(tmp_ctx, io.out.write_time));
+ torture_comment(tctx, "change_time = %s\n", nt_time_string(tmp_ctx, io.out.change_time));
+ torture_comment(tctx, "alloc_size = %lld\n", (long long)io.out.alloc_size);
+ torture_comment(tctx, "size = %lld\n", (long long)io.out.size);
+ torture_comment(tctx, "file_attr = 0x%x\n", io.out.file_attr);
+ torture_comment(tctx, "handle = %016llx%016llx\n",
+ (long long)io.out.file.handle.data[0],
+ (long long)io.out.file.handle.data[1]);
+ }
+
+ talloc_free(tmp_ctx);
+
+ *handle = io.out.file.handle;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ basic testing of SMB2 connection calls
+*/
+bool torture_smb2_connect(struct torture_context *tctx)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_tree *tree;
+ struct smb2_request *req;
+ struct smb2_handle h1, h2;
+ NTSTATUS status;
+ bool ok;
+
+ ok = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ok, "torture_smb2_connection failed");
+
+ smb2_util_unlink(tree, "test9.dat");
+
+ status = torture_smb2_createfile(tctx, tree, "test9.dat", &h1);
+ torture_assert_ntstatus_ok(tctx, status, "create failed");
+
+ status = torture_smb2_createfile(tctx, tree, "test9.dat", &h2);
+ torture_assert_ntstatus_ok(tctx, status, "create failed");
+
+ status = torture_smb2_write(tctx, tree, h1);
+ torture_assert_ntstatus_ok(tctx, status, "write failed");
+
+ status = torture_smb2_close(tctx, tree, h1);
+ torture_assert_ntstatus_ok(tctx, status, "close failed");
+
+ status = torture_smb2_close(tctx, tree, h2);
+ torture_assert_ntstatus_ok(tctx, status, "close failed");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_CLOSED,
+ "close should have closed the handle");
+
+ status = smb2_tdis(tree);
+ torture_assert_ntstatus_ok(tctx, status, "tdis failed");
+
+ status = smb2_tdis(tree);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_NETWORK_NAME_DELETED,
+ "tdis should have closed the tcon");
+
+ status = smb2_logoff(tree->session);
+ torture_assert_ntstatus_ok(tctx, status, "logoff failed");
+
+ req = smb2_logoff_send(tree->session);
+ torture_assert_not_null(tctx, req, "smb2_logoff_send failed");
+
+ req->session = NULL;
+
+ status = smb2_logoff_recv(req);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_USER_SESSION_DELETED,
+ "logoff should have disabled session");
+
+ status = smb2_keepalive(tree->session->transport);
+ torture_assert_ntstatus_ok(tctx, status, "keepalive failed");
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c
new file mode 100644
index 0000000..c1d132d
--- /dev/null
+++ b/source4/torture/smb2/create.c
@@ -0,0 +1,3629 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 create test suite
+
+ Copyright (C) Andrew Tridgell 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+
+#include "system/filesys.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/security.h"
+#include "lib/events/events.h"
+
+#define FNAME "test_create.dat"
+#define DNAME "smb2_open"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ return false; \
+ }} while (0)
+
+#define CHECK_EQUAL(v, correct) do { \
+ if (v != correct) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value for %s 0x%08llx - " \
+ "should be 0x%08llx\n", \
+ __location__, #v, \
+ (unsigned long long)v, \
+ (unsigned long long)correct); \
+ return false; \
+ }} while (0)
+
+#define CHECK_TIME(t, field) do { \
+ time_t t1, t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo.all_info.in.file.handle = h1; \
+ status = smb2_getinfo_file(tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t1 = t & ~1; \
+ t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
+ if (abs(t1-t2) > 2) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong time for field %s %s - %s\n", \
+ __location__, #field, \
+ timestring(tctx, t1), \
+ timestring(tctx, t2)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_NTTIME(t, field) do { \
+ NTTIME t2; \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo.all_info.in.file.handle = h1; \
+ status = smb2_getinfo_file(tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ t2 = finfo.all_info.out.field; \
+ if (llabs((int64_t)(t-t2)) > 20000) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong time for field %s %s - %s\n", \
+ __location__, #field, \
+ nt_time_string(tctx, t), \
+ nt_time_string(tctx, t2)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_ALL_INFO(v, field) do { \
+ finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo.all_info.in.file.handle = h1; \
+ status = smb2_getinfo_file(tree, tctx, &finfo); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if ((v) != (finfo.all_info.out.field)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for field %s 0x%x - 0x%x\n", \
+ __location__, #field, (int)v,\
+ (int)(finfo.all_info.out.field)); \
+ dump_all_info(tctx, &finfo); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)(v), (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define SET_ATTRIB(sattrib) do { \
+ union smb_setfileinfo sfinfo; \
+ ZERO_STRUCT(sfinfo.basic_info.in); \
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
+ sfinfo.basic_info.in.file.handle = h1; \
+ sfinfo.basic_info.in.attrib = sattrib; \
+ status = smb2_setinfo_file(tree, &sfinfo); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_comment(tctx, \
+ "(%s) Failed to set attrib 0x%x on %s\n", \
+ __location__, (unsigned int)(sattrib), fname); \
+ }} while (0)
+
+/*
+ test some interesting combinations found by gentest
+ */
+static bool test_create_gentest(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t access_mask, file_attributes_set;
+ uint32_t ok_mask, not_supported_mask, invalid_parameter_mask;
+ uint32_t not_a_directory_mask, unexpected_mask;
+ union smb_fileinfo q;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.create_options = 0xF0000000;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ io.in.create_options = 0;
+
+ io.in.file_attributes = FILE_ATTRIBUTE_DEVICE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.file_attributes = FILE_ATTRIBUTE_VOLUME;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.desired_access = 0x08000000;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ io.in.desired_access = 0x04000000;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ ok_mask = 0;
+ not_supported_mask = 0;
+ invalid_parameter_mask = 0;
+ not_a_directory_mask = 0;
+ unexpected_mask = 0;
+ {
+ int i;
+ for (i=0;i<32;i++) {
+ io.in.create_options = (uint32_t)1<<i;
+ if (io.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
+ continue;
+ }
+ status = smb2_create(tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ not_supported_mask |= 1<<i;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ invalid_parameter_mask |= 1<<i;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
+ not_a_directory_mask |= 1<<i;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ ok_mask |= 1<<i;
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ } else {
+ unexpected_mask |= 1<<i;
+ torture_comment(tctx,
+ "create option 0x%08x returned %s\n",
+ 1<<i, nt_errstr(status));
+ }
+ }
+ }
+ io.in.create_options = 0;
+
+ CHECK_EQUAL(ok_mask, 0x00efcf7e);
+ CHECK_EQUAL(not_a_directory_mask, 0x00000001);
+ CHECK_EQUAL(not_supported_mask, 0x00102080);
+ CHECK_EQUAL(invalid_parameter_mask, 0xff000000);
+ CHECK_EQUAL(unexpected_mask, 0x00000000);
+
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.file_attributes = 0;
+ access_mask = 0;
+ {
+ int i;
+ for (i=0;i<32;i++) {
+ io.in.desired_access = (uint32_t)1<<i;
+ status = smb2_create(tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_PRIVILEGE_NOT_HELD)) {
+ access_mask |= io.in.desired_access;
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+ }
+ }
+
+ if (TARGET_IS_WIN7(tctx)) {
+ CHECK_EQUAL(access_mask, 0x0de0fe00);
+ } else if (torture_setting_bool(tctx, "samba4", false)) {
+ CHECK_EQUAL(access_mask, 0x0cf0fe00);
+ } else {
+ CHECK_EQUAL(access_mask, 0x0df0fe00);
+ }
+
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = 0;
+ ok_mask = 0;
+ invalid_parameter_mask = 0;
+ unexpected_mask = 0;
+ file_attributes_set = 0;
+ {
+ int i;
+ for (i=0;i<32;i++) {
+ io.in.file_attributes = (uint32_t)1<<i;
+ if (io.in.file_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
+ continue;
+ }
+ smb2_deltree(tree, FNAME);
+ status = smb2_create(tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ invalid_parameter_mask |= 1<<i;
+ } else if (NT_STATUS_IS_OK(status)) {
+ uint32_t expected;
+ ok_mask |= 1<<i;
+
+ expected = (io.in.file_attributes | FILE_ATTRIBUTE_ARCHIVE) & 0x00005127;
+ io.out.file_attr &= ~FILE_ATTRIBUTE_NONINDEXED;
+ CHECK_EQUAL(io.out.file_attr, expected);
+ file_attributes_set |= io.out.file_attr;
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ } else {
+ unexpected_mask |= 1<<i;
+ torture_comment(tctx,
+ "file attribute 0x%08x returned %s\n",
+ 1<<i, nt_errstr(status));
+ }
+ }
+ }
+
+ CHECK_EQUAL(ok_mask, 0x00003fb7);
+ CHECK_EQUAL(invalid_parameter_mask, 0xffff8048);
+ CHECK_EQUAL(unexpected_mask, 0x00000000);
+ CHECK_EQUAL(file_attributes_set, 0x00001127);
+
+ smb2_deltree(tree, FNAME);
+
+ /*
+ * Standalone servers doesn't support encryption
+ */
+ io.in.file_attributes = FILE_ATTRIBUTE_ENCRYPTED;
+ status = smb2_create(tree, tctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ torture_comment(tctx,
+ "FILE_ATTRIBUTE_ENCRYPTED returned %s\n",
+ nt_errstr(status));
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_EQUAL(io.out.file_attr, (FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE));
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ smb2_deltree(tree, FNAME);
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = FNAME ":stream1";
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.in.fname = FNAME;
+ io.in.file_attributes = 0x8040;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ io.in.fname = FNAME;
+ io.in.file_attributes = 0;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
+ io.in.query_maximal_access = true;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
+
+ q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ q.access_information.in.file.handle = io.out.file.handle;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_EQUAL(q.access_information.out.access_flags, io.in.desired_access);
+
+ io.in.file_attributes = 0;
+ io.in.desired_access = 0;
+ io.in.query_maximal_access = false;
+ io.in.share_access = 0;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ smb2_deltree(tree, FNAME);
+
+ return true;
+}
+
+
+/*
+ try the various request blobs
+ */
+static bool test_create_blob(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ smb2_deltree(tree, FNAME);
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing alloc size\n");
+ /* FIXME We use 1M cause that's the rounded size of Samba.
+ * We should ask the server for the cluster size and calculate it
+ * correctly. */
+ io.in.alloc_size = 0x00100000;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing durable open\n");
+ io.in.durable_open = true;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing query maximal access\n");
+ io.in.query_maximal_access = true;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing timewarp\n");
+ io.in.timewarp = 10000;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ io.in.timewarp = 0;
+
+ torture_comment(tctx, "Testing query_on_disk\n");
+ io.in.query_on_disk_id = true;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing unknown tag\n");
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "FooO", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing bad tag length 0\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "x", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(tctx, "Testing bad tag length 1\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "x", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(tctx, "Testing bad tag length 2\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(tctx, "Testing bad tag length 3\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(tctx, "Testing tag length 4\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 5\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 6\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 7\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 8\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxxxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 16\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxxxxxxxxxxxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 17\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxxxxxxxxxxxxxx", data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "Testing tag length 34\n");
+ ZERO_STRUCT(io.in.blobs);
+ status = smb2_create_blob_add(tctx, &io.in.blobs,
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ data_blob(NULL, 0));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_deltree(tree, FNAME);
+
+ return true;
+}
+
+#define FAIL_UNLESS(__cond) \
+ do { \
+ if (__cond) {} else { \
+ torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
+ __location__, #__cond); \
+ ret = false; goto done; \
+ } \
+ } while(0)
+
+/*
+ try creating with acls
+ */
+static bool test_create_acl_ext(struct torture_context *tctx, struct smb2_tree *tree, bool test_dir)
+{
+ bool ret = true;
+ struct smb2_create io;
+ NTSTATUS status;
+ struct security_ace ace;
+ struct security_descriptor *sd;
+ struct dom_sid *test_sid;
+ union smb_fileinfo q = {};
+ uint32_t attrib =
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM |
+ (test_dir ? FILE_ATTRIBUTE_DIRECTORY : 0);
+ NTSTATUS (*delete_func)(struct smb2_tree *, const char *) =
+ test_dir ? smb2_util_rmdir : smb2_util_unlink;
+
+ ZERO_STRUCT(ace);
+
+ smb2_deltree(tree, FNAME);
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT | 0x00200000 |
+ (test_dir ? NTCREATEX_OPTIONS_DIRECTORY :
+ (NTCREATEX_OPTIONS_NON_DIRECTORY_FILE));
+
+ io.in.fname = FNAME;
+
+ torture_comment(tctx, "basic create\n");
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = io.out.file.handle;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd = q.query_secdesc.out.sd;
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "adding a new ACE\n");
+ test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS);
+
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_STD_ALL;
+ ace.trustee = *test_sid;
+
+ status = security_descriptor_dacl_add(sd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating a file with an initial ACL\n");
+
+ io.in.sec_desc = sd;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating with attributes\n");
+
+ io.in.sec_desc = NULL;
+ io.in.file_attributes = attrib;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating with attributes and ACL\n");
+
+ io.in.sec_desc = sd;
+ io.in.file_attributes = attrib;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
+ FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "creating with attributes, ACL and owner\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, SID_WORLD, SID_BUILTIN_USERS,
+ SID_WORLD,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ | SEC_STD_ALL,
+ 0,
+ NULL);
+
+ io.in.sec_desc = sd;
+ io.in.file_attributes = attrib;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, io.out.file.handle, sd));
+ FAIL_UNLESS(smb2_util_verify_attrib(tctx, tree, io.out.file.handle, attrib));
+
+ done:
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = delete_func(tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ return ret;
+}
+
+/*
+ test SMB2 open
+*/
+static bool test_smb2_open(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = DNAME "\\torture_ntcreatex.txt";
+ const char *dname = DNAME "\\torture_ntcreatex.dir";
+ NTSTATUS status;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h1 = {{0}};
+ bool ret = true;
+ size_t i;
+ struct {
+ uint32_t create_disp;
+ bool with_file;
+ NTSTATUS correct_status;
+ } open_funcs[] = {
+ { NTCREATEX_DISP_SUPERSEDE, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_SUPERSEDE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_CREATE, true, NT_STATUS_OBJECT_NAME_COLLISION },
+ { NTCREATEX_DISP_CREATE, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OPEN_IF, false, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE, false, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NTCREATEX_DISP_OVERWRITE_IF, true, NT_STATUS_OK },
+ { NTCREATEX_DISP_OVERWRITE_IF, false, NT_STATUS_OK },
+ { 6, true, NT_STATUS_INVALID_PARAMETER },
+ { 6, false, NT_STATUS_INVALID_PARAMETER },
+ };
+
+ torture_comment(tctx, "Checking SMB2 Open\n");
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, dname);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io.smb2);
+ /* reasonable default parameters */
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 1024*1024;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /* test the create disposition */
+ for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+ if (open_funcs[i].with_file) {
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status= smb2_create(tree, tctx, &(io.smb2));
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx,
+ "Failed to create file %s status %s %zu\n",
+ fname, nt_errstr(status), i);
+
+ ret = false;
+ goto done;
+ }
+ smb2_util_close(tree, io.smb2.out.file.handle);
+ }
+ io.smb2.in.create_disposition = open_funcs[i].create_disp;
+ status = smb2_create(tree, tctx, &(io.smb2));
+ if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
+ torture_comment(tctx,
+ "(%s) incorrect status %s should be %s (i=%zu "
+ "with_file=%d open_disp=%d)\n",
+ __location__, nt_errstr(status),
+ nt_errstr(open_funcs[i].correct_status),
+ i, (int)open_funcs[i].with_file,
+ (int)open_funcs[i].create_disp);
+
+ ret = false;
+ goto done;
+ }
+ if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
+ smb2_util_close(tree, io.smb2.out.file.handle);
+ smb2_util_unlink(tree, fname);
+ }
+ }
+
+ /* basic field testing */
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ CHECK_VAL(io.smb2.out.oplock_level, 0);
+ CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.smb2.out.create_time, create_time);
+ CHECK_NTTIME(io.smb2.out.access_time, access_time);
+ CHECK_NTTIME(io.smb2.out.write_time, write_time);
+ CHECK_NTTIME(io.smb2.out.change_time, change_time);
+ CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
+ CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.smb2.out.size, size);
+
+ /* check fields when the file already existed */
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+
+ status = smb2_create_complex_file(tctx, tree, fname, &h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h1);
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ CHECK_VAL(io.smb2.out.oplock_level, 0);
+ CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_NTTIME(io.smb2.out.create_time, create_time);
+ CHECK_NTTIME(io.smb2.out.access_time, access_time);
+ CHECK_NTTIME(io.smb2.out.write_time, write_time);
+ CHECK_NTTIME(io.smb2.out.change_time, change_time);
+ CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
+ CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.smb2.out.size, size);
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+
+ /* create a directory */
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.fname = dname;
+ fname = dname;
+
+ smb2_util_rmdir(tree, fname);
+ smb2_util_unlink(tree, fname);
+
+ io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ CHECK_VAL(io.smb2.out.oplock_level, 0);
+ CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_NTTIME(io.smb2.out.create_time, create_time);
+ CHECK_NTTIME(io.smb2.out.access_time, access_time);
+ CHECK_NTTIME(io.smb2.out.write_time, write_time);
+ CHECK_NTTIME(io.smb2.out.change_time, change_time);
+ CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
+ CHECK_VAL(io.smb2.out.file_attr & ~FILE_ATTRIBUTE_NONINDEXED,
+ FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_ALL_INFO(io.smb2.out.alloc_size, alloc_size);
+ CHECK_ALL_INFO(io.smb2.out.size, size);
+ CHECK_VAL(io.smb2.out.size, 0);
+ smb2_util_unlink(tree, fname);
+
+done:
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ return ret;
+}
+
+/*
+ test with an already opened and byte range locked file
+*/
+
+static bool test_smb2_open_brlocked(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ union smb_open io, io1;
+ union smb_lock io2;
+ struct smb2_lock_element lock[1];
+ const char *fname = DNAME "\\torture_ntcreatex.txt";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h;
+ char b = 42;
+
+ torture_comment(tctx,
+ "Testing SMB2 open with a byte range locked file\n");
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.desired_access = 0x2019f;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ io.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
+ io.smb2.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, io.smb2.out.file.handle, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io2.smb2);
+ io2.smb2.level = RAW_LOCK_SMB2;
+ io2.smb2.in.file.handle = io.smb2.out.file.handle;
+ io2.smb2.in.lock_count = 1;
+
+ ZERO_STRUCT(lock);
+ lock[0].offset = 0;
+ lock[0].length = 1;
+ lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ io2.smb2.in.locks = &lock[0];
+ status = smb2_lock(tree, &(io2.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io1.smb2);
+ io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io1.smb2.in.desired_access = 0x20196;
+ io1.smb2.in.alloc_size = 0;
+ io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io1.smb2.in.create_options = 0;
+ io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ io1.smb2.in.security_flags = SMB2_SECURITY_DYNAMIC_TRACKING;
+ io1.smb2.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, io.smb2.out.file.handle);
+ smb2_util_close(tree, io1.smb2.out.file.handle);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ return ret;
+}
+
+/* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
+
+static bool test_smb2_open_multi(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_oplock.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_tree **trees;
+ struct smb2_request **requests;
+ union smb_open *ios;
+ int i, num_files = 3;
+ int num_ok = 0;
+ int num_collision = 0;
+
+ torture_comment(tctx,
+ "Testing SMB2 Open with multiple connections\n");
+ trees = talloc_array(tctx, struct smb2_tree *, num_files);
+ requests = talloc_array(tctx, struct smb2_request *, num_files);
+ ios = talloc_array(tctx, union smb_open, num_files);
+ if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
+ (ios == NULL)) {
+ torture_comment(tctx, ("talloc failed\n"));
+ ret = false;
+ goto done;
+ }
+
+ tree->session->transport->options.request_timeout = 60;
+
+ for (i=0; i<num_files; i++) {
+ if (!torture_smb2_connection(tctx, &(trees[i]))) {
+ torture_comment(tctx,
+ "Could not open %d'th connection\n", i);
+ ret = false;
+ goto done;
+ }
+ trees[i]->session->transport->options.request_timeout = 60;
+ }
+
+ /* cleanup */
+ smb2_util_unlink(tree, fname);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_flags = 0;
+
+ for (i=0; i<num_files; i++) {
+ ios[i] = io;
+ requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
+ if (requests[i] == NULL) {
+ torture_comment(tctx,
+ "could not send %d'th request\n", i);
+ ret = false;
+ goto done;
+ }
+ }
+
+ torture_comment(tctx, "waiting for replies\n");
+ while (1) {
+ bool unreplied = false;
+ for (i=0; i<num_files; i++) {
+ if (requests[i] == NULL) {
+ continue;
+ }
+ if (requests[i]->state < SMB2_REQUEST_DONE) {
+ unreplied = true;
+ break;
+ }
+ status = smb2_create_recv(requests[i], tctx,
+ &(ios[i].smb2));
+
+ torture_comment(tctx,
+ "File %d returned status %s\n", i,
+ nt_errstr(status));
+
+ if (NT_STATUS_IS_OK(status)) {
+ num_ok += 1;
+ }
+
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_COLLISION)) {
+ num_collision += 1;
+ }
+
+ requests[i] = NULL;
+ }
+ if (!unreplied) {
+ break;
+ }
+
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_comment(tctx, "tevent_loop_once failed\n");
+ ret = false;
+ goto done;
+ }
+ }
+
+ if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
+ ret = false;
+ }
+done:
+ smb2_deltree(tree, fname);
+
+ return ret;
+}
+
+/*
+ test opening for delete on a read-only attribute file.
+*/
+
+static bool test_smb2_open_for_delete(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ union smb_open io;
+ union smb_fileinfo finfo;
+ const char *fname = DNAME "\\torture_open_for_delete.txt";
+ NTSTATUS status;
+ struct smb2_handle h, h1;
+ bool ret = true;
+
+ torture_comment(tctx,
+ "Checking SMB2_OPEN for delete on a readonly file.\n");
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* reasonable default parameters */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_READONLY;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /* Create the readonly file. */
+
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ CHECK_VAL(io.smb2.out.oplock_level, 0);
+ io.smb2.in.create_options = 0;
+ CHECK_VAL(io.smb2.out.create_action, NTCREATEX_ACTION_CREATED);
+ CHECK_ALL_INFO(io.smb2.out.file_attr, attrib);
+ smb2_util_close(tree, h1);
+
+ /* Now try and open for delete only - should succeed. */
+ io.smb2.in.desired_access = SEC_STD_DELETE;
+ io.smb2.in.file_attributes = 0;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /* Clear readonly flag to allow file deletion */
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ status = smb2_create(tree, tctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+ SET_ATTRIB(FILE_ATTRIBUTE_ARCHIVE);
+ smb2_util_close(tree, h1);
+
+ smb2_util_close(tree, h);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ return ret;
+}
+
+/*
+ test SMB2 open with a leading slash on the path.
+ Trying to create a directory with a leading slash
+ should give NT_STATUS_INVALID_PARAMETER error
+*/
+static bool test_smb2_leading_slash(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ union smb_open io;
+ const char *dnameslash = "\\"DNAME;
+ NTSTATUS status;
+ bool ret = true;
+
+ torture_comment(tctx,
+ "Trying to create a directory with leading slash on path\n");
+ smb2_deltree(tree, dnameslash);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.oplock_level = 0;
+ io.smb2.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.fname = dnameslash;
+
+ status = smb2_create(tree, tree, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ smb2_deltree(tree, dnameslash);
+ return ret;
+}
+
+/*
+ test SMB2 open with an invalid impersonation level.
+ Should give NT_STATUS_BAD_IMPERSONATION_LEVEL error
+*/
+static bool test_smb2_impersonation_level(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ union smb_open io;
+ const char *fname = DNAME "\\torture_invalid_impersonation_level.txt";
+ NTSTATUS status;
+ struct smb2_handle h;
+ bool ret = true;
+
+ torture_comment(tctx,
+ "Testing SMB2 open with an invalid impersonation level.\n");
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = 0x12345678;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_flags = 0;
+
+ status = smb2_create(tree, tree, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_BAD_IMPERSONATION_LEVEL);
+
+ smb2_util_close(tree, h);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ return ret;
+}
+
+static bool test_create_acl_file(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ torture_comment(tctx, "Testing nttrans create with sec_desc on files\n");
+
+ return test_create_acl_ext(tctx, tree, false);
+}
+
+static bool test_create_acl_dir(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ torture_comment(tctx, "Testing nttrans create with sec_desc on directories\n");
+
+ return test_create_acl_ext(tctx, tree, true);
+}
+
+#define CHECK_ACCESS_FLAGS(_fh, flags) do { \
+ union smb_fileinfo _q; \
+ _q.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; \
+ _q.access_information.in.file.handle = (_fh); \
+ status = smb2_getinfo_file(tree, tctx, &_q); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ if (_q.access_information.out.access_flags != (flags)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect access_flags 0x%08x - should be 0x%08x\n", \
+ __location__, _q.access_information.out.access_flags, (flags)); \
+ ret = false; \
+ goto done; \
+ } \
+} while (0)
+
+/*
+ * Test creating a file with a NULL DACL.
+ */
+static bool test_create_null_dacl(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ const char *fname = "nulldacl.txt";
+ bool ret = true;
+ struct smb2_handle handle;
+ union smb_fileinfo q;
+ union smb_setfileinfo s;
+ struct security_descriptor *sd = security_descriptor_initialise(tctx);
+ struct security_acl dacl;
+
+ torture_comment(tctx, "TESTING SEC_DESC WITH A NULL DACL\n");
+
+ smb2_util_unlink(tree, fname);
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access = SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC
+ | SEC_STD_WRITE_OWNER;
+ io.in.create_options = 0;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = fname;
+ io.in.sec_desc = sd;
+ /* XXX create_options ? */
+ io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+
+ torture_comment(tctx, "creating a file with a empty sd\n");
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Testing the created DACL,
+ * the server should add the inherited DACL
+ * when SEC_DESC_DACL_PRESENT isn't specified
+ */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
+ }
+ if (q.query_secdesc.out.sd->dacl == NULL) {
+ ret = false;
+ torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
+ }
+
+ torture_comment(tctx, "set NULL DACL\n");
+ sd->type |= SEC_DESC_DACL_PRESENT;
+
+ s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ s.set_secdesc.in.file.handle = handle;
+ s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ s.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &s);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "get the sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Testing the modified DACL */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
+ }
+ if (q.query_secdesc.out.sd->dacl != NULL) {
+ ret = false;
+ torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
+ }
+
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ torture_comment(tctx, "try open for read control\n");
+ io.in.desired_access = SEC_STD_READ_CONTROL;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_STD_READ_CONTROL);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for write\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_FILE_WRITE_DATA);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for read\n");
+ io.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_FILE_READ_DATA);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for generic write\n");
+ io.in.desired_access = SEC_GENERIC_WRITE;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_RIGHTS_FILE_WRITE);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for generic read\n");
+ io.in.desired_access = SEC_GENERIC_READ;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_RIGHTS_FILE_READ);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "set DACL with 0 aces\n");
+ ZERO_STRUCT(dacl);
+ dacl.revision = SECURITY_ACL_REVISION_NT4;
+ dacl.num_aces = 0;
+ sd->dacl = &dacl;
+
+ s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ s.set_secdesc.in.file.handle = handle;
+ s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ s.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &s);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "get the sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Testing the modified DACL */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
+ }
+ if (q.query_secdesc.out.sd->dacl == NULL) {
+ ret = false;
+ torture_fail_goto(tctx, done, "no DACL has been created on the server!\n");
+ }
+ if (q.query_secdesc.out.sd->dacl->num_aces != 0) {
+ torture_result(tctx, TORTURE_FAIL, "DACL has %u aces!\n",
+ q.query_secdesc.out.sd->dacl->num_aces);
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(tctx, "try open for read control\n");
+ io.in.desired_access = SEC_STD_READ_CONTROL;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_ACCESS_FLAGS(io.out.file.handle,
+ SEC_STD_READ_CONTROL);
+ smb2_util_close(tree, io.out.file.handle);
+
+ torture_comment(tctx, "try open for write => access_denied\n");
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "try open for read => access_denied\n");
+ io.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "try open for generic write => access_denied\n");
+ io.in.desired_access = SEC_GENERIC_WRITE;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "try open for generic read => access_denied\n");
+ io.in.desired_access = SEC_GENERIC_READ;
+ status = smb2_create(tree, tctx, &io);
+ if (torture_setting_bool(tctx, "hide_on_access_denied", false)) {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+ }
+
+ torture_comment(tctx, "set empty sd\n");
+ sd->type &= ~SEC_DESC_DACL_PRESENT;
+ sd->dacl = NULL;
+
+ s.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ s.set_secdesc.in.file.handle = handle;
+ s.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ s.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &s);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "get the sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Testing the modified DACL */
+ if (!(q.query_secdesc.out.sd->type & SEC_DESC_DACL_PRESENT)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "DACL_PRESENT flag not set by the server!\n");
+ }
+ if (q.query_secdesc.out.sd->dacl != NULL) {
+ ret = false;
+ torture_fail_goto(tctx, done, "DACL has been created on the server!\n");
+ }
+done:
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+ smb2_tdis(tree);
+ smb2_logoff(tree->session);
+ return ret;
+}
+
+/*
+ test SMB2 mkdir with OPEN_IF on the same name twice.
+ Must use 2 connections to hit the race.
+*/
+
+static bool test_mkdir_dup(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "mkdir_dup";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_tree **trees;
+ struct smb2_request **requests;
+ union smb_open *ios;
+ int i, num_files = 2;
+ int num_ok = 0;
+ int num_created = 0;
+ int num_existed = 0;
+
+ torture_comment(tctx,
+ "Testing SMB2 Create Directory with multiple connections\n");
+ trees = talloc_array(tctx, struct smb2_tree *, num_files);
+ requests = talloc_array(tctx, struct smb2_request *, num_files);
+ ios = talloc_array(tctx, union smb_open, num_files);
+ if ((tctx->ev == NULL) || (trees == NULL) || (requests == NULL) ||
+ (ios == NULL)) {
+ torture_fail(tctx, ("talloc failed\n"));
+ ret = false;
+ goto done;
+ }
+
+ tree->session->transport->options.request_timeout = 60;
+
+ for (i=0; i<num_files; i++) {
+ if (!torture_smb2_connection(tctx, &(trees[i]))) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "Could not open %d'th connection\n", i));
+ ret = false;
+ goto done;
+ }
+ trees[i]->session->transport->options.request_timeout = 60;
+ }
+
+ /* cleanup */
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, fname);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_flags = 0;
+
+ for (i=0; i<num_files; i++) {
+ ios[i] = io;
+ requests[i] = smb2_create_send(trees[i], &(ios[i].smb2));
+ if (requests[i] == NULL) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "could not send %d'th request\n", i));
+ ret = false;
+ goto done;
+ }
+ }
+
+ torture_comment(tctx, "waiting for replies\n");
+ while (1) {
+ bool unreplied = false;
+ for (i=0; i<num_files; i++) {
+ if (requests[i] == NULL) {
+ continue;
+ }
+ if (requests[i]->state < SMB2_REQUEST_DONE) {
+ unreplied = true;
+ break;
+ }
+ status = smb2_create_recv(requests[i], tctx,
+ &(ios[i].smb2));
+
+ if (NT_STATUS_IS_OK(status)) {
+ num_ok += 1;
+
+ if (ios[i].smb2.out.create_action ==
+ NTCREATEX_ACTION_CREATED) {
+ num_created++;
+ }
+ if (ios[i].smb2.out.create_action ==
+ NTCREATEX_ACTION_EXISTED) {
+ num_existed++;
+ }
+ } else {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "File %d returned status %s\n", i,
+ nt_errstr(status)));
+ }
+
+
+ requests[i] = NULL;
+ }
+ if (!unreplied) {
+ break;
+ }
+
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_fail(tctx, "tevent_loop_once failed\n");
+ ret = false;
+ goto done;
+ }
+ }
+
+ if (num_ok != 2) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "num_ok == %d\n", num_ok));
+ ret = false;
+ }
+ if (num_created != 1) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "num_created == %d\n", num_created));
+ ret = false;
+ }
+ if (num_existed != 1) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "num_existed == %d\n", num_existed));
+ ret = false;
+ }
+done:
+ smb2_deltree(tree, fname);
+
+ return ret;
+}
+
+/*
+ test directory creation with an initial allocation size > 0
+*/
+static bool test_dir_alloc_size(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ const char *dname = DNAME "\\torture_alloc_size.dir";
+ NTSTATUS status;
+ struct smb2_create c;
+ struct smb2_handle h1 = {{0}}, h2;
+
+ torture_comment(tctx, "Checking initial allocation size on directories\n");
+
+ smb2_deltree(tree, dname);
+
+ status = torture_smb2_testdir(tree, DNAME, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
+
+ ZERO_STRUCT(c);
+ c.in.create_disposition = NTCREATEX_DISP_CREATE;
+ c.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ c.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ c.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ c.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ c.in.fname = dname;
+ /*
+ * An insanely large value so we can check the value is
+ * ignored: Samba either returns 0 (current behaviour), or,
+ * once vfswrap_get_alloc_size() is fixed to allow retrieving
+ * the allocated size for directories, returns
+ * smb_roundup(..., stat.st_size) which would be 1 MB by
+ * default.
+ *
+ * Windows returns 0 for empty directories, once directories
+ * have a few entries it starts replying with values > 0.
+ */
+ c.in.alloc_size = 1024*1024*1024;
+
+ status = smb2_create(tree, tctx, &c);
+ h2 = c.out.file.handle;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "dir create with initial alloc size failed");
+
+ smb2_util_close(tree, h2);
+
+ torture_comment(tctx, "Got directory alloc size: %ju\n", (uintmax_t)c.out.alloc_size);
+
+ /*
+ * See above for the rational for this test
+ */
+ if (c.out.alloc_size > 1024*1024) {
+ torture_fail_goto(tctx, done, talloc_asprintf(tctx, "bad alloc size: %ju",
+ (uintmax_t)c.out.alloc_size));
+ }
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_deltree(tree, DNAME);
+ return ret;
+}
+
+static bool test_twrp_write(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ struct smb2_handle h1 = {{0}};
+ NTSTATUS status;
+ bool ret = true;
+ char *p = NULL;
+ struct tm tm;
+ time_t t;
+ uint64_t nttime;
+ const char *file = NULL;
+ const char *snapshot = NULL;
+ uint32_t expected_access;
+ union smb_fileinfo getinfo;
+ union smb_setfileinfo setinfo;
+ struct security_descriptor *sd = NULL, *sd_orig = NULL;
+ const char *owner_sid = NULL;
+ struct create_disps_tests {
+ const char *file;
+ uint32_t create_disposition;
+ uint32_t create_options;
+ NTSTATUS expected_status;
+ };
+ struct create_disps_tests *cd_test = NULL;
+
+ file = torture_setting_string(tctx, "twrp_file", NULL);
+ if (file == NULL) {
+ torture_skip(tctx, "missing 'twrp_file' option\n");
+ }
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_skip(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ torture_comment(tctx, "Testing timewarp (%s) (%s)\n", file, snapshot);
+
+ setenv("TZ", "GMT", 1);
+
+ /* strptime does not set tm.tm_isdst but mktime assumes DST is in
+ * effect if it is greater than 1. */
+ ZERO_STRUCT(tm);
+
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ t = mktime(&tm);
+ unix_to_nt_time(&nttime, t);
+
+ io = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = file,
+ .in.query_maximal_access = true,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ smb2_util_close(tree, io.out.file.handle);
+
+ expected_access = SEC_RIGHTS_FILE_ALL &
+ ~(SEC_FILE_EXECUTE | SEC_DIR_DELETE_CHILD);
+
+ torture_assert_int_equal_goto(tctx,
+ io.out.maximal_access & expected_access,
+ expected_access,
+ ret, done, "Bad access\n");
+
+ {
+ /*
+ * Test create dispositions
+ */
+ struct create_disps_tests cd_tests[] = {
+ {
+ .file = file,
+ .create_disposition = NTCREATEX_DISP_OPEN,
+ .expected_status = NT_STATUS_OK,
+ },
+ {
+ .file = file,
+ .create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .expected_status = NT_STATUS_OK,
+ },
+ {
+ .file = file,
+ .create_disposition = NTCREATEX_DISP_OVERWRITE,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = file,
+ .create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = file,
+ .create_disposition = NTCREATEX_DISP_SUPERSEDE,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = "newfile",
+ .create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = "newfile",
+ .create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = "newfile",
+ .create_disposition = NTCREATEX_DISP_CREATE,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = "newfile",
+ .create_disposition = NTCREATEX_DISP_SUPERSEDE,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = "newdir",
+ .create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = "newdir",
+ .create_disposition = NTCREATEX_DISP_CREATE,
+ .create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .expected_status = NT_STATUS_MEDIA_WRITE_PROTECTED,
+ },
+ {
+ .file = NULL,
+ },
+ };
+
+ for (cd_test = &cd_tests[0]; cd_test->file != NULL; cd_test++) {
+ io = (struct smb2_create) {
+ .in.fname = cd_test->file,
+ .in.create_disposition = cd_test->create_disposition,
+ .in.create_options = cd_test->create_options,
+
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, cd_test->expected_status, ret, done,
+ "Bad status\n");
+ }
+ }
+
+ io = (struct smb2_create) {
+ .in.desired_access = expected_access,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = file,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h1 = io.out.file.handle;
+
+ status = smb2_util_write(tree, h1, "123", 0, 3);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_MEDIA_WRITE_PROTECTED,
+ ret, done, "smb2_create\n");
+
+ /*
+ * Verify access mask
+ */
+
+ ZERO_STRUCT(getinfo);
+ getinfo.generic.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ getinfo.generic.in.file.handle = h1;
+
+ status = smb2_getinfo_file(tree, tree, &getinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file\n");
+
+ torture_assert_int_equal_goto(
+ tctx,
+ getinfo.access_information.out.access_flags,
+ expected_access,
+ ret, done,
+ "Bad access mask\n");
+
+ /*
+ * Check we can't set various things
+ */
+
+ ZERO_STRUCT(getinfo);
+ getinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ getinfo.query_secdesc.in.file.handle = h1;
+ getinfo.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+
+ status = smb2_getinfo_file(tree, tctx, &getinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file\n");
+
+ sd_orig = getinfo.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_WRITE_DATA,
+ 0,
+ NULL);
+
+ /* Try to set ACL */
+
+ ZERO_STRUCT(setinfo);
+ setinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ setinfo.set_secdesc.in.file.handle = h1;
+ setinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ setinfo.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx,
+ status,
+ NT_STATUS_MEDIA_WRITE_PROTECTED,
+ ret, done,
+ "smb2_setinfo_file\n");
+
+ /* Try to delete */
+
+ ZERO_STRUCT(setinfo);
+ setinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ setinfo.disposition_info.in.delete_on_close = 1;
+ setinfo.generic.in.file.handle = h1;
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx,
+ status,
+ NT_STATUS_MEDIA_WRITE_PROTECTED,
+ ret, done,
+ "smb2_setinfo_file\n");
+
+ ZERO_STRUCT(setinfo);
+ setinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ setinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ setinfo.generic.in.file.handle = h1;
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx,
+ status,
+ NT_STATUS_MEDIA_WRITE_PROTECTED,
+ ret, done,
+ "smb2_setinfo_file\n");
+
+ /* Try to truncate */
+
+ ZERO_STRUCT(setinfo);
+ setinfo.generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
+ setinfo.generic.in.file.handle = h1;
+ setinfo.end_of_file_info.in.size = 0x100000;
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx,
+ status,
+ NT_STATUS_MEDIA_WRITE_PROTECTED,
+ ret, done,
+ "smb2_setinfo_file\n");
+
+ /* Try to set a hardlink */
+
+ ZERO_STRUCT(setinfo);
+ setinfo.generic.level = RAW_SFILEINFO_LINK_INFORMATION;
+ setinfo.generic.in.file.handle = h1;
+ setinfo.link_information.in.new_name = "hardlink";
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx,
+ status,
+ NT_STATUS_NOT_SAME_DEVICE,
+ ret, done,
+ "smb2_setinfo_file\n");
+
+ /* Try to rename */
+
+ ZERO_STRUCT(setinfo);
+ setinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ setinfo.rename_information.in.file.handle = h1;
+ setinfo.rename_information.in.new_name = "renamed";
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx,
+ status,
+ NT_STATUS_NOT_SAME_DEVICE,
+ ret, done,
+ "smb2_setinfo_file\n");
+
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ return ret;
+}
+
+static bool test_twrp_stream(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ bool ret = true;
+ char *p = NULL;
+ struct tm tm;
+ time_t t;
+ uint64_t nttime;
+ const char *file = NULL;
+ const char *stream = NULL;
+ const char *snapshot = NULL;
+ int stream_size;
+ char *path = NULL;
+ uint8_t *buf = NULL;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_read r;
+
+ file = torture_setting_string(tctx, "twrp_file", NULL);
+ if (file == NULL) {
+ torture_skip(tctx, "missing 'twrp_file' option\n");
+ }
+
+ stream = torture_setting_string(tctx, "twrp_stream", NULL);
+ if (stream == NULL) {
+ torture_skip(tctx, "missing 'twrp_stream' option\n");
+ }
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_skip(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ stream_size = torture_setting_int(tctx, "twrp_stream_size", 0);
+ if (stream_size == 0) {
+ torture_skip(tctx, "missing 'twrp_stream_size' option\n");
+ }
+
+ torture_comment(tctx, "Testing timewarp on stream (%s) (%s)\n",
+ file, snapshot);
+
+ path = talloc_asprintf(tree, "%s:%s", file, stream);
+ torture_assert_not_null_goto(tctx, path, ret, done, "path\n");
+
+ buf = talloc_zero_array(tree, uint8_t, stream_size);
+ torture_assert_not_null_goto(tctx, buf, ret, done, "buf\n");
+
+ setenv("TZ", "GMT", 1);
+
+ /* strptime does not set tm.tm_isdst but mktime assumes DST is in
+ * effect if it is greater than 1. */
+ ZERO_STRUCT(tm);
+
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ t = mktime(&tm);
+ unix_to_nt_time(&nttime, t);
+
+ io = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = path,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h1 = io.out.file.handle;
+
+ r = (struct smb2_read) {
+ .in.file.handle = h1,
+ .in.length = stream_size,
+ .in.offset = 0,
+ };
+
+ status = smb2_read(tree, tree, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+
+ smb2_util_close(tree, h1);
+
+done:
+ return ret;
+}
+
+static bool test_twrp_openroot(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ bool ret = true;
+ char *p = NULL;
+ struct tm tm;
+ time_t t;
+ uint64_t nttime;
+ const char *snapshot = NULL;
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_skip(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ torture_comment(tctx, "Testing open of root of "
+ "share with timewarp (%s)\n",
+ snapshot);
+
+ setenv("TZ", "GMT", 1);
+
+ /* strptime does not set tm.tm_isdst but mktime assumes DST is in
+ * effect if it is greater than 1. */
+ ZERO_STRUCT(tm);
+
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ t = mktime(&tm);
+ unix_to_nt_time(&nttime, t);
+
+ io = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = "",
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ smb2_util_close(tree, io.out.file.handle);
+
+done:
+ return ret;
+}
+
+static bool test_twrp_listdir(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create create;
+ struct smb2_handle h = {{0}};
+ struct smb2_find find;
+ unsigned int count;
+ union smb_search_data *d;
+ char *p = NULL;
+ struct tm tm;
+ time_t t;
+ uint64_t nttime;
+ const char *snapshot = NULL;
+ uint64_t normal_fileid;
+ uint64_t snapshot_fileid;
+ NTSTATUS status;
+ bool ret = true;
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_fail(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ torture_comment(tctx, "Testing File-Ids of directory listing "
+ "with timewarp (%s)\n",
+ snapshot);
+
+ setenv("TZ", "GMT", 1);
+
+ /* strptime does not set tm.tm_isdst but mktime assumes DST is in
+ * effect if it is greater than 1. */
+ ZERO_STRUCT(tm);
+
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ t = mktime(&tm);
+ unix_to_nt_time(&nttime, t);
+
+ /*
+ * 1: Query the file's File-Id
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = "subdir/hardlink",
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ smb2_util_close(tree, create.out.file.handle);
+ normal_fileid = BVAL(&create.out.on_disk_id, 0);
+
+ /*
+ * 2: check directory listing of the file returns same File-Id
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_DIR_LIST,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = "subdir",
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h = create.out.file.handle;
+
+ find = (struct smb2_find) {
+ .in.file.handle = h,
+ .in.pattern = "*",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree, tree, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+
+ smb2_util_close(tree, h);
+
+ torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
+ torture_assert_str_equal_goto(tctx,
+ d[2].id_both_directory_info.name.s,
+ "hardlink",
+ ret, done, "bad name");
+ torture_assert_u64_equal_goto(tctx,
+ d[2].id_both_directory_info.file_id,
+ normal_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * 3: Query File-Id of snapshot of the file and check the File-Id is
+ * different compared to the basefile
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = "subdir/hardlink",
+ .in.query_on_disk_id = true,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ smb2_util_close(tree, create.out.file.handle);
+
+ snapshot_fileid = BVAL(&create.out.on_disk_id, 0);
+
+ /*
+ * 4: List directory of the snapshot and check the File-Id returned here
+ * is the same as in 3.
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_DIR_LIST,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = "subdir",
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h = create.out.file.handle;
+
+ find = (struct smb2_find) {
+ .in.file.handle = h,
+ .in.pattern = "*",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree, tree, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+ smb2_util_close(tree, h);
+
+ torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
+ torture_assert_str_equal_goto(tctx,
+ d[2].id_both_directory_info.name.s,
+ "hardlink",
+ ret, done, "bad name");
+ torture_assert_u64_equal_goto(tctx,
+ snapshot_fileid,
+ d[2].id_both_directory_info.file_id,
+ ret, done, "bad fileid\n");
+
+done:
+ return ret;
+}
+
+static bool test_fileid(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = DNAME "\\foo";
+ const char *sname = DNAME "\\foo:bar";
+ struct smb2_handle testdirh;
+ struct smb2_handle h1;
+ struct smb2_create create;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sinfo;
+ struct smb2_find f;
+ unsigned int count;
+ union smb_search_data *d;
+ uint64_t expected_fileid;
+ uint64_t returned_fileid;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+
+ /*
+ * Initial create with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.fname = fname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ expected_fileid = BVAL(&create.out.on_disk_id, 0);
+
+ /*
+ * Getinfo the File-ID on the just opened handle
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Open existing with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = fname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the just opened handle
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Overwrite with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
+ .in.fname = fname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the open with overwrite handle
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Do some modifications on the basefile (IO, setinfo), verifying
+ * File-ID after each step.
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = fname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+
+ status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ sinfo = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = h1,
+ };
+ unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
+
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Create stream, check the stream's File-ID, should be the same as the
+ * base file (sic!, tested against Windows).
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the created stream
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Open stream, check the stream's File-ID, should be the same as the
+ * base file (sic!, tested against Windows).
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the opened stream
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Overwrite stream, check the stream's File-ID, should be the same as
+ * the base file (sic!, tested against Windows).
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the overwritten stream
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Do some modifications on the stream (IO, setinfo), verifying File-ID
+ * after each step.
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+
+ status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ sinfo = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = h1,
+ };
+ unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
+
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Final open of the basefile with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = fname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Final Getinfo checking File-ID
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Final list directory, verifying the operations on basefile and stream
+ * didn't modify the base file metadata.
+ */
+ f = (struct smb2_find) {
+ .in.file.handle = testdirh,
+ .in.pattern = "foo",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
+ };
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+ torture_assert_u64_equal_goto(tctx,
+ d->id_both_directory_info.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+done:
+ smb2_util_close(tree, testdirh);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_fileid_dir(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *dname = DNAME "\\foo";
+ const char *sname = DNAME "\\foo:bar";
+ struct smb2_handle testdirh;
+ struct smb2_handle h1;
+ struct smb2_create create;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sinfo;
+ struct smb2_find f;
+ unsigned int count;
+ union smb_search_data *d;
+ uint64_t expected_fileid;
+ uint64_t returned_fileid;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+
+ /*
+ * Initial directory create with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.fname = dname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ expected_fileid = BVAL(&create.out.on_disk_id, 0);
+
+ /*
+ * Getinfo the File-ID on the just opened handle
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Open existing directory with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.fname = dname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the just opened handle
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Create stream, check the stream's File-ID, should be the same as the
+ * base file (sic!, tested against Windows).
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the created stream
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Open stream, check the stream's File-ID, should be the same as the
+ * base file (sic!, tested against Windows).
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the opened stream
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Overwrite stream, check the stream's File-ID, should be the same as
+ * the base file (sic!, tested against Windows).
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OVERWRITE,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Getinfo the File-ID on the overwritten stream
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Do some modifications on the stream (IO, setinfo), verifying File-ID
+ * after each step.
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = sname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+
+ status = smb2_util_write(tree, h1, "foo", 0, strlen("foo"));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ sinfo = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = h1,
+ };
+ unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL));
+
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Final open of the directory with QFID
+ */
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = dname,
+ .in.query_on_disk_id = true,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test file could not be created\n");
+ h1 = create.out.file.handle;
+ returned_fileid = BVAL(&create.out.on_disk_id, 0);
+ torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Final Getinfo checking File-ID
+ */
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+ torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+ /*
+ * Final list directory, verifying the operations on basefile and stream
+ * didn't modify the base file metadata.
+ */
+ f = (struct smb2_find) {
+ .in.file.handle = testdirh,
+ .in.pattern = "foo",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
+ };
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+ torture_assert_u64_equal_goto(tctx,
+ d->id_both_directory_info.file_id,
+ expected_fileid,
+ ret, done, "bad fileid\n");
+
+done:
+ smb2_util_close(tree, testdirh);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_fileid_unique_object(
+ struct torture_context *tctx,
+ struct smb2_tree *tree,
+ unsigned int num_objs,
+ bool create_dirs)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char *fname = NULL;
+ struct smb2_handle testdirh;
+ struct smb2_handle h1;
+ struct smb2_create create;
+ unsigned int i;
+ uint64_t fileid_array[num_objs];
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "test_fileid_unique failed\n");
+ smb2_util_close(tree, testdirh);
+
+ /* Create num_obj files as rapidly as we can. */
+ for (i = 0; i < num_objs; i++) {
+ fname = talloc_asprintf(mem_ctx,
+ "%s\\testfile.%u",
+ DNAME,
+ i);
+ torture_assert_goto(tctx,
+ fname != NULL,
+ ret,
+ done,
+ "talloc failed\n");
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.fname = fname,
+ };
+
+ if (create_dirs) {
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.create_options = FILE_DIRECTORY_FILE;
+ }
+
+ status = smb2_create(tree, tctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "test file %s could not be created\n",
+ fname));
+ TALLOC_FREE(fname);
+ ret = false;
+ goto done;
+ }
+
+ h1 = create.out.file.handle;
+ smb2_util_close(tree, h1);
+ TALLOC_FREE(fname);
+ }
+
+ /*
+ * Get the file ids.
+ */
+ for (i = 0; i < num_objs; i++) {
+ union smb_fileinfo finfo;
+
+ fname = talloc_asprintf(mem_ctx,
+ "%s\\testfile.%u",
+ DNAME,
+ i);
+ torture_assert_goto(tctx,
+ fname != NULL,
+ ret,
+ done,
+ "talloc failed\n");
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = fname,
+ };
+
+ if (create_dirs) {
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.create_options = FILE_DIRECTORY_FILE;
+ }
+
+ status = smb2_create(tree, tctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "test file %s could not "
+ "be opened: %s\n",
+ fname,
+ nt_errstr(status)));
+ TALLOC_FREE(fname);
+ ret = false;
+ goto done;
+ }
+
+ h1 = create.out.file.handle;
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "failed to get fileid for "
+ "test file %s: %s\n",
+ fname,
+ nt_errstr(status)));
+ TALLOC_FREE(fname);
+ ret = false;
+ goto done;
+ }
+ smb2_util_close(tree, h1);
+
+ fileid_array[i] = finfo.all_info2.out.file_id;
+ TALLOC_FREE(fname);
+ }
+
+ /* All returned fileids must be unique. 100 is small so brute force. */
+ for (i = 0; i < num_objs - 1; i++) {
+ unsigned int j;
+ for (j = i + 1; j < num_objs; j++) {
+ if (fileid_array[i] == fileid_array[j]) {
+ torture_fail(tctx,
+ talloc_asprintf(tctx,
+ "fileid %u == fileid %u (0x%"PRIu64")\n",
+ i,
+ j,
+ fileid_array[i]));
+ ret = false;
+ goto done;
+ }
+ }
+ }
+
+done:
+
+ smb2_util_close(tree, testdirh);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_fileid_unique(
+ struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_fileid_unique_object(tctx, tree, 100, false);
+}
+
+static bool test_fileid_unique_dir(
+ struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_fileid_unique_object(tctx, tree, 100, true);
+}
+
+static bool test_dosattr_tmp_dir(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create c;
+ struct smb2_handle h1 = {{0}};
+ const char *fname = DNAME;
+
+ smb2_deltree(tree, fname);
+ smb2_util_rmdir(tree, fname);
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_DIR_ALL,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.fname = DNAME,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h1 = c.out.file.handle;
+
+ /* Try to set temporary attribute on directory */
+ SET_ATTRIB(FILE_ATTRIBUTE_TEMPORARY);
+
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_INVALID_PARAMETER,
+ ret, done,
+ "Unexpected setinfo result\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+
+ return ret;
+}
+
+/*
+ test opening quota fakefile handle and returned attributes
+*/
+static bool test_smb2_open_quota_fake_file(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "$Extend\\$Quota:$Q:$INDEX_ALLOCATION";
+ struct smb2_create create;
+ struct smb2_handle h = {{0}};
+ NTSTATUS status;
+ bool ret = true;
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_READ,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tree, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h = create.out.file.handle;
+
+ torture_assert_u64_equal_goto(tctx,
+ create.out.file_attr,
+ FILE_ATTRIBUTE_HIDDEN
+ | FILE_ATTRIBUTE_SYSTEM
+ | FILE_ATTRIBUTE_DIRECTORY
+ | FILE_ATTRIBUTE_ARCHIVE,
+ ret,
+ done,
+ "Wrong attributes\n");
+
+ torture_assert_u64_equal_goto(tctx,
+ create.out.create_time, 0,
+ ret,
+ done,
+ "create_time is not 0\n");
+ torture_assert_u64_equal_goto(tctx,
+ create.out.access_time, 0,
+ ret,
+ done,
+ "access_time is not 0\n");
+ torture_assert_u64_equal_goto(tctx,
+ create.out.write_time, 0,
+ ret,
+ done,
+ "write_time is not 0\n");
+ torture_assert_u64_equal_goto(tctx,
+ create.out.change_time, 0,
+ ret,
+ done,
+ "change_time is not 0\n");
+
+done:
+ smb2_util_close(tree, h);
+ return ret;
+}
+
+/**
+ Find Maximum Path Length
+ */
+static bool generate_path(const size_t len,
+ char *buffer,
+ const size_t buf_len)
+{
+ size_t i;
+
+ if (len >= buf_len) {
+ return false;
+ }
+
+ for (i = 0; i < len ; i++) {
+ buffer[i] = (char)(i % 10) + 48;
+ }
+ buffer[i] = '\0';
+ return true;
+}
+
+static bool test_path_length_test(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const size_t max_name = 2048;
+ char *name = talloc_array(tctx, char, max_name);
+ struct smb2_handle fh = {{0}};
+ size_t length = 128;
+ size_t max_file_name = 0;
+ size_t max_path_length = 0;
+ char *path_ok = NULL;
+ char *path_next = NULL;
+ char *topdir = NULL;
+ bool is_interactive = torture_setting_bool(tctx, "interactive", false);
+ NTSTATUS status;
+ bool ret = true;
+
+ if (!is_interactive) {
+ torture_result(tctx, TORTURE_SKIP,
+ "Interactive Test: Skipping... "
+ "(enable with --interactive)\n");
+ return ret;
+ }
+
+ torture_comment(tctx, "Testing filename and path lengths\n");
+
+ /* Find Longest File Name */
+ for (length = 128; length < max_name; length++) {
+ if (!generate_path(length, name, max_name)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to generate path.");
+ return false;
+ }
+
+ status = torture_smb2_testfile(tree, name, &fh);
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ smb2_util_close(tree, fh);
+ smb2_util_unlink(tree, name);
+
+ max_file_name = length;
+ }
+
+ torture_assert_int_not_equal_goto(tctx, length, max_name, ret, done,
+ "Name too big\n");
+
+ torture_comment(tctx, "Max file name length: %zu\n", max_file_name);
+
+ /* Remove one char that caused the failure above */
+ name[max_file_name] = '\0';
+
+ path_ok = talloc_strdup(tree, name);
+ torture_assert_not_null_goto(tctx, path_ok, ret, done,
+ "talloc_strdup failed\n");
+
+ topdir = talloc_strdup(tree, name);
+ torture_assert_not_null_goto(tctx, topdir, ret, done,
+ "talloc_strdup failed\n");
+
+ status = smb2_util_mkdir(tree, path_ok);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "mkdir [%s] failed: %s\n",
+ path_ok, nt_errstr(status));
+ torture_result(tctx, TORTURE_FAIL, "Initial mkdir failed");
+ return false;
+ }
+
+ while (true) {
+ path_next = talloc_asprintf(tctx, "%s\\%s", path_ok, name);
+ torture_assert_not_null_goto(tctx, path_next, ret, done,
+ "talloc_asprintf failed\n");
+
+ status = smb2_util_mkdir(tree, path_next);
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ path_ok = path_next;
+ }
+
+ for (length = 1; length < max_name; length++) {
+ if (!generate_path(length, name, max_name)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Failed to generate path.");
+ return false;
+ }
+
+ path_next = talloc_asprintf(tctx, "%s\\%s", path_ok, name);
+ torture_assert_not_null_goto(tctx, path_next, ret, done,
+ "talloc_asprintf failed\n");
+
+ status = torture_smb2_testfile(tree, path_next, &fh);
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ smb2_util_close(tree, fh);
+ path_ok = path_next;
+ }
+
+ max_path_length = talloc_array_length(path_ok);
+
+ torture_comment(tctx, "Max path name length: %zu\n", max_path_length);
+
+done:
+ return ret;
+}
+
+/*
+ basic testing of SMB2 read
+*/
+struct torture_suite *torture_smb2_create_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "create");
+
+ torture_suite_add_1smb2_test(suite, "gentest", test_create_gentest);
+ torture_suite_add_1smb2_test(suite, "blob", test_create_blob);
+ torture_suite_add_1smb2_test(suite, "open", test_smb2_open);
+ torture_suite_add_1smb2_test(suite, "brlocked", test_smb2_open_brlocked);
+ torture_suite_add_1smb2_test(suite, "multi", test_smb2_open_multi);
+ torture_suite_add_1smb2_test(suite, "delete", test_smb2_open_for_delete);
+ torture_suite_add_1smb2_test(suite, "leading-slash", test_smb2_leading_slash);
+ torture_suite_add_1smb2_test(suite, "impersonation", test_smb2_impersonation_level);
+ torture_suite_add_1smb2_test(suite, "aclfile", test_create_acl_file);
+ torture_suite_add_1smb2_test(suite, "acldir", test_create_acl_dir);
+ torture_suite_add_1smb2_test(suite, "nulldacl", test_create_null_dacl);
+ torture_suite_add_1smb2_test(suite, "mkdir-dup", test_mkdir_dup);
+ torture_suite_add_1smb2_test(suite, "dir-alloc-size", test_dir_alloc_size);
+ torture_suite_add_1smb2_test(suite, "dosattr_tmp_dir", test_dosattr_tmp_dir);
+ torture_suite_add_1smb2_test(suite, "quota-fake-file", test_smb2_open_quota_fake_file);
+ torture_suite_add_1smb2_test(suite, "path-length", test_path_length_test);
+ torture_suite_add_1smb2_test(suite, "bench-path-contention-shared", test_smb2_bench_path_contention_shared);
+
+ suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
+
+ return suite;
+}
+
+struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "twrp");
+
+ torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
+ torture_suite_add_1smb2_test(suite, "stream", test_twrp_stream);
+ torture_suite_add_1smb2_test(suite, "openroot", test_twrp_openroot);
+ torture_suite_add_1smb2_test(suite, "listdir", test_twrp_listdir);
+
+ suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
+
+ return suite;
+}
+
+/*
+ basic testing of SMB2 File-IDs
+*/
+struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "fileid");
+
+ torture_suite_add_1smb2_test(suite, "fileid", test_fileid);
+ torture_suite_add_1smb2_test(suite, "fileid-dir", test_fileid_dir);
+ torture_suite_add_1smb2_test(suite, "unique", test_fileid_unique);
+ torture_suite_add_1smb2_test(suite, "unique-dir", test_fileid_unique_dir);
+
+ suite->description = talloc_strdup(suite, "SMB2-FILEID tests");
+
+ return suite;
+}
+
+static bool test_no_stream(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create c;
+ NTSTATUS status;
+ bool ret = true;
+ const char *names[] = {
+ "test_no_stream::$DATA",
+ "test_no_stream::foooooooooooo",
+ "test_no_stream:stream",
+ "test_no_stream:stream:$DATA",
+ NULL
+ };
+ int i;
+
+ for (i = 0; names[i] != NULL; i++) {
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = names[i],
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_INVALID)) {
+ torture_comment(
+ tctx, "Expected NT_STATUS_OBJECT_NAME_INVALID, "
+ "got %s, name: '%s'\n",
+ nt_errstr(status), names[i]);
+ torture_fail_goto(tctx, done, "Bad create result\n");
+ }
+ }
+done:
+ return ret;
+}
+
+struct torture_suite *torture_smb2_create_no_streams_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "create_no_streams");
+
+ torture_suite_add_1smb2_test(suite, "no_stream", test_no_stream);
+
+ suite->description = talloc_strdup(suite, "SMB2-CREATE stream test on share without streams support");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/credits.c b/source4/torture/smb2/credits.c
new file mode 100644
index 0000000..b06bae7
--- /dev/null
+++ b/source4/torture/smb2/credits.c
@@ -0,0 +1,268 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 credits
+
+ Copyright (C) Ralph Boehme 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/param/param.h"
+
+/**
+ * Request 64k credits in negprot/sessionsetup and require at least 8k
+ *
+ * This passes against Windows 2016
+ **/
+static bool test_session_setup_credits_granted(struct torture_context *tctx,
+ struct smb2_tree *_tree)
+{
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_tree *tree = NULL;
+ uint16_t cur_credits;
+ NTSTATUS status;
+ bool ret = true;
+
+ transport = _tree->session->transport;
+ options = transport->options;
+
+ status = smb2_logoff(_tree->session);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_logoff failed\n");
+ TALLOC_FREE(_tree);
+
+ options.max_credits = 65535;
+
+ ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_smb2_connection_ext failed\n");
+
+ transport = tree->session->transport;
+
+ cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
+ if (cur_credits < 8192) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Server only granted %" PRIu16" credits\n",
+ cur_credits);
+ ret = false;
+ goto done;
+ }
+
+done:
+ TALLOC_FREE(tree);
+ return ret;
+}
+
+/**
+ * Request 64K credits in a single SMB2 request and requite at least 8192
+ *
+ * This passes against Windows 2016
+ **/
+static bool test_single_req_credits_granted(struct torture_context *tctx,
+ struct smb2_tree *_tree)
+{
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_tree *tree = NULL;
+ struct smb2_handle h = {{0}};
+ struct smb2_create create;
+ const char *fname = "single_req_credits_granted.dat";
+ uint16_t cur_credits;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_util_unlink(_tree, fname);
+
+ transport = _tree->session->transport;
+ options = transport->options;
+
+ status = smb2_logoff(_tree->session);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_logoff failed\n");
+ TALLOC_FREE(_tree);
+
+ options.max_credits = 1;
+
+ ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_smb2_connection_ext failed\n");
+
+ transport = tree->session->transport;
+
+ cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
+ if (cur_credits != 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Only wanted 1 credit but server granted %" PRIu16"\n",
+ cur_credits);
+ ret = false;
+ goto done;
+ }
+
+ smb2cli_conn_set_max_credits(transport->conn, 65535);
+
+ ZERO_STRUCT(create);
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h = create.out.file.handle;
+
+ cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
+ if (cur_credits < 8192) {
+ torture_result(tctx, TORTURE_FAIL,
+ "Server only granted %" PRIu16" credits\n",
+ cur_credits);
+ ret = false;
+ goto done;
+ }
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_util_unlink(tree, fname);
+ TALLOC_FREE(tree);
+ return ret;
+}
+
+static bool test_crediting_skipped_mid(struct torture_context *tctx,
+ struct smb2_tree *_tree)
+{
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_tree *tree = NULL;
+ struct smb2_handle h = {{0}};
+ struct smb2_create create;
+ const char *fname = "skipped_mid.dat";
+ uint64_t mid;
+ uint16_t cur_credits;
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+
+ smb2_util_unlink(_tree, fname);
+
+ transport = _tree->session->transport;
+ options = transport->options;
+
+ status = smb2_logoff(_tree->session);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_logoff failed\n");
+ TALLOC_FREE(_tree);
+
+ options.max_credits = 8192;
+
+ ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_smb2_connection_ext failed\n");
+
+ transport = tree->session->transport;
+
+ cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
+ if (cur_credits != 8192) {
+ torture_result(tctx, TORTURE_FAIL, "Server only granted %" PRIu16" credits\n", cur_credits);
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(create);
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
+ h = create.out.file.handle;
+
+ /*
+ * See what happens if we skip a mid. As we want to avoid triggering our
+ * client side mid window check we keep conn->smb2.cur_credits
+ * unchanged so the server keeps granting credits until it's max mid
+ * windows size is reached at which point it will disconnect us:
+ *
+ * o Windows 2016 currently has a maximum mid window size of 8192 by
+ * default
+ *
+ * o Samba's limit is 512
+ *
+ * o Windows 2008r2 uses some special algorithm (MS-SMB2 3.3.1.1
+ * footnote <167>) that kicks in once a mid is skipped, resulting in a
+ * maximum window size of 100-300 depending on the number of granted
+ * credits at the moment of skipping a mid.
+ */
+
+ mid = smb2cli_conn_get_mid(tree->session->transport->conn);
+ smb2cli_conn_set_mid(tree->session->transport->conn, mid + 1);
+
+ for (i = 0; i < 8191; i++) {
+ status = smb2_util_write(tree, h, "\0", 0, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "Server only allowed %d writes\n", i);
+ ret = false;
+ goto done;
+ }
+ }
+
+ /*
+ * Now use the skipped mid (the smb2_util_close...), we should
+ * immediately get a full mid window of size 8192.
+ */
+ smb2cli_conn_set_mid(tree->session->transport->conn, mid);
+ status = smb2_util_close(tree, h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_close failed\n");
+ ZERO_STRUCT(h);
+
+ cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
+ if (cur_credits != 8192) {
+ torture_result(tctx, TORTURE_FAIL, "Server only granted %" PRIu16" credits\n", cur_credits);
+ ret = false;
+ goto done;
+ }
+
+ smb2cli_conn_set_mid(tree->session->transport->conn, mid + 8192);
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_util_unlink(tree, fname);
+ TALLOC_FREE(tree);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_crediting_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "credits");
+
+ torture_suite_add_1smb2_test(suite, "session_setup_credits_granted", test_session_setup_credits_granted);
+ torture_suite_add_1smb2_test(suite, "single_req_credits_granted", test_single_req_credits_granted);
+ torture_suite_add_1smb2_test(suite, "skipped_mid", test_crediting_skipped_mid);
+
+ suite->description = talloc_strdup(suite, "SMB2-CREDITS tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/delete-on-close.c b/source4/torture/smb2/delete-on-close.c
new file mode 100644
index 0000000..0524287
--- /dev/null
+++ b/source4/torture/smb2/delete-on-close.c
@@ -0,0 +1,762 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test delete-on-close in more detail
+
+ Copyright (C) Richard Sharpe, 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+#define DNAME "test_dir"
+#define FNAME DNAME "\\test_create.dat"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ return false; \
+ }} while (0)
+
+static bool create_dir(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ struct smb2_handle handle;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig;
+ const char *owner_sid;
+ uint32_t perms = 0;
+
+ torture_comment(tctx, "Creating Directory for testing: %s\n", DNAME);
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = DNAME;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ /*
+ * We create an SD that allows us to do most things but we do not
+ * get DELETE and DELETE CHILD access!
+ */
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_OWNER |
+ SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_TRAVERSE | SEC_DIR_WRITE_EA |
+ SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA | SEC_FILE_READ_DATA;
+
+ torture_comment(tctx, "Setting permissions on dir to 0x1e01bf\n");
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ perms,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, handle);
+
+ return true;
+}
+
+static bool set_dir_delete_perms(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create io;
+ struct smb2_handle handle;
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd, *sd_orig;
+ const char *owner_sid;
+ uint32_t perms = 0;
+
+ torture_comment(tctx, "Opening Directory for setting new SD: %s\n", DNAME);
+
+ ZERO_STRUCT(io);
+ io.level = RAW_OPEN_SMB2;
+ io.in.create_flags = 0;
+ io.in.desired_access =
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.alloc_size = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.security_flags = 0;
+ io.in.fname = DNAME;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ handle = io.out.file.handle;
+
+ torture_comment(tctx, "get the original sd\n");
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ /*
+ * We create an SD that allows us to do most things including
+ * get DELETE and DELETE CHILD access!
+ */
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_OWNER |
+ SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_TRAVERSE | SEC_DIR_WRITE_EA |
+ SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA |
+ SEC_DIR_DELETE_CHILD | SEC_STD_DELETE |
+ SEC_FILE_WRITE_DATA | SEC_FILE_READ_DATA;
+
+ torture_comment(tctx, "Setting permissions on dir to 0x%0x\n", perms);
+ sd = security_descriptor_dacl_create(tctx,
+ 0, owner_sid, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ perms,
+ 0,
+ NULL);
+
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = handle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ set.set_secdesc.in.sd = sd;
+
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, handle);
+
+ return true;
+}
+
+static bool test_doc_overwrite_if(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t perms = 0;
+
+ /* File should not exist for this first test, so make sure */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (OVERWRITE_IF)\n");
+ torture_comment(tctx, "We expect NT_STATUS_OK\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ /* Check it was deleted */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = 0;
+ io.in.fname = FNAME;
+
+ torture_comment(tctx, "Testing if the file was deleted when closed\n");
+ torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return true;
+}
+
+static bool test_doc_overwrite_if_exist(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t perms = 0;
+
+ /* File should not exist for this first test, so make sure */
+ /* And set the SEC Descriptor appropriately */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "Create file with DeleteOnClose on existing file (OVERWRITE_IF)\n");
+ torture_comment(tctx, "We expect NT_STATUS_ACCESS_DENIED\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ /* First, create this file ... */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = 0x0;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ /* Next, try to open it for Delete On Close */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ return true;
+}
+
+static bool test_doc_create(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t perms = 0;
+
+ /* File should not exist for this first test, so make sure */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (CREATE) \n");
+ torture_comment(tctx, "We expect NT_STATUS_OK\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ /* Check it was deleted */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = 0;
+ io.in.fname = FNAME;
+
+ torture_comment(tctx, "Testing if the file was deleted when closed\n");
+ torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return true;
+}
+
+static bool test_doc_create_exist(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t perms = 0;
+
+ /* File should not exist for this first test, so make sure */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (CREATE) \n");
+ torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_COLLISION\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ /* First, create the file */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = 0x0;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ /* Next, try to open it for Delete on Close */
+ status = smb2_util_close(tree, io.out.file.handle);
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ return true;
+}
+
+static bool test_doc_create_if(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t perms = 0;
+
+ /* File should not exist for this first test, so make sure */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "Create file with DeleteOnClose on non-existent file (OPEN_IF)\n");
+ torture_comment(tctx, "We expect NT_STATUS_OK\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ /* Check it was deleted */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = 0;
+ io.in.fname = FNAME;
+
+ torture_comment(tctx, "Testing if the file was deleted when closed\n");
+ torture_comment(tctx, "We expect NT_STATUS_OBJECT_NAME_NOT_FOUND\n");
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ return true;
+}
+
+static bool test_doc_create_if_exist(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ uint32_t perms = 0;
+
+ /* File should not exist for this first test, so make sure */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "Create file with DeleteOnClose on existing file (OPEN_IF)\n");
+ torture_comment(tctx, "We expect NT_STATUS_ACCESS_DENIED\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ /* Create the file first */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = 0x0;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ /* Now try to create it for delete on close */
+ ZERO_STRUCT(io);
+ io.in.desired_access = 0x130196;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.in.fname = FNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+
+ return true;
+}
+
+static bool test_doc_find_and_set_doc(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ struct smb2_find find;
+ NTSTATUS status;
+ union smb_search_data *d;
+ union smb_setfileinfo sfinfo;
+ unsigned int count;
+ uint32_t perms = 0;
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA | SEC_DIR_LIST;
+
+ /* File should not exist for this first test, so make sure */
+ set_dir_delete_perms(tctx, tree);
+
+ smb2_deltree(tree, DNAME);
+
+ create_dir(tctx, tree);
+
+ torture_comment(tctx, "FIND and delete directory\n");
+ torture_comment(tctx, "We expect NT_STATUS_OK\n");
+
+ /* open the directory first */
+ ZERO_STRUCT(io);
+ io.in.desired_access = perms;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.fname = DNAME;
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* list directory */
+ ZERO_STRUCT(find);
+ find.in.file.handle = io.out.file.handle;
+ find.in.pattern = "*";
+ find.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ find.in.max_response_size = 0x100;
+ find.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ /* start enumeration on directory */
+ status = smb2_find_level(tree, tree, &find, &count, &d);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* set delete-on-close */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.in.file.handle = io.out.file.handle;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* close directory */
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ return true;
+}
+
+static bool test_doc_read_only(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle dir_handle;
+ union smb_setfileinfo sfinfo = {{0}};
+ struct smb2_create create = {0};
+ struct smb2_close close = {0};
+ NTSTATUS status, expected_status;
+ bool ret = true, delete_readonly;
+
+ /*
+ * Allow testing of the Samba 'delete readonly' option.
+ */
+ delete_readonly = torture_setting_bool(tctx, "delete_readonly", false);
+ expected_status = delete_readonly ?
+ NT_STATUS_OK : NT_STATUS_CANNOT_DELETE;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &dir_handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE directory failed\n");
+
+ create = (struct smb2_create) {0};
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ create.in.file_attributes = FILE_ATTRIBUTE_READONLY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = FNAME;
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, expected_status, ret,
+ done, "Unexpected status for CREATE "
+ "of new file.\n");
+
+ if (delete_readonly) {
+ close.in.file.handle = create.out.file.handle;
+ status = smb2_close(tree, &close);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE of READONLY file "
+ "failed.\n");
+ }
+
+ torture_comment(tctx, "Creating file with READ_ONLY attribute.\n");
+
+ create = (struct smb2_create) {0};
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ create.in.file_attributes = FILE_ATTRIBUTE_READONLY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = FNAME;
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE of READONLY file failed.\n");
+
+ close.in.file.handle = create.out.file.handle;
+ status = smb2_close(tree, &close);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE of READONLY file failed.\n");
+
+ torture_comment(tctx, "Testing CREATE with DELETE_ON_CLOSE on "
+ "READ_ONLY attribute file.\n");
+
+ create = (struct smb2_create) {0};
+ create.in.desired_access = SEC_RIGHTS_FILE_READ | SEC_STD_DELETE;
+ create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ create.in.file_attributes = 0;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = FNAME;
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ expected_status, ret, done,
+ "CREATE returned unexpected "
+ "status.\n");
+
+ torture_comment(tctx, "Testing setting DELETE_ON_CLOSE disposition on "
+ " file with READONLY attribute.\n");
+
+ create = (struct smb2_create) {0};
+ create.in.desired_access = SEC_RIGHTS_FILE_READ | SEC_STD_DELETE;;
+ create.in.create_options = 0;
+ create.in.file_attributes = 0;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = FNAME;
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Opening file failed.\n");
+
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = create.out.file.handle;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal(tctx, status, expected_status,
+ "Set DELETE_ON_CLOSE disposition "
+ "returned un expected status.\n");
+
+ status = smb2_util_close(tree, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE failed\n");
+
+done:
+ smb2_deltree(tree, DNAME);
+ return ret;
+}
+
+/*
+ * This is a regression test for
+ * https://bugzilla.samba.org/show_bug.cgi?id=14427
+ *
+ * It's not really a delete-on-close specific test.
+ */
+static bool test_doc_bug14427(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ struct smb2_tree *tree2 = NULL;
+ NTSTATUS status;
+ char fname[256];
+ bool ret = false;
+ bool ok;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "doc_bug14427_%s.dat",
+ generate_random_str(tctx, 8));
+
+ ok = torture_smb2_tree_connect(tctx, tree1->session, tctx, &tree2);
+ torture_assert_goto(tctx, ok, ret, done,
+ "torture_smb2_tree_connect() failed.\n");
+
+ status = torture_setup_simple_file(tctx, tree1, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_setup_simple_file() failed on tree1.\n");
+
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink() failed on tree2.\n");
+ TALLOC_FREE(tree2);
+ ret = true;
+done:
+ if (tree2 != NULL) {
+ TALLOC_FREE(tree2);
+ smb2_util_unlink(tree1, fname);
+ }
+
+ TALLOC_FREE(tree1);
+ return ret;
+}
+
+/*
+ * Extreme testing of Delete On Close and permissions
+ */
+struct torture_suite *torture_smb2_doc_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "delete-on-close-perms");
+
+ torture_suite_add_1smb2_test(suite, "OVERWRITE_IF", test_doc_overwrite_if);
+ torture_suite_add_1smb2_test(suite, "OVERWRITE_IF Existing", test_doc_overwrite_if_exist);
+ torture_suite_add_1smb2_test(suite, "CREATE", test_doc_create);
+ torture_suite_add_1smb2_test(suite, "CREATE Existing", test_doc_create_exist);
+ torture_suite_add_1smb2_test(suite, "CREATE_IF", test_doc_create_if);
+ torture_suite_add_1smb2_test(suite, "CREATE_IF Existing", test_doc_create_if_exist);
+ torture_suite_add_1smb2_test(suite, "FIND_and_set_DOC", test_doc_find_and_set_doc);
+ torture_suite_add_1smb2_test(suite, "READONLY", test_doc_read_only);
+ torture_suite_add_1smb2_test(suite, "BUG14427", test_doc_bug14427);
+
+ suite->description = talloc_strdup(suite, "SMB2-Delete-on-Close-Perms tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/deny.c b/source4/torture/smb2/deny.c
new file mode 100644
index 0000000..e42fd56
--- /dev/null
+++ b/source4/torture/smb2/deny.c
@@ -0,0 +1,526 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB2 torture tester - deny mode scanning functions
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) David Mulder 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+enum deny_result {A_0=0, A_X=1, A_R=2, A_W=3, A_RW=5};
+
+static const char *denystr(int denymode)
+{
+ const struct {
+ int v;
+ const char *name;
+ } deny_modes[] = {
+ {NTCREATEX_SHARE_ACCESS_NONE, "NTCREATEX_SHARE_ACCESS_NONE"},
+ {NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, "NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE"},
+ {NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, "NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE"},
+ {NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, "NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE"},
+ {-1, NULL}};
+ int i;
+ for (i=0;deny_modes[i].name;i++) {
+ if (deny_modes[i].v == denymode) return deny_modes[i].name;
+ }
+ return "DENY_XXX";
+}
+
+static const char *openstr(int mode)
+{
+ const struct {
+ int v;
+ const char *name;
+ } open_modes[] = {
+ {SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, "SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA"},
+ {SEC_FILE_READ_DATA, "SEC_FILE_READ_DATA"},
+ {SEC_FILE_WRITE_DATA, "SEC_FILE_WRITE_DATA"},
+ {-1, NULL}};
+ int i;
+ for (i=0;open_modes[i].name;i++) {
+ if (open_modes[i].v == mode) return open_modes[i].name;
+ }
+ return "O_XXX";
+}
+
+static const char *resultstr(enum deny_result res)
+{
+ const struct {
+ enum deny_result res;
+ const char *name;
+ } results[] = {
+ {A_X, "X"},
+ {A_0, "-"},
+ {A_R, "R"},
+ {A_W, "W"},
+ {A_RW,"RW"}};
+ int i;
+ for (i=0;i<ARRAY_SIZE(results);i++) {
+ if (results[i].res == res) return results[i].name;
+ }
+ return "*";
+}
+
+static const struct {
+ int isexe;
+ int mode1, deny1;
+ int mode2, deny2;
+ enum deny_result result;
+} denytable[] = {
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{1, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_NONE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE, A_0},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_RW},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_R},
+{0, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, SEC_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, A_W},
+};
+
+
+static void progress_bar(struct torture_context *tctx, unsigned int i, unsigned int total)
+{
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%5d/%5d\r", i, total);
+ fflush(stdout);
+ }
+}
+
+
+/*
+ this produces a matrix of deny mode behaviour with 2 connections
+ */
+static bool torture_smb2_denytest2(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ struct smb2_handle fnum1 = {{0}}, fnum2 = {{0}};
+ int i;
+ bool correct = true;
+ const char *fnames[2] = {"denytest2.dat", "denytest2.exe"};
+ struct timespec tv, tv_start;
+
+ for (i=0;i<2;i++) {
+ struct smb2_create io = {0};
+ smb2_util_unlink(tree1, fnames[i]);
+ io.in.fname = fnames[i];
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tree1, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, correct, failed,
+ talloc_asprintf(tctx, "Open of %s failed (%s)",
+ fnames[i], nt_errstr(status)));
+ fnum1 = io.out.file.handle;
+ smb2_util_write(tree1, fnum1, fnames[i], 0, strlen(fnames[i]));
+ smb2_util_close(tree1, fnum1);
+ }
+
+ clock_gettime_mono(&tv_start);
+
+ for (i=0; i<ARRAY_SIZE(denytable); i++) {
+ NTSTATUS s1, s2;
+ struct smb2_create io1 = {0}, io2 = {0};
+ enum deny_result res;
+ const char *fname = fnames[denytable[i].isexe];
+
+ progress_bar(tctx, i, ARRAY_SIZE(denytable));
+
+ io1.in.fname = fname;
+ io1.in.desired_access = denytable[i].mode1;
+ io1.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io1.in.share_access = denytable[i].deny1;
+ s1 = smb2_create(tree1, tree1, &io1);
+ fnum1 = io1.out.file.handle;
+
+ io2.in.fname = fname;
+ io2.in.desired_access = denytable[i].mode2;
+ io2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io2.in.share_access = denytable[i].deny2;
+ s2 = smb2_create(tree2, tree2, &io2);
+ fnum2 = io2.out.file.handle;
+
+ if (!NT_STATUS_IS_OK(s1)) {
+ res = A_X;
+ } else if (!NT_STATUS_IS_OK(s2)) {
+ res = A_0;
+ } else {
+ struct smb2_read io = {0};
+ struct smb2_write wio = {0};
+ uint8_t x = 1;
+ res = A_0;
+
+ io.in.file.handle = fnum2;
+ io.in.length = 1;
+ status = smb2_read(tree2, tree2, &io);
+ if (NT_STATUS_IS_OK(status) && io.out.data.length == 1) {
+ res += A_R;
+ }
+
+ wio.in.file.handle = fnum2;
+ wio.in.data = data_blob_const(&x, 1);
+ status = smb2_write(tree2, &wio);
+ if (NT_STATUS_IS_OK(status) && wio.out.nwritten == 1) {
+ res += A_W;
+ }
+ }
+
+ if (torture_setting_bool(tctx, "showall", false) ||
+ res != denytable[i].result) {
+ int64_t tdif;
+ clock_gettime_mono(&tv);
+ tdif = nsec_time_diff(&tv, &tv_start);
+ tdif /= 1000000;
+ torture_comment(tctx, "%lld: %s %8s %10s %8s %10s %s (correct=%s)\n",
+ (long long)tdif,
+ fname,
+ denystr(denytable[i].deny1),
+ openstr(denytable[i].mode1),
+ denystr(denytable[i].deny2),
+ openstr(denytable[i].mode2),
+ resultstr(res),
+ resultstr(denytable[i].result));
+ }
+
+ torture_assert_goto(tctx, res == denytable[i].result,
+ correct, failed,
+ talloc_asprintf(tctx,
+ "Result %s did not match deny table %s\n",
+ resultstr(res),
+ resultstr(denytable[i].result)));
+
+ smb2_util_close(tree1, fnum1);
+ smb2_util_close(tree2, fnum2);
+ }
+
+failed:
+ for (i=0;i<2;i++) {
+ smb2_util_unlink(tree1, fnames[i]);
+ }
+
+ return correct;
+}
+
+
+/*
+ this produces a matrix of deny mode behaviour for 1 connection
+ */
+static bool torture_smb2_denytest1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return torture_smb2_denytest2(tctx, tree, tree);
+}
+
+
+struct torture_suite *torture_smb2_deny_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "deny");
+
+ torture_suite_add_1smb2_test(suite, "deny1", torture_smb2_denytest1);
+ torture_suite_add_2smb2_test(suite, "deny2", torture_smb2_denytest2);
+
+ suite->description = talloc_strdup(suite, "SMB2 deny tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/dir.c b/source4/torture/smb2/dir.c
new file mode 100644
index 0000000..4020e6b
--- /dev/null
+++ b/source4/torture/smb2/dir.c
@@ -0,0 +1,1606 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 dir list test suite
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Zachary Loafman 2009
+ Copyright (C) Aravind Srinivasan 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/util.h"
+
+#include "system/filesys.h"
+#include "lib/util/tsort.h"
+
+#define DNAME "smb2_dir"
+#define NFILES 100
+
+struct file_elem {
+ char *name;
+ NTTIME create_time;
+ bool found;
+};
+
+static NTSTATUS populate_tree(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct file_elem *files,
+ int nfiles,
+ struct smb2_handle *h_out)
+{
+ struct smb2_create create;
+ char **strs = NULL;
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+
+ smb2_deltree(tree, DNAME);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = DNAME;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ *h_out = create.out.file.handle;
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ strs = generate_unique_strs(mem_ctx, 8, nfiles);
+ if (strs == NULL) {
+ status = NT_STATUS_OBJECT_NAME_COLLISION;
+ goto done;
+ }
+ for (i = 0; i < nfiles; i++) {
+ files[i].name = strs[i];
+ create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s",
+ DNAME, files[i].name);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ files[i].create_time = create.out.create_time;
+ smb2_util_close(tree, create.out.file.handle);
+ }
+ done:
+ if (!ret) {
+ return status;
+ }
+
+ return status;
+}
+
+/*
+ test find continue
+*/
+
+static bool test_find(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle h;
+ struct smb2_find f;
+ union smb_search_data *d;
+ struct file_elem files[NFILES] = {};
+ NTSTATUS status;
+ bool ret = true;
+ unsigned int count;
+ int i, j = 0, file_count = 0;
+
+ status = populate_tree(tctx, mem_ctx, tree, files, NFILES, &h);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ f.in.max_response_size = 0x100;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ for (i = 0; i < count; i++) {
+ bool expected;
+ const char *found = d[i].both_directory_info.name.s;
+ NTTIME ct = d[i].both_directory_info.create_time;
+
+ if (!strcmp(found, ".") || !strcmp(found, ".."))
+ continue;
+
+ expected = false;
+ for (j = 0; j < NFILES; j++) {
+ if (strcmp(files[j].name, found) != 0) {
+ continue;
+ }
+
+ torture_assert_u64_equal_goto(tctx,
+ files[j].create_time,
+ ct, ret, done,
+ talloc_asprintf(tctx,
+ "file[%d]\n", j));
+
+ files[j].found = true;
+ expected = true;
+ break;
+ }
+
+ if (expected)
+ continue;
+
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): didn't expect %s\n",
+ __location__, found);
+ ret = false;
+ goto done;
+ }
+
+ file_count = file_count + i;
+ f.in.continue_flags = 0;
+ f.in.max_response_size = 4096;
+ } while (count != 0);
+
+ torture_assert_int_equal_goto(tctx, file_count, NFILES + 2, ret, done,
+ "");
+
+ for (i = 0; i < NFILES; i++) {
+ if (files[j].found)
+ continue;
+
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): expected to find %s, but didn't\n",
+ __location__, files[j].name);
+ ret = false;
+ goto done;
+ }
+
+ done:
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ test fixed enumeration
+*/
+
+static bool test_fixed(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create create;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_find f;
+ union smb_search_data *d;
+ struct file_elem files[NFILES] = {};
+ NTSTATUS status;
+ bool ret = true;
+ unsigned int count;
+ int i;
+
+ status = populate_tree(tctx, mem_ctx, tree, files, NFILES, &h);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = DNAME;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ h2 = create.out.file.handle;
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ f.in.max_response_size = 0x100;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ /* Start enumeration on h, then delete all from h2 */
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ f.in.file.handle = h2;
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ for (i = 0; i < count; i++) {
+ const char *found = d[i].both_directory_info.name.s;
+ char *path = talloc_asprintf(mem_ctx, "%s\\%s",
+ DNAME, found);
+
+ if (!strcmp(found, ".") || !strcmp(found, ".."))
+ continue;
+
+ status = smb2_util_unlink(tree, path);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "");
+
+ talloc_free(path);
+ }
+
+ f.in.continue_flags = 0;
+ f.in.max_response_size = 4096;
+ } while (count != 0);
+
+ /* Now finish h enumeration. */
+ f.in.file.handle = h;
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ for (i = 0; i < count; i++) {
+ const char *found = d[i].both_directory_info.name.s;
+
+ if (!strcmp(found, ".") || !strcmp(found, ".."))
+ continue;
+
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): didn't expect %s (count=%u)\n",
+ __location__, found, count);
+ ret = false;
+ goto done;
+ }
+
+ f.in.continue_flags = 0;
+ f.in.max_response_size = 4096;
+ } while (count != 0);
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static struct {
+ const char *name;
+ uint8_t level;
+ enum smb_search_data_level data_level;
+ int name_offset;
+ int resume_key_offset;
+ uint32_t capability_mask;
+ NTSTATUS status;
+ union smb_search_data data;
+} levels[] = {
+ {
+ .name = "SMB2_FIND_DIRECTORY_INFO",
+ .level = SMB2_FIND_DIRECTORY_INFO,
+ .data_level = RAW_SEARCH_DATA_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ directory_info.file_index),
+ },
+ {
+ .name = "SMB2_FIND_FULL_DIRECTORY_INFO",
+ .level = SMB2_FIND_FULL_DIRECTORY_INFO,
+ .data_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ full_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ full_directory_info.file_index),
+ },
+ {
+ .name = "SMB2_FIND_NAME_INFO",
+ .level = SMB2_FIND_NAME_INFO,
+ .data_level = RAW_SEARCH_DATA_NAME_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ name_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ name_info.file_index),
+ },
+ {
+ .name = "SMB2_FIND_BOTH_DIRECTORY_INFO",
+ .level = SMB2_FIND_BOTH_DIRECTORY_INFO,
+ .data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ both_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ both_directory_info.file_index),
+ },
+ {
+ .name = "SMB2_FIND_ID_FULL_DIRECTORY_INFO",
+ .level = SMB2_FIND_ID_FULL_DIRECTORY_INFO,
+ .data_level = RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ id_full_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ id_full_directory_info.file_index),
+ },
+ {
+ .name = "SMB2_FIND_ID_BOTH_DIRECTORY_INFO",
+ .level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ .data_level = RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO,
+ .name_offset = offsetof(union smb_search_data,
+ id_both_directory_info.name.s),
+ .resume_key_offset = offsetof(union smb_search_data,
+ id_both_directory_info.file_index),
+ }
+};
+
+/*
+ extract the name from a smb_data structure and level
+*/
+static const char *extract_name(union smb_search_data *data,
+ uint8_t level,
+ enum smb_search_data_level data_level)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (level == levels[i].level &&
+ data_level == levels[i].data_level) {
+ return *(const char **)(levels[i].name_offset + (char *)data);
+ }
+ }
+ return NULL;
+}
+
+/* find a level in the table by name */
+static union smb_search_data *find(const char *name)
+{
+ int i;
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ if (NT_STATUS_IS_OK(levels[i].status) &&
+ strcmp(levels[i].name, name) == 0) {
+ return &levels[i].data;
+ }
+ }
+ return NULL;
+}
+
+static bool fill_level_data(TALLOC_CTX *mem_ctx,
+ union smb_search_data *data,
+ union smb_search_data *d,
+ unsigned int count,
+ uint8_t level,
+ enum smb_search_data_level data_level)
+{
+ int i;
+ const char *sname = NULL;
+ for (i=0; i < count ; i++) {
+ sname = extract_name(&d[i], level, data_level);
+ if (sname == NULL)
+ return false;
+ if (!strcmp(sname, ".") || !strcmp(sname, ".."))
+ continue;
+ *data = d[i];
+ }
+ return true;
+}
+
+
+NTSTATUS torture_single_file_search(struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ const char *pattern,
+ uint8_t level,
+ enum smb_search_data_level data_level,
+ int idx,
+ union smb_search_data *d,
+ unsigned int *count,
+ struct smb2_handle *h)
+{
+ struct smb2_find f;
+ NTSTATUS status;
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = *h;
+ f.in.pattern = pattern;
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
+ f.in.max_response_size = 0x100;
+ f.in.level = level;
+
+ status = smb2_find_level(tree, tree, &f, count, &d);
+ if (NT_STATUS_IS_OK(status))
+ fill_level_data(mem_ctx, &levels[idx].data, d, *count, level,
+ data_level);
+ return status;
+}
+
+/*
+ basic testing of all File Information Classes using a single file
+*/
+static bool test_one_file(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ bool ret = true;
+ const char *fname = "torture_search.txt";
+ NTSTATUS status;
+ int i;
+ unsigned int count;
+ union smb_fileinfo all_info2, alt_info, internal_info;
+ union smb_search_data *s;
+ union smb_search_data d;
+ struct smb2_handle h, h2;
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ status = smb2_create_complex_file(tctx, tree, DNAME "\\torture_search.txt",
+ &h2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ /* call all the File Information Classes */
+ for (i=0;i<ARRAY_SIZE(levels);i++) {
+ torture_comment(tctx, "Testing %s %d\n", levels[i].name,
+ levels[i].level);
+
+ levels[i].status = torture_single_file_search(tree, mem_ctx,
+ fname, levels[i].level, levels[i].data_level,
+ i, &d, &count, &h);
+ torture_assert_ntstatus_ok_goto(tctx, levels[i].status, ret,
+ done, "");
+ }
+
+ /* get the all_info file into to check against */
+ all_info2.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ all_info2.generic.in.file.handle = h2;
+ status = smb2_getinfo_file(tree, tctx, &all_info2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "RAW_FILEINFO_ALL_INFO failed");
+
+ alt_info.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
+ alt_info.generic.in.file.handle = h2;
+ status = smb2_getinfo_file(tree, tctx, &alt_info);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "RAW_FILEINFO_ALT_NAME_INFO failed");
+
+ internal_info.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
+ internal_info.generic.in.file.handle = h2;
+ status = smb2_getinfo_file(tree, tctx, &internal_info);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "RAW_FILEINFO_INTERNAL_INFORMATION "
+ "failed");
+
+#define CHECK_VAL(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if ((s->sname1.field1) != (v.sname2.out.field2)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \
+ __location__, \
+ #sname1, #field1, (int)s->sname1.field1, \
+ #sname2, #field2, (int)v.sname2.out.field2); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_TIME(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (s->sname1.field1 != \
+ (~1 & nt_time_to_unix(v.sname2.out.field2))) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, \
+ timestring(tctx, s->sname1.field1), \
+ #sname2, #field2, \
+ nt_time_string(tctx, v.sname2.out.field2)); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_NTTIME(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (s->sname1.field1 != v.sname2.out.field2) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, \
+ nt_time_string(tctx, s->sname1.field1), \
+ #sname2, #field2, \
+ nt_time_string(tctx, v.sname2.out.field2)); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_STR(name, sname1, field1, v, sname2, field2) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1 || \
+ strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1, \
+ #sname2, #field2, v.sname2.out.field2.s); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_WSTR(name, sname1, field1, v, sname2, field2, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1.s || \
+ strcmp(s->sname1.field1.s, v.sname2.out.field2.s)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [%s] != %s/%s [%s]\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1.s, \
+ #sname2, #field2, v.sname2.out.field2.s); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_NAME(name, sname1, field1, fname, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1.s || \
+ strcmp(s->sname1.field1.s, fname)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [%s] != %s\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1.s, fname); \
+ ret = false; \
+ } \
+ }} while (0)
+
+#define CHECK_UNIX_NAME(name, sname1, field1, fname, flags) do { \
+ s = find(name); \
+ if (s) { \
+ if (!s->sname1.field1 || \
+ strcmp(s->sname1.field1, fname)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s/%s [%s] != %s\n", \
+ __location__, \
+ #sname1, #field1, s->sname1.field1, fname); \
+ ret = false; \
+ } \
+ }} while (0)
+
+ /* check that all the results are as expected */
+ CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info, attrib, all_info2, all_info2, attrib);
+ CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, attrib, all_info2, all_info2, attrib);
+ CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, attrib, all_info2, all_info2, attrib);
+ CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, attrib, all_info2, all_info2, attrib);
+ CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, attrib, all_info2, all_info2, attrib);
+
+ CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, write_time, all_info2, all_info2, write_time);
+ CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, write_time, all_info2, all_info2, write_time);
+ CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, write_time, all_info2, all_info2, write_time);
+ CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, write_time, all_info2, all_info2, write_time);
+ CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, write_time, all_info2, all_info2, write_time);
+
+ CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, create_time, all_info2, all_info2, create_time);
+ CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, create_time, all_info2, all_info2, create_time);
+ CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, create_time, all_info2, all_info2, create_time);
+ CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, create_time, all_info2, all_info2, create_time);
+ CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, create_time, all_info2, all_info2, create_time);
+
+ CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, access_time, all_info2, all_info2, access_time);
+ CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, access_time, all_info2, all_info2, access_time);
+ CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, access_time, all_info2, all_info2, access_time);
+ CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, access_time, all_info2, all_info2, access_time);
+ CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, access_time, all_info2, all_info2, access_time);
+
+ CHECK_NTTIME("SMB2_FIND_DIRECTORY_INFO", directory_info, change_time, all_info2, all_info2, change_time);
+ CHECK_NTTIME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, change_time, all_info2, all_info2, change_time);
+ CHECK_NTTIME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, change_time, all_info2, all_info2, change_time);
+ CHECK_NTTIME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, change_time, all_info2, all_info2, change_time);
+ CHECK_NTTIME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, change_time, all_info2, all_info2, change_time);
+
+ CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info, size, all_info2, all_info2, size);
+ CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, size, all_info2, all_info2, size);
+ CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, size, all_info2, all_info2, size);
+ CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, size, all_info2, all_info2, size);
+ CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, size, all_info2, all_info2, size);
+
+ CHECK_VAL("SMB2_FIND_DIRECTORY_INFO", directory_info, alloc_size, all_info2, all_info2, alloc_size);
+ CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, alloc_size, all_info2, all_info2, alloc_size);
+ CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, alloc_size, all_info2, all_info2, alloc_size);
+ CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, alloc_size, all_info2, all_info2, alloc_size);
+ CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, alloc_size, all_info2, all_info2, alloc_size);
+
+ CHECK_VAL("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, ea_size, all_info2, all_info2, ea_size);
+ CHECK_VAL("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, ea_size, all_info2, all_info2, ea_size);
+ CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, ea_size, all_info2, all_info2, ea_size);
+ CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, ea_size, all_info2, all_info2, ea_size);
+
+ CHECK_NAME("SMB2_FIND_DIRECTORY_INFO", directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("SMB2_FIND_FULL_DIRECTORY_INFO", full_directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("SMB2_FIND_NAME_INFO", name_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname, STR_TERMINATE_ASCII);
+ CHECK_NAME("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname, STR_TERMINATE_ASCII);
+
+ CHECK_WSTR("SMB2_FIND_BOTH_DIRECTORY_INFO", both_directory_info, short_name, alt_info, alt_name_info, fname, STR_UNICODE);
+
+ CHECK_VAL("SMB2_FIND_ID_FULL_DIRECTORY_INFO", id_full_directory_info, file_id, internal_info, internal_information, file_id);
+ CHECK_VAL("SMB2_FIND_ID_BOTH_DIRECTORY_INFO", id_both_directory_info, file_id, internal_info, internal_information, file_id);
+
+done:
+ smb2_util_close(tree, h);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+struct multiple_result {
+ TALLOC_CTX *tctx;
+ int count;
+ union smb_search_data *list;
+};
+
+bool fill_result(void *private_data,
+ union smb_search_data *file,
+ int count,
+ uint8_t level,
+ enum smb_search_data_level data_level)
+{
+ int i;
+ const char *sname;
+ struct multiple_result *data = (struct multiple_result *)private_data;
+
+ for (i=0; i<count; i++) {
+ sname = extract_name(&file[i], level, data_level);
+ if (!strcmp(sname, ".") || !(strcmp(sname, "..")))
+ continue;
+ data->count++;
+ data->list = talloc_realloc(data->tctx,
+ data->list,
+ union smb_search_data,
+ data->count);
+ data->list[data->count-1] = file[i];
+ }
+ return true;
+}
+
+enum continue_type {CONT_SINGLE, CONT_INDEX, CONT_RESTART, CONT_REOPEN};
+
+static NTSTATUS multiple_smb2_search(struct smb2_tree *tree,
+ TALLOC_CTX *tctx,
+ const char *pattern,
+ uint8_t level,
+ enum smb_search_data_level data_level,
+ enum continue_type cont_type,
+ void *data,
+ struct smb2_handle *h)
+{
+ struct smb2_find f;
+ bool ret = true;
+ unsigned int count = 0;
+ union smb_search_data *d;
+ NTSTATUS status;
+ struct multiple_result *result = (struct multiple_result *)data;
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = *h;
+ f.in.pattern = pattern;
+ f.in.max_response_size = 1024*1024;
+ f.in.level = level;
+
+ /* The search should start from the beginning every time */
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
+ if (cont_type == CONT_REOPEN) {
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_REOPEN;
+ }
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ if (!fill_result(result, d, count, level, data_level)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (count == 0 || result == NULL || result->count == 0) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /*
+ * After the first iteration is complete set the CONTINUE
+ * FLAGS appropriately
+ */
+ switch (cont_type) {
+ case CONT_INDEX:
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_INDEX;
+ switch (data_level) {
+ case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
+ f.in.file_index =
+ result->list[result->count-1].both_directory_info.file_index;
+ break;
+ case RAW_SEARCH_DATA_DIRECTORY_INFO:
+ f.in.file_index =
+ result->list[result->count-1].directory_info.file_index;
+ break;
+ case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
+ f.in.file_index =
+ result->list[result->count-1].full_directory_info.file_index;
+ break;
+ case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
+ f.in.file_index =
+ result->list[result->count-1].id_full_directory_info.file_index;
+ break;
+ case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
+ f.in.file_index =
+ result->list[result->count-1].id_both_directory_info.file_index;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ break;
+ case CONT_SINGLE:
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ break;
+ case CONT_RESTART:
+ default:
+ /* we should prevent staying in the loop
+ * forever */
+ f.in.continue_flags = 0;
+ break;
+ }
+ } while (count != 0);
+done:
+ if (!ret) {
+ return status;
+ }
+ return status;
+}
+
+
+static enum smb_search_data_level compare_data_level;
+uint8_t level_sort;
+
+static int search_compare(union smb_search_data *d1,
+ union smb_search_data *d2)
+{
+ const char *s1, *s2;
+
+ s1 = extract_name(d1, level_sort, compare_data_level);
+ s2 = extract_name(d2, level_sort, compare_data_level);
+ return strcmp_safe(s1, s2);
+}
+
+/*
+ basic testing of search calls using many files
+*/
+static bool test_many_files(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const int num_files = 700;
+ int i, t;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ struct smb2_create create;
+ struct smb2_handle h;
+ struct {
+ const char *name;
+ const char *cont_name;
+ uint8_t level;
+ enum smb_search_data_level data_level;
+ enum continue_type cont_type;
+ } search_types[] = {
+ {"SMB2_FIND_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_SINGLE},
+ {"SMB2_FIND_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_INDEX},
+ {"SMB2_FIND_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_RESTART},
+ {"SMB2_FIND_BOTH_DIRECTORY_INFO", "REOPEN", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_REOPEN},
+ {"SMB2_FIND_DIRECTORY_INFO", "SINGLE", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_SINGLE},
+ {"SMB2_FIND_DIRECTORY_INFO", "INDEX", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_INDEX},
+ {"SMB2_FIND_DIRECTORY_INFO", "RESTART", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_RESTART},
+ {"SMB2_FIND_DIRECTORY_INFO", "REOPEN", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_REOPEN},
+ {"SMB2_FIND_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_SINGLE},
+ {"SMB2_FIND_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_INDEX},
+ {"SMB2_FIND_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_RESTART},
+ {"SMB2_FIND_FULL_DIRECTORY_INFO", "REOPEN", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_REOPEN},
+ {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_SINGLE},
+ {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_INDEX},
+ {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESTART},
+ {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "REOPEN", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_REOPEN},
+ {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_SINGLE},
+ {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_INDEX},
+ {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESTART},
+ {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "REOPEN", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_REOPEN},
+ };
+
+ smb2_deltree(tree, DNAME);
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ torture_comment(tctx, "Testing with %d files\n", num_files);
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ for (i=num_files-1;i>=0;i--) {
+ fname = talloc_asprintf(mem_ctx, DNAME "\\t%03d-%d.txt", i, i);
+ create.in.fname = talloc_asprintf(mem_ctx, "%s", fname);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ smb2_util_close(tree, create.out.file.handle);
+ talloc_free(fname);
+ }
+
+ for (t=0;t<ARRAY_SIZE(search_types);t++) {
+ ZERO_STRUCT(result);
+ result.tctx = talloc_new(tctx);
+
+ torture_comment(tctx,
+ "Continue %s via %s\n", search_types[t].name,
+ search_types[t].cont_name);
+ status = multiple_smb2_search(tree, tctx, "*",
+ search_types[t].level,
+ search_types[t].data_level,
+ search_types[t].cont_type,
+ &result, &h);
+
+ torture_assert_int_equal_goto(tctx, result.count, num_files,
+ ret, done, "");
+
+ compare_data_level = search_types[t].data_level;
+ level_sort = search_types[t].level;
+
+ TYPESAFE_QSORT(result.list, result.count, search_compare);
+
+ for (i=0;i<result.count;i++) {
+ const char *s;
+ s = extract_name(&result.list[i],
+ search_types[t].level,
+ compare_data_level);
+ fname = talloc_asprintf(mem_ctx, "t%03d-%d.txt", i, i);
+ torture_assert_str_equal_goto(tctx, s, fname, ret,
+ done, "Incorrect name");
+ talloc_free(fname);
+ }
+ talloc_free(result.tctx);
+ }
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ check an individual file result
+*/
+static bool check_result(struct torture_context *tctx,
+ struct multiple_result *result,
+ const char *name,
+ bool exist,
+ uint32_t attrib)
+{
+ int i;
+ for (i=0;i<result->count;i++) {
+ if (strcmp(name,
+ result->list[i].both_directory_info.name.s) == 0) {
+ break;
+ }
+ }
+ if (i == result->count) {
+ if (exist) {
+ torture_result(tctx, TORTURE_FAIL,
+ "failed: '%s' should exist with attribute %s\n",
+ name, attrib_string(result->list, attrib));
+ return false;
+ }
+ return true;
+ }
+
+ if (!exist) {
+ torture_result(tctx, TORTURE_FAIL,
+ "failed: '%s' should NOT exist (has attribute %s)\n",
+ name, attrib_string(result->list,
+ result->list[i].both_directory_info.attrib));
+ return false;
+ }
+
+ if ((result->list[i].both_directory_info.attrib&0xFFF) != attrib) {
+ torture_result(tctx, TORTURE_FAIL,
+ "failed: '%s' should have attribute 0x%x (has 0x%x)\n",
+ name, attrib, result->list[i].both_directory_info.attrib);
+ return false;
+ }
+ return true;
+}
+
+/*
+ test what happens when the directory is modified during a search
+*/
+static bool test_modify_search(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct multiple_result result;
+ union smb_setfileinfo sfinfo;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create create;
+ struct smb2_handle h;
+ struct smb2_find f;
+ union smb_search_data *d;
+ struct file_elem files[703] = {};
+ int num_files = ARRAY_SIZE(files)-3;
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+ unsigned int count;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ torture_comment(tctx, "Creating %d files\n", num_files);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ for (i = num_files-1; i >= 0; i--) {
+ files[i].name = talloc_asprintf(mem_ctx, "t%03d-%d.txt", i, i);
+ create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s",
+ DNAME, files[i].name);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ smb2_util_close(tree, create.out.file.handle);
+ }
+
+ torture_comment(tctx, "pulling the first two files\n");
+ ZERO_STRUCT(result);
+ result.tctx = talloc_new(tctx);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ f.in.max_response_size = 0x100;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ if (!fill_result(&result, d, count, f.in.level,
+ RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO)) {
+ ret = false;
+ goto done;
+ }
+ } while (result.count < 2);
+
+ torture_comment(tctx, "Changing attributes and deleting\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ files[num_files].name = talloc_asprintf(mem_ctx, "T003-03.txt.2");
+ create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s", DNAME,
+ files[num_files].name);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ smb2_util_close(tree, create.out.file.handle);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ files[num_files + 1].name = talloc_asprintf(mem_ctx, "T013-13.txt.2");
+ create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s", DNAME,
+ files[num_files + 1].name);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ smb2_util_close(tree, create.out.file.handle);
+
+ files[num_files + 2].name = talloc_asprintf(mem_ctx, "T013-13.txt.3");
+ status = smb2_create_complex_file(tctx, tree, DNAME "\\T013-13.txt.3", &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ smb2_util_unlink(tree, DNAME "\\T014-14.txt");
+ smb2_util_setatr(tree, DNAME "\\T015-15.txt", FILE_ATTRIBUTE_HIDDEN);
+ smb2_util_setatr(tree, DNAME "\\T016-16.txt", FILE_ATTRIBUTE_NORMAL);
+ smb2_util_setatr(tree, DNAME "\\T017-17.txt", FILE_ATTRIBUTE_SYSTEM);
+ smb2_util_setatr(tree, DNAME "\\T018-18.txt", 0);
+ smb2_util_setatr(tree, DNAME "\\T039-39.txt", FILE_ATTRIBUTE_HIDDEN);
+ smb2_util_setatr(tree, DNAME "\\T000-0.txt", FILE_ATTRIBUTE_HIDDEN);
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.path = DNAME "\\T013-13.txt.3";
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb2_composite_setpathinfo(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ /* Reset the numfiles to include the new files and start the
+ * search from the beginning */
+ num_files = num_files + 2;
+ f.in.pattern = "*";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
+ result.count = 0;
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ if (!fill_result(&result, d, count, f.in.level,
+ RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO)) {
+ ret = false;
+ goto done;
+ }
+ f.in.continue_flags = 0;
+ f.in.max_response_size = 4096;
+ } while (count != 0);
+
+
+ ret &= check_result(tctx, &result, "t039-39.txt", true, FILE_ATTRIBUTE_HIDDEN);
+ ret &= check_result(tctx, &result, "t000-0.txt", true, FILE_ATTRIBUTE_HIDDEN);
+ ret &= check_result(tctx, &result, "t014-14.txt", false, 0);
+ ret &= check_result(tctx, &result, "t015-15.txt", true, FILE_ATTRIBUTE_HIDDEN);
+ ret &= check_result(tctx, &result, "t016-16.txt", true, FILE_ATTRIBUTE_NORMAL);
+ ret &= check_result(tctx, &result, "t017-17.txt", true, FILE_ATTRIBUTE_SYSTEM);
+ ret &= check_result(tctx, &result, "t018-18.txt", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(tctx, &result, "t019-19.txt", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(tctx, &result, "T013-13.txt.2", true, FILE_ATTRIBUTE_ARCHIVE);
+ ret &= check_result(tctx, &result, "T003-3.txt.2", false, 0);
+ ret &= check_result(tctx, &result, "T013-13.txt.3", true, FILE_ATTRIBUTE_NORMAL);
+
+ if (!ret) {
+ for (i=0;i<result.count;i++) {
+ torture_warning(tctx, "%s %s (0x%x)\n",
+ result.list[i].both_directory_info.name.s,
+ attrib_string(tctx,
+ result.list[i].both_directory_info.attrib),
+ result.list[i].both_directory_info.attrib);
+ }
+ }
+ done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ testing if directories always come back sorted
+*/
+static bool test_sorted(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const int num_files = 700;
+ int i;
+ struct file_elem files[700] = {};
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ struct smb2_handle h;
+
+ torture_comment(tctx, "Testing if directories always come back "
+ "sorted\n");
+ status = populate_tree(tctx, mem_ctx, tree, files, num_files, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+
+ status = multiple_smb2_search(tree, tctx, "*",
+ SMB2_FIND_BOTH_DIRECTORY_INFO,
+ RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,
+ SMB2_CONTINUE_FLAG_SINGLE,
+ &result, &h);
+
+ torture_assert_int_equal_goto(tctx, result.count, num_files, ret, done,
+ "");
+
+ for (i=0;i<num_files-1;i++) {
+ const char *name1, *name2;
+ name1 = result.list[i].both_directory_info.name.s;
+ name2 = result.list[i+1].both_directory_info.name.s;
+ if (strcasecmp_m(name1, name2) > 0) {
+ torture_comment(tctx, "non-alphabetical order at entry "
+ "%d '%s' '%s'\n", i, name1, name2);
+ torture_comment(tctx,
+ "Server does not produce sorted directory listings"
+ "(not an error)\n");
+ goto done;
+ }
+ }
+ talloc_free(result.list);
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/* test the behavior of file_index field in the SMB2_FIND struct */
+static bool test_file_index(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const int num_files = 100;
+ int resume_index = 4;
+ int i;
+ char *fname;
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ struct smb2_create create;
+ struct smb2_find f;
+ struct smb2_handle h;
+ union smb_search_data *d;
+ unsigned count;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ torture_comment(tctx, "Testing the behavior of file_index flag\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ for (i = num_files-1; i >= 0; i--) {
+ fname = talloc_asprintf(mem_ctx, DNAME "\\file%u.txt", i);
+ create.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ talloc_free(fname);
+ smb2_util_close(tree, create.out.file.handle);
+ }
+
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_FULL_DIRECTORY_INFO;
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ if (!fill_result(&result, d, count, f.in.level,
+ RAW_SEARCH_DATA_FULL_DIRECTORY_INFO)) {
+ ret = false;
+ goto done;
+ }
+ } while(result.count < 10);
+
+ if (result.list[0].full_directory_info.file_index == 0) {
+ torture_skip_goto(tctx, done,
+ "Talking to a server that doesn't provide a "
+ "file index.\nWindows servers using NTFS do "
+ "not provide a file_index. Skipping test\n");
+ } else {
+ /* We are not talking to a Windows based server. Windows
+ * servers using NTFS do not provide a file_index. Windows
+ * servers using FAT do provide a file index, however in both
+ * cases they do not honor a file index on a resume request.
+ * See MS-FSCC <62> and MS-SMB2 <54> for more information. */
+
+ /* Set the file_index flag to point to the fifth file from the
+ * previous enumeration and try to start the subsequent
+ * searches from that point */
+ f.in.file_index =
+ result.list[resume_index].full_directory_info.file_index;
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_INDEX;
+
+ /* get the name of the next expected file */
+ fname = talloc_asprintf(mem_ctx, DNAME "\\%s",
+ result.list[resume_index].full_directory_info.name.s);
+
+ ZERO_STRUCT(result);
+ result.tctx = tctx;
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ goto done;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ if (!fill_result(&result, d, count, f.in.level,
+ RAW_SEARCH_DATA_FULL_DIRECTORY_INFO)) {
+ ret = false;
+ goto done;
+ }
+ if (strcmp(fname,
+ result.list[0].full_directory_info.name.s)) {
+ torture_comment(tctx, "Next expected file: %s but the "
+ "server returned %s\n", fname,
+ result.list[0].full_directory_info.name.s);
+ torture_comment(tctx,
+ "Not an error. Resuming using a file "
+ "index is an optional feature of the "
+ "protocol.\n");
+ goto done;
+ }
+ }
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Tests directory enumeration in a directory containing >1000 files with
+ * names of varying lengths.
+ */
+static bool test_large_files(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const int num_files = 2000;
+ int max_len = 200;
+ /* These should be evenly divisible */
+ int num_at_len = num_files / max_len;
+ struct file_elem files[2000] = {};
+ size_t len = 1;
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_find f;
+ struct smb2_handle h = {{0}};
+ union smb_search_data *d;
+ int i, j = 0, file_count = 0;
+ char **strs = NULL;
+ unsigned count;
+ struct timespec ts1, ts2;
+
+ torture_comment(tctx,
+ "Testing directory enumeration in a directory with >1000 files\n");
+
+ smb2_deltree(tree, DNAME);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = DNAME;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ h = create.out.file.handle;
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ for (i = 0; i < num_files; i++) {
+ if (i % num_at_len == 0) {
+ strs = generate_unique_strs(mem_ctx, len, num_at_len);
+ len++;
+ }
+ files[i].name = strs[i % num_at_len];
+ create.in.fname = talloc_asprintf(mem_ctx, "%s\\%s",
+ DNAME, files[i].name);
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+ smb2_util_close(tree, create.out.file.handle);
+ }
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "*";
+ f.in.max_response_size = 0x100;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ clock_gettime_mono(&ts1);
+
+ do {
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES))
+ break;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ for (i = 0; i < count; i++) {
+ bool expected;
+ const char *found = d[i].both_directory_info.name.s;
+
+ if (!strcmp(found, ".") || !strcmp(found, ".."))
+ continue;
+
+ expected = false;
+ for (j = 0; j < 2000; j++) {
+ if (!strcmp(files[j].name, found)) {
+ files[j].found = true;
+ expected = true;
+ break;
+ }
+ }
+
+ if (expected)
+ continue;
+
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): didn't expect %s\n",
+ __location__, found);
+ ret = false;
+ goto done;
+ }
+ file_count = file_count + i;
+ f.in.continue_flags = 0;
+ f.in.max_response_size = 4096;
+ } while (count != 0);
+
+ torture_assert_int_equal_goto(tctx, file_count, num_files + 2, ret,
+ done, "");
+
+ clock_gettime_mono(&ts2);
+
+ for (i = 0; i < num_files; i++) {
+ if (files[j].found)
+ continue;
+
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s): expected to find %s, but didn't\n",
+ __location__, files[j].name);
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(tctx, "Directory enumeration completed in %.3f s.\n",
+ timespec_elapsed2(&ts1, &ts2));
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * basic testing of search calls using many files,
+ * including renaming files
+ */
+#define NUM_FILES 1000
+static bool test_1k_files_rename(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const int num_files = NUM_FILES;
+ int rename_index = 0;
+ int i, j;
+ char *fname_list[NUM_FILES] = {0};
+ bool ret = true;
+ NTSTATUS status;
+ struct multiple_result result;
+ struct smb2_create create;
+ struct smb2_create dir;
+ struct smb2_handle dir_handle;
+ struct smb2_create open;
+ union smb_setfileinfo sinfo;
+ struct timespec ts1, ts2;
+ bool reopen;
+
+ reopen = torture_setting_bool(tctx, "1k_files_rename_reopendir", false);
+
+ torture_comment(tctx, "Testing with %d files\n", num_files);
+
+ smb2_deltree(tree, DNAME);
+
+ dir = (struct smb2_create) {
+ .in.desired_access = SEC_DIR_LIST,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.fname = DNAME,
+ };
+
+ status = smb2_create(tree, tree, &dir);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Could not create test directory");
+
+ dir_handle = dir.out.file.handle;
+
+ /* Create 1k files, store in array for later rename */
+
+ torture_comment(tctx, "Create files.\n");
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_ALL,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ };
+
+ for (i = num_files - 1; i >= 0; i--) {
+ fname_list[i] = talloc_asprintf(mem_ctx, DNAME "\\t%03d.txt", i);
+ torture_assert_not_null_goto(tctx, fname_list[i], ret, done,
+ "talloc_asprintf failed");
+
+ create.in.fname = fname_list[i];
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ status = smb2_util_close(tree, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ }
+
+ open = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_ALL | SEC_STD_DELETE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ };
+
+ clock_gettime_mono(&ts1);
+
+ for (j = 0; j < 100; j++) {
+ ZERO_STRUCT(result);
+ result.tctx = talloc_new(tctx);
+
+ torture_comment(tctx, "Iteration: %02d of 100.\n", j);
+
+ if (reopen) {
+ torture_comment(
+ tctx, "Close and reopen test directory \n");
+ smb2_util_close(tree, dir_handle);
+
+ status = smb2_create(tree, tree, &dir);
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ret, done,
+ "Could not reopen test directory");
+
+ dir_handle = dir.out.file.handle;
+ }
+
+ status = multiple_smb2_search(tree, tctx, "*",
+ SMB2_FIND_FULL_DIRECTORY_INFO,
+ RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,
+ 100,
+ &result, &dir_handle);
+ torture_assert_int_equal_goto(tctx, result.count, num_files,
+ ret, done, "Wrong number of files");
+
+ /* Check name validity of all files*/
+ compare_data_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO;
+ level_sort = SMB2_FIND_FULL_DIRECTORY_INFO;
+
+ TYPESAFE_QSORT(result.list, result.count, search_compare);
+
+ for (i = 0; i < result.count; i++) {
+ const char *s = NULL;
+ char *dname_s = NULL;
+
+ s = extract_name(&result.list[i],
+ SMB2_FIND_FULL_DIRECTORY_INFO,
+ RAW_SEARCH_DATA_FULL_DIRECTORY_INFO);
+ dname_s = talloc_asprintf(mem_ctx, DNAME "\\%s", s);
+ torture_assert_not_null_goto(tctx, dname_s, ret, done,
+ "talloc_asprintf failed");
+
+ torture_assert_str_equal_goto(tctx, dname_s, fname_list[i], ret,
+ done, "Incorrect name\n");
+ TALLOC_FREE(dname_s);
+ }
+
+ TALLOC_FREE(result.tctx);
+
+ /* Rename one file */
+ open.in.fname = fname_list[rename_index];
+
+ status = smb2_create(tree, tctx, &open);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed open\n");
+
+ sinfo = (union smb_setfileinfo) {
+ .rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION,
+ .rename_information.in.file.handle = open.out.file.handle,
+ };
+
+ TALLOC_FREE(fname_list[rename_index]);
+ fname_list[rename_index] = talloc_asprintf(
+ mem_ctx, DNAME "\\t%03d-rename.txt", rename_index);
+ sinfo.rename_information.in.new_name = fname_list[rename_index];
+
+ torture_comment(tctx, "Renaming test file to: %s\n",
+ sinfo.rename_information.in.new_name);
+
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed setinfo/rename\n");
+
+ rename_index++;
+ smb2_util_close(tree, open.out.file.handle);
+ }
+
+ clock_gettime_mono(&ts2);
+
+ torture_comment(tctx, "\nDirectory enumeration completed in %.3f s.\n",
+ timespec_elapsed2(&ts1, &ts2));
+
+done:
+ TALLOC_FREE(mem_ctx);
+ smb2_util_close(tree, dir_handle);
+ smb2_deltree(tree, DNAME);
+ return ret;
+}
+#undef NUM_FILES
+
+struct torture_suite *torture_smb2_dir_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "dir");
+
+ torture_suite_add_1smb2_test(suite, "find", test_find);
+ torture_suite_add_1smb2_test(suite, "fixed", test_fixed);
+ torture_suite_add_1smb2_test(suite, "one", test_one_file);
+ torture_suite_add_1smb2_test(suite, "many", test_many_files);
+ torture_suite_add_1smb2_test(suite, "modify", test_modify_search);
+ torture_suite_add_1smb2_test(suite, "sorted", test_sorted);
+ torture_suite_add_1smb2_test(suite, "file-index", test_file_index);
+ torture_suite_add_1smb2_test(suite, "large-files", test_large_files);
+ torture_suite_add_1smb2_test(suite, "1kfiles_rename", test_1k_files_rename);
+
+ suite->description = talloc_strdup(suite, "SMB2-DIR tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/dosmode.c b/source4/torture/smb2/dosmode.c
new file mode 100644
index 0000000..7610a20
--- /dev/null
+++ b/source4/torture/smb2/dosmode.c
@@ -0,0 +1,254 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 setinfo individual test suite
+
+ Copyright (C) Ralph Boehme 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+/*
+ test dosmode and hidden files
+*/
+bool torture_smb2_dosmode(struct torture_context *tctx)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_tree *tree = NULL;
+ const char *dname = "torture_dosmode";
+ const char *fname = "torture_dosmode\\file";
+ const char *hidefile = "torture_dosmode\\hidefile";
+ const char *dotfile = "torture_dosmode\\.dotfile";
+ struct smb2_handle h1 = {{0}};
+ struct smb2_create io;
+ union smb_setfileinfo sfinfo;
+ union smb_fileinfo finfo2;
+
+ torture_comment(tctx, "Checking dosmode with \"hide files\" "
+ "and \"hide dot files\"\n");
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ smb2_deltree(tree, dname);
+
+ status = torture_smb2_testdir(tree, dname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed");
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.generic.in.file.handle = io.out.file.handle;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_filefailed");
+
+ ZERO_STRUCT(finfo2);
+ finfo2.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ finfo2.generic.in.file.handle = io.out.file.handle;
+ status = smb2_getinfo_file(tree, tctx, &finfo2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ torture_assert_int_equal_goto(tctx, finfo2.all_info2.out.attrib & FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_HIDDEN, ret, done,
+ "FILE_ATTRIBUTE_HIDDEN is not set");
+
+ smb2_util_close(tree, io.out.file.handle);
+
+ /* This must fail with attribute mismatch */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done,"smb2_create failed");
+
+ /* Create a file in "hide files" */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.create_options = 0;
+ io.in.fname = hidefile;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+
+ ZERO_STRUCT(finfo2);
+ finfo2.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ finfo2.generic.in.file.handle = io.out.file.handle;
+ status = smb2_getinfo_file(tree, tctx, &finfo2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ torture_assert_int_equal_goto(tctx, finfo2.all_info2.out.attrib & FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_HIDDEN, ret, done,
+ "FILE_ATTRIBUTE_HIDDEN is not set");
+
+ smb2_util_close(tree, io.out.file.handle);
+
+ /* Overwrite a file in "hide files", should pass */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.create_options = 0;
+ io.in.fname = hidefile;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ smb2_util_close(tree, io.out.file.handle);
+
+ /* Create a "hide dot files" */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.create_options = 0;
+ io.in.fname = dotfile;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+
+ ZERO_STRUCT(finfo2);
+ finfo2.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ finfo2.generic.in.file.handle = io.out.file.handle;
+ status = smb2_getinfo_file(tree, tctx, &finfo2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ torture_assert_int_equal_goto(tctx, finfo2.all_info2.out.attrib & FILE_ATTRIBUTE_HIDDEN,
+ FILE_ATTRIBUTE_HIDDEN, ret, done,
+ "FILE_ATTRIBUTE_HIDDEN is not set");
+
+ smb2_util_close(tree, io.out.file.handle);
+
+ /* Overwrite a "hide dot files", should pass */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.create_options = 0;
+ io.in.fname = dotfile;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ smb2_util_close(tree, io.out.file.handle);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_deltree(tree, dname);
+ return ret;
+}
+
+bool torture_smb2_async_dosmode(struct torture_context *tctx)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_tree *tree = NULL;
+ const char *dname = "torture_dosmode";
+ const char *fname = "torture_dosmode\\file";
+ struct smb2_handle h = {{0}};
+ struct smb2_create io;
+ union smb_setfileinfo sfinfo;
+ struct smb2_find f;
+ union smb_search_data *d;
+ unsigned int count;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ smb2_deltree(tree, dname);
+
+ status = torture_smb2_testdir(tree, dname, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed");
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.generic.in.file.handle = io.out.file.handle;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_filefailed");
+
+ smb2_util_close(tree, io.out.file.handle);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = h;
+ f.in.pattern = "file";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "");
+
+ smb2_util_close(tree, h);
+ ZERO_STRUCT(h);
+
+ torture_assert_goto(tctx,
+ d->both_directory_info.attrib & FILE_ATTRIBUTE_HIDDEN,
+ ret, done,
+ "FILE_ATTRIBUTE_HIDDEN is not set\n");
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_deltree(tree, dname);
+ return ret;
+}
diff --git a/source4/torture/smb2/durable_open.c b/source4/torture/smb2/durable_open.c
new file mode 100644
index 0000000..f56c558
--- /dev/null
+++ b/source4/torture/smb2/durable_open.c
@@ -0,0 +1,2872 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 durable opens
+
+ Copyright (C) Stefan Metzmacher 2008
+ Copyright (C) Michael Adam 2011-2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should be 0x%llx\n", \
+ __location__, #v, (unsigned long long)v, (unsigned long long)correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_NOT_VAL(v, incorrect) do { \
+ if ((v) == (incorrect)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%llx - should not be 0x%llx\n", \
+ __location__, #v, (unsigned long long)v, (unsigned long long)incorrect); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_NOT_NULL(p) do { \
+ if ((p) == NULL) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): %s is NULL but it should not be.\n", \
+ __location__, #p); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_CREATED(__io, __created, __attribute) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
+ CHECK_VAL((__io)->out.size, 0); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while(0)
+
+#define CHECK_CREATED_SIZE(__io, __created, __attribute, __alloc_size, __size) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
+ if (__alloc_size != 0) { \
+ CHECK_VAL((__io)->out.alloc_size, (__alloc_size)); \
+ } \
+ CHECK_VAL((__io)->out.size, (__size)); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while(0)
+
+
+
+/**
+ * basic durable_open test.
+ * durable state should only be granted when requested
+ * along with a batch oplock or a handle lease.
+ *
+ * This test tests durable open with all possible oplock types.
+ */
+
+struct durable_open_vs_oplock {
+ const char *level;
+ const char *share_mode;
+ bool expected;
+};
+
+#define NUM_OPLOCK_TYPES 4
+#define NUM_SHARE_MODES 8
+#define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
+static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
+{
+ { "", "", false },
+ { "", "R", false },
+ { "", "W", false },
+ { "", "D", false },
+ { "", "RD", false },
+ { "", "RW", false },
+ { "", "WD", false },
+ { "", "RWD", false },
+
+ { "s", "", false },
+ { "s", "R", false },
+ { "s", "W", false },
+ { "s", "D", false },
+ { "s", "RD", false },
+ { "s", "RW", false },
+ { "s", "WD", false },
+ { "s", "RWD", false },
+
+ { "x", "", false },
+ { "x", "R", false },
+ { "x", "W", false },
+ { "x", "D", false },
+ { "x", "RD", false },
+ { "x", "RW", false },
+ { "x", "WD", false },
+ { "x", "RWD", false },
+
+ { "b", "", true },
+ { "b", "R", true },
+ { "b", "W", true },
+ { "b", "D", true },
+ { "b", "RD", true },
+ { "b", "RW", true },
+ { "b", "WD", true },
+ { "b", "RWD", true },
+};
+
+static bool test_one_durable_open_open_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ struct durable_open_vs_oplock test)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ bool ret = true;
+ struct smb2_create io;
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(test.share_mode),
+ smb2_util_oplock_level(test.level));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, test.expected);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_durable_open_open_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ bool ret = true;
+ int i;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_open_oplock_%s.dat", generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ /* test various oplock levels with durable open */
+
+ for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) {
+ ret = test_one_durable_open_open_oplock(tctx,
+ tree,
+ fname,
+ durable_open_vs_oplock_table[i]);
+ if (ret == false) {
+ goto done;
+ }
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic durable_open test.
+ * durable state should only be granted when requested
+ * along with a batch oplock or a handle lease.
+ *
+ * This test tests durable open with all valid lease types.
+ */
+
+struct durable_open_vs_lease {
+ const char *type;
+ const char *share_mode;
+ bool expected;
+};
+
+#define NUM_LEASE_TYPES 5
+#define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
+static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
+{
+ { "", "", false },
+ { "", "R", false },
+ { "", "W", false },
+ { "", "D", false },
+ { "", "RW", false },
+ { "", "RD", false },
+ { "", "WD", false },
+ { "", "RWD", false },
+
+ { "R", "", false },
+ { "R", "R", false },
+ { "R", "W", false },
+ { "R", "D", false },
+ { "R", "RW", false },
+ { "R", "RD", false },
+ { "R", "DW", false },
+ { "R", "RWD", false },
+
+ { "RW", "", false },
+ { "RW", "R", false },
+ { "RW", "W", false },
+ { "RW", "D", false },
+ { "RW", "RW", false },
+ { "RW", "RD", false },
+ { "RW", "WD", false },
+ { "RW", "RWD", false },
+
+ { "RH", "", true },
+ { "RH", "R", true },
+ { "RH", "W", true },
+ { "RH", "D", true },
+ { "RH", "RW", true },
+ { "RH", "RD", true },
+ { "RH", "WD", true },
+ { "RH", "RWD", true },
+
+ { "RHW", "", true },
+ { "RHW", "R", true },
+ { "RHW", "W", true },
+ { "RHW", "D", true },
+ { "RHW", "RW", true },
+ { "RHW", "RD", true },
+ { "RHW", "WD", true },
+ { "RHW", "RWD", true },
+};
+
+static bool test_one_durable_open_open_lease(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ struct durable_open_vs_lease test)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ bool ret = true;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ uint64_t lease;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ lease = random();
+
+ smb2_lease_create_share(&io, &ls, false /* dir */, fname,
+ smb2_util_share_access(test.share_mode),
+ lease,
+ smb2_util_lease_state(test.type));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, test.expected);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state(test.type));
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_durable_open_open_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ bool ret = true;
+ int i;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_open_lease_%s.dat", generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+
+ /* test various oplock levels with durable open */
+
+ for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) {
+ ret = test_one_durable_open_open_lease(tctx,
+ tree,
+ fname,
+ durable_open_vs_lease_table[i]);
+ if (ret == false) {
+ goto done;
+ }
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic test for doing a durable open
+ * and do a durable reopen on the same connection
+ * while the first open is still active (fails)
+ */
+static bool test_durable_open_reopen1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io1, io2;
+ bool ret = true;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io1.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /* try a durable reconnect while the file is still open */
+ ZERO_STRUCT(io2);
+ io2.in.fname = fname;
+ io2.in.durable_handle = h;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Basic test for doing a durable open
+ * and do a session reconnect while the first
+ * session is still active and the handle is
+ * still open in the client.
+ * This closes the original session and a
+ * durable reconnect on the new session succeeds.
+ */
+static bool test_durable_open_reopen1a(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ bool ret = true;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_tree *tree3 = NULL;
+ uint64_t previous_session_id;
+ struct smbcli_options options;
+ struct GUID orig_client_guid;
+
+ options = tree->session->transport->options;
+ orig_client_guid = options.client_guid;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen1a_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /*
+ * a session reconnect on a second tcp connection
+ */
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* for oplocks, the client guid can be different: */
+ options.client_guid = GUID_random();
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree2);
+ torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+
+ TALLOC_FREE(tree);
+
+ /*
+ * but a durable reconnect on the new session succeeds:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /*
+ * a session reconnect on a second tcp connection
+ */
+
+ previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli);
+
+ /* the original client_guid works just the same */
+ options.client_guid = orig_client_guid;
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree3);
+ torture_assert_goto(tctx, ret, ret, done, "could not reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+
+ TALLOC_FREE(tree2);
+
+ /*
+ * but a durable reconnect on the new session succeeds:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+
+ status = smb2_create(tree3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree == NULL) {
+ tree = tree2;
+ }
+
+ if (tree == NULL) {
+ tree = tree3;
+ }
+
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ h = NULL;
+ }
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * lease variant of reopen1a
+ *
+ * Basic test for doing a durable open and doing a session
+ * reconnect while the first session is still active and the
+ * handle is still open in the client.
+ * This closes the original session and a durable reconnect on
+ * the new session succeeds depending on the client guid:
+ *
+ * Durable reconnect on a session with a different client guid fails.
+ * Durable reconnect on a session with the original client guid succeeds.
+ */
+bool test_durable_open_reopen1a_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_tree *tree3 = NULL;
+ uint64_t previous_session_id;
+ struct smbcli_options options;
+ struct GUID orig_client_guid;
+
+ options = tree->session->transport->options;
+ orig_client_guid = options.client_guid;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = random();
+ smb2_lease_create(&io, &ls, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RWH"));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /*
+ * a session reconnect on a second tcp connection
+ * with a different client_guid does not allow
+ * the durable reconnect.
+ */
+
+ options.client_guid = GUID_random();
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree2);
+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+ TALLOC_FREE(tree);
+
+
+ /*
+ * but a durable reconnect on the new session with the wrong
+ * client guid fails
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * now a session reconnect on a second tcp connection
+ * with original client_guid allows the durable reconnect.
+ */
+
+ options.client_guid = orig_client_guid;
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree3);
+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
+
+ /*
+ * check that this has deleted the old session
+ * In this case, a durable reconnect attempt with the
+ * correct client_guid yields a different error code.
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ TALLOC_FREE(tree2);
+
+ /*
+ * but a durable reconnect on the new session succeeds:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false); /* no dh response context... */
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree == NULL) {
+ tree = tree2;
+ }
+
+ if (tree == NULL) {
+ tree = tree3;
+ }
+
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+static bool test_durable_open_reopen2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ bool ret = true;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /* disconnect, leaving the durable in place */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ /* the path name is ignored by the server */
+ io.in.fname = fname;
+ io.in.durable_handle = h; /* durable v1 reconnect request */
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect again, leaving the durable in place */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * show that the filename and many other fields
+ * are ignored. only the reconnect request blob
+ * is important.
+ */
+ ZERO_STRUCT(io);
+ /* the path name is ignored by the server */
+ io.in.security_flags = 0x78;
+ io.in.oplock_level = 0x78;
+ io.in.impersonation_level = 0x12345678;
+ io.in.create_flags = 0x12345678;
+ io.in.reserved = 0x12345678;
+ io.in.desired_access = 0x12345678;
+ io.in.file_attributes = 0x12345678;
+ io.in.share_access = 0x12345678;
+ io.in.create_disposition = 0x12345678;
+ io.in.create_options = 0x12345678;
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_handle = h; /* durable v1 reconnect request */
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect, leaving the durable in place */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * show that an additionally specified durable v1 request
+ * is ignored by the server.
+ * See MS-SMB2, 3.3.5.9.7
+ * Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
+ */
+ ZERO_STRUCT(io);
+ /* the path name is ignored by the server */
+ io.in.fname = fname;
+ io.in.durable_handle = h; /* durable v1 reconnect request */
+ io.in.durable_open = true; /* durable v1 handle request */
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * lease variant of reopen2
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+static bool test_durable_open_reopen2_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smbcli_options options;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = random();
+ smb2_lease_create(&io, &ls, false /* dir */, fname, lease_key,
+ smb2_util_lease_state("RWH"));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+
+ /* disconnect, reconnect and then do durable reopen */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+
+ /* a few failure tests: */
+
+ /*
+ * several attempts without lease attached:
+ * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * irrespective of file name provided
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_handle = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * attempt with lease provided, but
+ * with a changed lease key. => fails
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open = false;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+ /* a wrong lease key lets the request fail */
+ ls.lease_key.data[0]++;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* restore the correct lease key */
+ ls.lease_key.data[0]--;
+
+ /*
+ * this last failing attempt is almost correct:
+ * only problem is: we use the wrong filename...
+ * Note that this gives INVALID_PARAMETER.
+ * This is different from oplocks!
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_open = false;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Now for a succeeding reconnect:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open = false;
+ io.in.durable_handle = h;
+ io.in.lease_request = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect one more time */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * demonstrate that various parameters are ignored
+ * in the reconnect
+ */
+
+ ZERO_STRUCT(io);
+ /*
+ * These are completely ignored by the server
+ */
+ io.in.security_flags = 0x78;
+ io.in.oplock_level = 0x78;
+ io.in.impersonation_level = 0x12345678;
+ io.in.create_flags = 0x12345678;
+ io.in.reserved = 0x12345678;
+ io.in.desired_access = 0x12345678;
+ io.in.file_attributes = 0x12345678;
+ io.in.share_access = 0x12345678;
+ io.in.create_disposition = 0x12345678;
+ io.in.create_options = 0x12345678;
+
+ /*
+ * only these are checked:
+ * - io.in.fname
+ * - io.in.durable_handle,
+ * - io.in.lease_request->lease_key
+ */
+
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.lease_request = &ls;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * lease v2 variant of reopen2
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+static bool test_durable_open_reopen2_lease_v2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smbcli_options options;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = random();
+ smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
+ lease_key, 0, /* parent lease key */
+ smb2_util_lease_state("RWH"), 0 /* lease epoch */);
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
+
+ /* disconnect, reconnect and then do durable reopen */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /* a few failure tests: */
+
+ /*
+ * several attempts without lease attached:
+ * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * irrespective of file name provided
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_handle = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * attempt with lease provided, but
+ * with a changed lease key. => fails
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open = false;
+ io.in.durable_handle = h;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+ /* a wrong lease key lets the request fail */
+ ls.lease_key.data[0]++;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* restore the correct lease key */
+ ls.lease_key.data[0]--;
+
+ /*
+ * this last failing attempt is almost correct:
+ * only problem is: we use the wrong filename...
+ * Note that this gives INVALID_PARAMETER.
+ * This is different from oplocks!
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_open = false;
+ io.in.durable_handle = h;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Now for a succeeding reconnect:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open = false;
+ io.in.durable_handle = h;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect one more time */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * demonstrate that various parameters are ignored
+ * in the reconnect
+ */
+
+ ZERO_STRUCT(io);
+ /*
+ * These are completely ignored by the server
+ */
+ io.in.security_flags = 0x78;
+ io.in.oplock_level = 0x78;
+ io.in.impersonation_level = 0x12345678;
+ io.in.create_flags = 0x12345678;
+ io.in.reserved = 0x12345678;
+ io.in.desired_access = 0x12345678;
+ io.in.file_attributes = 0x12345678;
+ io.in.share_access = 0x12345678;
+ io.in.create_disposition = 0x12345678;
+ io.in.create_options = 0x12345678;
+
+ /*
+ * only these are checked:
+ * - io.in.fname
+ * - io.in.durable_handle,
+ * - io.in.lease_request->lease_key
+ */
+
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.lease_request_v2 = &ls;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
+
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect with a session reconnect and
+ * do a durable reopen (succeeds)
+ */
+static bool test_durable_open_reopen2a(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io1, io2;
+ uint64_t previous_session_id;
+ bool ret = true;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io1.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /* disconnect, reconnect and then do durable reopen */
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io2);
+ io2.in.fname = fname;
+ io2.in.durable_handle = h;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io2.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * basic test for doing a durable open:
+ * tdis, new tcon, try durable reopen (fails)
+ */
+static bool test_durable_open_reopen3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io1, io2;
+ bool ret = true;
+ struct smb2_tree *tree2;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen3_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io1.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /* disconnect, reconnect and then do durable reopen */
+ status = smb2_tdis(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!torture_smb2_tree_connect(tctx, tree->session, mem_ctx, &tree2)) {
+ torture_warning(tctx, "couldn't reconnect to share, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+
+ ZERO_STRUCT(io2);
+ io2.in.fname = fname;
+ io2.in.durable_handle = h;
+
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree2, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic test for doing a durable open:
+ * logoff, create a new session, do a durable reopen (succeeds)
+ */
+static bool test_durable_open_reopen4(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io1, io2;
+ bool ret = true;
+ struct smb2_transport *transport;
+ struct smb2_session *session2;
+ struct smb2_tree *tree2;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_reopen4_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io1.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /*
+ * do a session logoff, establish a new session and tree
+ * connect on the same transport, and try a durable reopen
+ */
+ transport = tree->session->transport;
+ status = smb2_logoff(tree->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!torture_smb2_session_setup(tctx, transport,
+ 0, /* previous_session_id */
+ mem_ctx, &session2))
+ {
+ torture_warning(tctx, "session setup failed.\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * the session setup has talloc-stolen the transport,
+ * so we can safely free the old tree+session for clarity
+ */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_tree_connect(tctx, session2, mem_ctx, &tree2)) {
+ torture_warning(tctx, "tree connect failed.\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io2);
+ io2.in.fname = fname;
+ io2.in.durable_handle = h;
+ h = NULL;
+
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ _h = io2.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree2, *h);
+ }
+
+ smb2_util_unlink(tree2, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_durable_open_delete_on_close1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io1, io2;
+ bool ret = true;
+ uint8_t b = 0;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_delete_on_close1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.durable_open = true;
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io1.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+
+ status = smb2_util_write(tree, *h, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, leaving the durable handle in place */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "could not reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Open the file on the new connection again
+ * and check that it has been newly created,
+ * i.e. delete on close was effective on the disconnected handle.
+ * Also check that the file is really empty,
+ * the previously written byte gone.
+ */
+ smb2_oplock_create_share(&io2, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io2.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io2.out.file.handle;
+ h = &_h;
+ CHECK_CREATED_SIZE(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
+ CHECK_VAL(io2.out.durable_open, false);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+static bool test_durable_open_delete_on_close2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ bool ret = true;
+ uint8_t b = 0;
+ uint64_t previous_session_id;
+ uint64_t alloc_size_step;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_delete_on_close2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+ io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ status = smb2_util_write(tree, *h, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* disconnect, leaving the durable handle in place */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "could not reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ alloc_size_step = io.out.alloc_size;
+ CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE, alloc_size_step, 1);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /* close the file, thereby deleting it */
+ smb2_util_close(tree, *h);
+ status = smb2_logoff(tree->session);
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "could not reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Open the file on the new connection again
+ * and check that it has been newly created,
+ * i.e. delete on close was effective on the reconnected handle.
+ * Also check that the file is really empty,
+ * the previously written byte gone.
+ */
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+ io.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE, 0, 0);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ basic testing of SMB2 durable opens
+ regarding the position information on the handle
+*/
+static bool test_durable_open_file_position(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle h;
+ struct smb2_create io;
+ NTSTATUS status;
+ const char *fname = "durable_open_position.dat";
+ union smb_fileinfo qfinfo;
+ union smb_setfileinfo sfinfo;
+ bool ret = true;
+ uint64_t pos;
+ uint64_t previous_session_id;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* TODO: check extra blob content */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = h;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(qfinfo.position_information.out.position, 0);
+ pos = qfinfo.position_information.out.position;
+ torture_comment(tctx, "position: %llu\n",
+ (unsigned long long)pos);
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = h;
+ sfinfo.position_information.in.position = 0x1000;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = h;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
+ pos = qfinfo.position_information.out.position;
+ torture_comment(tctx, "position: %llu\n",
+ (unsigned long long)pos);
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* tcp disconnect */
+ talloc_free(tree);
+ tree = NULL;
+
+ /* do a session reconnect */
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = h;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = &h;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ CHECK_VAL(io.out.reserved, 0x00);
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_VAL(io.out.size, 0);
+ CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.reserved2, 0);
+
+ h = io.out.file.handle;
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = h;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
+ pos = qfinfo.position_information.out.position;
+ torture_comment(tctx, "position: %llu\n",
+ (unsigned long long)pos);
+
+ smb2_util_close(tree, h);
+
+ talloc_free(mem_ctx);
+
+ smb2_util_unlink(tree, fname);
+
+done:
+ talloc_free(tree);
+
+ return ret;
+}
+
+/*
+ Open, disconnect, oplock break, reconnect.
+*/
+static bool test_durable_open_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1, io2;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
+
+ /* Clean slate */
+ smb2_util_unlink(tree1, fname);
+
+ /* Create with batch oplock */
+ smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ io1.in.durable_open = true;
+
+ io2 = io1;
+ io2.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* Disconnect after getting the batch */
+ talloc_free(tree1);
+ tree1 = NULL;
+
+ /*
+ * Windows7 (build 7000) will break a batch oplock immediately if the
+ * original client is gone. (ZML: This seems like a bug. It should give
+ * some time for the client to reconnect!)
+ */
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.durable_open, true);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* What if tree1 tries to come back and reclaim? */
+ if (!torture_smb2_connection(tctx, &tree1)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io1);
+ io1.in.fname = fname;
+ io1.in.durable_handle = &h1;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ done:
+ smb2_util_close(tree2, h2);
+ smb2_util_unlink(tree2, fname);
+
+ talloc_free(tree1);
+ talloc_free(tree2);
+
+ return ret;
+}
+
+/*
+ Open, disconnect, lease break, reconnect.
+*/
+static bool test_durable_open_lease(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1, io2;
+ struct smb2_lease ls1, ls2;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+ uint64_t lease1, lease2;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /*
+ * Choose a random name and random lease in case the state is left a
+ * little funky.
+ */
+ lease1 = random();
+ lease2 = random();
+ snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
+
+ /* Clean slate */
+ smb2_util_unlink(tree1, fname);
+
+ /* Create with lease */
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ lease1, smb2_util_lease_state("RHW"));
+ io1.in.durable_open = true;
+
+ smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+ lease2, smb2_util_lease_state("RHW"));
+ io2.in.durable_open = true;
+ io2.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
+
+ /* Disconnect after getting the lease */
+ talloc_free(tree1);
+ tree1 = NULL;
+
+ /*
+ * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
+ * even if the original client is gone. (ZML: This seems like a bug. It
+ * should give some time for the client to reconnect! And why RH?)
+ *
+ * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH.
+ * Test is adapted accordingly.
+ */
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_VAL(io2.out.durable_open, true);
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
+ CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
+ CHECK_VAL(io2.out.lease_response.lease_state,
+ SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
+
+ /* What if tree1 tries to come back and reclaim? */
+ if (!torture_smb2_connection(tctx, &tree1)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io1);
+ io1.in.fname = fname;
+ io1.in.durable_handle = &h1;
+ io1.in.lease_request = &ls1;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ done:
+ smb2_util_close(tree2, h2);
+ smb2_util_unlink(tree2, fname);
+
+ talloc_free(tree1);
+ talloc_free(tree2);
+
+ return ret;
+}
+
+static bool test_durable_open_lock_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_handle h = {{0}};
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+
+ /*
+ */
+ snprintf(fname, 256, "durable_open_oplock_lock_%s.dat", generate_random_str(tctx, 8));
+
+ /* Clean slate */
+ smb2_util_unlink(tree, fname);
+
+ /* Create with oplock */
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ ZERO_STRUCT(lck);
+ ZERO_STRUCT(el);
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 1;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Disconnect/Reconnect. */
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = &h;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_unlink(tree, fname);
+ talloc_free(tree);
+
+ return ret;
+}
+
+/*
+ Open, take BRL, disconnect, reconnect.
+*/
+static bool test_durable_open_lock_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h = {{0}};
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+ uint64_t lease;
+ uint32_t caps;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /*
+ * Choose a random name and random lease in case the state is left a
+ * little funky.
+ */
+ lease = random();
+ snprintf(fname, 256, "durable_open_lease_lock_%s.dat", generate_random_str(tctx, 8));
+
+ /* Clean slate */
+ smb2_util_unlink(tree, fname);
+
+ /* Create with lease */
+
+ smb2_lease_create(&io, &ls, false /* dir */, fname, lease,
+ smb2_util_lease_state("RWH"));
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
+
+ ZERO_STRUCT(lck);
+ ZERO_STRUCT(el);
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 1;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Disconnect/Reconnect. */
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = &h;
+ io.in.lease_request = &ls;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_unlink(tree, fname);
+ talloc_free(tree);
+
+ return ret;
+}
+
+/**
+ * Open with a RH lease, disconnect, open in another tree, reconnect.
+ *
+ * This test actually demonstrates a minimum level of respect for the durable
+ * open in the face of another open. As long as this test shows an inability to
+ * reconnect after an open, the oplock/lease tests above will certainly
+ * demonstrate an error on reconnect.
+ */
+static bool test_durable_open_open2_lease(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1, io2;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+ uint64_t lease;
+ uint32_t caps;
+ struct smbcli_options options;
+
+ options = tree1->session->transport->options;
+
+ caps = smb2cli_conn_server_capabilities(tree1->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /*
+ * Choose a random name and random lease in case the state is left a
+ * little funky.
+ */
+ lease = random();
+ snprintf(fname, 256, "durable_open_open2_lease_%s.dat",
+ generate_random_str(tctx, 8));
+
+ /* Clean slate */
+ smb2_util_unlink(tree1, fname);
+
+ /* Create with lease */
+ smb2_lease_create_share(&io1, &ls, false /* dir */, fname,
+ smb2_util_share_access(""),
+ lease,
+ smb2_util_lease_state("RH"));
+ io1.in.durable_open = true;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("RH"));
+
+ /* Disconnect */
+ talloc_free(tree1);
+ tree1 = NULL;
+
+ /* Open the file in tree2 */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+
+ /* Reconnect */
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree1)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io1);
+ io1.in.fname = fname;
+ io1.in.durable_handle = &h1;
+ io1.in.lease_request = &ls;
+
+ /*
+ * Windows7 (build 7000) will give away an open immediately if the
+ * original client is gone. (ZML: This seems like a bug. It should give
+ * some time for the client to reconnect!)
+ */
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ h1 = io1.out.file.handle;
+
+ done:
+ if (tree1 != NULL){
+ smb2_util_close(tree1, h1);
+ smb2_util_unlink(tree1, fname);
+ talloc_free(tree1);
+ }
+
+ smb2_util_close(tree2, h2);
+ smb2_util_unlink(tree2, fname);
+ talloc_free(tree2);
+
+ return ret;
+}
+
+/**
+ * Open with a batch oplock, disconnect, open in another tree, reconnect.
+ *
+ * This test actually demonstrates a minimum level of respect for the durable
+ * open in the face of another open. As long as this test shows an inability to
+ * reconnect after an open, the oplock/lease tests above will certainly
+ * demonstrate an error on reconnect.
+ */
+static bool test_durable_open_open2_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1, io2;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+
+ /*
+ * Choose a random name and random lease in case the state is left a
+ * little funky.
+ */
+ snprintf(fname, 256, "durable_open_open2_oplock_%s.dat",
+ generate_random_str(tctx, 8));
+
+ /* Clean slate */
+ smb2_util_unlink(tree1, fname);
+
+ /* Create with batch oplock */
+ smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ io1.in.durable_open = true;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, true);
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* Disconnect */
+ talloc_free(tree1);
+ tree1 = NULL;
+
+ /* Open the file in tree2 */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ /* Reconnect */
+ if (!torture_smb2_connection(tctx, &tree1)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io1);
+ io1.in.fname = fname;
+ io1.in.durable_handle = &h1;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ h1 = io1.out.file.handle;
+
+ done:
+ smb2_util_close(tree2, h2);
+ smb2_util_unlink(tree2, fname);
+ if (tree1 != NULL) {
+ smb2_util_close(tree1, h1);
+ smb2_util_unlink(tree1, fname);
+ }
+
+ talloc_free(tree1);
+ talloc_free(tree2);
+
+ return ret;
+}
+
+/**
+ * test behaviour with initial allocation size
+ */
+static bool test_durable_open_alloc_size(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ bool ret = true;
+ uint64_t previous_session_id;
+ uint64_t alloc_size_step;
+ uint64_t initial_alloc_size = 0x1000;
+ const uint8_t *b = NULL;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_alloc_size_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+ io.in.alloc_size = initial_alloc_size;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_NOT_VAL(io.out.alloc_size, 0);
+ alloc_size_step = io.out.alloc_size;
+ CHECK_CREATED_SIZE(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE,
+ alloc_size_step, 0);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ /* prepare buffer */
+ b = talloc_zero_size(mem_ctx, alloc_size_step);
+ CHECK_NOT_NULL(b);
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* disconnect, reconnect and then do durable reopen */
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
+ alloc_size_step, 0);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* write one byte */
+ status = smb2_util_write(tree, *h, b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, reconnect and then do durable reopen */
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
+ alloc_size_step, 1);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* write more byte than initial allocation size */
+ status = smb2_util_write(tree, *h, b, 1, alloc_size_step);
+
+ /* disconnect, reconnect and then do durable reopen */
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED_SIZE(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE,
+ alloc_size_step * 2, alloc_size_step + 1);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * test behaviour when a disconnect happens while creating a read-only file
+ */
+static bool test_durable_open_read_only(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ bool ret = true;
+ uint64_t previous_session_id;
+ const uint8_t b = 0;
+ uint64_t alloc_size = 0;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_initial_alloc_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+ io.in.file_attributes = FILE_ATTRIBUTE_READONLY;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* write one byte */
+ status = smb2_util_write(tree, *h, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, reconnect and then do durable reopen */
+ talloc_free(tree);
+ tree = NULL;
+
+ if (!torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree))
+ {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ alloc_size = io.out.alloc_size;
+ CHECK_CREATED_SIZE(&io, EXISTED,
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE,
+ alloc_size, 1);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* write one byte */
+ status = smb2_util_write(tree, *h, &b, 1, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ if (h != NULL) {
+ union smb_setfileinfo sfinfo;
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.basic_info.in.file.handle = *h;
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ smb2_setinfo_file(tree, &sfinfo);
+
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * durable open with oplock, disconnect, exit
+ */
+static bool test_durable_open_oplock_disconnect(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+
+ snprintf(fname, 256, "durable_open_oplock_disconnect_%s.dat",
+ generate_random_str(mem_ctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ io.in.durable_open = true;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ _h = io.out.file.handle;
+ h = &_h;
+
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* disconnect */
+ talloc_free(tree);
+ tree = NULL;
+
+done:
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_util_unlink(tree, fname);
+ }
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/**
+ * durable stat open with lease.
+ */
+static bool test_durable_open_stat_open(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_lease ls;
+ NTSTATUS status;
+ char fname[256];
+ bool ret = true;
+ uint64_t lease;
+
+ snprintf(fname, 256, "durable_open_stat_open_%s.dat",
+ generate_random_str(mem_ctx, 8));
+
+ /* Ensure file doesn't exist. */
+ smb2_util_unlink(tree, fname);
+
+ /* Create a normal file. */
+ smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ /* Close. */
+ smb2_util_close(tree, *h);
+ h = NULL;
+
+ /* Now try a leased, durable handle stat open. */
+ lease = random();
+ /* Create with lease */
+ smb2_lease_create(&io,
+ &ls,
+ false /* dir */,
+ fname,
+ lease,
+ smb2_util_lease_state("RH"));
+ io.in.durable_open = true;
+ io.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, true);
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_durable_open_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "durable-open");
+
+ torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_open_open_oplock);
+ torture_suite_add_1smb2_test(suite, "open-lease", test_durable_open_open_lease);
+ torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1);
+ torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_open_reopen1a);
+ torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_open_reopen1a_lease);
+ torture_suite_add_1smb2_test(suite, "reopen2", test_durable_open_reopen2);
+ torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_open_reopen2_lease);
+ torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_open_reopen2_lease_v2);
+ torture_suite_add_1smb2_test(suite, "reopen2a", test_durable_open_reopen2a);
+ torture_suite_add_1smb2_test(suite, "reopen3", test_durable_open_reopen3);
+ torture_suite_add_1smb2_test(suite, "reopen4", test_durable_open_reopen4);
+ torture_suite_add_1smb2_test(suite, "delete_on_close1",
+ test_durable_open_delete_on_close1);
+ torture_suite_add_1smb2_test(suite, "delete_on_close2",
+ test_durable_open_delete_on_close2);
+ torture_suite_add_1smb2_test(suite, "file-position",
+ test_durable_open_file_position);
+ torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
+ torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
+ torture_suite_add_1smb2_test(suite, "lock-oplock", test_durable_open_lock_oplock);
+ torture_suite_add_1smb2_test(suite, "lock-lease", test_durable_open_lock_lease);
+ torture_suite_add_2smb2_test(suite, "open2-lease",
+ test_durable_open_open2_lease);
+ torture_suite_add_2smb2_test(suite, "open2-oplock",
+ test_durable_open_open2_oplock);
+ torture_suite_add_1smb2_test(suite, "alloc-size",
+ test_durable_open_alloc_size);
+ torture_suite_add_1smb2_test(suite, "read-only",
+ test_durable_open_read_only);
+ torture_suite_add_1smb2_test(suite, "stat-open",
+ test_durable_open_stat_open);
+
+ suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
+
+ return suite;
+}
+
+struct torture_suite *torture_smb2_durable_open_disconnect_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx,
+ "durable-open-disconnect");
+
+ torture_suite_add_1smb2_test(suite, "open-oplock-disconnect",
+ test_durable_open_oplock_disconnect);
+
+ suite->description = talloc_strdup(suite,
+ "SMB2-DURABLE-OPEN-DISCONNECT tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/durable_v2_open.c b/source4/torture/smb2/durable_v2_open.c
new file mode 100644
index 0000000..9b9af11
--- /dev/null
+++ b/source4/torture/smb2/durable_v2_open.c
@@ -0,0 +1,2371 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 version two of durable opens
+
+ Copyright (C) Michael Adam 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "librpc/ndr/libndr.h"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_CREATED(__io, __created, __attribute) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
+ CHECK_VAL((__io)->out.size, 0); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while(0)
+
+static struct {
+ int count;
+ struct smb2_close cl;
+} break_info;
+
+static void torture_oplock_close_callback(struct smb2_request *req)
+{
+ smb2_close_recv(req, &break_info.cl);
+}
+
+/* A general oplock break notification handler. This should be used when a
+ * test expects to break from batch or exclusive to a lower level. */
+static bool torture_oplock_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ struct smb2_request *req;
+
+ break_info.count++;
+
+ ZERO_STRUCT(break_info.cl);
+ break_info.cl.in.file.handle = *handle;
+
+ req = smb2_close_send(tree, &break_info.cl);
+ req->async.fn = torture_oplock_close_callback;
+ req->async.private_data = NULL;
+ return true;
+}
+
+/**
+ * testing various create blob combinations.
+ */
+bool test_durable_v2_open_create_blob(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_create_blob_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+
+ /* disconnect */
+ TALLOC_FREE(tree);
+
+ /* create a new session (same client_guid) */
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * check invalid combinations of durable handle
+ * request and reconnect blobs
+ * See MS-SMB2: 3.3.5.9.12
+ * Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
+ io.in.durable_open = true; /* durable v1 handle request */
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h; /* durable v1 reconnect request */
+ io.in.durable_open_v2 = true; /* durable v2 handle request */
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h; /* durable v1 reconnect request */
+ io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h; /* durable v2 reconnect request */
+ io.in.durable_open_v2 = true; /* durable v2 handle request */
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * basic durable_open test.
+ * durable state should only be granted when requested
+ * along with a batch oplock or a handle lease.
+ *
+ * This test tests durable open with all possible oplock types.
+ */
+
+struct durable_open_vs_oplock {
+ const char *level;
+ const char *share_mode;
+ bool durable;
+ bool persistent;
+};
+
+#define NUM_OPLOCK_TYPES 4
+#define NUM_SHARE_MODES 8
+#define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
+static struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
+{
+ { "", "", false, false },
+ { "", "R", false, false },
+ { "", "W", false, false },
+ { "", "D", false, false },
+ { "", "RD", false, false },
+ { "", "RW", false, false },
+ { "", "WD", false, false },
+ { "", "RWD", false, false },
+
+ { "s", "", false, false },
+ { "s", "R", false, false },
+ { "s", "W", false, false },
+ { "s", "D", false, false },
+ { "s", "RD", false, false },
+ { "s", "RW", false, false },
+ { "s", "WD", false, false },
+ { "s", "RWD", false, false },
+
+ { "x", "", false, false },
+ { "x", "R", false, false },
+ { "x", "W", false, false },
+ { "x", "D", false, false },
+ { "x", "RD", false, false },
+ { "x", "RW", false, false },
+ { "x", "WD", false, false },
+ { "x", "RWD", false, false },
+
+ { "b", "", true, false },
+ { "b", "R", true, false },
+ { "b", "W", true, false },
+ { "b", "D", true, false },
+ { "b", "RD", true, false },
+ { "b", "RW", true, false },
+ { "b", "WD", true, false },
+ { "b", "RWD", true, false },
+};
+
+static bool test_one_durable_v2_open_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ bool request_persistent,
+ struct durable_open_vs_oplock test)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ bool ret = true;
+ struct smb2_create io;
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(test.share_mode),
+ smb2_util_oplock_level(test.level));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = request_persistent;
+ io.in.create_guid = GUID_random();
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, test.durable);
+ CHECK_VAL(io.out.persistent_open, test.persistent);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_durable_v2_open_oplock_table(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ bool request_persistent,
+ struct durable_open_vs_oplock *table,
+ uint8_t num_tests)
+{
+ bool ret = true;
+ uint8_t i;
+
+ smb2_util_unlink(tree, fname);
+
+ for (i = 0; i < num_tests; i++) {
+ ret = test_one_durable_v2_open_oplock(tctx,
+ tree,
+ fname,
+ request_persistent,
+ table[i]);
+ if (ret == false) {
+ goto done;
+ }
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+
+ return ret;
+}
+
+bool test_durable_v2_open_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret;
+ char fname[256];
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_oplock_%s.dat",
+ generate_random_str(tctx, 8));
+
+ ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
+ false, /* request_persistent */
+ durable_open_vs_oplock_table,
+ NUM_OPLOCK_OPEN_TESTS);
+
+ talloc_free(tree);
+
+ return ret;
+}
+
+/**
+ * basic durable handle open test.
+ * persistent state should only be granted when requested
+ * along with a batch oplock or a handle lease.
+ *
+ * This test tests persistent open with all valid lease types.
+ */
+
+struct durable_open_vs_lease {
+ const char *type;
+ const char *share_mode;
+ bool durable;
+ bool persistent;
+};
+
+#define NUM_LEASE_TYPES 5
+#define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
+static struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
+{
+ { "", "", false, false },
+ { "", "R", false, false },
+ { "", "W", false, false },
+ { "", "D", false, false },
+ { "", "RW", false, false },
+ { "", "RD", false, false },
+ { "", "WD", false, false },
+ { "", "RWD", false, false },
+
+ { "R", "", false, false },
+ { "R", "R", false, false },
+ { "R", "W", false, false },
+ { "R", "D", false, false },
+ { "R", "RW", false, false },
+ { "R", "RD", false, false },
+ { "R", "DW", false, false },
+ { "R", "RWD", false, false },
+
+ { "RW", "", false, false },
+ { "RW", "R", false, false },
+ { "RW", "W", false, false },
+ { "RW", "D", false, false },
+ { "RW", "RW", false, false },
+ { "RW", "RD", false, false },
+ { "RW", "WD", false, false },
+ { "RW", "RWD", false, false },
+
+ { "RH", "", true, false },
+ { "RH", "R", true, false },
+ { "RH", "W", true, false },
+ { "RH", "D", true, false },
+ { "RH", "RW", true, false },
+ { "RH", "RD", true, false },
+ { "RH", "WD", true, false },
+ { "RH", "RWD", true, false },
+
+ { "RHW", "", true, false },
+ { "RHW", "R", true, false },
+ { "RHW", "W", true, false },
+ { "RHW", "D", true, false },
+ { "RHW", "RW", true, false },
+ { "RHW", "RD", true, false },
+ { "RHW", "WD", true, false },
+ { "RHW", "RWD", true, false },
+};
+
+static bool test_one_durable_v2_open_lease(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ bool request_persistent,
+ struct durable_open_vs_lease test)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ bool ret = true;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ uint64_t lease;
+
+ smb2_util_unlink(tree, fname);
+
+ lease = random();
+
+ smb2_lease_create_share(&io, &ls, false /* dir */, fname,
+ smb2_util_share_access(test.share_mode),
+ lease,
+ smb2_util_lease_state(test.type));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = request_persistent;
+ io.in.create_guid = GUID_random();
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, test.durable);
+ CHECK_VAL(io.out.persistent_open, test.persistent);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state(test.type));
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_durable_v2_open_lease_table(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ bool request_persistent,
+ struct durable_open_vs_lease *table,
+ uint8_t num_tests)
+{
+ bool ret = true;
+ uint8_t i;
+
+ smb2_util_unlink(tree, fname);
+
+ for (i = 0; i < num_tests; i++) {
+ ret = test_one_durable_v2_open_lease(tctx,
+ tree,
+ fname,
+ request_persistent,
+ table[i]);
+ if (ret == false) {
+ goto done;
+ }
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+
+ return ret;
+}
+
+bool test_durable_v2_open_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ char fname[256];
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
+
+ ret = test_durable_v2_open_lease_table(tctx, tree, fname,
+ false, /* request_persistent */
+ durable_open_vs_lease_table,
+ NUM_LEASE_OPEN_TESTS);
+
+ talloc_free(tree);
+ return ret;
+}
+
+/**
+ * basic test for doing a durable open
+ * and do a durable reopen on the same connection
+ * while the first open is still active (fails)
+ */
+bool test_durable_v2_open_reopen1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+
+ /* try a durable reconnect while the file is still open */
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Basic test for doing a durable open
+ * and do a session reconnect while the first
+ * session is still active and the handle is
+ * still open in the client.
+ * This closes the original session and a
+ * durable reconnect on the new session succeeds.
+ */
+bool test_durable_v2_open_reopen1a(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_tree *tree3 = NULL;
+ uint64_t previous_session_id;
+ struct smbcli_options options;
+ struct GUID orig_client_guid;
+
+ options = tree->session->transport->options;
+ orig_client_guid = options.client_guid;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen1a_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+
+ /*
+ * a session reconnect on a second tcp connection
+ */
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* for oplocks, the client guid can be different: */
+ options.client_guid = GUID_random();
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree2);
+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+
+ TALLOC_FREE(tree);
+
+ /*
+ * but a durable reconnect on the new session succeeds:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /*
+ * a session reconnect on a second tcp connection
+ */
+
+ previous_session_id = smb2cli_session_current_id(tree2->session->smbXcli);
+
+ /* it works the same with the original guid */
+ options.client_guid = orig_client_guid;
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree3);
+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+ TALLOC_FREE(tree2);
+
+ /*
+ * but a durable reconnect on the new session succeeds:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree == NULL) {
+ tree = tree2;
+ }
+
+ if (tree == NULL) {
+ tree = tree3;
+ }
+
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * lease variant of reopen1a
+ *
+ * Basic test for doing a durable open and doing a session
+ * reconnect while the first session is still active and the
+ * handle is still open in the client.
+ * This closes the original session and a durable reconnect on
+ * the new session succeeds depending on the client guid:
+ *
+ * Durable reconnect on a session with a different client guid fails.
+ * Durable reconnect on a session with the original client guid succeeds.
+ */
+bool test_durable_v2_open_reopen1a_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_tree *tree3 = NULL;
+ uint64_t previous_session_id;
+ struct smbcli_options options;
+ struct GUID orig_client_guid;
+
+ options = tree->session->transport->options;
+ orig_client_guid = options.client_guid;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen1a_lease_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = random();
+ smb2_lease_create(&io, &ls, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RWH"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /*
+ * a session reconnect on a second tcp connection
+ * with a different client_guid does not allow
+ * the durable reconnect.
+ */
+
+ options.client_guid = GUID_random();
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree2);
+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+ TALLOC_FREE(tree);
+
+ /*
+ * but a durable reconnect on the new session with the wrong
+ * client guid fails
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+
+ /*
+ * now a session reconnect on a second tcp connection
+ * with original client_guid allows the durable reconnect.
+ */
+
+ options.client_guid = orig_client_guid;
+ //options.client_guid = GUID_random();
+
+ ret = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree3);
+ torture_assert_goto(tctx, ret, ret, done, "couldn't reconnect");
+
+ /*
+ * check that this has deleted the old session
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ TALLOC_FREE(tree2);
+
+ /*
+ * but a durable reconnect on the new session succeeds:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ status = smb2_create(tree3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 0);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (tree == NULL) {
+ tree = tree2;
+ }
+
+ if (tree == NULL) {
+ tree = tree3;
+ }
+
+ if (tree != NULL) {
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ }
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+bool test_durable_v2_open_reopen2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ struct GUID create_guid_invalid = GUID_random();
+ bool ret = true;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * first a few failure cases
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* a non-zero but non-matching create_guid does not change it: */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid_invalid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * now success:
+ * The important difference is that the create_guid is provided.
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect one more time */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ /* These are completely ignored by the server */
+ io.in.security_flags = 0x78;
+ io.in.oplock_level = 0x78;
+ io.in.impersonation_level = 0x12345678;
+ io.in.create_flags = 0x12345678;
+ io.in.reserved = 0x12345678;
+ io.in.desired_access = 0x12345678;
+ io.in.file_attributes = 0x12345678;
+ io.in.share_access = 0x12345678;
+ io.in.create_disposition = 0x12345678;
+ io.in.create_options = 0x12345678;
+ io.in.fname = "__non_existing_fname__";
+
+ /*
+ * only io.in.durable_handle_v2 and
+ * io.in.create_guid are checked
+ */
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * durable reconnect test:
+ * connect with v2, reconnect with v1
+ */
+bool test_durable_v2_open_reopen2b(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen2b_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h; /* durable v2 reconnect */
+ io.in.create_guid = GUID_zero(); /* but zero create GUID */
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle = h; /* durable v1 (!) reconnect */
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+/**
+ * durable reconnect test:
+ * connect with v1, reconnect with v2 : fails (no create_guid...)
+ */
+bool test_durable_v2_open_reopen2c(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ struct smbcli_options options;
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen2c_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = true;
+ io.in.durable_open_v2 = false;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, true);
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 0);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h; /* durable v2 reconnect */
+ io.in.create_guid = create_guid;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * lease variant of reopen2
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+bool test_durable_v2_open_reopen2_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smbcli_options options;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ options = tree->session->transport->options;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_reopen2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = generate_random_u64();
+ smb2_lease_create(&io, &ls, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RWH"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+
+ /* disconnect, reconnect and then do durable reopen */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /* a few failure tests: */
+
+ /*
+ * several attempts without lease attached:
+ * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * irrespective of file name provided
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * attempt with lease provided, but
+ * with a changed lease key. => fails
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+ /* a wrong lease key lets the request fail */
+ ls.lease_key.data[0]++;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* restore the correct lease key */
+ ls.lease_key.data[0]--;
+
+ /*
+ * this last failing attempt is almost correct:
+ * only problem is: we use the wrong filename...
+ * Note that this gives INVALID_PARAMETER.
+ * This is different from oplocks!
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Now for a succeeding reconnect:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect one more time */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * demonstrate that various parameters are ignored
+ * in the reconnect
+ */
+
+ ZERO_STRUCT(io);
+ /*
+ * These are completely ignored by the server
+ */
+ io.in.security_flags = 0x78;
+ io.in.oplock_level = 0x78;
+ io.in.impersonation_level = 0x12345678;
+ io.in.create_flags = 0x12345678;
+ io.in.reserved = 0x12345678;
+ io.in.desired_access = 0x12345678;
+ io.in.file_attributes = 0x12345678;
+ io.in.share_access = 0x12345678;
+ io.in.create_disposition = 0x12345678;
+ io.in.create_options = 0x12345678;
+
+ /*
+ * only these are checked:
+ * - io.in.fname
+ * - io.in.durable_handle_v2,
+ * - io.in.create_guid
+ * - io.in.lease_request->lease_key
+ */
+
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request = &ls;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response.lease_duration, 0);
+
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * lease_v2 variant of reopen2
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+bool test_durable_v2_open_reopen2_lease_v2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smbcli_options options;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ options = tree->session->transport->options;
+
+ smb2_deltree(tree, __func__);
+ status = torture_smb2_testdir(tree, __func__, &_h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree, _h);
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "%s\\durable_v2_open_reopen2_%s.dat",
+ __func__, generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = random();
+ smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
+ lease_key, 0, /* parent lease key */
+ smb2_util_lease_state("RWH"), 0 /* lease epoch */);
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+
+ /* disconnect, reconnect and then do durable reopen */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /* a few failure tests: */
+
+ /*
+ * several attempts without lease attached:
+ * all fail with NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * irrespective of file name provided
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = "";
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_handle_v2 = h;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * attempt with lease provided, but
+ * with a changed lease key. => fails
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+ /* a wrong lease key lets the request fail */
+ ls.lease_key.data[0]++;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* restore the correct lease key */
+ ls.lease_key.data[0]--;
+
+
+ /*
+ * this last failing attempt is almost correct:
+ * only problem is: we use the wrong filename...
+ * Note that this gives INVALID_PARAMETER.
+ * This is different from oplocks!
+ */
+ ZERO_STRUCT(io);
+ io.in.fname = "__non_existing_fname__";
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /*
+ * Now for a succeeding reconnect:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+ /* disconnect one more time */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * demonstrate that various parameters are ignored
+ * in the reconnect
+ */
+
+ ZERO_STRUCT(io);
+ /*
+ * These are completely ignored by the server
+ */
+ io.in.security_flags = 0x78;
+ io.in.oplock_level = 0x78;
+ io.in.impersonation_level = 0x12345678;
+ io.in.create_flags = 0x12345678;
+ io.in.reserved = 0x12345678;
+ io.in.desired_access = 0x12345678;
+ io.in.file_attributes = 0x12345678;
+ io.in.share_access = 0x12345678;
+ io.in.create_disposition = 0x12345678;
+ io.in.create_options = 0x12345678;
+ io.in.fname = "__non_existing_fname__";
+
+ /*
+ * only these are checked:
+ * - io.in.fname
+ * - io.in.durable_handle_v2,
+ * - io.in.create_guid
+ * - io.in.lease_request_v2->lease_key
+ */
+
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request_v2 = &ls;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
+
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, __func__);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test durable request / reconnect with AppInstanceId
+ */
+bool test_durable_v2_open_app_instance(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1, _h2;
+ struct smb2_handle *h1 = NULL, *h2 = NULL;
+ struct smb2_create io1, io2;
+ bool ret = true;
+ struct GUID create_guid_1 = GUID_random();
+ struct GUID create_guid_2 = GUID_random();
+ struct GUID app_instance_id = GUID_random();
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "durable_v2_open_app_instance_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree1, fname);
+
+ ZERO_STRUCT(break_info);
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid_1;
+ io1.in.app_instance_id = &app_instance_id;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.persistent_open, false);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+
+ /*
+ * try to open the file as durable from a second tree with
+ * a different create guid but the same app_instance_id
+ * while the first handle is still open.
+ */
+
+ smb2_oplock_create_share(&io2, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io2.in.durable_open = false;
+ io2.in.durable_open_v2 = true;
+ io2.in.persistent_open = false;
+ io2.in.create_guid = create_guid_2;
+ io2.in.app_instance_id = &app_instance_id;
+ io2.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h2 = io2.out.file.handle;
+ h2 = &_h2;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io2.out.durable_open, false);
+ CHECK_VAL(io2.out.durable_open_v2, true);
+ CHECK_VAL(io2.out.persistent_open, false);
+ CHECK_VAL(io2.out.timeout, 300*1000);
+
+ CHECK_VAL(break_info.count, 0);
+
+ status = smb2_util_close(tree1, *h1);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ h1 = NULL;
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+ if (h2 != NULL) {
+ smb2_util_close(tree2, *h2);
+ }
+
+ smb2_util_unlink(tree2, fname);
+
+ talloc_free(tree1);
+ talloc_free(tree2);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * basic persistent open test.
+ *
+ * This test tests durable open with all possible oplock types.
+ */
+
+struct durable_open_vs_oplock persistent_open_oplock_ca_table[NUM_OPLOCK_OPEN_TESTS] =
+{
+ { "", "", true, true },
+ { "", "R", true, true },
+ { "", "W", true, true },
+ { "", "D", true, true },
+ { "", "RD", true, true },
+ { "", "RW", true, true },
+ { "", "WD", true, true },
+ { "", "RWD", true, true },
+
+ { "s", "", true, true },
+ { "s", "R", true, true },
+ { "s", "W", true, true },
+ { "s", "D", true, true },
+ { "s", "RD", true, true },
+ { "s", "RW", true, true },
+ { "s", "WD", true, true },
+ { "s", "RWD", true, true },
+
+ { "x", "", true, true },
+ { "x", "R", true, true },
+ { "x", "W", true, true },
+ { "x", "D", true, true },
+ { "x", "RD", true, true },
+ { "x", "RW", true, true },
+ { "x", "WD", true, true },
+ { "x", "RWD", true, true },
+
+ { "b", "", true, true },
+ { "b", "R", true, true },
+ { "b", "W", true, true },
+ { "b", "D", true, true },
+ { "b", "RD", true, true },
+ { "b", "RW", true, true },
+ { "b", "WD", true, true },
+ { "b", "RWD", true, true },
+};
+
+bool test_persistent_open_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ char fname[256];
+ bool ret = true;
+ uint32_t share_capabilities;
+ bool share_is_ca = false;
+ struct durable_open_vs_oplock *table;
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "persistent_open_oplock_%s.dat", generate_random_str(tctx, 8));
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
+
+ if (share_is_ca) {
+ table = persistent_open_oplock_ca_table;
+ } else {
+ table = durable_open_vs_oplock_table;
+ }
+
+ ret = test_durable_v2_open_oplock_table(tctx, tree, fname,
+ true, /* request_persistent */
+ table,
+ NUM_OPLOCK_OPEN_TESTS);
+
+ talloc_free(tree);
+
+ return ret;
+}
+
+/**
+ * basic persistent handle open test.
+ * persistent state should only be granted when requested
+ * along with a batch oplock or a handle lease.
+ *
+ * This test tests persistent open with all valid lease types.
+ */
+
+struct durable_open_vs_lease persistent_open_lease_ca_table[NUM_LEASE_OPEN_TESTS] =
+{
+ { "", "", true, true },
+ { "", "R", true, true },
+ { "", "W", true, true },
+ { "", "D", true, true },
+ { "", "RW", true, true },
+ { "", "RD", true, true },
+ { "", "WD", true, true },
+ { "", "RWD", true, true },
+
+ { "R", "", true, true },
+ { "R", "R", true, true },
+ { "R", "W", true, true },
+ { "R", "D", true, true },
+ { "R", "RW", true, true },
+ { "R", "RD", true, true },
+ { "R", "DW", true, true },
+ { "R", "RWD", true, true },
+
+ { "RW", "", true, true },
+ { "RW", "R", true, true },
+ { "RW", "W", true, true },
+ { "RW", "D", true, true },
+ { "RW", "RW", true, true },
+ { "RW", "RD", true, true },
+ { "RW", "WD", true, true },
+ { "RW", "RWD", true, true },
+
+ { "RH", "", true, true },
+ { "RH", "R", true, true },
+ { "RH", "W", true, true },
+ { "RH", "D", true, true },
+ { "RH", "RW", true, true },
+ { "RH", "RD", true, true },
+ { "RH", "WD", true, true },
+ { "RH", "RWD", true, true },
+
+ { "RHW", "", true, true },
+ { "RHW", "R", true, true },
+ { "RHW", "W", true, true },
+ { "RHW", "D", true, true },
+ { "RHW", "RW", true, true },
+ { "RHW", "RD", true, true },
+ { "RHW", "WD", true, true },
+ { "RHW", "RWD", true, true },
+};
+
+bool test_persistent_open_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ char fname[256];
+ bool ret = true;
+ uint32_t caps;
+ uint32_t share_capabilities;
+ bool share_is_ca;
+ struct durable_open_vs_lease *table;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "persistent_open_lease_%s.dat", generate_random_str(tctx, 8));
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
+
+ if (share_is_ca) {
+ table = persistent_open_lease_ca_table;
+ } else {
+ table = durable_open_vs_lease_table;
+ }
+
+ ret = test_durable_v2_open_lease_table(tctx, tree, fname,
+ true, /* request_persistent */
+ table,
+ NUM_LEASE_OPEN_TESTS);
+
+ talloc_free(tree);
+
+ return ret;
+}
+
+/**
+ * setfileinfo test for doing a durable open
+ * create the file with lease and durable handle,
+ * write to it (via set end-of-file), tcp disconnect,
+ * reconnect, do a durable reopen - should succeed.
+ *
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=15022
+ */
+bool test_durable_v2_setinfo(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ union smb_setfileinfo si;
+ struct GUID create_guid = GUID_random();
+ struct smb2_lease ls;
+ uint64_t lease_key;
+ bool ret = true;
+ struct smbcli_options options;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ options = tree->session->transport->options;
+
+ smb2_deltree(tree, __func__);
+ status = torture_smb2_testdir(tree, __func__, &_h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree, _h);
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname, 256, "%s\\durable_v2_setinfo%s.dat",
+ __func__, generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ lease_key = random();
+ smb2_lease_v2_create(&io, &ls, false /* dir */, fname,
+ lease_key, 0, /* parent lease key */
+ smb2_util_lease_state("RWH"), 0 /* lease epoch */);
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+
+ /*
+ * Set EOF to 0x100000.
+ * Mimics an Apple client test, but most importantly
+ * causes the mtime timestamp on disk to be updated.
+ */
+ ZERO_STRUCT(si);
+ si.generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
+ si.generic.in.file.handle = io.out.file.handle;
+ si.end_of_file_info.in.size = 0x100000;
+ status = smb2_setinfo_file(tree, &si);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, reconnect and then do durable reopen */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Now for a succeeding reconnect:
+ */
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = h;
+ io.in.create_guid = create_guid;
+ io.in.lease_request_v2 = &ls;
+ io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
+
+ /* the requested lease state is irrelevant */
+ ls.lease_state = smb2_util_lease_state("");
+
+ h = NULL;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_VAL(io.out.size, 0x100000); \
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, false); /* no dh2q response blob */
+ CHECK_VAL(io.out.persistent_open, false);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[0], lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_key.data[1], ~lease_key);
+ CHECK_VAL(io.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ CHECK_VAL(io.out.lease_response_v2.lease_flags, 0);
+ CHECK_VAL(io.out.lease_response_v2.lease_duration, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, __func__);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_durable_v2_open_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "durable-v2-open");
+
+ torture_suite_add_1smb2_test(suite, "create-blob", test_durable_v2_open_create_blob);
+ torture_suite_add_1smb2_test(suite, "open-oplock", test_durable_v2_open_oplock);
+ torture_suite_add_1smb2_test(suite, "open-lease", test_durable_v2_open_lease);
+ torture_suite_add_1smb2_test(suite, "reopen1", test_durable_v2_open_reopen1);
+ torture_suite_add_1smb2_test(suite, "reopen1a", test_durable_v2_open_reopen1a);
+ torture_suite_add_1smb2_test(suite, "reopen1a-lease", test_durable_v2_open_reopen1a_lease);
+ torture_suite_add_1smb2_test(suite, "reopen2", test_durable_v2_open_reopen2);
+ torture_suite_add_1smb2_test(suite, "reopen2b", test_durable_v2_open_reopen2b);
+ torture_suite_add_1smb2_test(suite, "reopen2c", test_durable_v2_open_reopen2c);
+ torture_suite_add_1smb2_test(suite, "reopen2-lease", test_durable_v2_open_reopen2_lease);
+ torture_suite_add_1smb2_test(suite, "reopen2-lease-v2", test_durable_v2_open_reopen2_lease_v2);
+ torture_suite_add_1smb2_test(suite, "durable-v2-setinfo", test_durable_v2_setinfo);
+ torture_suite_add_2smb2_test(suite, "app-instance", test_durable_v2_open_app_instance);
+ torture_suite_add_1smb2_test(suite, "persistent-open-oplock", test_persistent_open_oplock);
+ torture_suite_add_1smb2_test(suite, "persistent-open-lease", test_persistent_open_lease);
+
+ suite->description = talloc_strdup(suite, "SMB2-DURABLE-V2-OPEN tests");
+
+ return suite;
+}
+
+/**
+ * basic test for doing a durable open
+ * tcp disconnect, reconnect, do a durable reopen (succeeds)
+ */
+static bool test_durable_v2_reconnect_delay(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ struct smbcli_options options;
+ uint64_t previous_session_id;
+ uint8_t b = 0;
+ bool ret = true;
+ bool ok;
+
+ options = tree->session->transport->options;
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname,
+ sizeof(fname),
+ "durable_v2_reconnect_delay_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = 0;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+
+ status = smb2_util_write(tree, *h, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+ h = NULL;
+
+ ok = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree);
+ torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = &_h;
+ io.in.create_guid = create_guid;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ TALLOC_FREE(tree);
+
+ smb2_util_unlink(tree2, fname);
+
+ TALLOC_FREE(tree2);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic test for doing a durable open with 1msec cleanup time
+ * tcp disconnect, wait a bit, reconnect, do a durable reopen (fails)
+ */
+static bool test_durable_v2_reconnect_delay_msec(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct GUID create_guid = GUID_random();
+ struct smbcli_options options;
+ uint64_t previous_session_id;
+ uint8_t b = 0;
+ bool ret = true;
+ bool ok;
+
+ options = tree->session->transport->options;
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ /* Choose a random name in case the state is left a little funky. */
+ snprintf(fname,
+ sizeof(fname),
+ "durable_v2_reconnect_delay_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_lease_create(
+ &io,
+ &ls,
+ false /* dir */,
+ fname,
+ generate_random_u64(),
+ smb2_util_lease_state("RWH"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = 1;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io.out.durable_open_v2, true);
+
+ status = smb2_util_write(tree, *h, &b, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+ h = NULL;
+
+ ok = torture_smb2_connection_ext(tctx, previous_session_id,
+ &options, &tree);
+ torture_assert_goto(tctx, ok, ret, done, "couldn't reconnect, bailing\n");
+
+ sleep(10);
+
+ ZERO_STRUCT(io);
+ io.in.fname = fname;
+ io.in.durable_open_v2 = false;
+ io.in.durable_handle_v2 = &_h;
+ io.in.create_guid = create_guid;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ _h = io.out.file.handle;
+ h = &_h;
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ TALLOC_FREE(tree);
+
+ smb2_util_unlink(tree2, fname);
+
+ TALLOC_FREE(tree2);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_durable_v2_delay_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "durable-v2-delay");
+
+ torture_suite_add_2smb2_test(suite,
+ "durable_v2_reconnect_delay",
+ test_durable_v2_reconnect_delay);
+ torture_suite_add_2smb2_test(suite,
+ "durable_v2_reconnect_delay_msec",
+ test_durable_v2_reconnect_delay_msec);
+
+ return suite;
+}
diff --git a/source4/torture/smb2/ea.c b/source4/torture/smb2/ea.c
new file mode 100644
index 0000000..987d90d
--- /dev/null
+++ b/source4/torture/smb2/ea.c
@@ -0,0 +1,152 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB2 EA tests
+
+ Copyright (C) Ralph Boehme 2022
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "ntstatus_gen.h"
+#include "system/time.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+#define BASEDIR "test_ea"
+
+static bool find_returned_ea(union smb_fileinfo *finfo2,
+ const char *eaname)
+{
+ unsigned int i;
+ unsigned int num_eas = finfo2->all_eas.out.num_eas;
+ struct ea_struct *eas = finfo2->all_eas.out.eas;
+
+ for (i = 0; i < num_eas; i++) {
+ if (eas[i].name.s == NULL) {
+ continue;
+ }
+ /* Windows capitalizes returned EA names. */
+ if (strequal(eas[i].name.s, eaname)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool torture_smb2_acl_xattr(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = BASEDIR "\\test_acl_xattr";
+ const char *xattr_name = NULL;
+ struct smb2_handle h1;
+ struct ea_struct ea;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status;
+ bool ret = true;
+
+ torture_comment(tctx, "Verify NTACL xattr can't be accessed\n");
+
+ xattr_name = torture_setting_string(tctx, "acl_xattr_name", NULL);
+ torture_assert_not_null(tctx, xattr_name, "Missing acl_xattr_name option\n");
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ /*
+ * 1. Set an EA, so we have something to list
+ */
+ ZERO_STRUCT(ea);
+ ea.name.s = "void";
+ ea.name.private_length = strlen("void") + 1;
+ ea.value = data_blob_string_const("testme");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_FULL_EA_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.full_ea_information.in.eas.num_eas = 1;
+ sfinfo.full_ea_information.in.eas.eas = &ea;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Setting EA should fail\n");
+
+ /*
+ * 2. Verify NT ACL EA is not listed
+ */
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
+ finfo.generic.in.file.handle = h1;
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+
+ if (find_returned_ea(&finfo, xattr_name)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "%s: NTACL EA leaked\n",
+ __location__);
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * 3. Try to set EA, should fail
+ */
+ ZERO_STRUCT(ea);
+ ea.name.s = xattr_name;
+ ea.name.private_length = strlen(xattr_name) + 1;
+ ea.value = data_blob_string_const("testme");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_FULL_EA_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.full_ea_information.in.eas.num_eas = 1;
+ sfinfo.full_ea_information.in.eas.eas = &ea;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_ACCESS_DENIED,
+ ret, done, "Setting EA should fail\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+
+ smb2_deltree(tree, BASEDIR);
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_ea(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ea");
+ suite->description = talloc_strdup(suite, "SMB2-EA tests");
+
+ torture_suite_add_1smb2_test(suite, "acl_xattr", torture_smb2_acl_xattr);
+
+ return suite;
+}
diff --git a/source4/torture/smb2/getinfo.c b/source4/torture/smb2/getinfo.c
new file mode 100644
index 0000000..539090a
--- /dev/null
+++ b/source4/torture/smb2/getinfo.c
@@ -0,0 +1,951 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 getinfo test suite
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smbXcli_base.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/util.h"
+
+static struct {
+ const char *name;
+ uint16_t level;
+ NTSTATUS fstatus;
+ NTSTATUS dstatus;
+ union smb_fileinfo finfo;
+ union smb_fileinfo dinfo;
+} file_levels[] = {
+#define LEVEL(x) .name = #x, .level = x
+ { LEVEL(RAW_FILEINFO_BASIC_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_STANDARD_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_INTERNAL_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_EA_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_ACCESS_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_POSITION_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_MODE_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_ALIGNMENT_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_ALL_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_ALT_NAME_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_STREAM_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_COMPRESSION_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_NETWORK_OPEN_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION) },
+
+ { LEVEL(RAW_FILEINFO_SMB2_ALL_EAS) },
+
+ { LEVEL(RAW_FILEINFO_SMB2_ALL_INFORMATION) },
+ { LEVEL(RAW_FILEINFO_SEC_DESC) }
+};
+
+static struct {
+ const char *name;
+ uint16_t level;
+ NTSTATUS status;
+ union smb_fsinfo info;
+} fs_levels[] = {
+ { LEVEL(RAW_QFS_VOLUME_INFORMATION) },
+ { LEVEL(RAW_QFS_SIZE_INFORMATION) },
+ { LEVEL(RAW_QFS_DEVICE_INFORMATION) },
+ { LEVEL(RAW_QFS_ATTRIBUTE_INFORMATION) },
+ { LEVEL(RAW_QFS_QUOTA_INFORMATION) },
+ { LEVEL(RAW_QFS_FULL_SIZE_INFORMATION) },
+ { LEVEL(RAW_QFS_OBJECTID_INFORMATION) },
+ { LEVEL(RAW_QFS_SECTOR_SIZE_INFORMATION) },
+};
+
+#define FNAME "testsmb2_file.dat"
+#define DNAME "testsmb2_dir"
+
+/*
+ test fileinfo levels
+*/
+static bool torture_smb2_fileinfo(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_handle hfile, hdir;
+ NTSTATUS status;
+ int i;
+
+ status = torture_smb2_testfile(tree, FNAME, &hfile);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create test file "
+ FNAME "\n");
+
+ status = torture_smb2_testdir(tree, DNAME, &hdir);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create test dir "
+ DNAME "\n");
+
+ torture_comment(tctx, "Testing file info levels\n");
+ torture_smb2_all_info(tctx, tree, hfile);
+ torture_smb2_all_info(tctx, tree, hdir);
+
+ for (i=0;i<ARRAY_SIZE(file_levels);i++) {
+ if (file_levels[i].level == RAW_FILEINFO_SEC_DESC) {
+ file_levels[i].finfo.query_secdesc.in.secinfo_flags = 0x7;
+ file_levels[i].dinfo.query_secdesc.in.secinfo_flags = 0x7;
+ }
+ if (file_levels[i].level == RAW_FILEINFO_SMB2_ALL_EAS) {
+ file_levels[i].finfo.all_eas.in.continue_flags =
+ SMB2_CONTINUE_FLAG_RESTART;
+ file_levels[i].dinfo.all_eas.in.continue_flags =
+ SMB2_CONTINUE_FLAG_RESTART;
+ }
+ file_levels[i].finfo.generic.level = file_levels[i].level;
+ file_levels[i].finfo.generic.in.file.handle = hfile;
+ file_levels[i].fstatus = smb2_getinfo_file(tree, tree, &file_levels[i].finfo);
+ torture_assert_ntstatus_ok(tctx, file_levels[i].fstatus,
+ talloc_asprintf(tctx, "%s on file",
+ file_levels[i].name));
+ file_levels[i].dinfo.generic.level = file_levels[i].level;
+ file_levels[i].dinfo.generic.in.file.handle = hdir;
+ file_levels[i].dstatus = smb2_getinfo_file(tree, tree, &file_levels[i].dinfo);
+ torture_assert_ntstatus_ok(tctx, file_levels[i].dstatus,
+ talloc_asprintf(tctx, "%s on dir",
+ file_levels[i].name));
+ }
+
+ return true;
+}
+
+/*
+ test granted access when desired access includes
+ FILE_EXECUTE and does not include FILE_READ_DATA
+*/
+static bool torture_smb2_fileinfo_grant_read(struct torture_context *tctx)
+{
+ struct smb2_tree *tree;
+ bool ret;
+ struct smb2_handle hfile, hdir;
+ NTSTATUS status;
+ uint32_t file_granted_access, dir_granted_access;
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ status = torture_smb2_testfile_access(
+ tree, FNAME, &hfile, SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Unable to create test file " FNAME "\n");
+ status =
+ torture_smb2_get_allinfo_access(tree, hfile, &file_granted_access);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Unable to query test file access ");
+ torture_assert_int_equal(tctx, file_granted_access,
+ SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE,
+ "granted file access ");
+ smb2_util_close(tree, hfile);
+
+ status = torture_smb2_testdir_access(
+ tree, DNAME, &hdir, SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Unable to create test dir " DNAME "\n");
+ status =
+ torture_smb2_get_allinfo_access(tree, hdir, &dir_granted_access);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Unable to query test dir access ");
+ torture_assert_int_equal(tctx, dir_granted_access,
+ SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE,
+ "granted dir access ");
+ smb2_util_close(tree, hdir);
+
+ return true;
+}
+
+static bool torture_smb2_fileinfo_normalized(struct torture_context *tctx)
+{
+ struct smb2_tree *tree = NULL;
+ bool ret;
+ struct smb2_handle hroot;
+ const char *d1 = NULL, *d1l = NULL, *d1u = NULL;
+ struct smb2_handle hd1, hd1l, hd1u;
+ const char *d2 = NULL, *d2l = NULL, *d2u = NULL;
+ struct smb2_handle hd2, hd2l, hd2u;
+ const char *d3 = NULL, *d3l = NULL, *d3u = NULL;
+ struct smb2_handle hd3, hd3l, hd3u;
+ const char *d3s = NULL, *d3sl = NULL, *d3su = NULL, *d3sd = NULL;
+ struct smb2_handle hd3s, hd3sl, hd3su, hd3sd;
+ const char *f4 = NULL, *f4l = NULL, *f4u = NULL, *f4d = NULL;
+ struct smb2_handle hf4, hf4l, hf4u, hf4d;
+ const char *f4s = NULL, *f4sl = NULL, *f4su = NULL, *f4sd = NULL;
+ struct smb2_handle hf4s, hf4sl, hf4su, hf4sd;
+ union smb_fileinfo info = {
+ .normalized_name_info = {
+ .level = RAW_FILEINFO_NORMALIZED_NAME_INFORMATION,
+ },
+ };
+ NTSTATUS status;
+ enum protocol_types protocol;
+ struct smb2_tree *tree_3_0 = NULL;
+ struct smbcli_options options3_0;
+ struct smb2_handle hroot_3_0;
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+
+ d1 = talloc_asprintf(tctx, "torture_dIr1N");
+ torture_assert_not_null(tctx, d1, "d1");
+ d1l = strlower_talloc(tctx, d1);
+ torture_assert_not_null(tctx, d1l, "d1l");
+ d1u = strupper_talloc(tctx, d1);
+ torture_assert_not_null(tctx, d1u, "d1u");
+
+ d2 = talloc_asprintf(tctx, "%s\\dIr2Na", d1);
+ torture_assert_not_null(tctx, d2, "d2");
+ d2l = strlower_talloc(tctx, d2);
+ torture_assert_not_null(tctx, d2l, "d2l");
+ d2u = strupper_talloc(tctx, d2);
+ torture_assert_not_null(tctx, d2u, "d2u");
+
+ d3 = talloc_asprintf(tctx, "%s\\dIr3NaM", d2);
+ torture_assert_not_null(tctx, d3, "d3");
+ d3l = strlower_talloc(tctx, d3);
+ torture_assert_not_null(tctx, d3l, "d3l");
+ d3u = strupper_talloc(tctx, d3);
+ torture_assert_not_null(tctx, d3u, "d3u");
+
+ d3s = talloc_asprintf(tctx, "%s:sTrEaM3", d3);
+ torture_assert_not_null(tctx, d3s, "d3s");
+ d3sl = strlower_talloc(tctx, d3s);
+ torture_assert_not_null(tctx, d3sl, "d3sl");
+ d3su = strupper_talloc(tctx, d3s);
+ torture_assert_not_null(tctx, d3su, "d3su");
+ d3sd = talloc_asprintf(tctx, "%s:$DaTa", d3s);
+ torture_assert_not_null(tctx, d3sd, "d3sd");
+
+ f4 = talloc_asprintf(tctx, "%s\\fIlE4NaMe", d3);
+ torture_assert_not_null(tctx, f4, "f4");
+ f4l = strlower_talloc(tctx, f4);
+ torture_assert_not_null(tctx, f4l, "f4l");
+ f4u = strupper_talloc(tctx, f4);
+ torture_assert_not_null(tctx, f4u, "f4u");
+ f4d = talloc_asprintf(tctx, "%s::$dAtA", f4);
+ torture_assert_not_null(tctx, f4d, "f4d");
+
+ f4s = talloc_asprintf(tctx, "%s:StReAm4", f4);
+ torture_assert_not_null(tctx, f4s, "f4s");
+ f4sl = strlower_talloc(tctx, f4s);
+ torture_assert_not_null(tctx, f4sl, "f4sl");
+ f4su = strupper_talloc(tctx, f4s);
+ torture_assert_not_null(tctx, f4su, "f4su");
+ f4sd = talloc_asprintf(tctx, "%s:$dAtA", f4s);
+ torture_assert_not_null(tctx, f4sd, "f4sd");
+
+ status = smb2_util_roothandle(tree, &hroot);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create root handle");
+
+ info.normalized_name_info.in.file.handle = hroot;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ if (protocol < PROTOCOL_SMB3_11) {
+ /*
+ * Only SMB 3.1.1 and above should offer this.
+ */
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_NOT_SUPPORTED,
+ "getinfo hroot");
+ torture_skip(tctx, "SMB 3.1.1 not supported");
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ /*
+ * Not all servers support this.
+ * (only Windows 10 1803 and higher)
+ */
+ torture_skip(tctx, "NORMALIZED_NAME_INFORMATION not supported");
+ }
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hroot");
+ torture_assert(tctx, info.normalized_name_info.out.fname.s == NULL,
+ "getinfo hroot should be empty");
+
+ smb2_deltree(tree, d1);
+
+ status = torture_smb2_testdir(tree, d1, &hd1);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create hd1");
+ status = torture_smb2_open(tree, d1l, SEC_RIGHTS_FILE_ALL, &hd1l);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd1l");
+ status = torture_smb2_open(tree, d1u, SEC_RIGHTS_FILE_ALL, &hd1u);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd1u");
+
+ status = torture_smb2_testdir(tree, d2, &hd2);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create hd2");
+ status = torture_smb2_open(tree, d2l, SEC_RIGHTS_FILE_ALL, &hd2l);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd2l");
+ status = torture_smb2_open(tree, d2u, SEC_RIGHTS_FILE_ALL, &hd2u);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd2u");
+
+ status = torture_smb2_testdir(tree, d3, &hd3);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create hd3");
+ status = torture_smb2_open(tree, d3l, SEC_RIGHTS_FILE_ALL, &hd3l);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd3l");
+ status = torture_smb2_open(tree, d3u, SEC_RIGHTS_FILE_ALL, &hd3u);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd3u");
+
+ status = torture_smb2_testfile(tree, d3s, &hd3s);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create hd3s");
+ status = torture_smb2_open(tree, d3sl, SEC_RIGHTS_FILE_ALL, &hd3sl);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd3sl");
+ status = torture_smb2_open(tree, d3su, SEC_RIGHTS_FILE_ALL, &hd3su);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd3su");
+ status = torture_smb2_open(tree, d3sd, SEC_RIGHTS_FILE_ALL, &hd3sd);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hd3sd");
+
+ status = torture_smb2_testfile(tree, f4, &hf4);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create hf4");
+ status = torture_smb2_open(tree, f4l, SEC_RIGHTS_FILE_ALL, &hf4l);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hf4l");
+ status = torture_smb2_open(tree, f4u, SEC_RIGHTS_FILE_ALL, &hf4u);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hf4u");
+ status = torture_smb2_open(tree, f4d, SEC_RIGHTS_FILE_ALL, &hf4d);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hf4d");
+
+ status = torture_smb2_testfile(tree, f4s, &hf4s);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create hf4s");
+ status = torture_smb2_open(tree, f4sl, SEC_RIGHTS_FILE_ALL, &hf4sl);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hf4sl");
+ status = torture_smb2_open(tree, f4su, SEC_RIGHTS_FILE_ALL, &hf4su);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hf4su");
+ status = torture_smb2_open(tree, f4sd, SEC_RIGHTS_FILE_ALL, &hf4sd);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to open hf4sd");
+
+ info.normalized_name_info.in.file.handle = hd1;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd1");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d1, "getinfo hd1");
+ info.normalized_name_info.in.file.handle = hd1l;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd1l");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d1, "getinfo hd1l");
+ info.normalized_name_info.in.file.handle = hd1u;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd1u");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d1, "getinfo hd1u");
+
+ info.normalized_name_info.in.file.handle = hd2;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd2");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d2, "getinfo hd2");
+ info.normalized_name_info.in.file.handle = hd2l;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd2l");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d2, "getinfo hd2l");
+ info.normalized_name_info.in.file.handle = hd2u;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd2u");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d2, "getinfo hd2u");
+
+ info.normalized_name_info.in.file.handle = hd3;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3, "getinfo hd3");
+ info.normalized_name_info.in.file.handle = hd3l;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3l");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3, "getinfo hd3l");
+ info.normalized_name_info.in.file.handle = hd3u;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3u");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3, "getinfo hd3u");
+
+ info.normalized_name_info.in.file.handle = hd3s;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3s");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3s, "getinfo hd3s");
+ info.normalized_name_info.in.file.handle = hd3sl;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3sl");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3s, "getinfo hd3sl");
+ info.normalized_name_info.in.file.handle = hd3su;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3su");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3s, "getinfo hd3su");
+ info.normalized_name_info.in.file.handle = hd3sd;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hd3sd");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ d3s, "getinfo hd3sd");
+
+ info.normalized_name_info.in.file.handle = hf4;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4, "getinfo hf4");
+ info.normalized_name_info.in.file.handle = hf4l;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4l");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4, "getinfo hf4l");
+ info.normalized_name_info.in.file.handle = hf4u;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4u");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4, "getinfo hf4u");
+ info.normalized_name_info.in.file.handle = hf4d;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4d");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4, "getinfo hf4d");
+
+ info.normalized_name_info.in.file.handle = hf4s;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4s");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4s, "getinfo hf4s");
+ info.normalized_name_info.in.file.handle = hf4sl;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4sl");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4s, "getinfo hf4sl");
+ info.normalized_name_info.in.file.handle = hf4su;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4su");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4s, "getinfo hf4su");
+ info.normalized_name_info.in.file.handle = hf4sd;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree, tree, &info);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo hf4sd");
+ torture_assert_str_equal(tctx, info.normalized_name_info.out.fname.s,
+ f4s, "getinfo hf4sd");
+
+ /* Set max protocol to SMB 3.0.2 */
+ options3_0 = tree->session->transport->options;
+ options3_0.max_protocol = PROTOCOL_SMB3_02;
+ options3_0.client_guid = GUID_zero();
+ ret = torture_smb2_connection_ext(tctx, 0, &options3_0, &tree_3_0);
+ torture_assert(tctx, ret, "connection with SMB < 3.1.1 failed");
+
+ status = smb2_util_roothandle(tree_3_0, &hroot_3_0);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create root handle 3_0");
+
+ info.normalized_name_info.in.file.handle = hroot_3_0;
+ ZERO_STRUCT(info.normalized_name_info.out);
+ status = smb2_getinfo_file(tree_3_0, tree_3_0, &info);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_NOT_SUPPORTED,
+ "getinfo hroot");
+
+ return true;
+}
+
+/*
+ test fsinfo levels
+*/
+static bool torture_smb2_fsinfo(struct torture_context *tctx)
+{
+ bool ret;
+ struct smb2_tree *tree;
+ int i;
+ NTSTATUS status;
+ struct smb2_handle handle;
+
+ torture_comment(tctx, "Testing fsinfo levels\n");
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ status = smb2_util_roothandle(tree, &handle);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create root handle");
+
+ for (i=0;i<ARRAY_SIZE(fs_levels);i++) {
+ fs_levels[i].info.generic.level = fs_levels[i].level;
+ fs_levels[i].info.generic.handle = handle;
+ fs_levels[i].status = smb2_getinfo_fs(tree, tree, &fs_levels[i].info);
+ torture_assert_ntstatus_ok(tctx, fs_levels[i].status,
+ fs_levels[i].name);
+ }
+
+ return true;
+}
+
+static bool torture_smb2_buffercheck_err(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_getinfo *b,
+ size_t fixed,
+ DATA_BLOB full)
+{
+ size_t i;
+
+ for (i=0; i<=full.length; i++) {
+ NTSTATUS status;
+
+ b->in.output_buffer_length = i;
+
+ status = smb2_getinfo(tree, tree, b);
+
+ if (i < fixed) {
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_INFO_LENGTH_MISMATCH,
+ "Wrong error code small buffer");
+ continue;
+ }
+
+ if (i<full.length) {
+ torture_assert_ntstatus_equal(
+ tctx, status, STATUS_BUFFER_OVERFLOW,
+ "Wrong error code for large buffer");
+ /*
+ * TODO: compare the output buffer. That seems a bit
+ * difficult, because for level 5 for example the
+ * label length is adjusted to what is there. And some
+ * reserved fields seem to be not initialized to 0.
+ */
+ TALLOC_FREE(b->out.blob.data);
+ continue;
+ }
+
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_OK,
+ "Wrong error code for right sized buffer");
+ }
+
+ return true;
+}
+
+struct level_buffersize {
+ int level;
+ size_t fixed;
+};
+
+static bool torture_smb2_qfs_buffercheck(struct torture_context *tctx)
+{
+ bool ret;
+ struct smb2_tree *tree;
+ NTSTATUS status;
+ struct smb2_handle handle;
+ int i;
+
+ struct level_buffersize levels[] = {
+ { 1, 24 }, /* We don't have proper defines here */
+ { 3, 24 },
+ { 4, 8 },
+ { 5, 16 },
+ { 6, 48 },
+ { 7, 32 },
+ { 11, 28 },
+ };
+
+ torture_comment(tctx, "Testing SMB2_GETINFO_FS buffer sizes\n");
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ status = smb2_util_roothandle(tree, &handle);
+ torture_assert_ntstatus_ok(
+ tctx, status, "Unable to create root handle");
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+ struct smb2_getinfo b;
+
+ if (TARGET_IS_SAMBA3(tctx) &&
+ ((levels[i].level == 6) || (levels[i].level == 11))) {
+ continue;
+ }
+
+ ZERO_STRUCT(b);
+ b.in.info_type = SMB2_0_INFO_FILESYSTEM;
+ b.in.info_class = levels[i].level;
+ b.in.file.handle = handle;
+ b.in.output_buffer_length = 65535;
+
+ status = smb2_getinfo(tree, tree, &b);
+
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_OK,
+ "Wrong error code for large buffer");
+
+ ret = torture_smb2_buffercheck_err(
+ tctx, tree, &b, levels[i].fixed, b.out.blob);
+ if (!ret) {
+ return ret;
+ }
+ }
+
+ return true;
+}
+
+static bool torture_smb2_qfile_buffercheck(struct torture_context *tctx)
+{
+ bool ret;
+ struct smb2_tree *tree;
+ struct smb2_create c;
+ NTSTATUS status;
+ struct smb2_handle handle;
+ int i;
+
+ struct level_buffersize levels[] = {
+ { 4, 40 },
+ { 5, 24 },
+ { 6, 8 },
+ { 7, 4 },
+ { 8, 4 },
+ { 16, 4 },
+ { 17, 4 },
+ { 18, 104 },
+ { 21, 8 },
+ { 22, 32 },
+ { 28, 16 },
+ { 34, 56 },
+ { 35, 8 },
+ };
+
+ torture_comment(tctx, "Testing SMB2_GETINFO_FILE buffer sizes\n");
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ ZERO_STRUCT(c);
+ c.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ c.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ c.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ c.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ c.in.create_options = 0;
+ c.in.fname = "bufsize.txt";
+
+ c.in.eas.num_eas = 2;
+ c.in.eas.eas = talloc_array(tree, struct ea_struct, 2);
+ c.in.eas.eas[0].flags = 0;
+ c.in.eas.eas[0].name.s = "EAONE";
+ c.in.eas.eas[0].value = data_blob_talloc(c.in.eas.eas, "VALUE1", 6);
+ c.in.eas.eas[1].flags = 0;
+ c.in.eas.eas[1].name.s = "SECONDEA";
+ c.in.eas.eas[1].value = data_blob_talloc(c.in.eas.eas, "ValueTwo", 8);
+
+ status = smb2_create(tree, tree, &c);
+ torture_assert_ntstatus_ok(
+ tctx, status, "Unable to create test file");
+
+ handle = c.out.file.handle;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+ struct smb2_getinfo b;
+
+ ZERO_STRUCT(b);
+ b.in.info_type = SMB2_0_INFO_FILE;
+ b.in.info_class = levels[i].level;
+ b.in.file.handle = handle;
+ b.in.output_buffer_length = 65535;
+
+ status = smb2_getinfo(tree, tree, &b);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ continue;
+ }
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_OK,
+ "Wrong error code for large buffer");
+
+ ret = torture_smb2_buffercheck_err(
+ tctx, tree, &b, levels[i].fixed, b.out.blob);
+ if (!ret) {
+ return ret;
+ }
+ }
+ return true;
+}
+
+static bool torture_smb2_qsec_buffercheck(struct torture_context *tctx)
+{
+ struct smb2_getinfo b;
+ bool ret;
+ struct smb2_tree *tree;
+ struct smb2_create c;
+ NTSTATUS status;
+ struct smb2_handle handle;
+
+ torture_comment(tctx, "Testing SMB2_GETINFO_SECURITY buffer sizes\n");
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ ZERO_STRUCT(c);
+ c.in.oplock_level = 0;
+ c.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_LIST | SEC_STD_READ_CONTROL;
+ c.in.file_attributes = 0;
+ c.in.create_disposition = NTCREATEX_DISP_OPEN;
+ c.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ c.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
+ c.in.fname = "";
+
+ status = smb2_create(tree, tree, &c);
+ torture_assert_ntstatus_ok(
+ tctx, status, "Unable to create root handle");
+
+ handle = c.out.file.handle;
+
+ ZERO_STRUCT(b);
+ b.in.info_type = SMB2_0_INFO_SECURITY;
+ b.in.info_class = 0;
+ b.in.file.handle = handle;
+ b.in.output_buffer_length = 0;
+
+ status = smb2_getinfo(tree, tree, &b);
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_BUFFER_TOO_SMALL,
+ "Wrong error code for large buffer");
+
+ b.in.output_buffer_length = 1;
+ status = smb2_getinfo(tree, tree, &b);
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_BUFFER_TOO_SMALL,
+ "Wrong error code for large buffer");
+
+ return true;
+}
+
+/* basic testing of all SMB2 getinfo levels
+*/
+static bool torture_smb2_getinfo(struct torture_context *tctx)
+{
+ struct smb2_tree *tree;
+ bool ret = true;
+ NTSTATUS status;
+
+ ret = torture_smb2_connection(tctx, &tree);
+ torture_assert(tctx, ret, "connection failed");
+
+ smb2_deltree(tree, FNAME);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_setup_complex_file(tctx, tree, FNAME);
+ torture_assert_ntstatus_ok(tctx, status,
+ "setup complex file " FNAME);
+
+ status = torture_setup_complex_file(tctx, tree, FNAME ":streamtwo");
+ torture_assert_ntstatus_ok(tctx, status,
+ "setup complex file " FNAME ":streamtwo");
+
+ status = torture_setup_complex_dir(tctx, tree, DNAME);
+ torture_assert_ntstatus_ok(tctx, status,
+ "setup complex dir " DNAME);
+
+ status = torture_setup_complex_file(tctx, tree, DNAME ":streamtwo");
+ torture_assert_ntstatus_ok(tctx, status,
+ "setup complex dir " DNAME ":streamtwo");
+
+ ret &= torture_smb2_fileinfo(tctx, tree);
+
+ return ret;
+}
+
+#undef LEVEL
+#define LEVEL(l, u, ua, ra) \
+ .name = #l, \
+ .level = l, \
+ .unrestricted = u, \
+ .unrestricted_access = ua, \
+ .required_access = ra
+
+static struct {
+ const char *name;
+ uint16_t level;
+ bool unrestricted;
+ uint32_t unrestricted_access;
+ uint32_t required_access;
+} file_levels_access[] = {
+ /*
+ * The following info levels are not checked:
+ * - FileFullEaInformation and FileIdInformation:
+ * not implemented by the s4/libcli/raw
+ * - all pipe infolevels: that should be tested elsewhere by RPC tests
+ */
+
+ /*
+ * The following allow unrestricted access, so requesting
+ * SEC_FILE_READ_ATTRIBUTE works, SEC_FILE_READ_ATTRIBUTE or
+ * SEC_FILE_READ_EA as well of course.
+ */
+ { LEVEL(RAW_FILEINFO_STANDARD_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_INTERNAL_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_ACCESS_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_POSITION_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_MODE_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_ALIGNMENT_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_ALT_NAME_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_STREAM_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_COMPRESSION_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_NORMALIZED_NAME_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_EA_INFORMATION, true, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_EA) },
+
+ /*
+ * The following require either SEC_FILE_READ_ATTRIBUTE or
+ * SEC_FILE_READ_EA.
+ */
+ { LEVEL(RAW_FILEINFO_BASIC_INFORMATION, false, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_ALL_INFORMATION, false, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_NETWORK_OPEN_INFORMATION, false, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, false, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_SMB2_ALL_INFORMATION, false, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_ATTRIBUTE) },
+ { LEVEL(RAW_FILEINFO_SMB2_ALL_EAS, false, SEC_STD_SYNCHRONIZE, SEC_FILE_READ_EA) },
+ /* Also try SEC_FILE_READ_ATTRIBUTE to show that it is the wrong one */
+ { LEVEL(RAW_FILEINFO_SMB2_ALL_EAS, false, SEC_FILE_READ_ATTRIBUTE, SEC_FILE_READ_EA) },
+ { LEVEL(RAW_FILEINFO_SEC_DESC, false, SEC_STD_SYNCHRONIZE, SEC_STD_READ_CONTROL) },
+ /* Also try SEC_FILE_READ_ATTRIBUTE to show that it is the wrong one */
+ { LEVEL(RAW_FILEINFO_SEC_DESC, false, SEC_FILE_READ_ATTRIBUTE, SEC_STD_READ_CONTROL) }
+};
+
+
+/*
+ test fileinfo levels
+*/
+static bool torture_smb2_getfinfo_access(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "torture_smb2_getfinfo_access";
+ struct smb2_handle hfile;
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+
+ smb2_deltree(tree, fname);
+
+ torture_setup_complex_file(tctx, tree, fname);
+
+ for (i = 0; i < ARRAY_SIZE(file_levels_access); i++) {
+ union smb_fileinfo finfo;
+ NTSTATUS expected_status;
+
+ /*
+ * First open with unrestricted_access, SEC_STD_SYNCHRONIZE for
+ * most tests, info levels with unrestricted=true should allow
+ * this.
+ */
+ status = torture_smb2_testfile_access(
+ tree, fname, &hfile, file_levels_access[i].unrestricted_access);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Unable to open test file\n");
+
+ if (file_levels_access[i].level == RAW_FILEINFO_SEC_DESC) {
+ finfo.query_secdesc.in.secinfo_flags = 0x7;
+ }
+ if (file_levels_access[i].level == RAW_FILEINFO_SMB2_ALL_EAS) {
+ finfo.all_eas.in.continue_flags =
+ SMB2_CONTINUE_FLAG_RESTART;
+ }
+
+ finfo.generic.level = file_levels_access[i].level;
+ finfo.generic.in.file.handle = hfile;
+
+ if (file_levels_access[i].unrestricted) {
+ expected_status = NT_STATUS_OK;
+ } else {
+ expected_status = NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, expected_status, ret, done,
+ talloc_asprintf(tctx, "Level %s failed\n",
+ file_levels_access[i].name));
+
+ smb2_util_close(tree, hfile);
+
+ /*
+ * Now open with expected access, getinfo should work.
+ */
+ status = torture_smb2_testfile_access(
+ tree, fname, &hfile, file_levels_access[i].required_access);
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ret, done,
+ "Unable to open test file\n");
+
+ if (file_levels_access[i].level == RAW_FILEINFO_SEC_DESC) {
+ finfo.query_secdesc.in.secinfo_flags = 0x7;
+ }
+ if (file_levels_access[i].level == RAW_FILEINFO_SMB2_ALL_EAS) {
+ finfo.all_eas.in.continue_flags =
+ SMB2_CONTINUE_FLAG_RESTART;
+ }
+ finfo.generic.level = file_levels_access[i].level;
+ finfo.generic.in.file.handle = hfile;
+
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ret, done,
+ talloc_asprintf(tctx, "%s on file",
+ file_levels_access[i].name));
+
+ smb2_util_close(tree, hfile);
+ }
+
+done:
+ smb2_deltree(tree, fname);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_getinfo_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "getinfo");
+
+ torture_suite_add_simple_test(suite, "complex", torture_smb2_getinfo);
+ torture_suite_add_simple_test(suite, "fsinfo", torture_smb2_fsinfo);
+ torture_suite_add_simple_test(suite, "qfs_buffercheck",
+ torture_smb2_qfs_buffercheck);
+ torture_suite_add_simple_test(suite, "qfile_buffercheck",
+ torture_smb2_qfile_buffercheck);
+ torture_suite_add_simple_test(suite, "qsec_buffercheck",
+ torture_smb2_qsec_buffercheck);
+ torture_suite_add_simple_test(suite, "granted",
+ torture_smb2_fileinfo_grant_read);
+ torture_suite_add_simple_test(suite, "normalized",
+ torture_smb2_fileinfo_normalized);
+ torture_suite_add_1smb2_test(suite, "getinfo_access",
+ torture_smb2_getfinfo_access);
+ return suite;
+}
diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c
new file mode 100644
index 0000000..3765dc0
--- /dev/null
+++ b/source4/torture/smb2/ioctl.c
@@ -0,0 +1,7552 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 ioctl operations
+
+ Copyright (C) David Disseldorp 2011-2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/security.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/param/param.h"
+#include "lib/util/tevent_ntstatus.h"
+
+#define FNAME "testfsctl.dat"
+#define FNAME2 "testfsctl2.dat"
+#define DNAME "testfsctl_dir"
+
+/*
+ basic testing of SMB2 shadow copy calls
+*/
+static bool test_ioctl_get_shadow_copy(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle h;
+ uint8_t buf[100];
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ torture_assert_ntstatus_ok(torture, status, "create write");
+
+ ZERO_ARRAY(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ torture_assert_ntstatus_ok(torture, status, "write");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = h;
+ ioctl.smb2.in.function = FSCTL_SRV_ENUM_SNAPS;
+ ioctl.smb2.in.max_output_response = 16;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)
+ || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) {
+ torture_skip(torture, "FSCTL_SRV_ENUM_SNAPS not supported\n");
+ }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_ENUM_SNAPS");
+
+ return true;
+}
+
+/*
+ basic testing of the SMB2 server side copy ioctls
+*/
+static bool test_ioctl_req_resume_key(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle h;
+ uint8_t buf[100];
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct req_resume_key_rsp res_key;
+ enum ndr_err_code ndr_ret;
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ torture_assert_ntstatus_ok(torture, status, "create write");
+
+ ZERO_ARRAY(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ torture_assert_ntstatus_ok(torture, status, "write");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = h;
+ ioctl.smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
+ ioctl.smb2.in.max_output_response = 32;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
+ (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
+
+ NDR_PRINT_DEBUG(req_resume_key_rsp, &res_key);
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ testing fetching a resume key twice for one file handle
+*/
+static bool test_ioctl_req_two_resume_keys(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle h;
+ uint8_t buf[100];
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct req_resume_key_rsp res_key;
+ enum ndr_err_code ndr_ret;
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ torture_assert_ntstatus_ok(torture, status, "create write");
+
+ ZERO_ARRAY(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ torture_assert_ntstatus_ok(torture, status, "write");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = h;
+ ioctl.smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
+ ioctl.smb2.in.max_output_response = 32;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
+ (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
+
+ NDR_PRINT_DEBUG(req_resume_key_rsp, &res_key);
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = h;
+ ioctl.smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
+ ioctl.smb2.in.max_output_response = 32;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_REQUEST_RESUME_KEY");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &res_key,
+ (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
+
+ NDR_PRINT_DEBUG(req_resume_key_rsp, &res_key);
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static uint64_t patt_hash(uint64_t off)
+{
+ return off;
+}
+
+static bool write_pattern(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle h, uint64_t off, uint64_t len,
+ uint64_t patt_off)
+{
+ NTSTATUS status;
+ uint64_t i;
+ uint8_t *buf;
+ uint64_t io_sz = MIN(1024 * 64, len);
+
+ if (len == 0) {
+ return true;
+ }
+
+ torture_assert(torture, (len % 8) == 0, "invalid write len");
+
+ buf = talloc_zero_size(mem_ctx, io_sz);
+ torture_assert(torture, (buf != NULL), "no memory for file data buf");
+
+ while (len > 0) {
+ for (i = 0; i <= io_sz - 8; i += 8) {
+ SBVAL(buf, i, patt_hash(patt_off));
+ patt_off += 8;
+ }
+
+ status = smb2_util_write(tree, h,
+ buf, off, io_sz);
+ torture_assert_ntstatus_ok(torture, status, "file write");
+
+ len -= io_sz;
+ off += io_sz;
+ }
+
+ talloc_free(buf);
+
+ return true;
+}
+
+static bool check_pattern(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle h, uint64_t off, uint64_t len,
+ uint64_t patt_off)
+{
+ if (len == 0) {
+ return true;
+ }
+
+ torture_assert(torture, (len % 8) == 0, "invalid read len");
+
+ while (len > 0) {
+ uint64_t i;
+ struct smb2_read r;
+ NTSTATUS status;
+ uint64_t io_sz = MIN(1024 * 64, len);
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = h;
+ r.in.length = io_sz;
+ r.in.offset = off;
+ status = smb2_read(tree, mem_ctx, &r);
+ torture_assert_ntstatus_ok(torture, status, "read");
+
+ torture_assert_u64_equal(torture, r.out.data.length, io_sz,
+ "read data len mismatch");
+
+ for (i = 0; i <= io_sz - 8; i += 8, patt_off += 8) {
+ uint64_t data = BVAL(r.out.data.data, i);
+ torture_assert_u64_equal(torture, data, patt_hash(patt_off),
+ talloc_asprintf(torture, "read data "
+ "pattern bad at %llu\n",
+ (unsigned long long)off + i));
+ }
+ talloc_free(r.out.data.data);
+ len -= io_sz;
+ off += io_sz;
+ }
+
+ return true;
+}
+
+static bool check_zero(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle h, uint64_t off, uint64_t len)
+{
+ uint64_t i;
+ struct smb2_read r;
+ NTSTATUS status;
+
+ if (len == 0) {
+ return true;
+ }
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = h;
+ r.in.length = len;
+ r.in.offset = off;
+ status = smb2_read(tree, mem_ctx, &r);
+ torture_assert_ntstatus_ok(torture, status, "read");
+
+ torture_assert_u64_equal(torture, r.out.data.length, len,
+ "read data len mismatch");
+
+ for (i = 0; i <= len - 8; i += 8) {
+ uint64_t data = BVAL(r.out.data.data, i);
+ torture_assert_u64_equal(torture, data, 0,
+ talloc_asprintf(mem_ctx, "read zero "
+ "bad at %llu\n",
+ (unsigned long long)i));
+ }
+
+ talloc_free(r.out.data.data);
+ return true;
+}
+
+static bool test_setup_open(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ const char *fname,
+ struct smb2_handle *fh,
+ uint32_t desired_access,
+ uint32_t file_attributes)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = desired_access;
+ io.in.file_attributes = file_attributes;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ if (file_attributes & FILE_ATTRIBUTE_DIRECTORY) {
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ }
+ io.in.fname = fname;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "file create");
+
+ *fh = io.out.file.handle;
+
+ return true;
+}
+
+static bool test_setup_create_fill(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ const char *fname,
+ struct smb2_handle *fh,
+ uint64_t size,
+ uint32_t desired_access,
+ uint32_t file_attributes)
+{
+ bool ok;
+ uint32_t initial_access = desired_access;
+
+ if (size > 0) {
+ initial_access |= SEC_FILE_APPEND_DATA;
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ ok = test_setup_open(torture, tree, mem_ctx,
+ fname,
+ fh,
+ initial_access,
+ file_attributes);
+ torture_assert(torture, ok, "file create");
+
+ if (size > 0) {
+ ok = write_pattern(torture, tree, mem_ctx, *fh, 0, size, 0);
+ torture_assert(torture, ok, "write pattern");
+ }
+
+ if (initial_access != desired_access) {
+ smb2_util_close(tree, *fh);
+ ok = test_setup_open(torture, tree, mem_ctx,
+ fname,
+ fh,
+ desired_access,
+ file_attributes);
+ torture_assert(torture, ok, "file open");
+ }
+
+ return true;
+}
+
+static bool test_setup_copy_chunk(struct torture_context *torture,
+ struct smb2_tree *src_tree,
+ struct smb2_tree *dst_tree,
+ TALLOC_CTX *mem_ctx,
+ uint32_t nchunks,
+ const char *src_name,
+ struct smb2_handle *src_h,
+ uint64_t src_size,
+ uint32_t src_desired_access,
+ const char *dst_name,
+ struct smb2_handle *dest_h,
+ uint64_t dest_size,
+ uint32_t dest_desired_access,
+ struct srv_copychunk_copy *cc_copy,
+ union smb_ioctl *ioctl)
+{
+ struct req_resume_key_rsp res_key;
+ bool ok;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+
+ ok = test_setup_create_fill(torture, src_tree, mem_ctx, src_name,
+ src_h, src_size, src_desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "src file create fill");
+
+ ok = test_setup_create_fill(torture, dst_tree, mem_ctx, dst_name,
+ dest_h, dest_size, dest_desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "dest file create fill");
+
+ ZERO_STRUCTPN(ioctl);
+ ioctl->smb2.level = RAW_IOCTL_SMB2;
+ ioctl->smb2.in.file.handle = *src_h;
+ ioctl->smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
+ /* Allow for Key + ContextLength + Context */
+ ioctl->smb2.in.max_output_response = 32;
+ ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(src_tree, mem_ctx, &ioctl->smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_REQUEST_RESUME_KEY");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl->smb2.out.out, mem_ctx, &res_key,
+ (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
+
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
+
+ ZERO_STRUCTPN(ioctl);
+ ioctl->smb2.level = RAW_IOCTL_SMB2;
+ ioctl->smb2.in.file.handle = *dest_h;
+ ioctl->smb2.in.function = FSCTL_SRV_COPYCHUNK;
+ ioctl->smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp);
+ ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_STRUCTPN(cc_copy);
+ memcpy(cc_copy->source_key, res_key.resume_key, ARRAY_SIZE(cc_copy->source_key));
+ cc_copy->chunk_count = nchunks;
+ cc_copy->chunks = talloc_zero_array(mem_ctx, struct srv_copychunk, nchunks);
+ torture_assert(torture, (cc_copy->chunks != NULL), "no memory for chunks");
+
+ return true;
+}
+
+
+static bool check_copy_chunk_rsp(struct torture_context *torture,
+ struct srv_copychunk_rsp *cc_rsp,
+ uint32_t ex_chunks_written,
+ uint32_t ex_chunk_bytes_written,
+ uint32_t ex_total_bytes_written)
+{
+ torture_assert_int_equal(torture, cc_rsp->chunks_written,
+ ex_chunks_written, "num chunks");
+ torture_assert_int_equal(torture, cc_rsp->chunk_bytes_written,
+ ex_chunk_bytes_written, "chunk bytes written");
+ torture_assert_int_equal(torture, cc_rsp->total_bytes_written,
+ ex_total_bytes_written, "chunk total bytes");
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_simple(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_multi(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 2, /* chunks */
+ FNAME,
+ &src_h, 8192, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* copy all src file data via two chunks */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ cc_copy.chunks[1].source_off = 4096;
+ cc_copy.chunks[1].target_off = 4096;
+ cc_copy.chunks[1].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 2, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 8192); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_tiny(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 2, /* chunks */
+ FNAME,
+ &src_h, 96, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* copy all src file data via two chunks, sub block size chunks */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 48;
+
+ cc_copy.chunks[1].source_off = 48;
+ cc_copy.chunks[1].target_off = 48;
+ cc_copy.chunks[1].length = 48;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 2, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 96); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 96, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_over(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 2, /* chunks */
+ FNAME,
+ &src_h, 8192, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 4096, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* first chunk overwrites existing dest data */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* second chunk overwrites the first */
+ cc_copy.chunks[1].source_off = 4096;
+ cc_copy.chunks[1].target_off = 0;
+ cc_copy.chunks[1].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 2, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 8192); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 4096);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_append(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 2, /* chunks */
+ FNAME,
+ &src_h, 4096, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* second chunk appends the same data to the first */
+ cc_copy.chunks[1].source_off = 0;
+ cc_copy.chunks[1].target_off = 4096;
+ cc_copy.chunks[1].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 2, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 8192); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_limits(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* chunks */
+ FNAME,
+ &src_h, 4096, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* send huge chunk length request */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = UINT_MAX;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret, "marshalling request");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "bad oversize chunk response");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
+
+ torture_comment(torture, "limit max chunks, got %u\n",
+ cc_rsp.chunks_written);
+ torture_comment(torture, "limit max chunk len, got %u\n",
+ cc_rsp.chunk_bytes_written);
+ torture_comment(torture, "limit max total bytes, got %u\n",
+ cc_rsp.total_bytes_written);
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_src_lck(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle src_h2;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* chunks */
+ FNAME,
+ &src_h, 4096, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* open and lock the copychunk src file */
+ status = torture_smb2_testfile(tree, FNAME, &src_h2);
+ torture_assert_ntstatus_ok(torture, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = src_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].source_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "lock");
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ /*
+ * 2k12 & Samba return lock_conflict, Windows 7 & 2k8 return success...
+ *
+ * Edgar Olougouna @ MS wrote:
+ * Regarding the FSCTL_SRV_COPYCHUNK and STATUS_FILE_LOCK_CONFLICT
+ * discrepancy observed between Windows versions, we confirm that the
+ * behavior change is expected.
+ *
+ * CopyChunk in Windows Server 2012 use regular Readfile/Writefile APIs
+ * to move the chunks from the source to the destination.
+ * These ReadFile/WriteFile APIs go through the byte-range lock checks,
+ * and this explains the observed STATUS_FILE_LOCK_CONFLICT error.
+ *
+ * Prior to Windows Server 2012, CopyChunk used mapped sections to move
+ * the data. And byte range locks are not enforced on mapped I/O, and
+ * this explains the STATUS_SUCCESS observed on Windows Server 2008 R2.
+ */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_FILE_LOCK_CONFLICT,
+ "FSCTL_SRV_COPYCHUNK locked");
+
+ /* should get cc response data with the lock conflict status */
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 0, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 0); /* total bytes written */
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = src_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].source_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "unlock");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK unlocked");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h2);
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_dest_lck(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ struct smb2_handle dest_h2;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* chunks */
+ FNAME,
+ &src_h, 4096, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 4096, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* open and lock the copychunk dest file */
+ status = torture_smb2_testfile(tree, FNAME2, &dest_h2);
+ torture_assert_ntstatus_ok(torture, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = dest_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].target_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "lock");
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_FILE_LOCK_CONFLICT,
+ "FSCTL_SRV_COPYCHUNK locked");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = dest_h2;
+ lck.in.locks = el;
+ el[0].offset = cc_copy.chunks[0].target_off;
+ el[0].length = cc_copy.chunks[0].length;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "unlock");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK unlocked");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, dest_h2);
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_bad_key(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1,
+ FNAME,
+ &src_h, 4096,
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* overwrite the resume key with a bogus value */
+ memcpy(cc_copy.source_key, "deadbeefdeadbeefdeadbeef", 24);
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_src_is_dest(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1,
+ FNAME,
+ &src_h, 8192,
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* the source is also the destination */
+ ioctl.smb2.in.file.handle = src_h;
+
+ /* non-overlapping */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 4096;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+ ok = check_pattern(torture, tree, tmp_ctx, src_h, 4096, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * Test a single-chunk copychunk request, where the source and target ranges
+ * overlap, and the SourceKey refers to the same target file. E.g:
+ *
+ * Initial State
+ * -------------
+ * File: src_and_dest
+ * Offset: 0123456789
+ * Data: abcdefghij
+ *
+ * Request
+ * -------
+ * FSCTL_SRV_COPYCHUNK(src_and_dest)
+ * SourceKey = SRV_REQUEST_RESUME_KEY(src_and_dest)
+ * ChunkCount = 1
+ * Chunks[0].SourceOffset = 0
+ * Chunks[0].TargetOffset = 4
+ * Chunks[0].Length = 6
+ *
+ * Resultant State
+ * ---------------
+ * File: src_and_dest
+ * Offset: 0123456789
+ * Data: abcdabcdef
+ *
+ * The resultant contents of src_and_dest is dependent on the server's
+ * copy algorithm. In the above example, the server uses an IO buffer
+ * large enough to hold the entire six-byte source data before writing
+ * to TargetOffset. If the server were to use a four-byte IO buffer and
+ * started reads/writes from the lowest offset, then the two overlapping
+ * bytes in the above example would be overwritten before being read. The
+ * resultant file contents would be abcdabcdab.
+ *
+ * Windows 2008r2 appears to use a 2048 byte copy buffer, overlapping bytes
+ * after this offset are written before being read. Windows 2012 on the
+ * other hand appears to use a buffer large enough to hold its maximum
+ * supported chunk size (1M). Samba currently uses a 64k copy buffer by
+ * default (vfs_cc_state.buf).
+ *
+ * This test uses an 8-byte overlap at 2040-2048, so that it passes against
+ * Windows 2008r2, 2012 and Samba servers. Note, 2008GM fails, as it appears
+ * to use a different copy algorithm to 2008r2.
+ */
+static bool
+test_ioctl_copy_chunk_src_is_dest_overlap(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ /* exceed the vfs_default copy buffer */
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1,
+ FNAME,
+ &src_h, 2048 * 2,
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* the source is also the destination */
+ ioctl.smb2.in.file.handle = src_h;
+
+ /* 8 bytes overlap between source and target ranges */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 2048 - 8;
+ cc_copy.chunks[0].length = 2048;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 2048); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, src_h, 0, 2048 - 8, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+ ok = check_pattern(torture, tree, tmp_ctx, src_h, 2048 - 8, 2048, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_bad_access(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ /* read permission on src */
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
+ FNAME2, &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(
+ &ioctl.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+
+ /* execute permission on src */
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_EXECUTE | SEC_FILE_READ_ATTRIBUTE,
+ FNAME2, &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(
+ &ioctl.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+
+ /* neither read nor execute permission on src */
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_ATTRIBUTE, FNAME2, &dest_h,
+ 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL, &cc_copy, &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+
+ /* no write permission on dest */
+ ok = test_setup_copy_chunk(
+ torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE, FNAME2, &dest_h,
+ 0, /* 0 byte dest file */
+ (SEC_RIGHTS_FILE_ALL &
+ ~(SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)),
+ &cc_copy, &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+
+ /* no read permission on dest */
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx, 1, /* 1 chunk */
+ FNAME, &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE,
+ FNAME2, &dest_h, 0, /* 0 byte dest file */
+ (SEC_RIGHTS_FILE_ALL & ~SEC_FILE_READ_DATA),
+ &cc_copy, &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ /*
+ * FSCTL_SRV_COPYCHUNK requires read permission on dest,
+ * FSCTL_SRV_COPYCHUNK_WRITE on the other hand does not.
+ */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_write_access(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ /* no read permission on dest with FSCTL_SRV_COPYCHUNK_WRITE */
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ (SEC_RIGHTS_FILE_WRITE
+ | SEC_RIGHTS_FILE_EXECUTE),
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ ioctl.smb2.in.function = FSCTL_SRV_COPYCHUNK_WRITE;
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK_WRITE");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_src_exceed(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* Request copy where off + length exceeds size of src */
+ cc_copy.chunks[0].source_off = 1024;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_VIEW_SIZE,
+ "FSCTL_SRV_COPYCHUNK oversize");
+
+ /* Request copy where length exceeds size of src */
+ cc_copy.chunks[0].source_off = 1024;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 3072;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_COPYCHUNK just right");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 3072); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 3072, 1024);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool
+test_ioctl_copy_chunk_src_exceed_multi(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 2, /* 2 chunks */
+ FNAME,
+ &src_h, 8192, /* fill 8192 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* Request copy where off + length exceeds size of src */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ cc_copy.chunks[1].source_off = 4096;
+ cc_copy.chunks[1].target_off = 4096;
+ cc_copy.chunks[1].length = 8192;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_VIEW_SIZE,
+ "FSCTL_SRV_COPYCHUNK oversize");
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
+
+ /* first chunk should still be written */
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_sparse_dest(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ struct smb2_read r;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ int i;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 4096;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail(torture, "bad copy chunk response data");
+ }
+
+ /* check for zeros in first 4k */
+ ZERO_STRUCT(r);
+ r.in.file.handle = dest_h;
+ r.in.length = 4096;
+ r.in.offset = 0;
+ status = smb2_read(tree, tmp_ctx, &r);
+ torture_assert_ntstatus_ok(torture, status, "read");
+
+ torture_assert_u64_equal(torture, r.out.data.length, 4096,
+ "read data len mismatch");
+
+ for (i = 0; i < 4096; i++) {
+ torture_assert(torture, (r.out.data.data[i] == 0),
+ "sparse did not pass class");
+ }
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 4096, 4096, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * set the ioctl MaxOutputResponse size to less than
+ * sizeof(struct srv_copychunk_rsp)
+ */
+static bool test_ioctl_copy_chunk_max_output_sz(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+ /* req is valid, but use undersize max_output_response */
+ ioctl.smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp) - 1;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "FSCTL_SRV_COPYCHUNK");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_copy_chunk_zero_length(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ union smb_fileinfo q;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup copy chunk error");
+ }
+
+ /* zero length server-side copy (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 0;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "bad zero-length chunk response");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret, "unmarshalling response");
+
+ ZERO_STRUCT(q);
+ q.all_info2.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ q.all_info2.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, torture, &q);
+ torture_assert_ntstatus_ok(torture, status, "getinfo");
+
+ torture_assert_int_equal(torture, q.all_info2.out.size, 0,
+ "size after zero len clone");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool copy_one_stream(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *tmp_ctx,
+ const char *src_sname,
+ const char *dst_sname)
+{
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ NTSTATUS status;
+ union smb_ioctl io;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok = false;
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ src_sname,
+ &src_h, 256, /* fill 256 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ dst_sname,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "setup copy chunk error\n");
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 256;
+
+ ndr_ret = ndr_push_struct_blob(
+ &io.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &io.smb2.out.out, tmp_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 256); /* total bytes written */
+ torture_assert_goto(torture, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 256, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree, dest_h);
+ }
+
+ return ok;
+}
+
+/**
+ * Create a file
+ **/
+static bool torture_setup_file(TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ const char *name)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ smb2_util_unlink(tree, name);
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = name;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_copy_chunk_streams(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ const char *src_name = "src";
+ const char *dst_name = "dst";
+ struct names {
+ const char *src_sname;
+ const char *dst_sname;
+ } names[] = {
+ { "src:foo", "dst:foo" }
+ };
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool ok = false;
+
+ tmp_ctx = talloc_new(tree);
+ torture_assert_not_null_goto(torture, tmp_ctx, ok, done,
+ "torture_setup_file\n");
+
+ ok = torture_setup_file(torture, tree, src_name);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+ ok = torture_setup_file(torture, tree, dst_name);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ ok = copy_one_stream(torture, tree, tmp_ctx,
+ names[i].src_sname,
+ names[i].dst_sname);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "copy_one_stream failed\n");
+ }
+
+done:
+ smb2_util_unlink(tree, src_name);
+ smb2_util_unlink(tree, dst_name);
+ talloc_free(tmp_ctx);
+ return ok;
+}
+
+static bool test_copy_chunk_across_shares(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ union smb_ioctl ioctl;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ NTSTATUS status;
+ bool ok = false;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert_not_null_goto(tctx, mem_ctx, ok, done,
+ "talloc_new\n");
+
+ ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree2);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "torture_smb2_tree_connect failed\n");
+
+ ok = test_setup_copy_chunk(tctx, tree, tree2, mem_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "test_setup_copy_chunk failed\n");
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(
+ &ioctl.smb2.in.out, mem_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree2, mem_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &ioctl.smb2.out.out, mem_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ ok = check_copy_chunk_rsp(tctx, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_pattern(tctx, tree2, mem_ctx, dest_h, 0, 4096, 0);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "inconsistent file data\n");
+
+done:
+ TALLOC_FREE(mem_ctx);
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree2, dest_h);
+ }
+ smb2_util_unlink(tree, FNAME);
+ smb2_util_unlink(tree2, FNAME2);
+ if (tree2 != NULL) {
+ smb2_tdis(tree2);
+ }
+ return ok;
+}
+
+/* Test closing the src handle */
+static bool test_copy_chunk_across_shares2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ union smb_ioctl ioctl;
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ NTSTATUS status;
+ bool ok = false;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert_not_null_goto(tctx, mem_ctx, ok, done,
+ "talloc_new\n");
+
+ ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree2);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "torture_smb2_tree_connect failed\n");
+
+ ok = test_setup_copy_chunk(tctx, tree, tree2, mem_ctx,
+ 1, /* 1 chunk */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "test_setup_copy_chunk failed\n");
+
+ status = smb2_util_close(tree, src_h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(src_h);
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(
+ &ioctl.smb2.in.out, mem_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree2, mem_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ok, done, "smb2_ioctl failed\n");
+
+done:
+ TALLOC_FREE(mem_ctx);
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree2, dest_h);
+ }
+ smb2_util_unlink(tree, FNAME);
+ smb2_util_unlink(tree2, FNAME2);
+ if (tree2 != NULL) {
+ smb2_tdis(tree2);
+ }
+ return ok;
+}
+
+/* Test offset works */
+static bool test_copy_chunk_across_shares3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ union smb_ioctl ioctl;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ NTSTATUS status;
+ bool ok = false;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert_not_null_goto(tctx, mem_ctx, ok, done,
+ "talloc_new\n");
+
+ ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree2);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "torture_smb2_tree_connect failed\n");
+
+ ok = test_setup_copy_chunk(tctx, tree, tree2, mem_ctx,
+ 2, /* 2 chunks */
+ FNAME,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "test_setup_copy_chunk failed\n");
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ /* second chunk appends the same data to the first */
+ cc_copy.chunks[1].source_off = 0;
+ cc_copy.chunks[1].target_off = 4096;
+ cc_copy.chunks[1].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(
+ &ioctl.smb2.in.out, mem_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree2, mem_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, "smb2_ioctl failed\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &ioctl.smb2.out.out, mem_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(tctx, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ ok = check_copy_chunk_rsp(tctx, &cc_rsp,
+ 2, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 8192); /* total bytes written */
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "check_copy_chunk_rsp failed\n");
+
+ ok = check_pattern(tctx, tree2, mem_ctx, dest_h, 0, 4096, 0);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "check_pattern failed\n");
+
+ ok = check_pattern(tctx, tree2, mem_ctx, dest_h, 4096, 4096, 0);
+ torture_assert_goto(tctx, ok == true, ok, done,
+ "check_pattern failed\n");
+
+done:
+ TALLOC_FREE(mem_ctx);
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree2, dest_h);
+ }
+ smb2_util_unlink(tree, FNAME);
+ smb2_util_unlink(tree2, FNAME2);
+ if (tree2 != NULL) {
+ smb2_tdis(tree2);
+ }
+ return ok;
+}
+
+static NTSTATUS test_ioctl_compress_fs_supported(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_handle *fh,
+ bool *compress_support)
+{
+ NTSTATUS status;
+ union smb_fsinfo info;
+
+ ZERO_STRUCT(info);
+ info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
+ info.generic.handle = *fh;
+ status = smb2_getinfo_fs(tree, tree, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (info.attribute_info.out.fs_attr & FILE_FILE_COMPRESSION) {
+ *compress_support = true;
+ } else {
+ *compress_support = false;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_ioctl_compress_get(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ uint16_t *_compression_fmt)
+{
+ union smb_ioctl ioctl;
+ struct compression_state cmpr_state;
+ enum ndr_err_code ndr_ret;
+ NTSTATUS status;
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_GET_COMPRESSION;
+ ioctl.smb2.in.max_output_response = sizeof(struct compression_state);
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, mem_ctx,
+ &cmpr_state,
+ (ndr_pull_flags_fn_t)ndr_pull_compression_state);
+
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ *_compression_fmt = cmpr_state.format;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_ioctl_compress_set(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ uint16_t compression_fmt)
+{
+ union smb_ioctl ioctl;
+ struct compression_state cmpr_state;
+ enum ndr_err_code ndr_ret;
+ NTSTATUS status;
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_COMPRESSION;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ cmpr_state.format = compression_fmt;
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, mem_ctx,
+ &cmpr_state,
+ (ndr_push_flags_fn_t)ndr_push_compression_state);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
+ return status;
+}
+
+static bool test_ioctl_compress_file_flag(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint16_t compression_fmt;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "initial compression state not NONE");
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
+ "invalid compression state after set");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_dir_inherit(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle dirh;
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ uint16_t compression_fmt;
+ bool ok;
+ char path_buf[PATH_MAX];
+
+ smb2_deltree(tree, DNAME);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_DIRECTORY);
+ torture_assert(torture, ok, "setup compression directory");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, dirh);
+ smb2_deltree(tree, DNAME);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ /* set compression on parent dir, then check for inheritance */
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
+ COMPRESSION_FORMAT_LZNT1);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
+ "invalid compression state after set");
+
+ snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ path_buf, &fh, 4096, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
+ "compression attr not inherited by new file");
+
+ /* check compressed data is consistent */
+ ok = check_pattern(torture, tree, tmp_ctx, fh, 0, 4096, 0);
+
+ /* disable dir compression attr, file should remain compressed */
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
+ COMPRESSION_FORMAT_NONE);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
+ "file compression attr removed after dir change");
+ smb2_util_close(tree, fh);
+
+ /* new files should no longer inherit compression attr */
+ snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "compression attr present on new file");
+
+ smb2_util_close(tree, fh);
+ smb2_util_close(tree, dirh);
+ smb2_deltree(tree, DNAME);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_invalid_format(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint16_t compression_fmt;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ 0x0042); /* bogus */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "invalid FSCTL_SET_COMPRESSION");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "initial compression state not NONE");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_invalid_buf(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ union smb_ioctl ioctl;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_GET_COMPRESSION;
+ ioctl.smb2.in.max_output_response = 0; /* no room for rsp data */
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_USER_BUFFER)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /* neither Server 2k12 nor 2k8r2 response status */
+ torture_assert(torture, true,
+ "invalid FSCTL_SET_COMPRESSION");
+ }
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_query_file_attr(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_fileinfo io;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
+ "compression attr before set");
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ (io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
+ "no compression attr after set");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * Specify FILE_ATTRIBUTE_COMPRESSED on creation, Windows does not retain this
+ * attribute.
+ */
+static bool test_ioctl_compress_create_with_attr(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh2;
+ union smb_fileinfo io;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ uint16_t compression_fmt;
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME2, &fh2, 0, SEC_RIGHTS_FILE_ALL,
+ (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_COMPRESSED));
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh2,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh2);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh2,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "initial compression state not NONE");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = fh2;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ ((io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
+ "incorrect compression attr");
+
+ smb2_util_close(tree, fh2);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_inherit_disable(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ struct smb2_handle dirh;
+ char path_buf[PATH_MAX];
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint16_t compression_fmt;
+
+ struct smb2_create io;
+
+ smb2_deltree(tree, DNAME);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_DIRECTORY);
+ torture_assert(torture, ok, "setup compression directory");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &dirh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, dirh);
+ smb2_deltree(tree, DNAME);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ /* set compression on parent dir, then check for inheritance */
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, dirh,
+ COMPRESSION_FORMAT_LZNT1);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
+ "invalid compression state after set");
+ smb2_util_close(tree, dirh);
+
+ snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ path_buf, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_LZNT1),
+ "compression attr not inherited by new file");
+ smb2_util_close(tree, fh);
+
+ snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, FNAME2);
+
+ /* NO_COMPRESSION option should block inheritance */
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.create_options = NTCREATEX_OPTIONS_NO_COMPRESSION;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.fname = path_buf;
+
+ status = smb2_create(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "file create");
+
+ fh = io.out.file.handle;
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "compression attr inherited by NO_COMPRESSION file");
+ smb2_util_close(tree, fh);
+
+
+ snprintf(path_buf, PATH_MAX, "%s\\%s", DNAME, DNAME);
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.create_options = (NTCREATEX_OPTIONS_NO_COMPRESSION
+ | NTCREATEX_OPTIONS_DIRECTORY);
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.fname = path_buf;
+
+ status = smb2_create(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "dir create");
+
+ dirh = io.out.file.handle;
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "compression attr inherited by NO_COMPRESSION dir");
+ smb2_util_close(tree, dirh);
+ smb2_deltree(tree, DNAME);
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/* attempting to set compression via SetInfo should not stick */
+static bool test_ioctl_compress_set_file_attr(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ struct smb2_handle dirh;
+ union smb_fileinfo io;
+ union smb_setfileinfo set_io;
+ uint16_t compression_fmt;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
+ "compression attr before set");
+
+ ZERO_STRUCT(set_io);
+ set_io.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ set_io.basic_info.in.file.handle = fh;
+ set_io.basic_info.in.create_time = io.basic_info.out.create_time;
+ set_io.basic_info.in.access_time = io.basic_info.out.access_time;
+ set_io.basic_info.in.write_time = io.basic_info.out.write_time;
+ set_io.basic_info.in.change_time = io.basic_info.out.change_time;
+ set_io.basic_info.in.attrib = (io.basic_info.out.attrib
+ | FILE_ATTRIBUTE_COMPRESSED);
+ status = smb2_setinfo_file(tree, &set_io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_SETINFO_FILE");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
+ "compression attr after set");
+
+ smb2_util_close(tree, fh);
+ smb2_deltree(tree, DNAME);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_DIRECTORY);
+ torture_assert(torture, ok, "setup compression directory");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ io.generic.in.file.handle = dirh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ ((io.basic_info.out.attrib & FILE_ATTRIBUTE_COMPRESSED) == 0),
+ "compression attr before set");
+
+ ZERO_STRUCT(set_io);
+ set_io.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ set_io.basic_info.in.file.handle = dirh;
+ set_io.basic_info.in.create_time = io.basic_info.out.create_time;
+ set_io.basic_info.in.access_time = io.basic_info.out.access_time;
+ set_io.basic_info.in.write_time = io.basic_info.out.write_time;
+ set_io.basic_info.in.change_time = io.basic_info.out.change_time;
+ set_io.basic_info.in.attrib = (io.basic_info.out.attrib
+ | FILE_ATTRIBUTE_COMPRESSED);
+ status = smb2_setinfo_file(tree, &set_io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_SETINFO_FILE");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, dirh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "dir compression set after SetInfo");
+
+ smb2_util_close(tree, dirh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_perms(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ uint16_t compression_fmt;
+ union smb_fileinfo io;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ smb2_util_close(tree, fh);
+ if (!ok) {
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ /* attempt get compression without READ_ATTR permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_READ & ~(SEC_FILE_READ_ATTRIBUTE
+ | SEC_STD_READ_CONTROL
+ | SEC_FILE_READ_EA)),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "compression set after create");
+ smb2_util_close(tree, fh);
+
+ /* set compression without WRITE_ATTR permission should succeed */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_WRITE & ~(SEC_FILE_WRITE_ATTRIBUTE
+ | SEC_STD_WRITE_DAC
+ | SEC_FILE_WRITE_EA)),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+ smb2_util_close(tree, fh);
+
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ (io.all_info2.out.attrib & FILE_ATTRIBUTE_COMPRESSED),
+ "incorrect compression attr");
+ smb2_util_close(tree, fh);
+
+ /* attempt get compression without READ_DATA permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "compression enabled after set");
+ smb2_util_close(tree, fh);
+
+ /* attempt get compression with only SYNCHRONIZE permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ SEC_STD_SYNCHRONIZE,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "compression not enabled after set");
+ smb2_util_close(tree, fh);
+
+ /* attempt to set compression without WRITE_DATA permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_SET_COMPRESSION permission");
+ smb2_util_close(tree, fh);
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_WRITE & (~SEC_FILE_WRITE_DATA)),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_NONE);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_SET_COMPRESSION permission");
+ smb2_util_close(tree, fh);
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_notsup_get(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint16_t compression_fmt;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ /* skip if the server DOES support compression */
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression supported\n");
+ }
+
+ /*
+ * Despite not supporting compression, we should get a successful
+ * response indicating that the file is uncompressed - like WS2016.
+ */
+ status = test_ioctl_compress_get(torture, tmp_ctx, tree, fh,
+ &compression_fmt);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_GET_COMPRESSION");
+
+ torture_assert(torture, (compression_fmt == COMPRESSION_FORMAT_NONE),
+ "initial compression state not NONE");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_compress_notsup_set(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup compression file");
+
+ /* skip if the server DOES support compression */
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression supported\n");
+ }
+
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_NOT_SUPPORTED,
+ "FSCTL_SET_COMPRESSION default");
+
+ /*
+ * Despite not supporting compression, we should get a successful
+ * response for set(COMPRESSION_FORMAT_NONE) - like WS2016 ReFS.
+ */
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_NONE);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SET_COMPRESSION none");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ basic testing of the SMB2 FSCTL_QUERY_NETWORK_INTERFACE_INFO ioctl
+*/
+static bool test_ioctl_network_interface_info(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ union smb_ioctl ioctl;
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_net_iface_info net_iface;
+ enum ndr_err_code ndr_ret;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(torture, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
+ }
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ fh.data[0] = UINT64_MAX;
+ fh.data[1] = UINT64_MAX;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
+ ioctl.smb2.in.max_output_response = 0x10000; /* Windows client sets this to 64KiB */
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx, &net_iface,
+ (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_fsctl_net_iface_info");
+
+ NDR_PRINT_DEBUG(fsctl_net_iface_info, &net_iface);
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * Check whether all @fs_support_flags are set in the server's
+ * RAW_QFS_ATTRIBUTE_INFORMATION FileSystemAttributes response.
+ */
+static NTSTATUS test_ioctl_fs_supported(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_handle *fh,
+ uint64_t fs_support_flags,
+ bool *supported)
+{
+ NTSTATUS status;
+ union smb_fsinfo info;
+
+ ZERO_STRUCT(info);
+ info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
+ info.generic.handle = *fh;
+ status = smb2_getinfo_fs(tree, tree, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if ((info.attribute_info.out.fs_attr & fs_support_flags)
+ == fs_support_flags) {
+ *supported = true;
+ } else {
+ *supported = false;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_ioctl_sparse_req(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ bool set)
+{
+ union smb_ioctl ioctl;
+ NTSTATUS status;
+ uint8_t set_sparse;
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_SPARSE;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+ set_sparse = (set ? 0xFF : 0x0);
+ ioctl.smb2.in.out.data = &set_sparse;
+ ioctl.smb2.in.out.length = sizeof(set_sparse);
+
+ status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
+ return status;
+}
+
+static NTSTATUS test_sparse_get(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ bool *_is_sparse)
+{
+ union smb_fileinfo io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ *_is_sparse = !!(io.basic_info.out.attrib & FILE_ATTRIBUTE_SPARSE);
+
+ return status;
+}
+
+/*
+ * Manually test setting and clearing sparse flag. Intended for file system
+ * specific tests to toggle the flag through SMB and check the status in the
+ * file system.
+ */
+bool test_ioctl_set_sparse(struct torture_context *tctx)
+{
+ bool set, ret = true;
+ const char *filename = NULL;
+ struct smb2_create create = { };
+ struct smb2_tree *tree = NULL;
+ NTSTATUS status;
+
+ set = torture_setting_bool(tctx, "set_sparse", true);
+ filename = torture_setting_string(tctx, "filename", NULL);
+
+ if (filename == NULL) {
+ torture_fail(tctx, "Need to provide filename through "
+ "--option=torture:filename=testfile\n");
+ return false;
+ }
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_comment(tctx, "Initializing smb2 connection failed.\n");
+ return false;
+ }
+
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = 0;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.fname = filename;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE failed.\n");
+
+ status = test_ioctl_sparse_req(tctx, tctx, tree,
+ create.out.file.handle, set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "FSCTL_SET_SPARSE failed.\n");
+done:
+
+ return ret;
+}
+
+static bool test_ioctl_sparse_file_flag(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_fileinfo io;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FILE");
+
+ torture_assert(torture,
+ ((io.all_info2.out.attrib & FILE_ATTRIBUTE_SPARSE) == 0),
+ "sparse attr before set");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "no sparse attr after set");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr after unset");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_file_attr(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SPARSE));
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr on open");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_dir_flag(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle dirh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+
+ smb2_deltree(tree, DNAME);
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ DNAME, &dirh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_DIRECTORY);
+ torture_assert(torture, ok, "setup sparse directory");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &dirh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, dirh);
+ smb2_deltree(tree, DNAME);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ /* set sparse dir should fail, check for 2k12 & 2k8 response */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, dirh, true);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "dir FSCTL_SET_SPARSE status");
+
+ smb2_util_close(tree, dirh);
+ smb2_deltree(tree, DNAME);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * FSCTL_SET_SPARSE can be sent with (already tested) or without a SetSparse
+ * buffer to indicate whether the flag should be set or cleared. When sent
+ * without a buffer, it must be handled as if SetSparse=TRUE.
+ */
+static bool test_ioctl_sparse_set_nobuf(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_ioctl ioctl;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr before set");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_SPARSE;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+ /* ioctl.smb2.in.out is zeroed, no SetSparse buffer */
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "no sparse attr after set");
+
+ /* second non-SetSparse request shouldn't toggle sparse */
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_SPARSE;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "no sparse attr after 2nd set");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr after unset");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_set_oversize(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_ioctl ioctl;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+ uint8_t buf[100];
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr before set");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_SPARSE;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ /*
+ * Attach a request buffer larger than FILE_SET_SPARSE_BUFFER
+ * Windows still successfully processes the request.
+ */
+ ZERO_ARRAY(buf);
+ buf[0] = 0xFF; /* attempt to set sparse */
+ ioctl.smb2.in.out.data = buf;
+ ioctl.smb2.in.out.length = ARRAY_SIZE(buf);
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "no sparse attr after set");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_SPARSE;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_ARRAY(buf); /* clear sparse */
+ ioctl.smb2.in.out.data = buf;
+ ioctl.smb2.in.out.length = ARRAY_SIZE(buf);
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr after clear");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static NTSTATUS test_ioctl_qar_req(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ int64_t req_off,
+ int64_t req_len,
+ struct file_alloced_range_buf **_rsp,
+ uint64_t *_rsp_count)
+{
+ union smb_ioctl ioctl;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+ struct file_alloced_range_buf far_buf;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
+ ioctl.smb2.in.max_output_response = 1024;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ far_buf.file_off = req_off;
+ far_buf.len = req_len;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &far_buf,
+ (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto err_out;
+ }
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err_out;
+ }
+
+ if (ioctl.smb2.out.out.length == 0) {
+ goto done;
+ }
+
+ if ((ioctl.smb2.out.out.length % sizeof(far_buf)) != 0) {
+ torture_comment(torture, "invalid qry_alloced rsp len: %zd:",
+ ioctl.smb2.out.out.length);
+ status = NT_STATUS_INVALID_VIEW_SIZE;
+ goto err_out;
+ }
+
+ far_count = (ioctl.smb2.out.out.length / sizeof(far_buf));
+ far_rsp = talloc_array(mem_ctx, struct file_alloced_range_buf,
+ far_count);
+ if (far_rsp == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto err_out;
+ }
+
+ for (i = 0; i < far_count; i++) {
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &far_rsp[i],
+ (ndr_pull_flags_fn_t)ndr_pull_file_alloced_range_buf);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto err_out;
+ }
+ /* move to next buffer */
+ ioctl.smb2.out.out.data += sizeof(far_buf);
+ ioctl.smb2.out.out.length -= sizeof(far_buf);
+ }
+
+done:
+ *_rsp = far_rsp;
+ *_rsp_count = far_count;
+ status = NT_STATUS_OK;
+err_out:
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+static bool test_ioctl_sparse_qar(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ /* zero length file, shouldn't have any ranges */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr before set");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 0, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "no sparse attr after set");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ /* write into the (now) sparse file at 4k offset */
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 4096, /* off */
+ 1024, /* len */
+ 4096); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /*
+ * Query range before write off. Whether it's allocated or not is FS
+ * dependent. NTFS deallocates chunks in 64K increments, but others
+ * (e.g. XFS, Btrfs, etc.) may deallocate 4K chunks.
+ */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ if (far_count == 0) {
+ torture_comment(torture, "FS deallocated 4K chunk\n");
+ } else {
+ /* expect fully allocated */
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0, "far offset");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 4096, "far len");
+ }
+
+ /*
+ * Query range before and past write, it should be allocated up to the
+ * end of the write.
+ */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 8192, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ /* FS dependent */
+ if (far_rsp[0].file_off == 4096) {
+ /* 4K chunk unallocated */
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 4096, "far offset");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 1024, "far len");
+ } else {
+ /* expect fully allocated */
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0, "far offset");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 5120, "far len");
+ }
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_qar_malformed(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_ioctl ioctl;
+ struct file_alloced_range_buf far_buf;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ size_t old_len;
+
+ /* zero length file, shouldn't have any ranges */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ /* no allocated ranges, no space for range response, should pass */
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ far_buf.file_off = 0;
+ far_buf.len = 1024;
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &far_buf,
+ (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_QUERY_ALLOCATED_RANGES");
+
+ /* write into the file at 4k offset */
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ 1024, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* allocated range, no space for range response, should fail */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_BUFFER_TOO_SMALL, "qar no space");
+
+ /* oversize (2x) file_alloced_range_buf in request, should pass */
+ ioctl.smb2.in.max_output_response = 1024;
+ old_len = ioctl.smb2.in.out.length;
+ ok = data_blob_realloc(tmp_ctx, &ioctl.smb2.in.out,
+ (ioctl.smb2.in.out.length * 2));
+ torture_assert(torture, ok, "2x data buffer");
+ memcpy(ioctl.smb2.in.out.data + old_len, ioctl.smb2.in.out.data,
+ old_len);
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "qar too big");
+
+ /* no file_alloced_range_buf in request, should fail */
+ data_blob_free(&ioctl.smb2.in.out);
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER, "qar empty");
+
+ return true;
+}
+
+bool test_ioctl_alternate_data_stream(struct torture_context *tctx)
+{
+ bool ret = false;
+ const char *fname = DNAME "\\test_stream_ioctl_dir";
+ const char *sname = DNAME "\\test_stream_ioctl_dir:stream";
+ NTSTATUS status;
+ struct smb2_create create = {};
+ struct smb2_tree *tree = NULL;
+ struct smb2_handle h1 = {{0}};
+ union smb_ioctl ioctl;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_comment(tctx, "Initializing smb2 connection failed.\n");
+ return false;
+ }
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_HIDDEN,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ h1 = create.out.file.handle;
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = sname,
+ };
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = create.out.file.handle;
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = h1;
+ ioctl.smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
+ ioctl.smb2.in.max_output_response = 64;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+ status = smb2_ioctl(tree, tctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_ioctl failed\n");
+ ret = true;
+
+done:
+
+ smb2_util_close(tree, h1);
+ smb2_deltree(tree, DNAME);
+ return ret;
+}
+
+/*
+ * 2.3.57 FSCTL_SET_ZERO_DATA Request
+ *
+ * How an implementation zeros data within a file is implementation-dependent.
+ * A file system MAY choose to deallocate regions of disk space that have been
+ * zeroed.<50>
+ * <50>
+ * ... NTFS might deallocate disk space in the file if the file is stored on an
+ * NTFS volume, and the file is sparse or compressed. It will free any allocated
+ * space in chunks of 64 kilobytes that begin at an offset that is a multiple of
+ * 64 kilobytes. Other bytes in the file (prior to the first freed 64-kilobyte
+ * chunk and after the last freed 64-kilobyte chunk) will be zeroed but not
+ * deallocated.
+ */
+static NTSTATUS test_ioctl_zdata_req(struct torture_context *torture,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree *tree,
+ struct smb2_handle fh,
+ int64_t off,
+ int64_t beyond_final_zero)
+{
+ union smb_ioctl ioctl;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+ struct file_zero_data_info zdata_info;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_SET_ZERO_DATA;
+ ioctl.smb2.in.max_output_response = 0;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ zdata_info.file_off = off;
+ zdata_info.beyond_final_zero = beyond_final_zero;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &zdata_info,
+ (ndr_push_flags_fn_t)ndr_push_file_zero_data_info);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto err_out;
+ }
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err_out;
+ }
+
+ status = NT_STATUS_OK;
+err_out:
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+bool test_ioctl_zero_data(struct torture_context *tctx)
+{
+ bool ret = true;
+ int offset, beyond_final_zero;
+ const char *filename;
+ NTSTATUS status;
+ struct smb2_create create = { };
+ struct smb2_tree *tree = NULL;
+
+ offset = torture_setting_int(tctx, "offset", -1);
+
+ if (offset < 0) {
+ torture_fail(tctx, "Need to provide non-negative offset "
+ "through --option=torture:offset=NNN\n");
+ return false;
+ }
+
+ beyond_final_zero = torture_setting_int(tctx, "beyond_final_zero",
+ -1);
+ if (beyond_final_zero < 0) {
+ torture_fail(tctx, "Need to provide non-negative "
+ "'beyond final zero' through "
+ "--option=torture:beyond_final_zero=NNN\n");
+ return false;
+ }
+ filename = torture_setting_string(tctx, "filename", NULL);
+ if (filename == NULL) {
+ torture_fail(tctx, "Need to provide filename through "
+ "--option=torture:filename=testfile\n");
+ return false;
+ }
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_comment(tctx, "Initializing smb2 connection failed.\n");
+ return false;
+ }
+
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = 0;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = filename;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE failed.\n");
+
+ status = test_ioctl_zdata_req(tctx, tctx, tree,
+ create.out.file.handle,
+ offset,
+ beyond_final_zero);
+ torture_assert_ntstatus_ok_goto(tctx,
+ status,
+ ret,
+ done,
+ "FSCTL_SET_ZERO_DATA failed.\n");
+
+done:
+ return ret;
+}
+
+static bool test_ioctl_sparse_punch(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 4096, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr before set");
+
+ /* zero (hole-punch) the data, without sparse flag */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+
+ /* expect fully allocated */
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
+ "unexpected far len");
+ /* check that the data is now zeroed */
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
+ torture_assert(torture, ok, "non-sparse zeroed range");
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* still fully allocated on NTFS, see note below for Samba */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ /*
+ * FS specific: Samba uses PUNCH_HOLE to zero the range, and
+ * subsequently uses fallocate() to allocate the punched range if the
+ * file is marked non-sparse and "strict allocate" is enabled. In both
+ * cases, the zeroed range will not be detected by SEEK_DATA, so the
+ * range won't be present in QAR responses until the file is marked
+ * non-sparse again.
+ */
+ if (far_count == 0) {
+ torture_comment(torture, "non-sparse zeroed range disappeared "
+ "after marking sparse\n");
+ } else {
+ /* NTFS: range remains fully allocated */
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
+ "unexpected far len");
+ }
+
+ /* zero (hole-punch) the data, _with_ sparse flag */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* the range should no longer be alloced */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ /* remove sparse flag, this should "unsparse" the zeroed range */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ /* expect fully allocated */
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 4096,
+ "unexpected far len");
+
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, 4096);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * Find the point at which a zeroed range in a sparse file is deallocated by the
+ * underlying filesystem. NTFS on Windows Server 2012 deallocates chunks in 64k
+ * increments. Also check whether zeroed neighbours are merged for deallocation.
+ */
+static bool test_ioctl_sparse_hole_dealloc(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t file_size;
+ uint64_t hlen;
+ uint64_t dealloc_chunk_len = 0;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file 1");
+
+ /* check for FS sparse file */
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ file_size = 1024 * 1024;
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ file_size, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* check allocated ranges, should be fully allocated */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
+ "unexpected far len");
+
+ /* punch holes in sizes of 1k increments */
+ for (hlen = 0; hlen <= file_size; hlen += 4096) {
+
+ /* punch a hole from zero to the current increment */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ hlen); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* ensure hole is zeroed, and pattern is consistent */
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, hlen);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, fh, hlen,
+ file_size - hlen, hlen);
+ torture_assert(torture, ok, "allocated pattern range");
+
+ /* Check allocated ranges, hole might have been deallocated */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES");
+ if ((hlen == file_size) && (far_count == 0)) {
+ /* hole covered entire file, deallocation occurred */
+ dealloc_chunk_len = file_size;
+ break;
+ }
+
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off != 0) {
+ /*
+ * We now know the hole punch length needed to trigger a
+ * deallocation on this FS...
+ */
+ dealloc_chunk_len = hlen;
+ torture_comment(torture, "hole punch %ju@0 resulted in "
+ "deallocation of %ju@0\n",
+ (uintmax_t)hlen,
+ (uintmax_t)far_rsp[0].file_off);
+ torture_assert_u64_equal(torture,
+ file_size - far_rsp[0].len,
+ far_rsp[0].file_off,
+ "invalid alloced range");
+ break;
+ }
+ }
+
+ if (dealloc_chunk_len == 0) {
+ torture_comment(torture, "strange, this FS never deallocates"
+ "zeroed ranges in sparse files\n");
+ return true; /* FS specific, not a failure */
+ }
+
+ /*
+ * Check whether deallocation occurs when the (now known)
+ * deallocation chunk size is punched via two ZERO_DATA requests.
+ * I.e. Does the FS merge the two ranges and deallocate the chunk?
+ * NTFS on Windows Server 2012 does not.
+ */
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ file_size, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* divide dealloc chunk size by two, to use as punch length */
+ hlen = dealloc_chunk_len >> 1;
+
+ /*
+ * /half of dealloc chunk size 1M\
+ * | |
+ * /offset 0 | /dealloc chunk size |
+ * |------------------ |-------------------|-------------------|
+ * | zeroed, 1st punch | zeroed, 2nd punch | existing pattern |
+ */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ hlen); /* beyond final zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ hlen, /* off */
+ dealloc_chunk_len); /* beyond final */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* ensure holes are zeroed, and pattern is consistent */
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, dealloc_chunk_len);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, fh, dealloc_chunk_len,
+ file_size - dealloc_chunk_len, dealloc_chunk_len);
+ torture_assert(torture, ok, "allocated pattern range");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+
+ if ((far_count == 0) && (dealloc_chunk_len == file_size)) {
+ torture_comment(torture, "holes merged for deallocation of "
+ "full file\n");
+ return true;
+ }
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off == dealloc_chunk_len) {
+ torture_comment(torture, "holes merged for deallocation of "
+ "%ju chunk\n", (uintmax_t)dealloc_chunk_len);
+ torture_assert_u64_equal(torture,
+ file_size - far_rsp[0].len,
+ far_rsp[0].file_off,
+ "invalid alloced range");
+ } else {
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected deallocation");
+ torture_comment(torture, "holes not merged for deallocation\n");
+ }
+
+ smb2_util_close(tree, fh);
+
+ /*
+ * Check whether an unwritten range is allocated when a sparse file is
+ * written to at an offset past the dealloc chunk size:
+ *
+ * /dealloc chunk size
+ * /offset 0 |
+ * |------------------ |-------------------|
+ * | unwritten | pattern |
+ */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file 1");
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ dealloc_chunk_len, /* off */
+ 1024, /* len */
+ dealloc_chunk_len); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off == 0) {
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len + 1024,
+ "unexpected far len");
+ torture_comment(torture, "unwritten range fully allocated\n");
+ } else {
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, dealloc_chunk_len,
+ "unexpected deallocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
+ "unexpected far len");
+ torture_comment(torture, "unwritten range not allocated\n");
+ }
+
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, dealloc_chunk_len);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, fh, dealloc_chunk_len,
+ 1024, dealloc_chunk_len);
+ torture_assert(torture, ok, "allocated pattern range");
+
+ /* unsparse, should now be fully allocated */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected deallocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len + 1024,
+ "unexpected far len");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/* check whether a file with compression and sparse attrs can be deallocated */
+static bool test_ioctl_sparse_compressed(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t file_size = 1024 * 1024;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file 1");
+
+ /* check for FS sparse file and compression support */
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ /* set compression and write some data */
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ file_size, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* set sparse - now sparse and compressed */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* check allocated ranges, should be fully alloced */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
+ "unexpected far len");
+
+ /* zero (hole-punch) all data, with sparse and compressed attrs */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /*
+ * Windows Server 2012 still deallocates a zeroed range when a sparse
+ * file carries the compression attribute.
+ */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ if (far_count == 0) {
+ torture_comment(torture, "sparse & compressed file "
+ "deallocated after hole-punch\n");
+ } else {
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
+ "unexpected far len");
+ torture_comment(torture, "sparse & compressed file fully "
+ "allocated after hole-punch\n");
+ }
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * Create a sparse file, then attempt to copy unallocated and allocated ranges
+ * into a target file using FSCTL_SRV_COPYCHUNK.
+ */
+static bool test_ioctl_sparse_copy_chunk(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+ union smb_ioctl ioctl;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &src_h, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ /* check for FS sparse file support */
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ smb2_util_close(tree, src_h);
+ if (!ok) {
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ ok = test_setup_copy_chunk(torture, tree, tree, tmp_ctx,
+ 1, /* chunks */
+ FNAME,
+ &src_h, 0, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ FNAME2,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ torture_assert(torture, ok, "setup copy chunk error");
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, src_h, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* start after dealloc_chunk_len, to create an unwritten sparse range */
+ ok = write_pattern(torture, tree, tmp_ctx, src_h,
+ dealloc_chunk_len, /* off */
+ 1024, /* len */
+ dealloc_chunk_len); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* Skip test if 64k chunk is allocated - FS specific */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, src_h,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off == 0) {
+ torture_skip(torture, "unwritten range fully allocated\n");
+ }
+
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, dealloc_chunk_len,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
+ "unexpected far len");
+
+ /* copy-chunk unallocated + written ranges into non-sparse dest */
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = dealloc_chunk_len + 1024;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ dealloc_chunk_len + 1024); /* bytes written */
+ torture_assert(torture, ok, "bad copy chunk response data");
+
+ ok = check_zero(torture, tree, tmp_ctx, dest_h, 0, dealloc_chunk_len);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, dealloc_chunk_len,
+ 1024, dealloc_chunk_len);
+ torture_assert(torture, ok, "copychunked range");
+
+ /* copied range should be allocated in non-sparse dest */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, dest_h,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len + 1024,
+ "unexpected far len");
+
+ /* set dest as sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, dest_h, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* zero (hole-punch) all data */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, dest_h,
+ 0, /* off */
+ dealloc_chunk_len + 1024);
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* zeroed range might be deallocated */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, dest_h,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ if (far_count == 0) {
+ /* FS specific (e.g. NTFS) */
+ torture_comment(torture, "FS deallocates file on full-range "
+ "punch\n");
+ } else {
+ /* FS specific (e.g. EXT4) */
+ torture_comment(torture, "FS doesn't deallocate file on "
+ "full-range punch\n");
+ }
+ ok = check_zero(torture, tree, tmp_ctx, dest_h, 0,
+ dealloc_chunk_len + 1024);
+ torture_assert(torture, ok, "punched zeroed range");
+
+ /* copy-chunk again, this time with sparse dest */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ dealloc_chunk_len + 1024); /* bytes written */
+ torture_assert(torture, ok, "bad copy chunk response data");
+
+ ok = check_zero(torture, tree, tmp_ctx, dest_h, 0, dealloc_chunk_len);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, dealloc_chunk_len,
+ 1024, dealloc_chunk_len);
+ torture_assert(torture, ok, "copychunked range");
+
+ /* copied range may be allocated in sparse dest */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, dest_h,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ /*
+ * FS specific: sparse region may be unallocated in dest if copy-chunk
+ * is handled in a sparse preserving way - E.g. vfs_btrfs
+ * with BTRFS_IOC_CLONE_RANGE.
+ */
+ if (far_rsp[0].file_off == dealloc_chunk_len) {
+ torture_comment(torture, "copy-chunk sparse range preserved\n");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
+ "unexpected far len");
+ } else {
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len + 1024,
+ "unexpected far len");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_punch_invalid(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+ int i;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 4096, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse attr before set");
+
+ /* loop twice, without and with sparse attrib */
+ for (i = 0; i <= 1; i++) {
+ union smb_fileinfo io;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ /* get size before & after. zero data should never change it */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "getinfo");
+ torture_assert_int_equal(torture, (int)io.all_info2.out.size,
+ 4096, "size after IO");
+
+ /* valid 8 byte zero data, but after EOF */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 4096, /* off */
+ 4104); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* valid 8 byte zero data, but after EOF */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 8192, /* off */
+ 8200); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "getinfo");
+ torture_assert_int_equal(torture, (int)io.all_info2.out.size,
+ 4096, "size after IO");
+
+ /* valid 0 byte zero data, without sparse flag */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 4095, /* off */
+ 4095); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* INVALID off is past beyond_final_zero */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 4096, /* off */
+ 4095); /* beyond_final_zero */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "invalid zero_data");
+
+ /* zero length QAR - valid */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 0, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ /* QAR after EOF - valid */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 4096, /* off */
+ 1024, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh,
+ true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+ }
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_perms(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ smb2_util_close(tree, fh);
+ if (!ok) {
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ /* set sparse without WRITE_ATTR permission should succeed */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_WRITE & ~(SEC_FILE_WRITE_ATTRIBUTE
+ | SEC_STD_WRITE_DAC
+ | SEC_FILE_WRITE_EA)),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+ smb2_util_close(tree, fh);
+
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "sparse after set");
+ smb2_util_close(tree, fh);
+
+ /* attempt get sparse without READ_DATA permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ (SEC_RIGHTS_FILE_READ & ~SEC_FILE_READ_DATA),
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse set");
+ smb2_util_close(tree, fh);
+
+ /* attempt to set sparse with only WRITE_ATTR permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ SEC_FILE_WRITE_ATTRIBUTE,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+ smb2_util_close(tree, fh);
+
+ /* attempt to set sparse with only WRITE_DATA permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ SEC_FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+ smb2_util_close(tree, fh);
+
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "sparse after set");
+ smb2_util_close(tree, fh);
+
+ /* attempt to set sparse with only APPEND_DATA permission */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ SEC_FILE_APPEND_DATA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+ smb2_util_close(tree, fh);
+
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "sparse after set");
+ smb2_util_close(tree, fh);
+
+ /* attempt to set sparse with only WRITE_EA permission - should fail */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0,
+ SEC_FILE_WRITE_EA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_SET_SPARSE permission");
+ smb2_util_close(tree, fh);
+
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, !is_sparse, "sparse after set");
+ smb2_util_close(tree, fh);
+
+ /* attempt QAR with only READ_ATTR permission - should fail */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_READ_ATTRIBUTE,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 4096, /* off */
+ 1024, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_QUERY_ALLOCATED_RANGES req passed");
+ smb2_util_close(tree, fh);
+
+ /* attempt QAR with only READ_DATA permission */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_READ_DATA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 1024, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+ smb2_util_close(tree, fh);
+
+ /* attempt QAR with only READ_EA permission - should fail */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_READ_EA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 4096, /* off */
+ 1024, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "FSCTL_QUERY_ALLOCATED_RANGES req passed");
+ smb2_util_close(tree, fh);
+
+ /* setup file for ZERO_DATA permissions tests */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 8192,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+ smb2_util_close(tree, fh);
+
+ /* attempt ZERO_DATA with only WRITE_ATTR permission - should fail */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_WRITE_ATTRIBUTE,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "zero_data permission");
+ smb2_util_close(tree, fh);
+
+ /* attempt ZERO_DATA with only WRITE_DATA permission */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_WRITE_DATA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+ smb2_util_close(tree, fh);
+
+ /* attempt ZERO_DATA with only APPEND_DATA permission - should fail */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_APPEND_DATA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "zero_data permission");
+ smb2_util_close(tree, fh);
+
+ /* attempt ZERO_DATA with only WRITE_EA permission - should fail */
+ ok = test_setup_open(torture, tree, tmp_ctx,
+ FNAME, &fh, SEC_FILE_WRITE_EA,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "zero_data permission");
+ smb2_util_close(tree, fh);
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_lck(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ struct smb2_handle fh2;
+ NTSTATUS status;
+ uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ bool is_sparse;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx, FNAME, &fh,
+ dealloc_chunk_len, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ torture_skip(torture, "Sparse files not supported\n");
+ smb2_util_close(tree, fh);
+ }
+
+ /* open and lock via separate fh2 */
+ status = torture_smb2_testfile(tree, FNAME, &fh2);
+ torture_assert_ntstatus_ok(torture, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = fh2;
+ lck.in.locks = el;
+ el[0].offset = 0;
+ el[0].length = dealloc_chunk_len;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "lock");
+
+ /* set sparse while locked */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_sparse_get(torture, tmp_ctx, tree, fh, &is_sparse);
+ torture_assert_ntstatus_ok(torture, status, "test_sparse_get");
+ torture_assert(torture, is_sparse, "sparse attr after set");
+
+ /* zero data over locked range should fail */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096); /* beyond_final_zero */
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_FILE_LOCK_CONFLICT,
+ "zero_data locked");
+
+ /* QAR over locked range should pass */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ 4096, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES locked");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ 4096,
+ "unexpected far len");
+
+ /* zero data over range past EOF should pass */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ dealloc_chunk_len, /* off */
+ dealloc_chunk_len + 4096);
+ torture_assert_ntstatus_ok(torture, status,
+ "zero_data past EOF locked");
+
+ /* QAR over range past EOF should pass */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ dealloc_chunk_len, /* off */
+ 4096, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES past EOF locked");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = fh2;
+ lck.in.locks = el;
+ el[0].offset = 0;
+ el[0].length = dealloc_chunk_len;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(torture, status, "unlock");
+
+ smb2_util_close(tree, fh2);
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/* alleviate QAR off-by-one bug paranoia - help me ob1 */
+static bool test_ioctl_sparse_qar_ob1(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, dealloc_chunk_len * 2,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ torture_skip(torture, "Sparse files not supported\n");
+ smb2_util_close(tree, fh);
+ }
+
+ /* non-sparse QAR with range one before EOF */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len * 2 - 1, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len * 2 - 1,
+ "unexpected far len");
+
+ /* non-sparse QAR with range one after EOF */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len * 2 + 1, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len * 2,
+ "unexpected far len");
+
+ /* non-sparse QAR with range one after EOF from off=1 */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 1, /* off */
+ dealloc_chunk_len * 2, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 1,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len * 2 - 1,
+ "unexpected far len");
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* punch out second chunk */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ dealloc_chunk_len, /* off */
+ dealloc_chunk_len * 2);
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* sparse QAR with range one before hole */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len - 1, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len - 1,
+ "unexpected far len");
+
+ /* sparse QAR with range one after hole */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len + 1, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len,
+ "unexpected far len");
+
+ /* sparse QAR with range one after hole from off=1 */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 1, /* off */
+ dealloc_chunk_len, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 1,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len - 1,
+ "unexpected far len");
+
+ /* sparse QAR with range one before EOF from off=chunk_len-1 */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ dealloc_chunk_len - 1, /* off */
+ dealloc_chunk_len, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off,
+ dealloc_chunk_len - 1,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ 1, "unexpected far len");
+
+ /* sparse QAR with range one after EOF from off=chunk_len+1 */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ dealloc_chunk_len + 1, /* off */
+ dealloc_chunk_len, /* len */
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 0,
+ "unexpected response len");
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/* test QAR with multi-range responses */
+static bool test_ioctl_sparse_qar_multi(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
+ uint64_t this_off;
+ int i;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, dealloc_chunk_len * 2,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ torture_skip(torture, "Sparse files not supported\n");
+ smb2_util_close(tree, fh);
+ }
+
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* each loop, write out two chunks and punch the first out */
+ for (i = 0; i < 10; i++) {
+ this_off = i * dealloc_chunk_len * 2;
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ this_off, /* off */
+ dealloc_chunk_len * 2, /* len */
+ this_off); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ this_off, /* off */
+ this_off + dealloc_chunk_len);
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+ }
+
+ /* should now have one separate region for each iteration */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0,
+ 10 * dealloc_chunk_len * 2,
+ &far_rsp, &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ if (far_count == 1) {
+ torture_comment(torture, "this FS doesn't deallocate 64K"
+ "zeroed ranges in sparse files\n");
+ return true; /* FS specific, not a failure */
+ }
+ torture_assert_u64_equal(torture, far_count, 10,
+ "unexpected response len");
+ for (i = 0; i < 10; i++) {
+ this_off = i * dealloc_chunk_len * 2;
+
+ torture_assert_u64_equal(torture, far_rsp[i].file_off,
+ this_off + dealloc_chunk_len,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[i].len,
+ dealloc_chunk_len,
+ "unexpected far len");
+ }
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_sparse_qar_overflow(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ union smb_ioctl ioctl;
+ struct file_alloced_range_buf far_buf;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 1024, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ status = test_ioctl_fs_supported(torture, tree, tmp_ctx, &fh,
+ FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ /* no allocated ranges, no space for range response, should pass */
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_ALLOCATED_RANGES;
+ ioctl.smb2.in.max_output_response = 1024;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ /* off + length wraps around to 511 */
+ far_buf.file_off = 512;
+ far_buf.len = 0xffffffffffffffffLL;
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &far_buf,
+ (ndr_push_flags_fn_t)ndr_push_file_alloced_range_buf);
+ torture_assert_ndr_success(torture, ndr_ret, "push far ndr buf");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "FSCTL_QUERY_ALLOCATED_RANGES overflow");
+
+ return true;
+}
+
+static NTSTATUS test_ioctl_trim_supported(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_handle *fh,
+ bool *trim_support)
+{
+ NTSTATUS status;
+ union smb_fsinfo info;
+
+ ZERO_STRUCT(info);
+ info.generic.level = RAW_QFS_SECTOR_SIZE_INFORMATION;
+ info.generic.handle = *fh;
+ status = smb2_getinfo_fs(tree, tree, &info);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ /*
+ * Windows < Server 2012, 8 etc. don't support this info level
+ * or the trim ioctl. Ignore the error and let the caller skip.
+ */
+ *trim_support = false;
+ return NT_STATUS_OK;
+ } else if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ torture_comment(torture, "sector size info: lb/s=%u, pb/sA=%u, "
+ "pb/sP=%u, fse/sA=%u, flags=0x%x, bosa=%u, bopa=%u\n",
+ (unsigned)info.sector_size_info.out.logical_bytes_per_sector,
+ (unsigned)info.sector_size_info.out.phys_bytes_per_sector_atomic,
+ (unsigned)info.sector_size_info.out.phys_bytes_per_sector_perf,
+ (unsigned)info.sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic,
+ (unsigned)info.sector_size_info.out.flags,
+ (unsigned)info.sector_size_info.out.byte_off_sector_align,
+ (unsigned)info.sector_size_info.out.byte_off_partition_align);
+
+ if (info.sector_size_info.out.flags & QFS_SSINFO_FLAGS_TRIM_ENABLED) {
+ *trim_support = true;
+ } else {
+ *trim_support = false;
+ }
+ return NT_STATUS_OK;
+}
+
+static bool test_setup_trim(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ uint32_t num_ranges,
+ struct smb2_handle *fh,
+ uint64_t file_size,
+ uint32_t desired_access,
+ struct fsctl_file_level_trim_req *trim_req,
+ union smb_ioctl *ioctl)
+{
+ bool ok;
+
+ ok = test_setup_create_fill(torture, tree, mem_ctx, FNAME,
+ fh, file_size, desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "src file create fill");
+
+ ZERO_STRUCTPN(ioctl);
+ ioctl->smb2.level = RAW_IOCTL_SMB2;
+ ioctl->smb2.in.file.handle = *fh;
+ ioctl->smb2.in.function = FSCTL_FILE_LEVEL_TRIM;
+ ioctl->smb2.in.max_output_response
+ = sizeof(struct fsctl_file_level_trim_rsp);
+ ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_STRUCTPN(trim_req);
+ /* leave key as zero for now. TODO test locking with differing keys */
+ trim_req->num_ranges = num_ranges;
+ trim_req->ranges = talloc_zero_array(mem_ctx,
+ struct file_level_trim_range,
+ num_ranges);
+ torture_assert(torture, (trim_req->ranges != NULL), "no memory for ranges");
+
+ return true;
+}
+
+static bool test_ioctl_trim_simple(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ bool trim_supported;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_file_level_trim_req trim_req;
+ struct fsctl_file_level_trim_rsp trim_rsp;
+ uint64_t trim_chunk_len = 64 * 1024; /* trim 64K chunks */
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_trim(torture, tree, tmp_ctx,
+ 1, /* 1 range */
+ &fh, 2 * trim_chunk_len, /* fill 128K file */
+ SEC_RIGHTS_FILE_ALL,
+ &trim_req,
+ &ioctl);
+ if (!ok) {
+ torture_fail(torture, "setup trim error");
+ }
+
+ status = test_ioctl_trim_supported(torture, tree, tmp_ctx, &fh,
+ &trim_supported);
+ torture_assert_ntstatus_ok(torture, status, "fsinfo");
+ if (!trim_supported) {
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ torture_skip(torture, "trim not supported\n");
+ }
+
+ /* trim first chunk, leave second */
+ trim_req.ranges[0].off = 0;
+ trim_req.ranges[0].len = trim_chunk_len;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx, &trim_req,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_file_level_trim_req);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_fsctl_file_level_trim_req");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FILE_LEVEL_TRIM_RANGE");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &trim_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_fsctl_file_level_trim_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_fsctl_file_level_trim_rsp");
+
+ torture_assert_int_equal(torture, trim_rsp.num_ranges_processed, 1, "");
+
+ /* second half of the file should remain consistent */
+ ok = check_pattern(torture, tree, tmp_ctx, fh, trim_chunk_len,
+ trim_chunk_len, trim_chunk_len);
+ torture_assert(torture, ok, "non-trimmed range inconsistent");
+
+ return true;
+}
+
+static bool test_setup_dup_extents(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_handle *src_h,
+ uint64_t src_size,
+ uint32_t src_desired_access,
+ struct smb2_handle *dest_h,
+ uint64_t dest_size,
+ uint32_t dest_desired_access,
+ struct fsctl_dup_extents_to_file *dup_ext_buf,
+ union smb_ioctl *ioctl)
+{
+ bool ok;
+
+ ok = test_setup_create_fill(tctx, tree, mem_ctx, FNAME,
+ src_h, src_size, src_desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(tctx, ok, "src file create fill");
+
+ ok = test_setup_create_fill(tctx, tree, mem_ctx, FNAME2,
+ dest_h, dest_size, dest_desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(tctx, ok, "dest file create fill");
+
+ ZERO_STRUCTPN(ioctl);
+ ioctl->smb2.level = RAW_IOCTL_SMB2;
+ ioctl->smb2.in.file.handle = *dest_h;
+ ioctl->smb2.in.function = FSCTL_DUP_EXTENTS_TO_FILE;
+ ioctl->smb2.in.max_output_response = 0;
+ ioctl->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_STRUCTPN(dup_ext_buf);
+ smb2_push_handle(dup_ext_buf->source_fid, src_h);
+
+ return true;
+}
+
+static bool test_ioctl_dup_extents_simple(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_fileinfo io;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ /* extend dest to match src len */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level =
+ RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = 4096;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ /* the file size shouldn't have been changed by this operation! */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 4096, "size after IO");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+
+ /* reopen for pattern check */
+ ok = test_setup_open(tctx, tree, tmp_ctx, FNAME, &src_h,
+ SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL);
+ torture_assert_ntstatus_ok(tctx, status, "src open after dup");
+ ok = test_setup_open(tctx, tree, tmp_ctx, FNAME2, &dest_h,
+ SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL);
+ torture_assert_ntstatus_ok(tctx, status, "dest open after dup");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent src file data");
+ }
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent dest file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_len_beyond_dest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_fileinfo io;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 0, "size after IO");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 32768;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+#if 0
+ /*
+ * 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE Reply - this should fail, but
+ * passes against WS2016 RTM!
+ */
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+#endif
+
+ /* the file sizes shouldn't have been changed */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = src_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 32768, "size after IO");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 0, "size after IO");
+
+ /* extend dest */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = 32768;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ ok = check_zero(tctx, tree, tmp_ctx, dest_h, 0, 32768);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ /* reissue ioctl, now with enough space */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_len_beyond_src(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_fileinfo io;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 0, "size after IO");
+
+ /* exceed src file len */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 32768 * 2;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ /* the file sizes shouldn't have been changed */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = src_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 32768, "size after IO");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 0, "size after IO");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_len_zero(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_fileinfo io;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 0, "size after IO");
+
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 0;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ /* the file sizes shouldn't have been changed */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = src_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 32768, "size after IO");
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = dest_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 0, "size after IO");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_sparse_src(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 0, /* filled after sparse flag */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING
+ | FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx,
+ "block refcounting and sparse files not supported\n");
+ }
+
+ /* set sparse flag on src */
+ status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, src_h, true);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
+
+ ok = write_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
+ torture_assert(tctx, ok, "write pattern");
+
+ /* extend dest */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = 4096;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ /*
+ * src is sparse, but spec says: 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE
+ * Reply... STATUS_NOT_SUPPORTED: Target file is sparse, while source
+ * is a non-sparse file.
+ */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_sparse_dest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING
+ | FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx,
+ "block refcounting and sparse files not supported\n");
+ }
+
+ /* set sparse flag on dest */
+ status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, dest_h, true);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
+
+ /* extend dest */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = dup_ext_buf.byte_count;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ /*
+ * dest is sparse, but spec says: 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE
+ * Reply... STATUS_NOT_SUPPORTED: Target file is sparse, while source
+ * is a non-sparse file.
+ */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_sparse_both(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 0, /* fill 4096 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING
+ | FILE_SUPPORTS_SPARSE_FILES, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx,
+ "block refcounting and sparse files not supported\n");
+ }
+
+ /* set sparse flag on src and dest */
+ status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, src_h, true);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
+ status = test_ioctl_sparse_req(tctx, tmp_ctx, tree, dest_h, true);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_SPARSE");
+
+ ok = write_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
+ torture_assert(tctx, ok, "write pattern");
+
+ /* extend dest */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = 4096;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+
+ /* reopen for pattern check */
+ ok = test_setup_open(tctx, tree, tmp_ctx, FNAME2, &dest_h,
+ SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL);
+ torture_assert_ntstatus_ok(tctx, status, "dest open ater dup");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_src_is_dest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_fileinfo io;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+ /* dest_h not needed for this test */
+ smb2_util_close(tree, dest_h);
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ /* src and dest are the same file handle */
+ ioctl.smb2.in.file.handle = src_h;
+
+ /* no overlap between src and tgt */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 16384;
+ dup_ext_buf.byte_count = 16384;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ /* the file size shouldn't have been changed */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = src_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 32768, "size after IO");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 16384, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+ ok = check_pattern(tctx, tree, tmp_ctx, src_h, 16384, 16384, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * unlike copy-chunk, dup extents doesn't support overlapping ranges between
+ * source and target. This makes it a *lot* cleaner to implement on the server.
+ */
+static bool
+test_ioctl_dup_extents_src_is_dest_overlap(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_fileinfo io;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+ /* dest_h not needed for this test */
+ smb2_util_close(tree, dest_h);
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ /* src and dest are the same file handle */
+ ioctl.smb2.in.file.handle = src_h;
+
+ /* 8K overlap between src and tgt */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 8192;
+ dup_ext_buf.byte_count = 16384;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_NOT_SUPPORTED,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ /* the file size and data should match beforehand */
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = src_h;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ torture_assert_ntstatus_ok(tctx, status, "getinfo");
+ torture_assert_int_equal(tctx, (int)io.all_info2.out.size,
+ 32768, "size after IO");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * The compression tests won't run against Windows servers yet - ReFS doesn't
+ * (yet) offer support for compression.
+ */
+static bool test_ioctl_dup_extents_compressed_src(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 0, /* filled after compressed flag */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING
+ | FILE_FILE_COMPRESSION, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx,
+ "block refcounting and compressed files not supported\n");
+ }
+
+ /* set compressed flag on src */
+ status = test_ioctl_compress_set(tctx, tmp_ctx, tree, src_h,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_COMPRESSION");
+
+ ok = write_pattern(tctx, tree, tmp_ctx, src_h, 0, 4096, 0);
+ torture_assert(tctx, ok, "write pattern");
+
+ /* extend dest */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = 4096;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_compressed_dest(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ union smb_setfileinfo sinfo;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 4096,
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING
+ | FILE_FILE_COMPRESSION, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx,
+ "block refcounting and compressed files not supported\n");
+ }
+
+ /* set compressed flag on dest */
+ status = test_ioctl_compress_set(tctx, tmp_ctx, tree, dest_h,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_SET_COMPRESSION");
+
+ /* extend dest */
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = dest_h;
+ sinfo.end_of_file_info.in.size = 4096;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_setinfo_file");
+
+ /* copy all src file data */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_bad_handle(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ struct smb2_handle bogus_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 32768,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ /* open and close a file, keeping the handle as now a "bogus" handle */
+ ok = test_setup_create_fill(tctx, tree, tmp_ctx, "bogus_file",
+ &bogus_h, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(tctx, ok, "bogus file create fill");
+ smb2_util_close(tree, bogus_h);
+
+ /* bogus dest file handle */
+ ioctl.smb2.in.file.handle = bogus_h;
+
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 32768;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_FILE_CLOSED,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ /* reinstate dest, add bogus src file handle */
+ ioctl.smb2.in.file.handle = dest_h;
+ smb2_push_handle(dup_ext_buf.source_fid, &bogus_h);
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_HANDLE,
+ "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, src_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_src_lck(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle src_h2;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ /* dest pattern is different to src */
+ ok = write_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 32768);
+ torture_assert(tctx, ok, "write pattern");
+
+ /* setup dup ext req, values used for locking */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 32768;
+
+ /* open and lock the dup extents src file */
+ status = torture_smb2_testfile(tree, FNAME, &src_h2);
+ torture_assert_ntstatus_ok(tctx, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = src_h2;
+ lck.in.locks = el;
+ el[0].offset = dup_ext_buf.source_off;
+ el[0].length = dup_ext_buf.byte_count;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "lock");
+
+ status = smb2_util_write(tree, src_h,
+ "conflicted", 0, sizeof("conflicted"));
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_FILE_LOCK_CONFLICT, "file write");
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ /*
+ * In contrast to copy-chunk, dup extents doesn't cause a lock conflict
+ * here.
+ */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = src_h2;
+ lck.in.locks = el;
+ el[0].offset = dup_ext_buf.source_off;
+ el[0].length = dup_ext_buf.byte_count;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "unlock");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_DUP_EXTENTS_TO_FILE unlocked");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h2);
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool test_ioctl_dup_extents_dest_lck(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ struct smb2_handle dest_h2;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct fsctl_dup_extents_to_file dup_ext_buf;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ok = test_setup_dup_extents(tctx, tree, tmp_ctx,
+ &src_h, 32768, /* fill 32768 byte src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0,
+ SEC_RIGHTS_FILE_ALL,
+ &dup_ext_buf,
+ &ioctl);
+ if (!ok) {
+ torture_fail(tctx, "setup dup extents error");
+ }
+
+ status = test_ioctl_fs_supported(tctx, tree, tmp_ctx, &src_h,
+ FILE_SUPPORTS_BLOCK_REFCOUNTING, &ok);
+ torture_assert_ntstatus_ok(tctx, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ talloc_free(tmp_ctx);
+ torture_skip(tctx, "block refcounting not supported\n");
+ }
+
+ /* dest pattern is different to src */
+ ok = write_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 32768);
+ torture_assert(tctx, ok, "write pattern");
+
+ /* setup dup ext req, values used for locking */
+ dup_ext_buf.source_off = 0;
+ dup_ext_buf.target_off = 0;
+ dup_ext_buf.byte_count = 32768;
+
+ /* open and lock the dup extents dest file */
+ status = torture_smb2_testfile(tree, FNAME2, &dest_h2);
+ torture_assert_ntstatus_ok(tctx, status, "2nd src open");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = dest_h2;
+ lck.in.locks = el;
+ el[0].offset = dup_ext_buf.source_off;
+ el[0].length = dup_ext_buf.byte_count;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "lock");
+
+ status = smb2_util_write(tree, dest_h,
+ "conflicted", 0, sizeof("conflicted"));
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_FILE_LOCK_CONFLICT, "file write");
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &dup_ext_buf,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_dup_extents_to_file);
+ torture_assert_ndr_success(tctx, ndr_ret,
+ "ndr_push_fsctl_dup_extents_to_file");
+
+ /*
+ * In contrast to copy-chunk, dup extents doesn't cause a lock conflict
+ * here.
+ */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status, "FSCTL_DUP_EXTENTS_TO_FILE");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000001;
+ lck.in.file.handle = dest_h2;
+ lck.in.locks = el;
+ el[0].offset = dup_ext_buf.source_off;
+ el[0].length = dup_ext_buf.byte_count;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "unlock");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(tctx, status,
+ "FSCTL_DUP_EXTENTS_TO_FILE unlocked");
+
+ ok = check_pattern(tctx, tree, tmp_ctx, dest_h, 0, 32768, 0);
+ if (!ok) {
+ torture_fail(tctx, "inconsistent file data");
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ smb2_util_close(tree, dest_h2);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ basic regression test for BUG 14607
+ https://bugzilla.samba.org/show_bug.cgi?id=14607
+*/
+static bool test_ioctl_bug14607(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ uint32_t timeout_msec;
+ NTSTATUS status;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ status = smb2cli_ioctl(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ tmp_ctx,
+ &out_input_buffer,
+ &out_output_buffer);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST))
+ {
+ torture_comment(torture,
+ "FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8: %s\n",
+ nt_errstr(status));
+ torture_skip(torture, "server doesn't support FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8\n");
+ }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8");
+
+ torture_assert_int_equal(torture, out_output_buffer.length, 1,
+ "output length");
+ torture_assert_int_equal(torture, out_output_buffer.data[0], 8,
+ "output buffer byte should be 8");
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ basic regression test for BUG 14769
+ https://bugzilla.samba.org/show_bug.cgi?id=14769
+*/
+static bool test_ioctl_bug14769(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ const char *fname = "bug14769";
+ bool ret = false;
+ struct smb2_handle h;
+ struct smb2_ioctl ioctl;
+ struct smb2_close cl;
+ struct smb2_request *smb2arr[2] = { 0 };
+ uint8_t tosend_msec = 200;
+ DATA_BLOB send_buf = { &tosend_msec, 1 };
+
+ /* Create a test file. */
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testfile(tree, fname, &h);
+ torture_assert_ntstatus_ok(torture, status, "create bug14769");
+
+ /*
+ * Send (not receive) the FSCTL.
+ * This should go async with a wait time of 200 msec.
+ */
+ ZERO_STRUCT(ioctl);
+ ioctl.in.file.handle = h;
+ ioctl.in.function = FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP;
+ ioctl.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+ ioctl.in.out = send_buf;
+
+ smb2arr[0] = smb2_ioctl_send(tree, &ioctl);
+ torture_assert_goto(torture,
+ smb2arr[0] != NULL,
+ ret,
+ done,
+ "smb2_ioctl_send failed\n");
+ /* Immediately send the close. */
+ ZERO_STRUCT(cl);
+ cl.in.file.handle = h;
+ cl.in.flags = 0;
+ smb2arr[1] = smb2_close_send(tree, &cl);
+ torture_assert_goto(torture,
+ smb2arr[1] != NULL,
+ ret,
+ done,
+ "smb2_close_send failed\n");
+
+ /* Now get the FSCTL reply. */
+ /*
+ * If we suffer from bug #14769 this will fail as
+ * the ioctl will return with NT_STATUS_FILE_CLOSED,
+ * as the close will have closed the handle without
+ * waiting for the ioctl to complete. The server shouldn't
+ * complete the close until the ioctl finishes.
+ */
+ status = smb2_ioctl_recv(smb2arr[0], tree, &ioctl);
+ torture_assert_ntstatus_ok_goto(torture,
+ status,
+ ret,
+ done,
+ "smb2_ioctl_recv failed\n");
+
+ /* Followed by the close reply. */
+ status = smb2_close_recv(smb2arr[1], &cl);
+ torture_assert_ntstatus_ok_goto(torture,
+ status,
+ ret,
+ done,
+ "smb2_ioctl_close failed\n");
+ ret = true;
+
+ done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/*
+ basic regression test for BUG 14788,
+ with FSCTL_VALIDATE_NEGOTIATE_INFO
+ https://bugzilla.samba.org/show_bug.cgi?id=14788
+*/
+static bool test_ioctl_bug14788_VALIDATE_NEGOTIATE(struct torture_context *torture,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(torture, "host", NULL);
+ const char *share = torture_setting_string(torture, "share", NULL);
+ const char *noperm_share = torture_setting_string(torture, "noperm_share", "noperm");
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_tree *tree = NULL;
+ struct smb2_session *session = NULL;
+ uint16_t noperm_flags = 0;
+ const char *noperm_unc = NULL;
+ struct smb2_tree *noperm_tree = NULL;
+ uint32_t timeout_msec;
+ struct tevent_req *subreq = NULL;
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(torture, "Can't test without SMB 3 support");
+ }
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.min_protocol = PROTOCOL_SMB3_00;
+ options.max_protocol = PROTOCOL_SMB3_02;
+
+ status = smb2_connect(torture,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ share,
+ lpcfg_resolve_context(torture->lp_ctx),
+ credentials,
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok(torture, status, "smb2_connect options failed");
+ session = tree->session;
+ transport = session->transport;
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ subreq = smb2cli_validate_negotiate_info_send(torture,
+ torture->ev,
+ transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ tree->smbXcli);
+ torture_assert(torture,
+ tevent_req_poll_ntstatus(subreq, torture->ev, &status),
+ "tevent_req_poll_ntstatus");
+ status = smb2cli_validate_negotiate_info_recv(subreq);
+ torture_assert_ntstatus_ok(torture, status, "smb2cli_validate_negotiate_info");
+
+ noperm_unc = talloc_asprintf(torture, "\\\\%s\\%s", host, noperm_share);
+ torture_assert(torture, noperm_unc != NULL, "talloc_asprintf");
+
+ noperm_tree = smb2_tree_init(session, torture, false);
+ torture_assert(torture, noperm_tree != NULL, "smb2_tree_init");
+
+ status = smb2cli_raw_tcon(transport->conn,
+ SMB2_HDR_FLAG_SIGNED,
+ 0, /* clear_flags */
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli,
+ noperm_flags,
+ noperm_unc);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_BAD_NETWORK_NAME)) {
+ torture_skip(torture, talloc_asprintf(torture,
+ "noperm_unc[%s] %s",
+ noperm_unc, nt_errstr(status)));
+ }
+ torture_assert_ntstatus_ok(torture, status,
+ talloc_asprintf(torture,
+ "smb2cli_tcon(%s)",
+ noperm_unc));
+
+ subreq = smb2cli_validate_negotiate_info_send(torture,
+ torture->ev,
+ transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli);
+ torture_assert(torture,
+ tevent_req_poll_ntstatus(subreq, torture->ev, &status),
+ "tevent_req_poll_ntstatus");
+ status = smb2cli_validate_negotiate_info_recv(subreq);
+ torture_assert_ntstatus_ok(torture, status, "smb2cli_validate_negotiate_info noperm");
+
+ return true;
+}
+
+/*
+ basic regression test for BUG 14788,
+ with FSCTL_QUERY_NETWORK_INTERFACE_INFO
+ https://bugzilla.samba.org/show_bug.cgi?id=14788
+*/
+static bool test_ioctl_bug14788_NETWORK_INTERFACE(struct torture_context *torture,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(torture, "host", NULL);
+ const char *share = torture_setting_string(torture, "share", NULL);
+ const char *noperm_share = torture_setting_string(torture, "noperm_share", "noperm");
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_tree *tree = NULL;
+ struct smb2_session *session = NULL;
+ uint16_t noperm_flags = 0;
+ const char *noperm_unc = NULL;
+ struct smb2_tree *noperm_tree = NULL;
+ uint32_t timeout_msec;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(torture, "Can't test without SMB 3 support");
+ }
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.min_protocol = PROTOCOL_SMB3_00;
+ options.max_protocol = PROTOCOL_SMB3_02;
+
+ status = smb2_connect(torture,
+ host,
+ lpcfg_smb_ports(torture->lp_ctx),
+ share,
+ lpcfg_resolve_context(torture->lp_ctx),
+ credentials,
+ &tree,
+ torture->ev,
+ &options,
+ lpcfg_socket_options(torture->lp_ctx),
+ lpcfg_gensec_settings(torture, torture->lp_ctx)
+ );
+ torture_assert_ntstatus_ok(torture, status, "smb2_connect options failed");
+ session = tree->session;
+ transport = session->transport;
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ /*
+ * A valid FSCTL_QUERY_NETWORK_INTERFACE_INFO
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ UINT16_MAX, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ /*
+ * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ * with file_id_* is being UINT64_MAX and
+ * in_max_output_length = 1.
+ *
+ * This demonstrates NT_STATUS_BUFFER_TOO_SMALL
+ * if the server is not able to return the
+ * whole response buffer to the client.
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_BUFFER_TOO_SMALL,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ /*
+ * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ * with file_id_* not being UINT64_MAX.
+ *
+ * This gives INVALID_PARAMETER instead
+ * of FILE_CLOSED.
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ tree->smbXcli,
+ INT64_MAX, /* in_fid_persistent */
+ INT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ UINT16_MAX, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ /*
+ * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ * with file_id_* not being UINT64_MAX and
+ * in_max_output_length = 1.
+ *
+ * This proves INVALID_PARAMETER instead
+ * of BUFFER_TOO_SMALL.
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ tree->smbXcli,
+ INT64_MAX, /* in_fid_persistent */
+ INT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ noperm_unc = talloc_asprintf(torture, "\\\\%s\\%s", host, noperm_share);
+ torture_assert(torture, noperm_unc != NULL, "talloc_asprintf");
+
+ noperm_tree = smb2_tree_init(session, torture, false);
+ torture_assert(torture, noperm_tree != NULL, "smb2_tree_init");
+
+ status = smb2cli_raw_tcon(transport->conn,
+ SMB2_HDR_FLAG_SIGNED,
+ 0, /* clear_flags */
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli,
+ noperm_flags,
+ noperm_unc);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_BAD_NETWORK_NAME)) {
+ torture_skip(torture, talloc_asprintf(torture,
+ "noperm_unc[%s] %s",
+ noperm_unc, nt_errstr(status)));
+ }
+ torture_assert_ntstatus_ok(torture, status,
+ talloc_asprintf(torture,
+ "smb2cli_tcon(%s)",
+ noperm_unc));
+
+ /*
+ * A valid FSCTL_QUERY_NETWORK_INTERFACE_INFO
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ UINT16_MAX, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ /*
+ * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ * with file_id_* is being UINT64_MAX and
+ * in_max_output_length = 1.
+ *
+ * This demonstrates NT_STATUS_BUFFER_TOO_SMALL
+ * if the server is not able to return the
+ * whole response buffer to the client.
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_BUFFER_TOO_SMALL,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ /*
+ * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ * with file_id_* not being UINT64_MAX.
+ *
+ * This gives INVALID_PARAMETER instead
+ * of FILE_CLOSED.
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli,
+ INT64_MAX, /* in_fid_persistent */
+ INT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ UINT16_MAX, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ /*
+ * An invalid FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ * with file_id_* not being UINT64_MAX and
+ * in_max_output_length = 1.
+ *
+ * This proves INVALID_PARAMETER instead
+ * of BUFFER_TOO_SMALL.
+ */
+ status = smb2cli_ioctl(transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ noperm_tree->smbXcli,
+ INT64_MAX, /* in_fid_persistent */
+ INT64_MAX, /* in_fid_volatile */
+ FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ torture,
+ &out_input_buffer,
+ &out_output_buffer);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_INVALID_PARAMETER,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO");
+
+ return true;
+}
+
+/*
+ * testing of SMB2 ioctls
+ */
+struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "ioctl");
+ struct torture_suite *bug14788 = torture_suite_create(ctx, "bug14788");
+
+ torture_suite_add_1smb2_test(suite, "shadow_copy",
+ test_ioctl_get_shadow_copy);
+ torture_suite_add_1smb2_test(suite, "req_resume_key",
+ test_ioctl_req_resume_key);
+ torture_suite_add_1smb2_test(suite, "req_two_resume_keys",
+ test_ioctl_req_two_resume_keys);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_simple",
+ test_ioctl_copy_chunk_simple);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_multi",
+ test_ioctl_copy_chunk_multi);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_tiny",
+ test_ioctl_copy_chunk_tiny);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_overwrite",
+ test_ioctl_copy_chunk_over);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_append",
+ test_ioctl_copy_chunk_append);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_limits",
+ test_ioctl_copy_chunk_limits);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_src_lock",
+ test_ioctl_copy_chunk_src_lck);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_dest_lock",
+ test_ioctl_copy_chunk_dest_lck);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_bad_key",
+ test_ioctl_copy_chunk_bad_key);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest",
+ test_ioctl_copy_chunk_src_is_dest);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest_overlap",
+ test_ioctl_copy_chunk_src_is_dest_overlap);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_bad_access",
+ test_ioctl_copy_chunk_bad_access);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_write_access",
+ test_ioctl_copy_chunk_write_access);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_src_exceed",
+ test_ioctl_copy_chunk_src_exceed);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_src_exceed_multi",
+ test_ioctl_copy_chunk_src_exceed_multi);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_sparse_dest",
+ test_ioctl_copy_chunk_sparse_dest);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_max_output_sz",
+ test_ioctl_copy_chunk_max_output_sz);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_zero_length",
+ test_ioctl_copy_chunk_zero_length);
+ torture_suite_add_1smb2_test(suite, "copy-chunk streams",
+ test_copy_chunk_streams);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_across_shares",
+ test_copy_chunk_across_shares);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_across_shares2",
+ test_copy_chunk_across_shares2);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_across_shares3",
+ test_copy_chunk_across_shares3);
+ torture_suite_add_1smb2_test(suite, "compress_file_flag",
+ test_ioctl_compress_file_flag);
+ torture_suite_add_1smb2_test(suite, "compress_dir_inherit",
+ test_ioctl_compress_dir_inherit);
+ torture_suite_add_1smb2_test(suite, "compress_invalid_format",
+ test_ioctl_compress_invalid_format);
+ torture_suite_add_1smb2_test(suite, "compress_invalid_buf",
+ test_ioctl_compress_invalid_buf);
+ torture_suite_add_1smb2_test(suite, "compress_query_file_attr",
+ test_ioctl_compress_query_file_attr);
+ torture_suite_add_1smb2_test(suite, "compress_create_with_attr",
+ test_ioctl_compress_create_with_attr);
+ torture_suite_add_1smb2_test(suite, "compress_inherit_disable",
+ test_ioctl_compress_inherit_disable);
+ torture_suite_add_1smb2_test(suite, "compress_set_file_attr",
+ test_ioctl_compress_set_file_attr);
+ torture_suite_add_1smb2_test(suite, "compress_perms",
+ test_ioctl_compress_perms);
+ torture_suite_add_1smb2_test(suite, "compress_notsup_get",
+ test_ioctl_compress_notsup_get);
+ torture_suite_add_1smb2_test(suite, "compress_notsup_set",
+ test_ioctl_compress_notsup_set);
+ torture_suite_add_1smb2_test(suite, "network_interface_info",
+ test_ioctl_network_interface_info);
+ torture_suite_add_1smb2_test(suite, "sparse_file_flag",
+ test_ioctl_sparse_file_flag);
+ torture_suite_add_1smb2_test(suite, "sparse_file_attr",
+ test_ioctl_sparse_file_attr);
+ torture_suite_add_1smb2_test(suite, "sparse_dir_flag",
+ test_ioctl_sparse_dir_flag);
+ torture_suite_add_1smb2_test(suite, "sparse_set_nobuf",
+ test_ioctl_sparse_set_nobuf);
+ torture_suite_add_1smb2_test(suite, "sparse_set_oversize",
+ test_ioctl_sparse_set_oversize);
+ torture_suite_add_1smb2_test(suite, "sparse_qar",
+ test_ioctl_sparse_qar);
+ torture_suite_add_1smb2_test(suite, "sparse_qar_malformed",
+ test_ioctl_sparse_qar_malformed);
+ torture_suite_add_1smb2_test(suite, "sparse_punch",
+ test_ioctl_sparse_punch);
+ torture_suite_add_1smb2_test(suite, "sparse_hole_dealloc",
+ test_ioctl_sparse_hole_dealloc);
+ torture_suite_add_1smb2_test(suite, "sparse_compressed",
+ test_ioctl_sparse_compressed);
+ torture_suite_add_1smb2_test(suite, "sparse_copy_chunk",
+ test_ioctl_sparse_copy_chunk);
+ torture_suite_add_1smb2_test(suite, "sparse_punch_invalid",
+ test_ioctl_sparse_punch_invalid);
+ torture_suite_add_1smb2_test(suite, "sparse_perms",
+ test_ioctl_sparse_perms);
+ torture_suite_add_1smb2_test(suite, "sparse_lock",
+ test_ioctl_sparse_lck);
+ torture_suite_add_1smb2_test(suite, "sparse_qar_ob1",
+ test_ioctl_sparse_qar_ob1);
+ torture_suite_add_1smb2_test(suite, "sparse_qar_multi",
+ test_ioctl_sparse_qar_multi);
+ torture_suite_add_1smb2_test(suite, "sparse_qar_overflow",
+ test_ioctl_sparse_qar_overflow);
+ torture_suite_add_1smb2_test(suite, "trim_simple",
+ test_ioctl_trim_simple);
+ torture_suite_add_1smb2_test(suite, "dup_extents_simple",
+ test_ioctl_dup_extents_simple);
+ torture_suite_add_1smb2_test(suite, "dup_extents_len_beyond_dest",
+ test_ioctl_dup_extents_len_beyond_dest);
+ torture_suite_add_1smb2_test(suite, "dup_extents_len_beyond_src",
+ test_ioctl_dup_extents_len_beyond_src);
+ torture_suite_add_1smb2_test(suite, "dup_extents_len_zero",
+ test_ioctl_dup_extents_len_zero);
+ torture_suite_add_1smb2_test(suite, "dup_extents_sparse_src",
+ test_ioctl_dup_extents_sparse_src);
+ torture_suite_add_1smb2_test(suite, "dup_extents_sparse_dest",
+ test_ioctl_dup_extents_sparse_dest);
+ torture_suite_add_1smb2_test(suite, "dup_extents_sparse_both",
+ test_ioctl_dup_extents_sparse_both);
+ torture_suite_add_1smb2_test(suite, "dup_extents_src_is_dest",
+ test_ioctl_dup_extents_src_is_dest);
+ torture_suite_add_1smb2_test(suite, "dup_extents_src_is_dest_overlap",
+ test_ioctl_dup_extents_src_is_dest_overlap);
+ torture_suite_add_1smb2_test(suite, "dup_extents_compressed_src",
+ test_ioctl_dup_extents_compressed_src);
+ torture_suite_add_1smb2_test(suite, "dup_extents_compressed_dest",
+ test_ioctl_dup_extents_compressed_dest);
+ torture_suite_add_1smb2_test(suite, "dup_extents_bad_handle",
+ test_ioctl_dup_extents_bad_handle);
+ torture_suite_add_1smb2_test(suite, "dup_extents_src_lock",
+ test_ioctl_dup_extents_src_lck);
+ torture_suite_add_1smb2_test(suite, "dup_extents_dest_lock",
+ test_ioctl_dup_extents_dest_lck);
+ torture_suite_add_1smb2_test(suite, "bug14607",
+ test_ioctl_bug14607);
+ torture_suite_add_1smb2_test(suite, "bug14769",
+ test_ioctl_bug14769);
+
+ torture_suite_add_1smb2_test(bug14788, "VALIDATE_NEGOTIATE",
+ test_ioctl_bug14788_VALIDATE_NEGOTIATE);
+ torture_suite_add_1smb2_test(bug14788, "NETWORK_INTERFACE",
+ test_ioctl_bug14788_NETWORK_INTERFACE);
+ torture_suite_add_suite(suite, bug14788);
+
+ suite->description = talloc_strdup(suite, "SMB2-IOCTL tests");
+
+ return suite;
+}
+
diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c
new file mode 100644
index 0000000..30bbefd
--- /dev/null
+++ b/source4/torture/smb2/lease.c
@@ -0,0 +1,4819 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 leases
+
+ Copyright (C) Zachary Loafman 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/util.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "libcli/security/security.h"
+#include "lib/param/param.h"
+#include "lease_break_handler.h"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)(v), (int)(correct)); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_CREATED(__io, __created, __attribute) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
+ CHECK_VAL((__io)->out.size, 0); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while(0)
+
+#define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
+ do { \
+ CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
+ if (__oplevel) { \
+ CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[0], (__key)); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[1], ~(__key)); \
+ CHECK_VAL((__io)->out.lease_response.lease_state, smb2_util_lease_state(__state)); \
+ } else { \
+ CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[0], 0); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[1], 0); \
+ CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
+ } \
+ \
+ CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
+ CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
+ CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
+ } while(0)
+
+#define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
+ do { \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
+ if (__oplevel) { \
+ CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
+ } else { \
+ CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
+ } \
+ \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
+ if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
+ CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
+ CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
+ } \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
+ } while(0)
+
+static const uint64_t LEASE1 = 0xBADC0FFEE0DDF00Dull;
+static const uint64_t LEASE2 = 0xDEADBEEFFEEDBEADull;
+static const uint64_t LEASE3 = 0xDAD0FFEDD00DF00Dull;
+static const uint64_t LEASE4 = 0xBAD0FFEDD00DF00Dull;
+
+#define NREQUEST_RESULTS 8
+static const char *request_results[NREQUEST_RESULTS][2] = {
+ { "", "" },
+ { "R", "R" },
+ { "H", "" },
+ { "W", "" },
+ { "RH", "RH" },
+ { "RW", "RW" },
+ { "HW", "" },
+ { "RHW", "RHW" },
+};
+
+static bool test_lease_request(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_request.dat";
+ const char *fname2 = "lease_request.2.dat";
+ const char *sname = "lease_request.dat:stream";
+ const char *dname = "lease_request.dir";
+ bool ret = true;
+ int i;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname2);
+ smb2_util_rmdir(tree, dname);
+
+ /* Win7 is happy to grant RHW leases on files. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
+
+ /* But will reject leases on directories. */
+ if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
+ smb2_lease_create(&io, &ls, true, dname, LEASE2, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+ smb2_util_close(tree, io.out.file.handle);
+ }
+
+ /* Also rejects multiple files leased under the same key. */
+ smb2_lease_create(&io, &ls, true, fname2, LEASE1, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /* And grants leases on streams (with separate leasekey). */
+ smb2_lease_create(&io, &ls, false, sname, LEASE2, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ h2 = io.out.file.handle;
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RHW", true, LEASE2, 0);
+ smb2_util_close(tree, h2);
+
+ smb2_util_close(tree, h1);
+
+ /* Now see what combos are actually granted. */
+ for (i = 0; i < NREQUEST_RESULTS; i++) {
+ torture_comment(tctx, "Requesting lease type %s(%x),"
+ " expecting %s(%x)\n",
+ request_results[i][0], smb2_util_lease_state(request_results[i][0]),
+ request_results[i][1], smb2_util_lease_state(request_results[i][1]));
+ smb2_lease_create(&io, &ls, false, fname, LEASE1,
+ smb2_util_lease_state(request_results[i][0]));
+ status = smb2_create(tree, mem_ctx, &io);
+ h2 = io.out.file.handle;
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, request_results[i][1], true, LEASE1, 0);
+ smb2_util_close(tree, io.out.file.handle);
+ }
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname2);
+ smb2_util_rmdir(tree, dname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_upgrade(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle hnew = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_upgrade.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ /* Grab a RH lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE1, 0);
+ h = io.out.file.handle;
+
+ /* Upgrades (sidegrades?) to RW leave us with an RH. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE1, 0);
+ hnew = io.out.file.handle;
+
+ smb2_util_close(tree, hnew);
+
+ /* Upgrade to RHW lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
+ hnew = io.out.file.handle;
+
+ smb2_util_close(tree, h);
+ h = hnew;
+
+ /* Attempt to downgrade - original lease state is maintained. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
+ hnew = io.out.file.handle;
+
+ smb2_util_close(tree, hnew);
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, hnew);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * upgrade2 test.
+ * full matrix of lease upgrade combinations
+ * (non-contended case)
+ *
+ * The summary of the behaviour is this:
+ * -------------------------------------
+ * An uncontended lease upgrade results in a change
+ * if and only if the requested lease state is
+ * - valid, and
+ * - strictly a superset of the lease state already held.
+ *
+ * In that case the resulting lease state is the one
+ * requested in the upgrade.
+ */
+struct lease_upgrade2_test {
+ const char *initial;
+ const char *upgrade_to;
+ const char *expected;
+};
+
+#define NUM_LEASE_TYPES 5
+#define NUM_UPGRADE_TESTS ( NUM_LEASE_TYPES * NUM_LEASE_TYPES )
+struct lease_upgrade2_test lease_upgrade2_tests[NUM_UPGRADE_TESTS] = {
+ { "", "", "" },
+ { "", "R", "R" },
+ { "", "RH", "RH" },
+ { "", "RW", "RW" },
+ { "", "RWH", "RWH" },
+
+ { "R", "", "R" },
+ { "R", "R", "R" },
+ { "R", "RH", "RH" },
+ { "R", "RW", "RW" },
+ { "R", "RWH", "RWH" },
+
+ { "RH", "", "RH" },
+ { "RH", "R", "RH" },
+ { "RH", "RH", "RH" },
+ { "RH", "RW", "RH" },
+ { "RH", "RWH", "RWH" },
+
+ { "RW", "", "RW" },
+ { "RW", "R", "RW" },
+ { "RW", "RH", "RW" },
+ { "RW", "RW", "RW" },
+ { "RW", "RWH", "RWH" },
+
+ { "RWH", "", "RWH" },
+ { "RWH", "R", "RWH" },
+ { "RWH", "RH", "RWH" },
+ { "RWH", "RW", "RWH" },
+ { "RWH", "RWH", "RWH" },
+};
+
+static bool test_lease_upgrade2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle h, hnew;
+ NTSTATUS status;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ const char *fname = "lease_upgrade2.dat";
+ bool ret = true;
+ int i;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ for (i = 0; i < NUM_UPGRADE_TESTS; i++) {
+ struct lease_upgrade2_test t = lease_upgrade2_tests[i];
+
+ smb2_util_unlink(tree, fname);
+
+ /* Grab a lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.initial));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, t.initial, true, LEASE1, 0);
+ h = io.out.file.handle;
+
+ /* Upgrade. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, t.expected, true, LEASE1, 0);
+ hnew = io.out.file.handle;
+
+ smb2_util_close(tree, hnew);
+ smb2_util_close(tree, h);
+ }
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, hnew);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * upgrade3:
+ * full matrix of lease upgrade combinations
+ * (contended case)
+ *
+ * We start with 2 leases, and check how one can
+ * be upgraded
+ *
+ * The summary of the behaviour is this:
+ * -------------------------------------
+ *
+ * If we have two leases (lease1 and lease2) on the same file,
+ * then attempt to upgrade lease1 results in a change if and only
+ * if the requested lease state:
+ * - is valid,
+ * - is strictly a superset of lease1, and
+ * - can held together with lease2.
+ *
+ * In that case, the resulting lease state of the upgraded lease1
+ * is the state requested in the upgrade. lease2 is not broken
+ * and remains unchanged.
+ *
+ * Note that this contrasts the case of directly opening with
+ * an initial requested lease state, in which case you get that
+ * portion of the requested state that can be shared with the
+ * already existing leases (or the states that they get broken to).
+ */
+struct lease_upgrade3_test {
+ const char *held1;
+ const char *held2;
+ const char *upgrade_to;
+ const char *upgraded_to;
+};
+
+#define NUM_UPGRADE3_TESTS ( 20 )
+struct lease_upgrade3_test lease_upgrade3_tests[NUM_UPGRADE3_TESTS] = {
+ {"R", "R", "", "R" },
+ {"R", "R", "R", "R" },
+ {"R", "R", "RW", "R" },
+ {"R", "R", "RH", "RH" },
+ {"R", "R", "RHW", "R" },
+
+ {"R", "RH", "", "R" },
+ {"R", "RH", "R", "R" },
+ {"R", "RH", "RW", "R" },
+ {"R", "RH", "RH", "RH" },
+ {"R", "RH", "RHW", "R" },
+
+ {"RH", "R", "", "RH" },
+ {"RH", "R", "R", "RH" },
+ {"RH", "R", "RW", "RH" },
+ {"RH", "R", "RH", "RH" },
+ {"RH", "R", "RHW", "RH" },
+
+ {"RH", "RH", "", "RH" },
+ {"RH", "RH", "R", "RH" },
+ {"RH", "RH", "RW", "RH" },
+ {"RH", "RH", "RH", "RH" },
+ {"RH", "RH", "RHW", "RH" },
+};
+
+static bool test_lease_upgrade3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle h, h2, hnew;
+ NTSTATUS status;
+ struct smb2_create io;
+ struct smb2_lease ls;
+ const char *fname = "lease_upgrade3.dat";
+ bool ret = true;
+ int i;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ for (i = 0; i < NUM_UPGRADE3_TESTS; i++) {
+ struct lease_upgrade3_test t = lease_upgrade3_tests[i];
+
+ smb2_util_unlink(tree, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* grab first lease */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, t.held1, true, LEASE1, 0);
+ h = io.out.file.handle;
+
+ /* grab second lease */
+ smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(t.held2));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, t.held2, true, LEASE2, 0);
+ h2 = io.out.file.handle;
+
+ /* no break has happened */
+ CHECK_VAL(lease_break_info.count, 0);
+ CHECK_VAL(lease_break_info.failures, 0);
+
+ /* try to upgrade lease1 */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, t.upgraded_to, true, LEASE1, 0);
+ hnew = io.out.file.handle;
+
+ /* no break has happened */
+ CHECK_VAL(lease_break_info.count, 0);
+ CHECK_VAL(lease_break_info.failures, 0);
+
+ smb2_util_close(tree, hnew);
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+ }
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, hnew);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+
+/*
+ break_results should be read as "held lease, new lease, hold broken to, new
+ grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2
+ tries for RW, key1 will be broken to RH (in this case, not broken at all)
+ and key2 will be granted R.
+
+ Note: break_results only includes things that Win7 will actually grant (see
+ request_results above).
+ */
+#define NBREAK_RESULTS 16
+static const char *break_results[NBREAK_RESULTS][4] = {
+ {"R", "R", "R", "R"},
+ {"R", "RH", "R", "RH"},
+ {"R", "RW", "R", "R"},
+ {"R", "RHW", "R", "RH"},
+
+ {"RH", "R", "RH", "R"},
+ {"RH", "RH", "RH", "RH"},
+ {"RH", "RW", "RH", "R"},
+ {"RH", "RHW", "RH", "RH"},
+
+ {"RW", "R", "R", "R"},
+ {"RW", "RH", "R", "RH"},
+ {"RW", "RW", "R", "R"},
+ {"RW", "RHW", "R", "RH"},
+
+ {"RHW", "R", "RH", "R"},
+ {"RHW", "RH", "RH", "RH"},
+ {"RHW", "RW", "RH", "R"},
+ {"RHW", "RHW", "RH", "RH"},
+};
+
+static bool test_lease_break(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h, h2, h3;
+ NTSTATUS status;
+ const char *fname = "lease_break.dat";
+ bool ret = true;
+ int i;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ for (i = 0; i < NBREAK_RESULTS; i++) {
+ const char *held = break_results[i][0];
+ const char *contend = break_results[i][1];
+ const char *brokento = break_results[i][2];
+ const char *granted = break_results[i][3];
+ torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
+ "expecting break to %s(%x) and grant of %s(%x)\n",
+ held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend),
+ brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted));
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, held, true, LEASE1, 0);
+
+ /* Possibly contend lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state(contend));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, granted, true, LEASE2, 0);
+
+ if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
+ CHECK_BREAK_INFO(held, brokento, LEASE1);
+ } else {
+ CHECK_NO_BREAK(tctx);
+ }
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ Now verify that an attempt to upgrade LEASE1 results in no
+ break and no change in LEASE1.
+ */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, brokento, true, LEASE1, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+ CHECK_VAL(lease_break_info.failures, 0);
+
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_nobreakself(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_nobreakself.dat";
+ bool ret = true;
+ uint32_t caps;
+ char c = 0;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ /* Win7 is happy to grant RHW leases on files. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1,
+ smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "R", true, LEASE1, 0);
+
+ smb2_lease_create(&io, &ls, false, fname, LEASE2,
+ smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_LEASE(&io, "R", true, LEASE2, 0);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ /* Make sure we don't break ourselves on write */
+
+ status = smb2_util_write(tree, h1, &c, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_BREAK_INFO("R", "", LEASE2);
+
+ /* Try the other way round. First, upgrade LEASE2 to R again */
+
+ smb2_lease_create(&io, &ls, false, fname, LEASE2,
+ smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io, "R", true, LEASE2, 0);
+ smb2_util_close(tree, io.out.file.handle);
+
+ /* Now break LEASE1 via h2 */
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ status = smb2_util_write(tree, h2, &c, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_BREAK_INFO("R", "", LEASE1);
+
+ /* .. and break LEASE2 via h1 */
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ status = smb2_util_write(tree, h1, &c, 0, 1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_BREAK_INFO("R", "", LEASE2);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_statopen(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_statopen.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ /* Create file. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+ smb2_util_close(tree, h1);
+
+ /* Stat open file with RWH lease. */
+ smb2_lease_create_share(&io, &ls, false, fname, 0, LEASE1,
+ smb2_util_lease_state("RWH"));
+ io.in.desired_access = FILE_READ_ATTRIBUTES;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ /* Ensure non-stat open doesn't break and gets same lease
+ state as existing stat open. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1,
+ smb2_util_lease_state(""));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ CHECK_NO_BREAK(tctx);
+ smb2_util_close(tree, h1);
+
+ /* Open with conflicting lease. stat open should break down to RH */
+ smb2_lease_create(&io, &ls, false, fname, LEASE2,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE2, 0);
+
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_statopen2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_statopen2.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /* Open file with RWH lease. */
+ smb2_lease_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = io.out.file.handle;
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ /* Stat open */
+ ZERO_STRUCT(io);
+ io.in.desired_access = FILE_READ_ATTRIBUTES;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h2 = io.out.file.handle;
+
+ /* Open file with RWH lease. */
+ smb2_lease_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h3 = io.out.file.handle;
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+done:
+ if (!smb2_util_handle_empty(h3)) {
+ smb2_util_close(tree, h3);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_statopen3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_statopen3.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /* Stat open */
+ ZERO_STRUCT(io);
+ io.in.desired_access = FILE_READ_ATTRIBUTES;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = io.out.file.handle;
+
+ /* Open file with RWH lease. */
+ smb2_lease_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h2 = io.out.file.handle;
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_statopen4_do(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ uint32_t access_mask,
+ bool expect_stat_open)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_statopen2.dat";
+ bool ret = true;
+
+ /* Open file with RWH lease. */
+ smb2_lease_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ io.in.desired_access = SEC_FILE_ALL;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = io.out.file.handle;
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ /* Stat open */
+ ZERO_STRUCT(io);
+ io.in.desired_access = access_mask;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h2 = io.out.file.handle;
+
+ if (expect_stat_open) {
+ CHECK_NO_BREAK(tctx);
+ if (!ret) {
+ goto done;
+ }
+ } else {
+ CHECK_VAL(lease_break_info.count, 1);
+ if (!ret) {
+ goto done;
+ }
+ /*
+ * Don't bother checking the lease state of an additional open
+ * below...
+ */
+ goto done;
+ }
+
+ /* Open file with RWH lease. */
+ smb2_lease_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h3 = io.out.file.handle;
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+done:
+ if (!smb2_util_handle_empty(h3)) {
+ smb2_util_close(tree, h3);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_statopen4(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "lease_statopen4.dat";
+ struct smb2_handle h1 = {{0}};
+ uint32_t caps;
+ size_t i;
+ NTSTATUS status;
+ bool ret = true;
+ struct {
+ uint32_t access_mask;
+ bool expect_stat_open;
+ } tests[] = {
+ {
+ .access_mask = FILE_READ_DATA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_WRITE_DATA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_READ_EA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_WRITE_EA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_EXECUTE,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_READ_ATTRIBUTES,
+ .expect_stat_open = true,
+ },
+ {
+ .access_mask = FILE_WRITE_ATTRIBUTES,
+ .expect_stat_open = true,
+ },
+ {
+ .access_mask = DELETE_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = READ_CONTROL_ACCESS,
+ .expect_stat_open = true,
+ },
+ {
+ .access_mask = WRITE_DAC_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = WRITE_OWNER_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = SYNCHRONIZE_ACCESS,
+ .expect_stat_open = true,
+ },
+ };
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ret = test_lease_statopen4_do(tctx,
+ tree,
+ tests[i].access_mask,
+ tests[i].expect_stat_open);
+ if (ret == true) {
+ continue;
+ }
+ torture_result(tctx, TORTURE_FAIL,
+ "test %zu: access_mask: %s, "
+ "expect_stat_open: %s\n",
+ i,
+ get_sec_mask_str(tree, tests[i].access_mask),
+ tests[i].expect_stat_open ? "yes" : "no");
+ goto done;
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+static void torture_oplock_break_callback(struct smb2_request *req)
+{
+ NTSTATUS status;
+ struct smb2_break br;
+
+ ZERO_STRUCT(br);
+ status = smb2_break_recv(req, &br);
+ if (!NT_STATUS_IS_OK(status))
+ lease_break_info.oplock_failures++;
+
+ return;
+}
+
+/* a oplock break request handler */
+static bool torture_oplock_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ struct smb2_request *req;
+ struct smb2_break br;
+
+ lease_break_info.oplock_handle = *handle;
+ lease_break_info.oplock_level = level;
+ lease_break_info.oplock_count++;
+
+ ZERO_STRUCT(br);
+ br.in.file.handle = *handle;
+ br.in.oplock_level = level;
+
+ if (lease_break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) {
+ req = smb2_break_send(tree, &br);
+ req->async.fn = torture_oplock_break_callback;
+ req->async.private_data = NULL;
+ }
+ lease_break_info.held_oplock_level = level;
+
+ return true;
+}
+
+#define NOPLOCK_RESULTS 12
+static const char *oplock_results[NOPLOCK_RESULTS][4] = {
+ {"R", "s", "R", "s"},
+ {"R", "x", "R", "s"},
+ {"R", "b", "R", "s"},
+
+ {"RH", "s", "RH", ""},
+ {"RH", "x", "RH", ""},
+ {"RH", "b", "RH", ""},
+
+ {"RW", "s", "R", "s"},
+ {"RW", "x", "R", "s"},
+ {"RW", "b", "R", "s"},
+
+ {"RHW", "s", "RH", ""},
+ {"RHW", "x", "RH", ""},
+ {"RHW", "b", "RH", ""},
+};
+
+static const char *oplock_results_2[NOPLOCK_RESULTS][4] = {
+ {"s", "R", "s", "R"},
+ {"s", "RH", "s", "R"},
+ {"s", "RW", "s", "R"},
+ {"s", "RHW", "s", "R"},
+
+ {"x", "R", "s", "R"},
+ {"x", "RH", "s", "R"},
+ {"x", "RW", "s", "R"},
+ {"x", "RHW", "s", "R"},
+
+ {"b", "R", "s", "R"},
+ {"b", "RH", "s", "R"},
+ {"b", "RW", "s", "R"},
+ {"b", "RHW", "s", "R"},
+};
+
+static bool test_lease_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h, h2;
+ NTSTATUS status;
+ const char *fname = "lease_oplock.dat";
+ bool ret = true;
+ int i;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ for (i = 0; i < NOPLOCK_RESULTS; i++) {
+ const char *held = oplock_results[i][0];
+ const char *contend = oplock_results[i][1];
+ const char *brokento = oplock_results[i][2];
+ const char *granted = oplock_results[i][3];
+ torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
+ "expecting break to %s(%x) and grant of %s(%x)\n",
+ held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend),
+ brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted));
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, held, true, LEASE1, 0);
+
+ /* Does an oplock contend the lease? */
+ smb2_oplock_create(&io, fname, smb2_util_oplock_level(contend));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted));
+ lease_break_info.held_oplock_level = io.out.oplock_level;
+
+ if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) {
+ CHECK_BREAK_INFO(held, brokento, LEASE1);
+ } else {
+ CHECK_NO_BREAK(tctx);
+ }
+
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ for (i = 0; i < NOPLOCK_RESULTS; i++) {
+ const char *held = oplock_results_2[i][0];
+ const char *contend = oplock_results_2[i][1];
+ const char *brokento = oplock_results_2[i][2];
+ const char *granted = oplock_results_2[i][3];
+ torture_comment(tctx, "Hold %s(%x), requesting %s(%x), "
+ "expecting break to %s(%x) and grant of %s(%x)\n",
+ held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend),
+ brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted));
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab an oplock. */
+ smb2_oplock_create(&io, fname, smb2_util_oplock_level(held));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held));
+ lease_break_info.held_oplock_level = io.out.oplock_level;
+
+ /* Grab lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, granted, true, LEASE1, 0);
+
+ if (smb2_util_oplock_level(held) != smb2_util_oplock_level(brokento)) {
+ CHECK_OPLOCK_BREAK(brokento);
+ } else {
+ CHECK_NO_BREAK(tctx);
+ }
+
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_multibreak(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "lease_multibreak.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab lease, upgrade to RHW .. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE1, 0);
+
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
+
+ /* Contend with LEASE2. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE2, smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE2, 0);
+
+ /* Verify that we were only sent one break. */
+ CHECK_BREAK_INFO("RHW", "RH", LEASE1);
+
+ /* Drop LEASE1 / LEASE2 */
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_close(tree, h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_close(tree, h3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab an R lease. */
+ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "R", true, LEASE1, 0);
+
+ /* Grab a level-II oplock. */
+ smb2_oplock_create(&io, fname, smb2_util_oplock_level("s"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ lease_break_info.held_oplock_level = io.out.oplock_level;
+
+ /* Verify no breaks. */
+ CHECK_NO_BREAK(tctx);
+
+ /* Open for truncate, force a break. */
+ smb2_generic_create(&io, NULL, false, fname,
+ NTCREATEX_DISP_OVERWRITE_IF, smb2_util_oplock_level(""), 0, 0);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+ CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(""));
+ lease_break_info.held_oplock_level = io.out.oplock_level;
+
+ /* Sleep, use a write to clear the recv queue. */
+ smb_msleep(250);
+ ZERO_STRUCT(w);
+ w.in.file.handle = h3;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Verify one oplock break, one lease break. */
+ CHECK_OPLOCK_BREAK("");
+ CHECK_BREAK_INFO("R", "", LEASE1);
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_v2_request_parent(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ uint64_t parent = LEASE2;
+ NTSTATUS status;
+ const char *fname = "lease_v2_request_parent.dat";
+ bool ret = true;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+ if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
+ torture_skip(tctx, "directory leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, &parent,
+ smb2_util_lease_state("RHW"),
+ 0x11);
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1,
+ SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
+ ls.lease_epoch + 1);
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_break_twice(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h1 = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_break_twice.dat";
+ bool ret = true;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ ZERO_STRUCT(io);
+
+ smb2_lease_v2_create_share(
+ &io, &ls1, false, fname, smb2_util_share_access("RWD"),
+ LEASE1, NULL, smb2_util_lease_state("RWH"), 0x11);
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ smb2_lease_v2_create_share(
+ &io, &ls2, false, fname, smb2_util_share_access("R"),
+ LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RWH", "RW", LEASE1, ls1.lease_epoch + 2);
+
+ smb2_lease_v2_create_share(
+ &io, &ls2, false, fname, smb2_util_share_access("RWD"),
+ LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RW", "R", LEASE1, ls1.lease_epoch + 3);
+
+done:
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_v2_request(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1, ls2, ls2t, ls3, ls4;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ struct smb2_handle h4 = {{0}};
+ struct smb2_handle h5 = {{0}};
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "lease_v2_request.dat";
+ const char *dname = "lease_v2_request.dir";
+ const char *dnamefname = "lease_v2_request.dir\\lease.dat";
+ const char *dnamefname2 = "lease_v2_request.dir\\lease2.dat";
+ bool ret = true;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+ if (!(caps & SMB2_CAP_DIRECTORY_LEASING)) {
+ torture_skip(tctx, "directory leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, dname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x11);
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch + 1);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls2, true, dname,
+ smb2_util_share_access("RWD"),
+ LEASE2, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x22);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch + 1);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls3, false, dnamefname,
+ smb2_util_share_access("RWD"),
+ LEASE3, &LEASE2,
+ smb2_util_lease_state("RHW"),
+ 0x33);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE3,
+ SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET, LEASE2,
+ ls3.lease_epoch + 1);
+
+ CHECK_NO_BREAK(tctx);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls4, false, dnamefname2,
+ smb2_util_share_access("RWD"),
+ LEASE4, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x44);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h4 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE4, 0, 0, ls4.lease_epoch + 1);
+
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RH", "", LEASE2, ls2.lease_epoch + 2);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls2t, true, dname,
+ smb2_util_share_access("RWD"),
+ LEASE2, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x222);
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h5 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_DIRECTORY);
+ CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch+3);
+ smb2_util_close(tree, h5);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h4;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Wait 4 seconds in order to check if the write time
+ * was updated (after 2 seconds).
+ */
+ smb_msleep(4000);
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * only the close on the modified file break the
+ * directory lease.
+ */
+ smb2_util_close(tree, h4);
+
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RH", "", LEASE2, ls2.lease_epoch+4);
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+ smb2_util_close(tree, h4);
+ smb2_util_close(tree, h5);
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, dname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_v2_epoch1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h;
+ const char *fname = "lease_v2_epoch1.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x4711);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls.lease_epoch + 1);
+ smb2_util_close(tree, h);
+ smb2_util_unlink(tree, fname);
+
+ smb2_lease_v2_create_share(&io, &ls, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x11);
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RWH", true, LEASE1, 0, 0, ls.lease_epoch + 1);
+ smb2_util_close(tree, h);
+
+done:
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_v2_epoch2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1v2, ls1v2t, ls1v1;
+ struct smb2_handle hv2 = {}, hv1 = {};
+ const char *fname = "lease_v2_epoch2.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("R"),
+ 0x4711);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv2 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "R", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
+
+ ZERO_STRUCT(io);
+ smb2_lease_create_share(&io, &ls1v1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1v2.lease_epoch + 2);
+
+ smb2_util_close(tree, hv2);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls1v2t, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x11);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 3);
+
+ smb2_util_close(tree, hv2);
+
+ smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RWH", "RH", LEASE1, ls1v2.lease_epoch + 4);
+
+ smb2_util_close(tree, hv2);
+ smb2_util_close(tree, hv1);
+
+ ZERO_STRUCT(io);
+ smb2_lease_create_share(&io, &ls1v1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RHW", true, LEASE1, 0);
+
+ smb2_util_close(tree, hv1);
+
+done:
+ smb2_util_close(tree, hv2);
+ smb2_util_close(tree, hv1);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_v2_epoch3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1v1 = {}, ls1v1t = {},ls1v2 = {};
+ struct smb2_handle hv1 = {}, hv2 = {};
+ const char *fname = "lease_v2_epoch3.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_create_share(&io, &ls1v1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "R", true, LEASE1, 0);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RW"),
+ 0x4711);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RW", true, LEASE1, 0);
+
+ smb2_util_close(tree, hv1);
+
+ ZERO_STRUCT(io);
+ smb2_lease_create_share(&io, &ls1v1t, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ smb2_util_close(tree, hv1);
+
+ smb2_oplock_create(&io, fname, SMB2_OPLOCK_LEVEL_NONE);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+
+ smb2_util_close(tree, hv1);
+ smb2_util_close(tree, hv2);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls1v2, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RWH"),
+ 0x4711);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ hv2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1v2.lease_epoch + 1);
+ smb2_util_close(tree, hv2);
+
+done:
+ smb2_util_close(tree, hv2);
+ smb2_util_close(tree, hv1);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_breaking1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_handle h1a = {};
+ struct smb2_handle h1b = {};
+ struct smb2_handle h2 = {};
+ struct smb2_request *req2 = NULL;
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "lease_breaking1.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1a = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
+
+ /*
+ * a conflicting open is blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * we got the lease break, but defer the ack.
+ */
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ /*
+ * We ack the lease break.
+ */
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
+
+ torture_assert(tctx, req2->cancel.can_cancel,
+ "req2 can_cancel");
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_NO_BREAK(tctx);
+done:
+ smb2_util_close(tree, h1a);
+ smb2_util_close(tree, h1b);
+ smb2_util_close(tree, h2);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_breaking2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_handle h1a = {};
+ struct smb2_handle h1b = {};
+ struct smb2_handle h2 = {};
+ struct smb2_request *req2 = NULL;
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "lease_breaking2.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1a = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
+
+ /*
+ * a conflicting open is blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * we got the lease break, but defer the ack.
+ */
+ CHECK_BREAK_INFO("RWH", "", LEASE1);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ /*
+ * We ack the lease break.
+ */
+ ack.in.lease.lease_state =
+ SMB2_LEASE_READ | SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ ack.in.lease.lease_state =
+ SMB2_LEASE_READ | SMB2_LEASE_WRITE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ ack.in.lease.lease_state =
+ SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ ack.in.lease.lease_state =
+ SMB2_LEASE_READ | SMB2_LEASE_HANDLE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ ack.in.lease.lease_state = SMB2_LEASE_WRITE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ ack.in.lease.lease_state = SMB2_LEASE_HANDLE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ ack.in.lease.lease_state = SMB2_LEASE_READ;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_REQUEST_NOT_ACCEPTED);
+
+ /* Try again with the correct state this time. */
+ ack.in.lease.lease_state = SMB2_LEASE_NONE;;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
+
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+ torture_assert(tctx, req2->cancel.can_cancel,
+ "req2 can_cancel");
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_NO_BREAK(tctx);
+
+ /* Get state of the original handle. */
+ smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io1, "", true, LEASE1, 0);
+ smb2_util_close(tree, io1.out.file.handle);
+
+done:
+ smb2_util_close(tree, h1a);
+ smb2_util_close(tree, h1b);
+ smb2_util_close(tree, h2);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_breaking3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_create io3 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_handle h1a = {};
+ struct smb2_handle h1b = {};
+ struct smb2_handle h2 = {};
+ struct smb2_handle h3 = {};
+ struct smb2_request *req2 = NULL;
+ struct smb2_request *req3 = NULL;
+ struct lease_break_info lease_break_info_tmp = {};
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "lease_breaking3.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1a = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
+
+ /*
+ * a conflicting open is blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * we got the lease break, but defer the ack.
+ */
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+ smb2_util_close(tree, h1b);
+
+ /*
+ * a conflicting open with NTCREATEX_DISP_OVERWRITE
+ * doesn't trigger an immediate lease break to none.
+ */
+ lease_break_info_tmp = lease_break_info;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
+ io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ req3 = smb2_create_send(tree, &io3);
+ torture_assert(tctx, req3 != NULL, "smb2_create_send");
+ CHECK_NO_BREAK(tctx);
+ lease_break_info = lease_break_info_tmp;
+
+ torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * We ack the lease break, but defer acking the next break (to "R")
+ */
+ lease_break_info.lease_skip_ack = true;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
+
+ /*
+ * We got an additional break downgrading to just "R"
+ * while we defer the ack.
+ */
+ CHECK_BREAK_INFO("RH", "R", LEASE1);
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+ torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
+
+ /*
+ * We ack the downgrade to "R" and get an immediate break to none
+ */
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
+
+ /*
+ * We get the downgrade to none.
+ */
+ CHECK_BREAK_INFO("R", "", LEASE1);
+
+ torture_assert(tctx, req2->cancel.can_cancel,
+ "req2 can_cancel");
+ torture_assert(tctx, req3->cancel.can_cancel,
+ "req3 can_cancel");
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ status = smb2_create_recv(req3, tctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_NO_BREAK(tctx);
+done:
+ smb2_util_close(tree, h1a);
+ smb2_util_close(tree, h1b);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_v2_breaking3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_create io3 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_handle h1a = {};
+ struct smb2_handle h1b = {};
+ struct smb2_handle h2 = {};
+ struct smb2_handle h3 = {};
+ struct smb2_request *req2 = NULL;
+ struct smb2_request *req3 = NULL;
+ struct lease_break_info lease_break_info_tmp = {};
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "v2_lease_breaking3.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_v2_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x11);
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1a = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ /* Epoch increases on open. */
+ ls1.lease_epoch += 1;
+ CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
+
+ /*
+ * a conflicting open is blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * we got the lease break, but defer the ack.
+ */
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ /* On receiving a lease break, we must sync the new epoch. */
+ ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
+ smb2_util_close(tree, h1b);
+
+ /*
+ * a conflicting open with NTCREATEX_DISP_OVERWRITE
+ * doesn't trigger an immediate lease break to none.
+ */
+ lease_break_info_tmp = lease_break_info;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE);
+ io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ req3 = smb2_create_send(tree, &io3);
+ torture_assert(tctx, req3 != NULL, "smb2_create_send");
+ CHECK_NO_BREAK(tctx);
+ lease_break_info = lease_break_info_tmp;
+
+ torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io1, "RHW", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * We ack the lease break, but defer acking the next break (to "R")
+ */
+ lease_break_info.lease_skip_ack = true;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
+
+ /*
+ * We got an additional break downgrading to just "R"
+ * while we defer the ack.
+ */
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RH", "R", LEASE1, ls1.lease_epoch);
+ /* On receiving a lease break, we must sync the new epoch. */
+ ls1.lease_epoch = lease_break_info.lease_break.new_epoch;
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io1, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS, 0, ls1.lease_epoch);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+ torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending");
+
+ /*
+ * We ack the downgrade to "R" and get an immediate break to none
+ */
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "R", LEASE1);
+
+ /*
+ * We get the downgrade to none.
+ */
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "R", "", LEASE1, ls1.lease_epoch);
+
+ torture_assert(tctx, req2->cancel.can_cancel,
+ "req2 can_cancel");
+ torture_assert(tctx, req3->cancel.can_cancel,
+ "req3 can_cancel");
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ status = smb2_create_recv(req3, tctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io3.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_NO_BREAK(tctx);
+done:
+ smb2_util_close(tree, h1a);
+ smb2_util_close(tree, h1b);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+static bool test_lease_breaking4(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_create io3 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_lease ls1t = {};
+ struct smb2_handle h1 = {};
+ struct smb2_handle h2 = {};
+ struct smb2_handle h3 = {};
+ struct smb2_request *req2 = NULL;
+ struct lease_break_info lease_break_info_tmp = {};
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "lease_breaking4.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * a conflicting open is *not* blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * We got a break from RH to NONE, we're supported to ack
+ * this downgrade
+ */
+ CHECK_BREAK_INFO("RH", "", LEASE1);
+
+ lease_break_info_tmp = lease_break_info;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+ smb2_util_close(tree, h2);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * a conflicting open is *not* blocked until we ack the
+ * lease break, even if the lease is in breaking state.
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+ smb2_util_close(tree, h2);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * We now ask the server about the current lease state
+ * which should still be "RH", but with
+ * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
+ */
+ smb2_lease_create_share(&io3, &ls1t, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state(""));
+ status = smb2_create(tree, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "RH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+
+ /*
+ * We finally ack the lease break...
+ */
+ CHECK_NO_BREAK(tctx);
+ lease_break_info = lease_break_info_tmp;
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
+
+ CHECK_NO_BREAK(tctx);
+
+done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_breaking5(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_create io3 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_lease ls1t = {};
+ struct smb2_handle h1 = {};
+ struct smb2_handle h2 = {};
+ struct smb2_handle h3 = {};
+ struct smb2_request *req2 = NULL;
+ struct lease_break_info lease_break_info_tmp = {};
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "lease_breaking5.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "R", true, LEASE1, 0);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * a conflicting open is *not* blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ io2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * We got a break from RH to NONE, we're supported to ack
+ * this downgrade
+ */
+ CHECK_BREAK_INFO("R", "", LEASE1);
+
+ lease_break_info_tmp = lease_break_info;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done");
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_NO_BREAK(tctx);
+
+ /*
+ * We now ask the server about the current lease state
+ * which should still be "RH", but with
+ * SMB2_LEASE_FLAG_BREAK_IN_PROGRESS.
+ */
+ smb2_lease_create_share(&io3, &ls1t, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state(""));
+ status = smb2_create(tree, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "", true, LEASE1, 0);
+
+ /*
+ * We send an ack without without being asked.
+ */
+ CHECK_NO_BREAK(tctx);
+ lease_break_info = lease_break_info_tmp;
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+ CHECK_NO_BREAK(tctx);
+
+done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_breaking6(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_handle h1a = {};
+ struct smb2_handle h1b = {};
+ struct smb2_handle h2 = {};
+ struct smb2_request *req2 = NULL;
+ struct smb2_lease_break_ack ack = {};
+ const char *fname = "lease_breaking6.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1a = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
+
+ /*
+ * a conflicting open is blocked until we ack the
+ * lease break
+ */
+ smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
+ req2 = smb2_create_send(tree, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ /*
+ * we got the lease break, but defer the ack.
+ */
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * a open using the same lease key is still works,
+ * but reports SMB2_LEASE_FLAG_BREAK_IN_PROGRESS
+ */
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1b = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, SMB2_LEASE_FLAG_BREAK_IN_PROGRESS);
+ smb2_util_close(tree, h1b);
+
+ CHECK_NO_BREAK(tctx);
+
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ /*
+ * We are asked to break to "RH", but we are allowed to
+ * break to any of "RH", "R" or NONE.
+ */
+ ack.in.lease.lease_state = SMB2_LEASE_NONE;
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "", LEASE1);
+
+ torture_assert(tctx, req2->cancel.can_cancel,
+ "req2 can_cancel");
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+ CHECK_NO_BREAK(tctx);
+done:
+ smb2_util_close(tree, h1a);
+ smb2_util_close(tree, h1b);
+ smb2_util_close(tree, h2);
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_lock1(struct torture_context *tctx,
+ struct smb2_tree *tree1a,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1 = {};
+ struct smb2_create io2 = {};
+ struct smb2_create io3 = {};
+ struct smb2_lease ls1 = {};
+ struct smb2_lease ls2 = {};
+ struct smb2_lease ls3 = {};
+ struct smb2_handle h1 = {};
+ struct smb2_handle h2 = {};
+ struct smb2_handle h3 = {};
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ const char *fname = "locktest.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+ struct smbcli_options options1;
+ struct smb2_tree *tree1b = NULL;
+
+ options1 = tree1a->session->transport->options;
+
+ caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Set up handlers. */
+ tree2->session->transport->lease.handler = torture_lease_handler;
+ tree2->session->transport->lease.private_data = tree2;
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ tree1a->session->transport->lease.handler = torture_lease_handler;
+ tree1a->session->transport->lease.private_data = tree1a;
+ tree1a->session->transport->oplock.handler = torture_oplock_handler;
+ tree1a->session->transport->oplock.private_data = tree1a;
+
+ /* create a new connection (same client_guid) */
+ if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ tree1b->session->transport->lease.handler = torture_lease_handler;
+ tree1b->session->transport->lease.private_data = tree1b;
+ tree1b->session->transport->oplock.handler = torture_oplock_handler;
+ tree1b->session->transport->oplock.private_data = tree1b;
+
+ smb2_util_unlink(tree1a, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ ZERO_STRUCT(lck);
+
+ /* Open a handle on tree1a. */
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree1a, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RWH", true, LEASE1, 0);
+
+ /* Open a second handle on tree1b. */
+ smb2_lease_create_share(&io2, &ls2, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE2,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree1b, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
+ /* And LEASE1 got broken to RH. */
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Now open a lease on a different client guid. */
+ smb2_lease_create_share(&io3, &ls3, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE3,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree2, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "RH", true, LEASE3, 0);
+ /* Doesn't break. */
+ CHECK_NO_BREAK(tctx);
+
+ lck.in.locks = el;
+ /*
+ * Try and get get an exclusive byte
+ * range lock on H1 (LEASE1).
+ */
+
+ lck.in.lock_count = 1;
+ lck.in.lock_sequence = 1;
+ lck.in.file.handle = h1;
+ el[0].offset = 0;
+ el[0].length = 1;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree1a, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* LEASE2 and LEASE3 should get broken to NONE. */
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+
+ CHECK_VAL(lease_break_info.failures, 0); \
+ CHECK_VAL(lease_break_info.count, 2); \
+
+ /* Get state of the H1 (LEASE1) */
+ smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
+ status = smb2_create(tree1a, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ /* Should still be RH. */
+ CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
+ smb2_util_close(tree1a, io1.out.file.handle);
+
+ /* Get state of the H2 (LEASE2) */
+ smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state(""));
+ status = smb2_create(tree1b, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io2, "", true, LEASE2, 0);
+ smb2_util_close(tree1b, io2.out.file.handle);
+
+ /* Get state of the H3 (LEASE3) */
+ smb2_lease_create(&io3, &ls3, false, fname, LEASE3, smb2_util_lease_state(""));
+ status = smb2_create(tree2, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io3, "", true, LEASE3, 0);
+ smb2_util_close(tree2, io3.out.file.handle);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * Try and get get an exclusive byte
+ * range lock on H3 (LEASE3).
+ */
+ lck.in.lock_count = 1;
+ lck.in.lock_sequence = 2;
+ lck.in.file.handle = h3;
+ el[0].offset = 100;
+ el[0].length = 1;
+ el[0].reserved = 0;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree2, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ /* LEASE1 got broken to NONE. */
+ CHECK_BREAK_INFO("RH", "", LEASE1);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+done:
+ smb2_util_close(tree1a, h1);
+ smb2_util_close(tree1b, h2);
+ smb2_util_close(tree2, h3);
+
+ smb2_util_unlink(tree1a, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_complex1(struct torture_context *tctx,
+ struct smb2_tree *tree1a)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "lease_complex1.dat";
+ bool ret = true;
+ uint32_t caps;
+ struct smb2_tree *tree1b = NULL;
+ struct smbcli_options options1;
+
+ options1 = tree1a->session->transport->options;
+
+ caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ tree1a->session->transport->lease.handler = torture_lease_handler;
+ tree1a->session->transport->lease.private_data = tree1a;
+ tree1a->session->transport->oplock.handler = torture_oplock_handler;
+ tree1a->session->transport->oplock.private_data = tree1a;
+
+ /* create a new connection (same client_guid) */
+ if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ tree1b->session->transport->lease.handler = torture_lease_handler;
+ tree1b->session->transport->lease.private_data = tree1b;
+ tree1b->session->transport->oplock.handler = torture_oplock_handler;
+ tree1b->session->transport->oplock.private_data = tree1b;
+
+ smb2_util_unlink(tree1a, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab R lease over connection 1a */
+ smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
+ status = smb2_create(tree1a, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "R", true, LEASE1, 0);
+
+ /* Upgrade to RWH over connection 1b */
+ ls1.lease_state = smb2_util_lease_state("RWH");
+ status = smb2_create(tree1b, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
+
+ /* close over connection 1b */
+ status = smb2_util_close(tree1b, h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Contend with LEASE2. */
+ smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
+ status = smb2_create(tree1b, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "R", true, LEASE2, 0);
+
+ /* Verify that we were only sent one break. */
+ CHECK_BREAK_INFO("RHW", "RH", LEASE1);
+
+ /* again RH over connection 1b doesn't change the epoch */
+ ls1.lease_state = smb2_util_lease_state("RH");
+ status = smb2_create(tree1b, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
+
+ /* close over connection 1b */
+ status = smb2_util_close(tree1b, h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree1a, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls2.lease_epoch += 1;
+ CHECK_BREAK_INFO("R", "", LEASE2);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h3;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree1b, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls1.lease_epoch += 1;
+ CHECK_BREAK_INFO("RH", "", LEASE1);
+
+ done:
+ smb2_util_close(tree1a, h);
+ smb2_util_close(tree1b, h2);
+ smb2_util_close(tree1b, h3);
+
+ smb2_util_unlink(tree1a, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_v2_complex1(struct torture_context *tctx,
+ struct smb2_tree *tree1a)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "lease_v2_complex1.dat";
+ bool ret = true;
+ uint32_t caps;
+ enum protocol_types protocol;
+ struct smb2_tree *tree1b = NULL;
+ struct smbcli_options options1;
+
+ options1 = tree1a->session->transport->options;
+
+ caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ tree1a->session->transport->lease.handler = torture_lease_handler;
+ tree1a->session->transport->lease.private_data = tree1a;
+ tree1a->session->transport->oplock.handler = torture_oplock_handler;
+ tree1a->session->transport->oplock.private_data = tree1a;
+
+ /* create a new connection (same client_guid) */
+ if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ tree1b->session->transport->lease.handler = torture_lease_handler;
+ tree1b->session->transport->lease.private_data = tree1b;
+ tree1b->session->transport->oplock.handler = torture_oplock_handler;
+ tree1b->session->transport->oplock.private_data = tree1b;
+
+ smb2_util_unlink(tree1a, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab R lease over connection 1a */
+ smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
+ smb2_util_lease_state("R"), 0x4711);
+ status = smb2_create(tree1a, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ ls1.lease_epoch += 1;
+ CHECK_LEASE_V2(&io1, "R", true, LEASE1,
+ 0, 0, ls1.lease_epoch);
+
+ /* Upgrade to RWH over connection 1b */
+ ls1.lease_state = smb2_util_lease_state("RWH");
+ status = smb2_create(tree1b, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ ls1.lease_epoch += 1;
+ CHECK_LEASE_V2(&io1, "RHW", true, LEASE1,
+ 0, 0, ls1.lease_epoch);
+
+ /* close over connection 1b */
+ status = smb2_util_close(tree1b, h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Contend with LEASE2. */
+ smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
+ smb2_util_lease_state("R"), 0x11);
+ status = smb2_create(tree1b, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ ls2.lease_epoch += 1;
+ CHECK_LEASE_V2(&io2, "R", true, LEASE2,
+ 0, 0, ls2.lease_epoch);
+
+ /* Verify that we were only sent one break. */
+ ls1.lease_epoch += 1;
+ CHECK_BREAK_INFO_V2(tree1a->session->transport,
+ "RHW", "RH", LEASE1, ls1.lease_epoch);
+
+ /* again RH over connection 1b doesn't change the epoch */
+ ls1.lease_state = smb2_util_lease_state("RH");
+ status = smb2_create(tree1b, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io1, "RH", true, LEASE1,
+ 0, 0, ls1.lease_epoch);
+
+ /* close over connection 1b */
+ status = smb2_util_close(tree1b, h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree1a, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls2.lease_epoch += 1;
+ CHECK_BREAK_INFO_V2(tree1a->session->transport,
+ "R", "", LEASE2, ls2.lease_epoch);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h3;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree1b, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls1.lease_epoch += 1;
+ CHECK_BREAK_INFO_V2(tree1a->session->transport,
+ "RH", "", LEASE1, ls1.lease_epoch);
+
+ done:
+ smb2_util_close(tree1a, h);
+ smb2_util_close(tree1b, h2);
+ smb2_util_close(tree1b, h3);
+
+ smb2_util_unlink(tree1a, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_v2_complex2(struct torture_context *tctx,
+ struct smb2_tree *tree1a)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_request *req2 = NULL;
+ struct smb2_lease_break_ack ack = {};
+ NTSTATUS status;
+ const char *fname = "lease_v2_complex2.dat";
+ bool ret = true;
+ uint32_t caps;
+ enum protocol_types protocol;
+ struct smb2_tree *tree1b = NULL;
+ struct smbcli_options options1;
+
+ options1 = tree1a->session->transport->options;
+
+ caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree1a->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ tree1a->session->transport->lease.handler = torture_lease_handler;
+ tree1a->session->transport->lease.private_data = tree1a;
+ tree1a->session->transport->oplock.handler = torture_oplock_handler;
+ tree1a->session->transport->oplock.private_data = tree1a;
+
+ /* create a new connection (same client_guid) */
+ if (!torture_smb2_connection_ext(tctx, 0, &options1, &tree1b)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ tree1b->session->transport->lease.handler = torture_lease_handler;
+ tree1b->session->transport->lease.private_data = tree1b;
+ tree1b->session->transport->oplock.handler = torture_oplock_handler;
+ tree1b->session->transport->oplock.private_data = tree1b;
+
+ smb2_util_unlink(tree1a, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab RWH lease over connection 1a */
+ smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
+ smb2_util_lease_state("RWH"), 0x4711);
+ status = smb2_create(tree1a, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ ls1.lease_epoch += 1;
+ CHECK_LEASE_V2(&io1, "RWH", true, LEASE1,
+ 0, 0, ls1.lease_epoch);
+
+ /*
+ * we defer acking the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ /* Ask for RWH on connection 1b, different lease. */
+ smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
+ smb2_util_lease_state("RWH"), 0x11);
+ req2 = smb2_create_send(tree1b, &io2);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+
+ ls1.lease_epoch += 1;
+
+ CHECK_BREAK_INFO_V2(tree1a->session->transport,
+ "RWH", "RH", LEASE1, ls1.lease_epoch);
+
+ /* Send the break ACK on tree1b. */
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ;
+
+ status = smb2_lease_break_ack(tree1b, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ status = smb2_create_recv(req2, tctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io2, "RH", true, LEASE2,
+ 0, 0, ls2.lease_epoch+1);
+ h2 = io2.out.file.handle;
+
+ done:
+ smb2_util_close(tree1a, h);
+ smb2_util_close(tree1b, h2);
+
+ smb2_util_unlink(tree1a, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+static bool test_lease_timeout(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle hnew = {{0}};
+ struct smb2_handle h1b = {{0}};
+ NTSTATUS status;
+ const char *fname = "lease_timeout.dat";
+ bool ret = true;
+ struct smb2_lease_break_ack ack = {};
+ struct smb2_request *req2 = NULL;
+ struct smb2_write w;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ /* Grab a RWH lease. */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+ h = io.out.file.handle;
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ * Just don't ack the lease break.
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ /* Break with a RWH request. */
+ smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH"));
+ req2 = smb2_create_send(tree, &io);
+ torture_assert(tctx, req2 != NULL, "smb2_create_send");
+ torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending");
+
+ CHECK_BREAK_INFO("RWH", "RH", LEASE1);
+
+ /* Copy the break request. */
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+
+ /* Now wait for the timeout and get the reply. */
+ status = smb2_create_recv(req2, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE2, 0);
+ hnew = io.out.file.handle;
+
+ /* Ack the break after the timeout... */
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+
+ /* Get state of the original handle. */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state(""));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io, "", true, LEASE1, 0);
+ smb2_util_close(tree, io.out.file.handle);
+
+ /* Write on the original handle and make sure it's still valid. */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ ZERO_STRUCT(w);
+ w.in.file.handle = h;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, '1', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Causes new handle to break to NONE. */
+ CHECK_BREAK_INFO("RH", "", LEASE2);
+
+ /* Write on the new handle. */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ ZERO_STRUCT(w);
+ w.in.file.handle = hnew;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
+ memset(w.in.data.data, '2', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ /* No break - original handle was already NONE. */
+ CHECK_NO_BREAK(tctx);
+ smb2_util_close(tree, hnew);
+
+ /* Upgrade to R on LEASE1. */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io, "R", true, LEASE1, 0);
+ h1b = io.out.file.handle;
+ smb2_util_close(tree, h1b);
+
+ /* Upgrade to RWH on LEASE1. */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+ h1b = io.out.file.handle;
+ smb2_util_close(tree, h1b);
+
+ done:
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, hnew);
+ smb2_util_close(tree, h1b);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_rename_wait(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_lease ls3;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ union smb_setfileinfo sinfo;
+ NTSTATUS status;
+ const char *fname_src = "lease_rename_src.dat";
+ const char *fname_dst = "lease_rename_dst.dat";
+ bool ret = true;
+ struct smb2_lease_break_ack ack = {};
+ struct smb2_request *rename_req = NULL;
+ uint32_t caps;
+ unsigned int i;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname_src);
+ smb2_util_unlink(tree, fname_dst);
+
+ /* Short timeout for fails. */
+ tree->session->transport->options.request_timeout = 15;
+
+ /* Grab a RH lease. */
+ smb2_lease_create(&io,
+ &ls1,
+ false,
+ fname_src,
+ LEASE1,
+ smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE1, 0);
+ h1 = io.out.file.handle;
+
+ /* Second open with a RH lease. */
+ smb2_lease_create(&io,
+ &ls2,
+ false,
+ fname_src,
+ LEASE2,
+ smb2_util_lease_state("RH"));
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = GENERIC_READ_ACCESS;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE2, 0);
+ h2 = io.out.file.handle;
+
+ /*
+ * Don't ack a lease break.
+ */
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ /* Break with a rename. */
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.new_name = fname_dst;
+ rename_req = smb2_setinfo_file_send(tree, &sinfo);
+
+ torture_assert(tctx,
+ rename_req != NULL,
+ "smb2_setinfo_file_send");
+ torture_assert(tctx,
+ rename_req->state == SMB2_REQUEST_RECV,
+ "rename pending");
+
+ /* Try and open the destination with a RH lease. */
+ smb2_lease_create(&io,
+ &ls3,
+ false,
+ fname_dst,
+ LEASE3,
+ smb2_util_lease_state("RH"));
+ /* We want to open, not create. */
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = GENERIC_READ_ACCESS;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * The smb2_create() I/O should have picked up the break request
+ * caused by the pending rename.
+ */
+
+ /* Copy the break request. */
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+
+ /*
+ * Give the server 3 more chances to have renamed
+ * the file. Better than doing a sleep.
+ */
+ for (i = 0; i < 3; i++) {
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ }
+
+ /* Ack the break. The server is now free to rename. */
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Get the rename reply. */
+ status = smb2_setinfo_recv(rename_req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* The target should now exist. */
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname_src);
+ smb2_util_unlink(tree, fname_dst);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_v2_rename(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ union smb_setfileinfo sinfo;
+ const char *fname = "lease_v2_rename_src.dat";
+ const char *fname_dst = "lease_v2_rename_dst.dat";
+ bool ret = true;
+ NTSTATUS status;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname_dst);
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(io);
+ smb2_lease_v2_create_share(&io, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x4711);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ ls1.lease_epoch += 1;
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
+
+ /* Now rename - what happens ? */
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.new_name = fname_dst;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* No lease break. */
+ CHECK_NO_BREAK(tctx);
+
+ /* Check we can open another handle on the new name. */
+ smb2_lease_v2_create_share(&io, &ls1, false, fname_dst,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state(""),
+ ls1.lease_epoch);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RHW", true, LEASE1, 0, 0, ls1.lease_epoch);
+ smb2_util_close(tree, h1);
+
+ /* Try another lease key. */
+ smb2_lease_v2_create_share(&io, &ls2, false, fname_dst,
+ smb2_util_share_access("RWD"),
+ LEASE2, NULL,
+ smb2_util_lease_state("RWH"),
+ 0x44);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ ls2.lease_epoch += 1;
+ CHECK_LEASE_V2(&io, "RH", true, LEASE2, 0, 0, ls2.lease_epoch );
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RWH", "RH", LEASE1, ls1.lease_epoch + 1);
+ ls1.lease_epoch += 1;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Now rename back. */
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.new_name = fname;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Breaks to R on LEASE2. */
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "RH", "R", LEASE2, ls2.lease_epoch + 1);
+ ls2.lease_epoch += 1;
+
+ /* Check we can open another handle on the current name. */
+ smb2_lease_v2_create_share(&io, &ls1, false, fname,
+ smb2_util_share_access("RWD"),
+ LEASE1, NULL,
+ smb2_util_lease_state(""),
+ ls1.lease_epoch);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io, "RH", true, LEASE1, 0, 0, ls1.lease_epoch);
+ smb2_util_close(tree, h1);
+
+done:
+
+ smb2_util_close(tree, h);
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname_dst);
+
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+static bool test_lease_dynamic_share(struct torture_context *tctx,
+ struct smb2_tree *tree1a)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1;
+ struct smb2_handle h, h1, h2;
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "dynamic_path.dat";
+ bool ret = true;
+ uint32_t caps;
+ struct smb2_tree *tree_2 = NULL;
+ struct smb2_tree *tree_3 = NULL;
+ struct smbcli_options options;
+ const char *orig_share = NULL;
+
+ if (!TARGET_IS_SAMBA3(tctx)) {
+ torture_skip(tctx, "dynamic shares are not supported");
+ return true;
+ }
+
+ options = tree1a->session->transport->options;
+ options.client_guid = GUID_random();
+
+ caps = smb2cli_conn_server_capabilities(tree1a->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /*
+ * Save off original share name and change it to dynamic_share.
+ * This must have been pre-created with a dynamic path containing
+ * %t. It means we'll sleep between the connects in order to
+ * get a different timestamp for the share path.
+ */
+
+ orig_share = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "share");
+ orig_share = talloc_strdup(tctx->lp_ctx, orig_share);
+ if (orig_share == NULL) {
+ torture_result(tctx, TORTURE_FAIL, __location__ "no memory\n");
+ ret = false;
+ goto done;
+ }
+ lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", "dynamic_share");
+
+ /* create a new connection (same client_guid) */
+ sleep(2);
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree_2)) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ "couldn't reconnect "
+ "max protocol 2.1, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ tree_2->session->transport->lease.handler = torture_lease_handler;
+ tree_2->session->transport->lease.private_data = tree_2;
+ tree_2->session->transport->oplock.handler = torture_oplock_handler;
+ tree_2->session->transport->oplock.private_data = tree_2;
+
+ smb2_util_unlink(tree_2, fname);
+
+ /* create a new connection (same client_guid) */
+ sleep(2);
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree_3)) {
+ torture_result(tctx, TORTURE_FAIL,
+ __location__ "couldn't reconnect "
+ "max protocol 3.0, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ tree_3->session->transport->lease.handler = torture_lease_handler;
+ tree_3->session->transport->lease.private_data = tree_3;
+ tree_3->session->transport->oplock.handler = torture_oplock_handler;
+ tree_3->session->transport->oplock.private_data = tree_3;
+
+ smb2_util_unlink(tree_3, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Get RWH lease over connection 2 */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree_2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+ h = io.out.file.handle;
+
+ /* Write some data into it. */
+ w.in.file.handle = h;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, '1', w.in.data.length);
+ status = smb2_write(tree_2, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Open the same name over connection 3. */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree_3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ /* h1 should have replied with NONE. */
+ CHECK_LEASE(&io, "", true, LEASE1, 0);
+
+ /* We should have broken h to NONE. */
+ CHECK_BREAK_INFO("RWH", "", LEASE1);
+
+ /* Try to upgrade to RWH over connection 2 */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree_2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_VAL(io.out.size, 4096);
+ CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
+ /* Should have been denied. */
+ CHECK_LEASE(&io, "", true, LEASE1, 0);
+ smb2_util_close(tree_2, h2);
+
+ /* Try to upgrade to RWH over connection 3 */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree_3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_VAL(io.out.size, 0);
+ CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
+ /* Should have been denied. */
+ CHECK_LEASE(&io, "", true, LEASE1, 0);
+ smb2_util_close(tree_3, h2);
+
+ /* Write some data into it. */
+ w.in.file.handle = h1;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 1024);
+ memset(w.in.data.data, '2', w.in.data.length);
+ status = smb2_write(tree_3, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Close everything.. */
+ smb2_util_close(tree_2, h);
+ smb2_util_close(tree_3, h1);
+
+ /* And ensure we can get a lease ! */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree_2, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+ h = io.out.file.handle;
+ /* And the file is the right size. */
+ CHECK_VAL(io.out.size, 4096); \
+ /* Close it. */
+ smb2_util_close(tree_2, h);
+
+ /* And ensure we can get a lease ! */
+ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH"));
+ status = smb2_create(tree_3, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(io.out.create_action, NTCREATEX_ACTION_EXISTED);
+ CHECK_VAL(io.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+ h = io.out.file.handle;
+ /* And the file is the right size. */
+ CHECK_VAL(io.out.size, 1024); \
+ /* Close it. */
+ smb2_util_close(tree_3, h);
+
+ done:
+
+ if (tree_2 != NULL) {
+ smb2_util_close(tree_2, h);
+ smb2_util_unlink(tree_2, fname);
+ }
+ if (tree_3 != NULL) {
+ smb2_util_close(tree_3, h1);
+ smb2_util_close(tree_3, h2);
+
+ smb2_util_unlink(tree_3, fname);
+ }
+
+ /* Set sharename back. */
+ lpcfg_set_cmdline(tctx->lp_ctx, "torture:share", orig_share);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Test identifies a bug where the Samba server will not trigger a lease break
+ * for a handle caching lease held by a client when the underlying file is
+ * deleted.
+ * Test:
+ * Connect session2.
+ * open file in session1
+ * session1 should have RWH lease.
+ * open file in session2
+ * lease break sent to session1 to downgrade lease to RH
+ * close file in session 2
+ * unlink file in session 2
+ * lease break sent to session1 to downgrade lease to R
+ * Cleanup
+ */
+static bool test_lease_unlink(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ bool ret = true;
+ struct smbcli_options transport2_options;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2;
+ struct smb2_handle h1 = {{ 0 }};
+ struct smb2_handle h2 = {{ 0 }};
+ const char *fname = "lease_unlink.dat";
+ uint32_t caps;
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Connect 2nd connection */
+ transport2_options = transport1->options;
+ transport2_options.client_guid = GUID_random();
+ if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ return false;
+ }
+ transport2 = tree2->session->transport;
+
+ /* Set lease handlers */
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ transport2->lease.handler = torture_lease_handler;
+ transport2->lease.private_data = tree2;
+
+
+ smb2_lease_create(&io1, &ls1, false, fname, LEASE1,
+ smb2_util_lease_state("RHW"));
+ smb2_lease_create(&io2, &ls2, false, fname, LEASE2,
+ smb2_util_lease_state("RHW"));
+
+ smb2_util_unlink(tree1, fname);
+
+ torture_comment(tctx, "Client opens fname with session 1\n");
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RHW", true, LEASE1, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_comment(tctx, "Client opens fname with session 2\n");
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ status = smb2_create(tree2, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "RH", true, LEASE2, 0);
+ CHECK_VAL(lease_break_info.count, 1);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE1);
+
+ torture_comment(tctx,
+ "Client closes and then unlinks fname with session 2\n");
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ smb2_util_close(tree2, h2);
+ smb2_util_unlink(tree2, fname);
+ CHECK_VAL(lease_break_info.count, 1);
+ CHECK_BREAK_INFO("RH", "R", LEASE1);
+
+done:
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_unlink(tree1, fname);
+
+ return ret;
+}
+
+static bool test_lease_timeout_disconnect(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ bool ret = true;
+ struct smbcli_options transport2_options;
+ struct smbcli_options transport3_options;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_tree *tree3 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2;
+ struct smb2_transport *transport3;
+ const char *fname = "lease_timeout_logoff.dat" ;
+ uint32_t caps;
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_request *req2 = NULL;
+ struct smb2_lease ls1;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree1, fname);
+
+ /* Connect 2nd connection */
+ torture_comment(tctx, "connect tree2 with the same client_guid\n");
+ transport2_options = transport1->options;
+ if (!torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ return false;
+ }
+ transport2 = tree2->session->transport;
+
+ /* Connect 3rd connection */
+ torture_comment(tctx, "connect tree3 with the same client_guid\n");
+ transport3_options = transport1->options;
+ if (!torture_smb2_connection_ext(tctx, 0, &transport3_options, &tree3)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ return false;
+ }
+ transport3 = tree3->session->transport;
+
+ /* Set lease handlers */
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ transport2->lease.handler = torture_lease_handler;
+ transport2->lease.private_data = tree2;
+ transport3->lease.handler = torture_lease_handler;
+ transport3->lease.private_data = tree3;
+
+ smb2_lease_create_share(&io1, &ls1, false, fname,
+ smb2_util_share_access(""),
+ LEASE1,
+ smb2_util_lease_state("RH"));
+ io1.in.durable_open = true;
+ smb2_generic_create(&io2, NULL, false, fname,
+ NTCREATEX_DISP_OPEN_IF,
+ SMB2_OPLOCK_LEVEL_NONE, 0, 0);
+
+ torture_comment(tctx, "tree1: create file[%s] with durable RH lease (SHARE NONE)\n", fname);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_comment(tctx, "tree1: skip lease acks\n");
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ torture_comment(tctx, "tree2: open file[%s] without lease (SHARE RWD)\n", fname);
+ req2 = smb2_create_send(tree2, &io2);
+ torture_assert(tctx, req2 != NULL, "req2 started");
+
+ torture_comment(tctx, "tree1: wait for lease break\n");
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(lease_break_info.count, 1);
+ CHECK_BREAK_INFO("RH", "R", LEASE1);
+
+ torture_comment(tctx, "tree1: reset lease handler\n");
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
+ torture_assert_int_equal(tctx, req2->state,
+ SMB2_REQUEST_RECV,
+ "SMB2_REQUEST_RECV");
+
+ torture_comment(tctx, "sleep 1\n");
+ smb_msleep(1000);
+
+ torture_comment(tctx, "transport1: keepalive\n");
+ status = smb2_keepalive(transport1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "transport2: keepalive\n");
+ status = smb2_keepalive(transport2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "transport3: keepalive\n");
+ status = smb2_keepalive(transport3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "tree2: check for SMB2_REQUEST_RECV\n");
+ torture_assert_int_equal(tctx, req2->state,
+ SMB2_REQUEST_RECV,
+ "SMB2_REQUEST_RECV");
+ torture_comment(tctx, "tree2: check for STATUS_PENDING\n");
+ torture_assert(tctx, req2->cancel.can_cancel, "STATUS_PENDING");
+
+ torture_comment(tctx, "sleep 1\n");
+ smb_msleep(1000);
+ torture_comment(tctx, "transport1: keepalive\n");
+ status = smb2_keepalive(transport1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_comment(tctx, "transport2: disconnect\n");
+ TALLOC_FREE(tree2);
+
+ torture_comment(tctx, "sleep 1\n");
+ smb_msleep(1000);
+ torture_comment(tctx, "transport1: keepalive\n");
+ status = smb2_keepalive(transport1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_comment(tctx, "transport1: disconnect\n");
+ TALLOC_FREE(tree1);
+
+ torture_comment(tctx, "sleep 1\n");
+ smb_msleep(1000);
+ torture_comment(tctx, "transport3: keepalive\n");
+ status = smb2_keepalive(transport3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_comment(tctx, "transport3: disconnect\n");
+ TALLOC_FREE(tree3);
+
+done:
+
+ return ret;
+}
+
+static bool test_lease_duplicate_create(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname1 = "duplicate_create1.dat";
+ const char *fname2 = "duplicate_create2.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Ensure files don't exist. */
+ smb2_util_unlink(tree, fname1);
+ smb2_util_unlink(tree, fname2);
+
+ /* Create file1 - LEASE1 key. */
+ smb2_lease_create(&io, &ls, false, fname1, LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ /*
+ * Create file2 with the same LEASE1 key - this should fail with.
+ * INVALID_PARAMETER.
+ */
+ smb2_lease_create(&io, &ls, false, fname2, LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ smb2_util_close(tree, h1);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname1);
+ smb2_util_unlink(tree, fname2);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_duplicate_open(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname1 = "duplicate_open1.dat";
+ const char *fname2 = "duplicate_open2.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ /* Ensure files don't exist. */
+ smb2_util_unlink(tree, fname1);
+ smb2_util_unlink(tree, fname2);
+
+ /* Create file1 - LEASE1 key. */
+ smb2_lease_create(&io, &ls, false, fname1, LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RWH", true, LEASE1, 0);
+
+ /* Leave file1 open and leased. */
+
+ /* Create file2 - no lease. */
+ smb2_lease_create(&io, NULL, false, fname2, 0,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ /* Close it. */
+ smb2_util_close(tree, h2);
+
+ /*
+ * Try and open file2 with the same LEASE1 key - this should fail with.
+ * INVALID_PARAMETER.
+ */
+ smb2_lease_create(&io, &ls, false, fname2, LEASE1,
+ smb2_util_lease_state("RWH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ /*
+ * If we did open this is an error, but save off
+ * the handle so we close below.
+ */
+ h2 = io.out.file.handle;
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname1);
+ smb2_util_unlink(tree, fname2);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_lease_v1_bug_15148(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "lease_v1_bug_15148.dat";
+ bool ret = true;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab R lease over connection 1a */
+ smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "R", true, LEASE1, 0);
+
+ CHECK_NO_BREAK(tctx);
+
+ /* Contend with LEASE2. */
+ smb2_lease_create(&io2, &ls2, false, fname, LEASE2, smb2_util_lease_state("R"));
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "R", true, LEASE2, 0);
+
+ CHECK_NO_BREAK(tctx);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h1;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls2.lease_epoch += 1;
+ CHECK_BREAK_INFO("R", "", LEASE2);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h1;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'O', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_NO_BREAK(tctx);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h2;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls1.lease_epoch += 1;
+ CHECK_BREAK_INFO("R", "", LEASE1);
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_lease_v2_bug_15148(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io1;
+ struct smb2_create io2;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_write w;
+ NTSTATUS status;
+ const char *fname = "lease_v2_bug_15148.dat";
+ bool ret = true;
+ uint32_t caps;
+ enum protocol_types protocol;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ protocol = smbXcli_conn_protocol(tree->session->transport->conn);
+ if (protocol < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "v2 leases are not supported");
+ }
+
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Grab R lease over connection 1a */
+ smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL,
+ smb2_util_lease_state("R"), 0x4711);
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ ls1.lease_epoch += 1;
+ CHECK_LEASE_V2(&io1, "R", true, LEASE1,
+ 0, 0, ls1.lease_epoch);
+
+ CHECK_NO_BREAK(tctx);
+
+ /* Contend with LEASE2. */
+ smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL,
+ smb2_util_lease_state("R"), 0x11);
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ ls2.lease_epoch += 1;
+ CHECK_LEASE_V2(&io2, "R", true, LEASE2,
+ 0, 0, ls2.lease_epoch);
+
+ CHECK_NO_BREAK(tctx);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h1;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls2.lease_epoch += 1;
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "R", "", LEASE2, ls2.lease_epoch);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h1;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'O', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_NO_BREAK(tctx);
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = h2;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(mem_ctx, NULL, 4096);
+ memset(w.in.data.data, 'o', w.in.data.length);
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ls1.lease_epoch += 1;
+ CHECK_BREAK_INFO_V2(tree->session->transport,
+ "R", "", LEASE1, ls1.lease_epoch);
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_lease_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "lease");
+
+ torture_suite_add_1smb2_test(suite, "request", test_lease_request);
+ torture_suite_add_1smb2_test(suite, "break_twice",
+ test_lease_break_twice);
+ torture_suite_add_1smb2_test(suite, "nobreakself",
+ test_lease_nobreakself);
+ torture_suite_add_1smb2_test(suite, "statopen", test_lease_statopen);
+ torture_suite_add_1smb2_test(suite, "statopen2", test_lease_statopen2);
+ torture_suite_add_1smb2_test(suite, "statopen3", test_lease_statopen3);
+ torture_suite_add_1smb2_test(suite, "statopen4", test_lease_statopen4);
+ torture_suite_add_1smb2_test(suite, "upgrade", test_lease_upgrade);
+ torture_suite_add_1smb2_test(suite, "upgrade2", test_lease_upgrade2);
+ torture_suite_add_1smb2_test(suite, "upgrade3", test_lease_upgrade3);
+ torture_suite_add_1smb2_test(suite, "break", test_lease_break);
+ torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
+ torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
+ torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
+ torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
+ torture_suite_add_1smb2_test(suite, "breaking3", test_lease_breaking3);
+ torture_suite_add_1smb2_test(suite, "v2_breaking3", test_lease_v2_breaking3);
+ torture_suite_add_1smb2_test(suite, "breaking4", test_lease_breaking4);
+ torture_suite_add_1smb2_test(suite, "breaking5", test_lease_breaking5);
+ torture_suite_add_1smb2_test(suite, "breaking6", test_lease_breaking6);
+ torture_suite_add_2smb2_test(suite, "lock1", test_lease_lock1);
+ torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
+ torture_suite_add_1smb2_test(suite, "v2_request_parent",
+ test_lease_v2_request_parent);
+ torture_suite_add_1smb2_test(suite, "v2_request", test_lease_v2_request);
+ torture_suite_add_1smb2_test(suite, "v2_epoch1", test_lease_v2_epoch1);
+ torture_suite_add_1smb2_test(suite, "v2_epoch2", test_lease_v2_epoch2);
+ torture_suite_add_1smb2_test(suite, "v2_epoch3", test_lease_v2_epoch3);
+ torture_suite_add_1smb2_test(suite, "v2_complex1", test_lease_v2_complex1);
+ torture_suite_add_1smb2_test(suite, "v2_complex2", test_lease_v2_complex2);
+ torture_suite_add_1smb2_test(suite, "v2_rename", test_lease_v2_rename);
+ torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
+ torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
+ torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
+ torture_suite_add_1smb2_test(suite, "timeout-disconnect", test_lease_timeout_disconnect);
+ torture_suite_add_1smb2_test(suite, "rename_wait",
+ test_lease_rename_wait);
+ torture_suite_add_1smb2_test(suite, "duplicate_create",
+ test_lease_duplicate_create);
+ torture_suite_add_1smb2_test(suite, "duplicate_open",
+ test_lease_duplicate_open);
+ torture_suite_add_1smb2_test(suite, "v1_bug15148",
+ test_lease_v1_bug_15148);
+ torture_suite_add_1smb2_test(suite, "v2_bug15148",
+ test_lease_v2_bug_15148);
+
+ suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/lease_break_handler.c b/source4/torture/smb2/lease_break_handler.c
new file mode 100644
index 0000000..6c865dc
--- /dev/null
+++ b/source4/torture/smb2/lease_break_handler.c
@@ -0,0 +1,161 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 leases
+
+ Copyright (C) Zachary Loafman 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/util.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "lease_break_handler.h"
+
+struct lease_break_info lease_break_info;
+
+void torture_lease_break_callback(struct smb2_request *req)
+{
+ NTSTATUS status;
+
+ status = smb2_lease_break_ack_recv(req, &lease_break_info.lease_break_ack);
+ if (!NT_STATUS_IS_OK(status))
+ lease_break_info.failures++;
+
+ return;
+}
+
+/* a lease break request handler */
+bool torture_lease_handler(struct smb2_transport *transport,
+ const struct smb2_lease_break *lb,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ struct smb2_lease_break_ack io;
+ struct smb2_request *req;
+ const char *action = NULL;
+ char *ls = smb2_util_lease_state_string(lease_break_info.tctx,
+ lb->new_lease_state);
+
+ if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
+ action = "acking";
+ } else {
+ action = "received";
+ }
+
+ lease_break_info.lease_transport = transport;
+ lease_break_info.lease_break = *lb;
+ lease_break_info.count++;
+
+ if (lease_break_info.lease_skip_ack) {
+ torture_comment(lease_break_info.tctx,
+ "transport[%p] Skip %s to %s in lease handler\n",
+ transport, action, ls);
+ return true;
+ }
+
+ torture_comment(lease_break_info.tctx,
+ "transport[%p] %s to %s in lease handler\n",
+ transport, action, ls);
+
+ if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) {
+ ZERO_STRUCT(io);
+ io.in.lease.lease_key = lb->current_lease.lease_key;
+ io.in.lease.lease_state = lb->new_lease_state;
+
+ req = smb2_lease_break_ack_send(tree, &io);
+ req->async.fn = torture_lease_break_callback;
+ req->async.private_data = NULL;
+ }
+
+ return true;
+}
+
+/*
+ * A lease break handler which ignores incoming lease break requests
+ * To be used in cases where the client is expected to ignore incoming
+ * lease break requests
+ */
+bool torture_lease_ignore_handler(struct smb2_transport *transport,
+ const struct smb2_lease_break *lb,
+ void *private_data)
+{
+ return true;
+}
+
+/*
+ Timer handler function notifies the registering function that time is up
+*/
+static void timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ bool *timesup = (bool *)private_data;
+ *timesup = true;
+ return;
+}
+
+/*
+ Wait a short period of time to receive a single oplock break request
+*/
+void torture_wait_for_lease_break(struct torture_context *tctx)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct tevent_timer *te = NULL;
+ struct timeval ne;
+ bool timesup = false;
+ int old_count = lease_break_info.count;
+
+ /* Wait 1 second for an lease break */
+ ne = tevent_timeval_current_ofs(0, 1000000);
+
+ te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
+ if (te == NULL) {
+ torture_comment(tctx, "Failed to wait for an lease break. "
+ "test results may not be accurate.\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "Waiting for a potential lease break...\n");
+ while (!timesup && lease_break_info.count < old_count + 1) {
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_comment(tctx, "Failed to wait for a lease "
+ "break. test results may not be "
+ "accurate.\n");
+ goto done;
+ }
+ }
+ if (timesup) {
+ torture_comment(tctx, "... waiting for a lease break timed out\n");
+ } else {
+ torture_comment(tctx, "Got %u lease breaks\n",
+ lease_break_info.count - old_count);
+ }
+
+done:
+ /* We don't know if the timed event fired and was freed, we received
+ * our oplock break, or some other event triggered the loop. Thus,
+ * we create a tmp_ctx to be able to safely free/remove the timed
+ * event in all 3 cases. */
+ talloc_free(tmp_ctx);
+
+ return;
+}
diff --git a/source4/torture/smb2/lease_break_handler.h b/source4/torture/smb2/lease_break_handler.h
new file mode 100644
index 0000000..90fde1a
--- /dev/null
+++ b/source4/torture/smb2/lease_break_handler.h
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 leases
+
+ Copyright (C) Zachary Loafman 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "torture/util.h"
+
+struct lease_break_info {
+ struct torture_context *tctx;
+
+ struct smb2_lease_break lease_break;
+ struct smb2_transport *lease_transport;
+ bool lease_skip_ack;
+ struct smb2_lease_break_ack lease_break_ack;
+ int count;
+ int failures;
+
+ struct smb2_handle oplock_handle;
+ uint8_t held_oplock_level;
+ uint8_t oplock_level;
+ int oplock_count;
+ int oplock_failures;
+};
+
+#define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key) \
+ do { \
+ uint16_t __new = smb2_util_lease_state(__state); \
+ uint16_t __old = smb2_util_lease_state(__oldstate); \
+ CHECK_VAL((__lb)->new_lease_state, __new); \
+ CHECK_VAL((__lb)->current_lease.lease_state, __old); \
+ CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \
+ CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \
+ if (__old & (SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE)) { \
+ CHECK_VAL((__lb)->break_flags, \
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); \
+ } else { \
+ CHECK_VAL((__lb)->break_flags, 0); \
+ } \
+ } while(0)
+
+#define CHECK_LEASE_BREAK_ACK(__lba, __state, __key) \
+ do { \
+ CHECK_VAL((__lba)->out.reserved, 0); \
+ CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \
+ CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \
+ CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \
+ CHECK_VAL((__lba)->out.lease.lease_flags, 0); \
+ CHECK_VAL((__lba)->out.lease.lease_duration, 0); \
+ } while(0)
+
+#define CHECK_NO_BREAK(tctx) \
+ do { \
+ torture_wait_for_lease_break(tctx); \
+ CHECK_VAL(lease_break_info.failures, 0); \
+ CHECK_VAL(lease_break_info.count, 0); \
+ CHECK_VAL(lease_break_info.oplock_failures, 0); \
+ CHECK_VAL(lease_break_info.oplock_count, 0); \
+ } while(0)
+
+#define CHECK_OPLOCK_BREAK(__brokento) \
+ do { \
+ torture_wait_for_lease_break(tctx); \
+ CHECK_VAL(lease_break_info.oplock_count, 1); \
+ CHECK_VAL(lease_break_info.oplock_failures, 0); \
+ CHECK_VAL(lease_break_info.oplock_level, \
+ smb2_util_oplock_level(__brokento)); \
+ lease_break_info.held_oplock_level = lease_break_info.oplock_level; \
+ } while(0)
+
+#define _CHECK_BREAK_INFO(__oldstate, __state, __key) \
+ do { \
+ torture_wait_for_lease_break(tctx); \
+ CHECK_VAL(lease_break_info.failures, 0); \
+ CHECK_VAL(lease_break_info.count, 1); \
+ CHECK_LEASE_BREAK(&lease_break_info.lease_break, (__oldstate), \
+ (__state), (__key)); \
+ if (!lease_break_info.lease_skip_ack && \
+ (lease_break_info.lease_break.break_flags & \
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)) \
+ { \
+ torture_wait_for_lease_break(tctx); \
+ CHECK_LEASE_BREAK_ACK(&lease_break_info.lease_break_ack, \
+ (__state), (__key)); \
+ } \
+ } while(0)
+
+#define CHECK_BREAK_INFO(__oldstate, __state, __key) \
+ do { \
+ _CHECK_BREAK_INFO(__oldstate, __state, __key); \
+ CHECK_VAL(lease_break_info.lease_break.new_epoch, 0); \
+ } while(0)
+
+#define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \
+ do { \
+ _CHECK_BREAK_INFO(__oldstate, __state, __key); \
+ CHECK_VAL(lease_break_info.lease_break.new_epoch, __epoch); \
+ if (!TARGET_IS_SAMBA3(tctx)) { \
+ CHECK_VAL((uintptr_t)lease_break_info.lease_transport, \
+ (uintptr_t)__transport); \
+ } \
+ } while(0)
+
+extern struct lease_break_info lease_break_info;
+
+bool torture_lease_handler(struct smb2_transport *transport,
+ const struct smb2_lease_break *lb,
+ void *private_data);
+bool torture_lease_ignore_handler(struct smb2_transport *transport,
+ const struct smb2_lease_break *lb,
+ void *private_data);
+void torture_wait_for_lease_break(struct torture_context *tctx);
+
+static inline void torture_reset_lease_break_info(struct torture_context *tctx,
+ struct lease_break_info *r)
+{
+ ZERO_STRUCTP(r);
+ r->tctx = tctx;
+}
diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c
new file mode 100644
index 0000000..eac0d55
--- /dev/null
+++ b/source4/torture/smb2/lock.c
@@ -0,0 +1,3513 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 lock test suite
+
+ Copyright (C) Stefan Metzmacher 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/util.h"
+
+#include "lib/events/events.h"
+#include "param/param.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ const char *_cmt = "(" __location__ ")"; \
+ torture_assert_ntstatus_equal_goto(torture,status,correct, \
+ ret,done,_cmt); \
+ } while (0)
+
+#define CHECK_STATUS_CMT(status, correct, cmt) do { \
+ torture_assert_ntstatus_equal_goto(torture,status,correct, \
+ ret,done,cmt); \
+ } while (0)
+
+#define CHECK_STATUS_CONT(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ const char *_cmt = "(" __location__ ")"; \
+ torture_assert_int_equal_goto(torture,v,correct,ret,done,_cmt); \
+ } while (0)
+
+#define BASEDIR "testlock"
+
+#define TARGET_SUPPORTS_INVALID_LOCK_RANGE(_tctx) \
+ (torture_setting_bool(_tctx, "invalid_lock_range_support", true))
+#define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
+
+#define WAIT_FOR_ASYNC_RESPONSE(req) \
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
+ if (tevent_loop_once(torture->ev) != 0) { \
+ break; \
+ } \
+ }
+
+static bool test_valid_request(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+
+ ZERO_STRUCT(buf);
+
+ status = torture_smb2_testfile(tree, "lock1.txt", &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ torture_comment(torture, "Test request with 0 locks.\n");
+
+ lck.in.lock_count = 0x0000;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0x0000000000000000;
+ el[0].length = 0x0000000000000000;
+ el[0].reserved = 0x0000000000000000;
+ el[0].flags = 0x00000000;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ lck.in.lock_count = 0x0000;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 0;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 0;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_NONE;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has bug validating lock flags "
+ "parameter.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ torture_comment(torture, "Test >63-bit lock requests.\n");
+
+ lck.in.file.handle.data[0] +=1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ lck.in.file.handle.data[0] -=1;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x123ab1;
+ lck.in.file.handle = h;
+ el[0].offset = UINT64_MAX;
+ el[0].length = UINT64_MAX;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+ }
+
+ lck.in.lock_sequence = 0x123ab2;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ }
+
+ torture_comment(torture, "Test basic lock stacking.\n");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x12345678;
+ lck.in.file.handle = h;
+ el[0].offset = UINT32_MAX;
+ el[0].length = UINT32_MAX;
+ el[0].reserved = 0x87654321;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ el[0].flags = SMB2_LOCK_FLAG_SHARED;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x87654321;
+ lck.in.file.handle = h;
+ el[0].offset = 0x00000000FFFFFFFF;
+ el[0].length = 0x00000000FFFFFFFF;
+ el[0].reserved = 0x1234567;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x1234567;
+ lck.in.file.handle = h;
+ el[0].offset = 0x00000000FFFFFFFF;
+ el[0].length = 0x00000000FFFFFFFF;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Test flags field permutations.\n");
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0;
+ lck.in.file.handle = h;
+ el[0].offset = 1;
+ el[0].length = 1;
+ el[0].reserved = 0x00000000;
+ el[0].flags = ~SMB2_LOCK_FLAG_ALL_MASK;
+
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has bug validating lock flags "
+ "parameter.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (TARGET_IS_W2K8(torture)) {
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
+ SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
+ SMB2_LOCK_FLAG_SHARED;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ torture_warning(torture, "Target has bug validating lock flags "
+ "parameter.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ torture_comment(torture, "Test return error when 2 locks are "
+ "requested\n");
+
+ lck.in.lock_count = 2;
+ lck.in.lock_sequence = 0;
+ lck.in.file.handle = h;
+ el[0].offset = 9999;
+ el[0].length = 1;
+ el[0].reserved = 0x00000000;
+ el[1].offset = 9999;
+ el[1].length = 1;
+ el[1].reserved = 0x00000000;
+
+ lck.in.lock_count = 2;
+ el[0].flags = 0;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ lck.in.lock_count = 2;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[1].flags = SMB2_LOCK_FLAG_SHARED;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ lck.in.lock_count = 2;
+ el[0].flags = 0;
+ el[1].flags = 0;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has bug validating lock flags "
+ "parameter.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ lck.in.lock_count = 2;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = 0;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has bug validating lock flags "
+ "parameter.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ }
+
+ lck.in.lock_count = 1;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ lck.in.lock_count = 1;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ lck.in.lock_count = 1;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ lck.in.lock_count = 1;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.lock_count = 2;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.lock_count = 1;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+done:
+ return ret;
+}
+
+struct test_lock_read_write_state {
+ const char *fname;
+ uint32_t lock_flags;
+ NTSTATUS write_h1_status;
+ NTSTATUS read_h1_status;
+ NTSTATUS write_h2_status;
+ NTSTATUS read_h2_status;
+};
+
+static bool test_lock_read_write(struct torture_context *torture,
+ struct smb2_tree *tree,
+ struct test_lock_read_write_state *s)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h1, h2;
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_create cr;
+ struct smb2_write wr;
+ struct smb2_read rd;
+ struct smb2_lock_element el[1];
+
+ lck.in.locks = el;
+
+ ZERO_STRUCT(buf);
+
+ status = torture_smb2_testfile(tree, s->fname, &h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h1, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h1;
+ el[0].offset = 0;
+ el[0].length = ARRAY_SIZE(buf)/2;
+ el[0].reserved = 0x00000000;
+ el[0].flags = s->lock_flags;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h1;
+ el[0].offset = ARRAY_SIZE(buf)/2;
+ el[0].length = ARRAY_SIZE(buf)/2;
+ el[0].reserved = 0x00000000;
+ el[0].flags = s->lock_flags;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ ZERO_STRUCT(cr);
+ cr.in.oplock_level = 0;
+ cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ cr.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ cr.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ cr.in.create_options = 0;
+ cr.in.fname = s->fname;
+
+ status = smb2_create(tree, tree, &cr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ h2 = cr.out.file.handle;
+
+ ZERO_STRUCT(wr);
+ wr.in.file.handle = h1;
+ wr.in.offset = ARRAY_SIZE(buf)/2;
+ wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
+
+ status = smb2_write(tree, &wr);
+ CHECK_STATUS(status, s->write_h1_status);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h1;
+ rd.in.offset = ARRAY_SIZE(buf)/2;
+ rd.in.length = ARRAY_SIZE(buf)/2;
+
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, s->read_h1_status);
+
+ ZERO_STRUCT(wr);
+ wr.in.file.handle = h2;
+ wr.in.offset = ARRAY_SIZE(buf)/2;
+ wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
+
+ status = smb2_write(tree, &wr);
+ CHECK_STATUS(status, s->write_h2_status);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h2;
+ rd.in.offset = ARRAY_SIZE(buf)/2;
+ rd.in.length = ARRAY_SIZE(buf)/2;
+
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, s->read_h2_status);
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h1;
+ el[0].offset = ARRAY_SIZE(buf)/2;
+ el[0].length = ARRAY_SIZE(buf)/2;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ ZERO_STRUCT(wr);
+ wr.in.file.handle = h2;
+ wr.in.offset = ARRAY_SIZE(buf)/2;
+ wr.in.data = data_blob_const(buf, ARRAY_SIZE(buf)/2);
+
+ status = smb2_write(tree, &wr);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h2;
+ rd.in.offset = ARRAY_SIZE(buf)/2;
+ rd.in.length = ARRAY_SIZE(buf)/2;
+
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ return ret;
+}
+
+static bool test_lock_rw_none(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct test_lock_read_write_state s = {
+ .fname = "lock_rw_none.dat",
+ .lock_flags = SMB2_LOCK_FLAG_NONE,
+ .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
+ .read_h1_status = NT_STATUS_OK,
+ .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
+ .read_h2_status = NT_STATUS_OK,
+ };
+
+ if (!TARGET_IS_W2K8(torture)) {
+ torture_skip(torture, "RW-NONE tests the behavior of a "
+ "NONE-type lock, which is the same as a SHARED "
+ "lock but is granted due to a bug in W2K8. If "
+ "target is not W2K8 we skip this test.\n");
+ }
+
+ return test_lock_read_write(torture, tree, &s);
+}
+
+static bool test_lock_rw_shared(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct test_lock_read_write_state s = {
+ .fname = "lock_rw_shared.dat",
+ .lock_flags = SMB2_LOCK_FLAG_SHARED,
+ .write_h1_status = NT_STATUS_FILE_LOCK_CONFLICT,
+ .read_h1_status = NT_STATUS_OK,
+ .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
+ .read_h2_status = NT_STATUS_OK,
+ };
+
+ return test_lock_read_write(torture, tree, &s);
+}
+
+static bool test_lock_rw_exclusive(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct test_lock_read_write_state s = {
+ .fname = "lock_rw_exclusive.dat",
+ .lock_flags = SMB2_LOCK_FLAG_EXCLUSIVE,
+ .write_h1_status = NT_STATUS_OK,
+ .read_h1_status = NT_STATUS_OK,
+ .write_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
+ .read_h2_status = NT_STATUS_FILE_LOCK_CONFLICT,
+ };
+
+ return test_lock_read_write(torture, tree, &s);
+}
+
+static bool test_lock_auto_unlock(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ ZERO_STRUCT(buf);
+
+ status = torture_smb2_testfile(tree, "autounlock.txt", &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(lck);
+ ZERO_STRUCT(el[0]);
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 1;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has \"pretty please\" bug. "
+ "A contending lock request on the same handle "
+ "unlocks the lock.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ }
+
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+done:
+ return ret;
+}
+
+/*
+ test different lock ranges and see if different handles conflict
+*/
+static bool test_lock(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+
+ const char *fname = BASEDIR "\\async.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ torture_comment(torture, "Trying 0/0 lock\n");
+ el[0].offset = 0x0000000000000000;
+ el[0].length = 0x0000000000000000;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Trying 0/1 lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = 0x0000000000000000;
+ el[0].length = 0x0000000000000001;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying 0xEEFFFFF lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = 0xEEFFFFFF;
+ el[0].length = 4000;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying 0xEF00000 lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = 0xEF000000;
+ el[0].length = 4000;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying (2^63 - 1)/1\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = 1;
+ el[0].offset <<= 63;
+ el[0].offset--;
+ el[0].length = 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying 2^63/1\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = 1;
+ el[0].offset <<= 63;
+ el[0].length = 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying max/0 lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = ~0;
+ el[0].length = 0;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying max/1 lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = ~0;
+ el[0].length = 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Trying max/2 lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = ~0;
+ el[0].length = 2;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_SUPPORTS_INVALID_LOCK_RANGE(torture)) {
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ torture_comment(torture, "Trying wrong handle unlock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[0].offset = 10001;
+ el[0].length = 40002;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test SMB2 LOCK async operation
+*/
+static bool test_async(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ struct smb2_request *req = NULL;
+
+ const char *fname = BASEDIR "\\async.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 100;
+ el[0].length = 50;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ torture_comment(torture, " Acquire first lock\n");
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should pend on first\n");
+ lck.in.file.handle = h2;
+ req = smb2_lock_send(tree, &lck);
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(torture, " Unlock first lock\n");
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should now succeed\n");
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock_recv(req, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test SMB2 LOCK Cancel operation
+*/
+static bool test_cancel(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ struct smb2_request *req = NULL;
+
+ const char *fname = BASEDIR "\\cancel.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 100;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ torture_comment(torture, "Testing basic cancel\n");
+
+ torture_comment(torture, " Acquire first lock\n");
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should pend on first\n");
+ lck.in.file.handle = h2;
+ req = smb2_lock_send(tree, &lck);
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(torture, " Cancel the second lock\n");
+ smb2_cancel(req);
+ lck.in.file.handle = h2;
+ status = smb2_lock_recv(req, &lck);
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ torture_comment(torture, " Unlock first lock\n");
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(torture, "Testing cancel by unlock\n");
+
+ torture_comment(torture, " Acquire first lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should pend on first\n");
+ lck.in.file.handle = h2;
+ req = smb2_lock_send(tree, &lck);
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(torture, " Attempt to unlock pending second lock\n");
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, " Now cancel the second lock\n");
+ smb2_cancel(req);
+ lck.in.file.handle = h2;
+ status = smb2_lock_recv(req, &lck);
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ torture_comment(torture, " Unlock first lock\n");
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(torture, "Testing cancel by close\n");
+
+ torture_comment(torture, " Acquire first lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should pend on first\n");
+ lck.in.file.handle = h2;
+ req = smb2_lock_send(tree, &lck);
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(torture, " Close the second lock handle\n");
+ smb2_util_close(tree, h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Check pending lock reply\n");
+ status = smb2_lock_recv(req, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, " Unlock first lock\n");
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test SMB2 LOCK Cancel by tree disconnect
+*/
+static bool test_cancel_tdis(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ struct smb2_request *req = NULL;
+
+ const char *fname = BASEDIR "\\cancel_tdis.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 100;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ torture_comment(torture, "Testing cancel by tree disconnect\n");
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Acquire first lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should pend on first\n");
+ lck.in.file.handle = h2;
+ req = smb2_lock_send(tree, &lck);
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(torture, " Disconnect the tree\n");
+ smb2_tdis(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Check pending lock reply\n");
+ status = smb2_lock_recv(req, &lck);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RANGE_NOT_LOCKED)) {
+ /*
+ * The status depends on the server internals
+ * the order in which the files are closed
+ * by smb2_tdis().
+ */
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ torture_comment(torture, " Attempt to unlock first lock\n");
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ /*
+ * Most Windows versions have a strange order to
+ * verify the session id, tree id and file id.
+ * (They should be checked in that order, but windows
+ * seems to check the file id before the others).
+ */
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ }
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ test SMB2 LOCK Cancel by user logoff
+*/
+static bool test_cancel_logoff(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ struct smb2_request *req = NULL;
+
+ const char *fname = BASEDIR "\\cancel_logoff.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 100;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+
+ torture_comment(torture, "Testing cancel by ulogoff\n");
+
+ torture_comment(torture, " Acquire first lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " Second lock should pend on first\n");
+ lck.in.file.handle = h2;
+ req = smb2_lock_send(tree, &lck);
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(torture, " Logoff user\n");
+ smb2_logoff(tree->session);
+
+ torture_comment(torture, " Check pending lock reply\n");
+ status = smb2_lock_recv(req, &lck);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RANGE_NOT_LOCKED)) {
+ /*
+ * The status depends on the server internals
+ * the order in which the files are closed
+ * by smb2_logoff().
+ */
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ torture_comment(torture, " Attempt to unlock first lock\n");
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ /*
+ * Most Windows versions have a strange order to
+ * verify the session id, tree id and file id.
+ * (They should be checked in that order, but windows
+ * seems to check the file id before the others).
+ */
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
+ CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
+ }
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * Test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
+ *
+ * The SMBv1 protocol returns a different error code on lock acquisition
+ * failure depending on a number of parameters, including what error code
+ * was returned to the previous failure.
+ *
+ * SMBv2 has cleaned up these semantics and should always return
+ * NT_STATUS_LOCK_NOT_GRANTED to failed lock requests, and
+ * NT_STATUS_FILE_LOCK_CONFLICT to failed read/write requests due to a lock
+ * being held on that range.
+*/
+static bool test_errorcode(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+
+ const char *fname = BASEDIR "\\errorcode.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = el;
+
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 100;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ torture_comment(torture, "Testing LOCK_NOT_GRANTED vs. "
+ "FILE_LOCK_CONFLICT\n");
+
+ if (TARGET_IS_W2K8(torture)) {
+ torture_result(torture, TORTURE_SKIP,
+ "Target has \"pretty please\" bug. A contending lock "
+ "request on the same handle unlocks the lock.");
+ goto done;
+ }
+
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Demonstrate that the first conflicting lock on each handle gives
+ * LOCK_NOT_GRANTED. */
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* Demonstrate that each following conflict also gives
+ * LOCK_NOT_GRANTED */
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* Demonstrate that the smbpid doesn't matter */
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* Demonstrate that a 0-byte lock inside the locked range still
+ * gives the same error. */
+
+ el[0].offset = 102;
+ el[0].length = 0;
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* Demonstrate that a lock inside the locked range still gives the
+ * same error. */
+
+ el[0].offset = 102;
+ el[0].length = 5;
+ lck.in.file.handle = h;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.file.handle = h2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Tests zero byte locks.
+ */
+
+struct double_lock_test {
+ struct smb2_lock_element lock1;
+ struct smb2_lock_element lock2;
+ NTSTATUS status;
+};
+
+static struct double_lock_test zero_byte_tests[] = {
+ /* {offset, count, reserved, flags},
+ * {offset, count, reserved, flags},
+ * status */
+
+ /** First, takes a zero byte lock at offset 10. Then:
+ * - Taking 0 byte lock at 10 should succeed.
+ * - Taking 1 byte locks at 9,10,11 should succeed.
+ * - Taking 2 byte lock at 9 should fail.
+ * - Taking 2 byte lock at 10 should succeed.
+ * - Taking 3 byte lock at 9 should fail.
+ */
+ {{10, 0, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
+ {{10, 0, 0, 0}, {9, 1, 0, 0}, NT_STATUS_OK},
+ {{10, 0, 0, 0}, {10, 1, 0, 0}, NT_STATUS_OK},
+ {{10, 0, 0, 0}, {11, 1, 0, 0}, NT_STATUS_OK},
+ {{10, 0, 0, 0}, {9, 2, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
+ {{10, 0, 0, 0}, {10, 2, 0, 0}, NT_STATUS_OK},
+ {{10, 0, 0, 0}, {9, 3, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
+
+ /** Same, but opposite order. */
+ {{10, 0, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
+ {{9, 1, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
+ {{10, 1, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
+ {{11, 1, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
+ {{9, 2, 0, 0}, {10, 0, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
+ {{10, 2, 0, 0}, {10, 0, 0, 0}, NT_STATUS_OK},
+ {{9, 3, 0, 0}, {10, 0, 0, 0}, NT_STATUS_LOCK_NOT_GRANTED},
+
+ /** Zero zero case. */
+ {{0, 0, 0, 0}, {0, 0, 0, 0}, NT_STATUS_OK},
+};
+
+static bool test_zerobytelength(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ int i;
+
+ const char *fname = BASEDIR "\\zero.txt";
+
+ torture_comment(torture, "Testing zero length byte range locks:\n");
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Setup initial parameters */
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+
+ /* Try every combination of locks in zero_byte_tests, using the same
+ * handle for both locks. The first lock is assumed to succeed. The
+ * second lock may contend, depending on the expected status. */
+ for (i = 0; i < ARRAY_SIZE(zero_byte_tests); i++) {
+ torture_comment(torture,
+ " ... {%llu, %llu} + {%llu, %llu} = %s\n",
+ (unsigned long long) zero_byte_tests[i].lock1.offset,
+ (unsigned long long) zero_byte_tests[i].lock1.length,
+ (unsigned long long) zero_byte_tests[i].lock2.offset,
+ (unsigned long long) zero_byte_tests[i].lock2.length,
+ nt_errstr(zero_byte_tests[i].status));
+
+ /* Lock both locks. */
+ lck.in.locks = &zero_byte_tests[i].lock1;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.locks = &zero_byte_tests[i].lock2;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CONT(status, zero_byte_tests[i].status);
+
+ /* Unlock both locks in reverse order. */
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ lck.in.locks = &zero_byte_tests[i].lock1;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ /* Try every combination of locks in zero_byte_tests, using two
+ * different handles. */
+ for (i = 0; i < ARRAY_SIZE(zero_byte_tests); i++) {
+ torture_comment(torture,
+ " ... {%llu, %llu} + {%llu, %llu} = %s\n",
+ (unsigned long long) zero_byte_tests[i].lock1.offset,
+ (unsigned long long) zero_byte_tests[i].lock1.length,
+ (unsigned long long) zero_byte_tests[i].lock2.offset,
+ (unsigned long long) zero_byte_tests[i].lock2.length,
+ nt_errstr(zero_byte_tests[i].status));
+
+ /* Lock both locks. */
+ lck.in.file.handle = h;
+ lck.in.locks = &zero_byte_tests[i].lock1;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.file.handle = h2;
+ lck.in.locks = &zero_byte_tests[i].lock2;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CONT(status, zero_byte_tests[i].status);
+
+ /* Unlock both locks in reverse order. */
+ lck.in.file.handle = h2;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ lck.in.file.handle = h;
+ lck.in.locks = &zero_byte_tests[i].lock1;
+ lck.in.locks[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_zerobyteread(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ struct smb2_read rd;
+
+ const char *fname = BASEDIR "\\zerobyteread.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h2;
+
+ torture_comment(torture, "Testing zero byte read on lock range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(torture, " taking exclusive lock.\n");
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ /* Try a zero byte read */
+ torture_comment(torture, " reading 0 bytes.\n");
+ rd.in.offset = 5;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ torture_comment(torture, "Testing zero byte read on zero byte lock "
+ "range:\n");
+
+ /* Take an exclusive lock */
+ torture_comment(torture, " taking exclusive 0-byte lock.\n");
+ el[0].offset = 5;
+ el[0].length = 0;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+ /* Try a zero byte read before the lock */
+ torture_comment(torture, " reading 0 bytes before the lock.\n");
+ rd.in.offset = 4;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read on the lock */
+ torture_comment(torture, " reading 0 bytes on the lock.\n");
+ rd.in.offset = 5;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try a zero byte read after the lock */
+ torture_comment(torture, " reading 0 bytes after the lock.\n");
+ rd.in.offset = 6;
+ rd.in.length = 0;
+ status = smb2_read(tree, tree, &rd);
+ torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done,
+ "zero byte read did not return 0 bytes");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock lock */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(lck.out.reserved, 0);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_unlock(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el1[1];
+ struct smb2_lock_element el2[1];
+
+ const char *fname = BASEDIR "\\unlock.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Setup initial parameters */
+ lck.in.locks = el1;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ el1[0].offset = 0;
+ el1[0].length = 10;
+ el1[0].reserved = 0x00000000;
+
+ /* Take exclusive lock, then unlock it with a shared-unlock call. */
+
+ torture_comment(torture, "Testing unlock exclusive with shared\n");
+
+ torture_comment(torture, " taking exclusive lock.\n");
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " try to unlock the exclusive with a shared "
+ "unlock call.\n");
+ el1[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(torture, " try shared lock on h2, to test the "
+ "unlock.\n");
+ lck.in.file.handle = h2;
+ el1[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_comment(torture, " unlock the exclusive lock\n");
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Unlock a shared lock with an exclusive-unlock call. */
+
+ torture_comment(torture, "Testing unlock shared with exclusive\n");
+
+ torture_comment(torture, " taking shared lock.\n");
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_SHARED;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, " try to unlock the shared with an exclusive "
+ "unlock call.\n");
+ el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(torture, " try exclusive lock on h2, to test the "
+ "unlock.\n");
+ lck.in.file.handle = h2;
+ el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_comment(torture, " unlock the exclusive lock\n");
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test unlocking of stacked 0-byte locks. SMB2 0-byte lock behavior
+ * should be the same as >0-byte behavior. Exclusive locks should be
+ * unlocked before shared. */
+
+ torture_comment(torture, "Test unlocking stacked 0-byte locks\n");
+
+ lck.in.locks = el1;
+ lck.in.file.handle = h;
+ el1[0].offset = 10;
+ el1[0].length = 0;
+ el1[0].reserved = 0x00000000;
+ el2[0].offset = 5;
+ el2[0].length = 10;
+ el2[0].reserved = 0x00000000;
+
+ /* lock 0-byte exclusive */
+ el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* lock 0-byte shared */
+ el1[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* test contention */
+ lck.in.locks = el2;
+ lck.in.file.handle = h2;
+ el2[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.locks = el2;
+ lck.in.file.handle = h2;
+ el2[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* unlock */
+ lck.in.locks = el1;
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* test - can we take a shared lock? */
+ lck.in.locks = el2;
+ lck.in.file.handle = h2;
+ el2[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el2[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ lck.in.locks = el1;
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test unlocking of stacked exclusive, shared locks. Exclusive
+ * should be unlocked before any shared. */
+
+ torture_comment(torture, "Test unlocking stacked exclusive/shared "
+ "locks\n");
+
+ lck.in.locks = el1;
+ lck.in.file.handle = h;
+ el1[0].offset = 10;
+ el1[0].length = 10;
+ el1[0].reserved = 0x00000000;
+ el2[0].offset = 5;
+ el2[0].length = 10;
+ el2[0].reserved = 0x00000000;
+
+ /* lock exclusive */
+ el1[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* lock shared */
+ el1[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* test contention */
+ lck.in.locks = el2;
+ lck.in.file.handle = h2;
+ el2[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ lck.in.locks = el2;
+ lck.in.file.handle = h2;
+ el2[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* unlock */
+ lck.in.locks = el1;
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* test - can we take a shared lock? */
+ lck.in.locks = el2;
+ lck.in.file.handle = h2;
+ el2[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el2[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ lck.in.locks = el1;
+ lck.in.file.handle = h;
+ el1[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_multiple_unlock(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h;
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+
+ const char *fname = BASEDIR "\\unlock_multiple.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing multiple unlocks:\n");
+
+ /* Setup initial parameters */
+ lck.in.lock_count = 0x0002;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+ el[1].offset = 10;
+ el[1].length = 10;
+ el[1].reserved = 0x00000000;
+
+ /* Test1: Acquire second lock, but not first. */
+ torture_comment(torture, " unlock 2 locks, first one not locked. "
+ "Expect no locks unlocked. \n");
+
+ lck.in.lock_count = 0x0001;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[1];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to unlock both locks */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* Second lock should not be unlocked. */
+ lck.in.lock_count = 0x0001;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[1];
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has \"pretty please\" bug. "
+ "A contending lock request on the same handle "
+ "unlocks the lock.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ }
+
+ /* cleanup */
+ lck.in.lock_count = 0x0001;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = &el[1];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test2: Acquire first lock, but not second. */
+ torture_comment(torture, " unlock 2 locks, second one not locked. "
+ "Expect first lock unlocked.\n");
+
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to unlock both locks */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* First lock should be unlocked. */
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test3: Request 2 locks, second will contend. What happens to the
+ * first? */
+ torture_comment(torture, " request 2 locks, second one will contend. "
+ "Expect both to fail.\n");
+
+ /* Lock the second range */
+ lck.in.lock_count = 0x0001;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[1];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Request both locks */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* First lock should be unlocked. */
+ lck.in.lock_count = 0x0001;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ if (TARGET_IS_W2K8(torture)) {
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has \"pretty please\" bug. "
+ "A contending lock request on the same handle "
+ "unlocks the lock.\n");
+ } else {
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ /* Test4: Request unlock and lock. The lock contends, is the unlock
+ * then relocked? SMB2 doesn't like the lock and unlock requests in the
+ * same packet. The unlock will succeed, but the lock will return
+ * INVALID_PARAMETER. This behavior is described in MS-SMB2
+ * 3.3.5.14.1 */
+ torture_comment(torture, " request unlock and lock, second one will "
+ "error. Expect the unlock to succeed.\n");
+
+ /* Lock both ranges */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Attempt to unlock the first range and lock the second. The lock
+ * request will error. */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /* The first lock should've been unlocked */
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test10: SMB2 only test. Request unlock and lock in same packet.
+ * Neither contend. SMB2 doesn't like lock and unlock requests in the
+ * same packet. The unlock will succeed, but the lock will return
+ * INVALID_PARAMETER. */
+ torture_comment(torture, " request unlock and lock. Unlock will "
+ "succeed, but lock will fail.\n");
+
+ /* Lock first range */
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Attempt to unlock the first range and lock the second */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /* Neither lock should still be locked */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Test11: SMB2 only test. Request lock and unlock in same packet.
+ * Neither contend. SMB2 doesn't like lock and unlock requests in the
+ * same packet. The lock will succeed, the unlock will fail with
+ * INVALID_PARAMETER, and the lock will be unlocked before return. */
+ torture_comment(torture, " request lock and unlock. Both will "
+ "fail.\n");
+
+ /* Lock second range */
+ lck.in.lock_count = 0x0001;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[1];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Attempt to lock the first range and unlock the second */
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ /* First range should be unlocked, second locked. */
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.lock_count = 0x0001;
+ el[1].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = &el[1];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ if (TARGET_IS_W2K8(torture)) {
+ lck.in.lock_count = 0x0001;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = &el[0];
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_warning(torture, "Target has \"pretty please\" bug. "
+ "A contending lock request on the same handle "
+ "unlocks the lock.\n");
+ } else {
+ lck.in.lock_count = 0x0002;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ el[1].flags = SMB2_LOCK_FLAG_UNLOCK;
+ lck.in.locks = el;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test lock stacking
+ * - some tests ported from BASE-LOCK-LOCK5
+ */
+static bool test_stacking(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ const char *fname = BASEDIR "\\stacking.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing lock stacking:\n");
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+
+ /* Try to take a shared lock, then a shared lock on same handle */
+ torture_comment(torture, " stacking a shared on top of a shared"
+ "lock succeeds.\n");
+
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* cleanup */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ /* Try to take an exclusive lock, then a shared lock on same handle */
+ torture_comment(torture, " stacking a shared on top of an exclusive "
+ "lock succeeds.\n");
+
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* stacking a shared from a different handle should fail */
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* ensure the 4th unlock fails */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* ensure a second handle can now take an exclusive lock */
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to take an exclusive lock, then a shared lock on a
+ * different handle */
+ torture_comment(torture, " stacking a shared on top of an exclusive "
+ "lock with different handles fails.\n");
+
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Try to take a shared lock, then stack an exclusive with same
+ * handle. */
+ torture_comment(torture, " stacking an exclusive on top of a shared "
+ "lock fails.\n");
+
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ torture_warning(torture, "Target has \"pretty please\" bug. "
+ "A contending lock request on the same handle "
+ "unlocks the lock.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ /* Prove that two exclusive locks do not stack on the same handle. */
+ torture_comment(torture, " two exclusive locks do not stack.\n");
+
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ if (TARGET_IS_W2K8(torture)) {
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+ torture_warning(torture, "Target has \"pretty please\" bug. "
+ "A contending lock request on the same handle "
+ "unlocks the lock.\n");
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test lock contention
+ * - shared lock should contend with exclusive lock on different handle
+ */
+static bool test_contend(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ const char *fname = BASEDIR "\\contend.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing lock contention:\n");
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+
+ /* Take an exclusive lock, then a shared lock on different handle */
+ torture_comment(torture, " shared should contend on exclusive on "
+ "different handle.\n");
+
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.file.handle = h2;
+ el[0].flags = SMB2_LOCK_FLAG_SHARED |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* cleanup */
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test locker context
+ * - test that pid does not affect the locker context
+ */
+static bool test_context(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+
+ const char *fname = BASEDIR "\\context.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing locker context:\n");
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+
+ /* Take an exclusive lock, then try to unlock with a different pid,
+ * same handle. This shows that the pid doesn't affect the locker
+ * context in SMB2. */
+ torture_comment(torture, " pid shouldn't affect locker context\n");
+
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test as much of the potential lock range as possible
+ * - test ported from BASE-LOCK-LOCK3
+ */
+static bool test_range(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ uint64_t offset, i;
+ extern int torture_numops;
+
+ const char *fname = BASEDIR "\\range.txt";
+
+#define NEXT_OFFSET offset += (~(uint64_t)0) / torture_numops
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing locks spread across the 64-bit "
+ "offset range\n");
+
+ if (TARGET_IS_W2K8(torture)) {
+ torture_result(torture, TORTURE_SKIP,
+ "Target has \"pretty please\" bug. A contending lock "
+ "request on the same handle unlocks the lock.");
+ goto done;
+ }
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 1;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ torture_comment(torture, " establishing %d locks\n", torture_numops);
+
+ for (offset=i=0; i<torture_numops; i++) {
+ NEXT_OFFSET;
+
+ lck.in.file.handle = h;
+ el[0].offset = offset - 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_OK,
+ talloc_asprintf(torture,
+ "lock h failed at offset %#llx ",
+ (unsigned long long) el[0].offset));
+
+ lck.in.file.handle = h2;
+ el[0].offset = offset - 2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_OK,
+ talloc_asprintf(torture,
+ "lock h2 failed at offset %#llx ",
+ (unsigned long long) el[0].offset));
+ }
+
+ torture_comment(torture, " testing %d locks\n", torture_numops);
+
+ for (offset=i=0; i<torture_numops; i++) {
+ NEXT_OFFSET;
+
+ lck.in.file.handle = h;
+ el[0].offset = offset - 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
+ talloc_asprintf(torture,
+ "lock h at offset %#llx should not have "
+ "succeeded ",
+ (unsigned long long) el[0].offset));
+
+ lck.in.file.handle = h;
+ el[0].offset = offset - 2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
+ talloc_asprintf(torture,
+ "lock h2 at offset %#llx should not have "
+ "succeeded ",
+ (unsigned long long) el[0].offset));
+
+ lck.in.file.handle = h2;
+ el[0].offset = offset - 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
+ talloc_asprintf(torture,
+ "lock h at offset %#llx should not have "
+ "succeeded ",
+ (unsigned long long) el[0].offset));
+
+ lck.in.file.handle = h2;
+ el[0].offset = offset - 2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_LOCK_NOT_GRANTED,
+ talloc_asprintf(torture,
+ "lock h2 at offset %#llx should not have "
+ "succeeded ",
+ (unsigned long long) el[0].offset));
+ }
+
+ torture_comment(torture, " removing %d locks\n", torture_numops);
+
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+
+ for (offset=i=0; i<torture_numops; i++) {
+ NEXT_OFFSET;
+
+ lck.in.file.handle = h;
+ el[0].offset = offset - 1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_OK,
+ talloc_asprintf(torture,
+ "unlock from h failed at offset %#llx ",
+ (unsigned long long) el[0].offset));
+
+ lck.in.file.handle = h2;
+ el[0].offset = offset - 2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS_CMT(status, NT_STATUS_OK,
+ talloc_asprintf(torture,
+ "unlock from h2 failed at offset %#llx ",
+ (unsigned long long) el[0].offset));
+ }
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static NTSTATUS test_smb2_lock(struct smb2_tree *tree, struct smb2_handle h,
+ uint64_t offset, uint64_t length, bool exclusive)
+{
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ NTSTATUS status;
+
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = offset;
+ el[0].length = length;
+ el[0].reserved = 0x00000000;
+ el[0].flags = (exclusive ?
+ SMB2_LOCK_FLAG_EXCLUSIVE :
+ SMB2_LOCK_FLAG_SHARED) |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ status = smb2_lock(tree, &lck);
+
+ return status;
+}
+
+static NTSTATUS test_smb2_unlock(struct smb2_tree *tree, struct smb2_handle h,
+ uint64_t offset, uint64_t length)
+{
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ NTSTATUS status;
+
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = offset;
+ el[0].length = length;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+
+ status = smb2_lock(tree, &lck);
+
+ return status;
+}
+
+#define EXPECTED(ret, v) if ((ret) != (v)) { \
+ torture_result(torture, TORTURE_FAIL, __location__": subtest failed");\
+ torture_comment(torture, "** "); correct = false; \
+ }
+
+/**
+ * Test overlapping lock ranges from various lockers
+ * - some tests ported from BASE-LOCK-LOCK4
+ */
+static bool test_overlap(struct torture_context *torture,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ uint8_t buf[200];
+ bool correct = true;
+
+ const char *fname = BASEDIR "\\overlap.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = torture_smb2_testfile(tree2, fname, &h3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing overlapping locks:\n");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 0, 4, true)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h, 2, 4, true));
+ EXPECTED(ret, false);
+ torture_comment(torture, "the same session/handle %s set overlapping "
+ "exclusive locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 10, 4, false)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h, 12, 4, false));
+ EXPECTED(ret, true);
+ torture_comment(torture, "the same session/handle %s set overlapping "
+ "shared locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 20, 4, true)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree2, h3, 22, 4, true));
+ EXPECTED(ret, false);
+ torture_comment(torture, "a different session %s set overlapping "
+ "exclusive locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 30, 4, false)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree2, h3, 32, 4, false));
+ EXPECTED(ret, true);
+ torture_comment(torture, "a different session %s set overlapping "
+ "shared locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 40, 4, true)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 42, 4, true));
+ EXPECTED(ret, false);
+ torture_comment(torture, "a different handle %s set overlapping "
+ "exclusive locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 50, 4, false)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 52, 4, false));
+ EXPECTED(ret, true);
+ torture_comment(torture, "a different handle %s set overlapping "
+ "shared locks\n", ret?"can":"cannot");
+
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 110, 4, false)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h, 112, 4, false)) &&
+ NT_STATUS_IS_OK(test_smb2_unlock(tree, h, 110, 6));
+ EXPECTED(ret, false);
+ torture_comment(torture, "the same handle %s coalesce read locks\n",
+ ret?"can":"cannot");
+
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_testfile(tree, fname, &h2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ret = NT_STATUS_IS_OK(test_smb2_lock(tree, h, 0, 8, false)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h2, 0, 1, false)) &&
+ NT_STATUS_IS_OK(smb2_util_close(tree, h)) &&
+ NT_STATUS_IS_OK(torture_smb2_testfile(tree, fname, &h)) &&
+ NT_STATUS_IS_OK(test_smb2_lock(tree, h, 7, 1, true));
+ EXPECTED(ret, true);
+ torture_comment(torture, "the server %s have the NT byte range lock "
+ "bug\n", !ret?"does":"doesn't");
+
+done:
+ smb2_util_close(tree2, h3);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return correct;
+}
+
+/**
+ * Test truncation of locked file
+ * - some tests ported from BASE-LOCK-LOCK7
+ */
+static bool test_truncate(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h2 = {{0}};
+ uint8_t buf[200];
+ struct smb2_lock lck;
+ struct smb2_lock_element el[1];
+ struct smb2_create io;
+
+ const char *fname = BASEDIR "\\truncate.txt";
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing truncation of locked file:\n");
+
+ /* Setup initial parameters */
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+ el[0].offset = 0;
+ el[0].length = 10;
+ el[0].reserved = 0x00000000;
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+
+ /* Take an exclusive lock */
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* On second handle open the file with OVERWRITE disposition */
+ torture_comment(torture, " overwrite disposition is allowed on a "
+ "locked file.\n");
+
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb2_create(tree, tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ smb2_util_close(tree, h2);
+
+ /* On second handle open the file with SUPERSEDE disposition */
+ torture_comment(torture, " supersede disposition is allowed on a "
+ "locked file.\n");
+
+ io.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
+ status = smb2_create(tree, tree, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+ smb2_util_close(tree, h2);
+
+ /* cleanup */
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test lock replay detection
+ *
+ * This test checks the SMB 2.1.0 behaviour of lock sequence checking,
+ * which is only turned on for resilient handles.
+ *
+ * Make it clear that this test is supposed to pass against the legacy
+ * Windows servers which violate the specification:
+ *
+ * [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request
+ *
+ * ...
+ *
+ * ... if Open.IsResilient or Open.IsDurable or Open.IsPersistent is
+ * TRUE or if Connection.Dialect belongs to the SMB 3.x dialect family
+ * and Connection.ServerCapabilities includes
+ * SMB2_GLOBAL_CAP_MULTI_CHANNEL bit, the server SHOULD<314>
+ * perform lock sequence verification ...
+ *
+ * ...
+ *
+ * <314> Section 3.3.5.14: Windows 7 and Windows Server 2008 R2 perform
+ * lock sequence verification only when Open.IsResilient is TRUE.
+ * Windows 8 through Windows 10 v1909 and Windows Server 2012 through
+ * Windows Server v1909 perform lock sequence verification only when
+ * Open.IsResilient or Open.IsPersistent is TRUE.
+ *
+ * Note <314> also applies to all versions (at least) up to Windows Server v2004.
+ *
+ * Hopefully this will be fixed in future Windows versions and they
+ * will avoid Note <314>.
+ */
+static bool test_replay_broken_windows(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle h;
+ struct smb2_ioctl ioctl;
+ struct smb2_lock lck;
+ struct smb2_lock_element el;
+ uint8_t res_req[8];
+ const char *fname = BASEDIR "\\replay_broken_windows.txt";
+ struct smb2_transport *transport = tree->session->transport;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB2_10) {
+ torture_skip(torture, "SMB 2.1.0 Dialect family or above \
+ required for Lock Replay tests\n");
+ }
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ torture_comment(torture, "Testing Open File:\n");
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Setup initial parameters
+ */
+ el = (struct smb2_lock_element) {
+ .length = 100,
+ .offset = 100,
+ };
+ lck = (struct smb2_lock) {
+ .in.locks = &el,
+ .in.lock_count = 0x0001,
+ .in.file.handle = h
+ };
+
+ torture_comment(torture, "Testing Lock Replay detection [ignored]:\n");
+ lck.in.lock_sequence = 0x010 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ if (NT_STATUS_IS_OK(status)) {
+ lck.in.lock_sequence = 0x020 + 0x2;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ lck.in.lock_sequence = 0x010 + 0x1;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
+ torture_skip_goto(torture, done,
+ "SMB3 Server implements LockSequence "
+ "for all handles\n");
+ }
+ }
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ if (smbXcli_conn_protocol(transport->conn) > PROTOCOL_SMB2_10) {
+ torture_comment(torture,
+ "\nSMB3 Server implements LockSequence as SMB 2.1.0"
+ " LEGACY BROKEN Windows!!!\n\n");
+ }
+ torture_comment(torture,
+ "Testing SMB 2.1.0 LockSequence for ResilientHandles\n");
+
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Testing Set Resiliency:\n");
+ SIVAL(res_req, 0, 1000); /* timeout */
+ SIVAL(res_req, 4, 0); /* reserved */
+ ioctl = (struct smb2_ioctl) {
+ .level = RAW_IOCTL_SMB2,
+ .in.file.handle = h,
+ .in.function = FSCTL_LMR_REQ_RESILIENCY,
+ .in.max_output_response = 0,
+ .in.flags = SMB2_IOCTL_FLAG_IS_FSCTL,
+ .in.out.data = res_req,
+ .in.out.length = sizeof(res_req)
+ };
+ status = smb2_ioctl(tree, torture, &ioctl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Test with an invalid bucket number (only 1..64 are valid).
+ * With an invalid number, lock replay detection is not performed.
+ */
+ torture_comment(torture, "Testing Lock (ignored) Replay detection "
+ "(Bucket No: 0 (invalid)) [ignored]:\n");
+ lck.in.lock_sequence = 0x000 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 1):\n");
+
+ /*
+ * Obtain Exclusive Lock of length 100 bytes using Bucket Num 1
+ * and Bucket Seq 1.
+ */
+ lck.in.lock_sequence = 0x010 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Server detects Replay of Byte Range locks using the Lock Sequence
+ * Numbers. And ignores the requests completely.
+ */
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* status: still locked */
+
+ /*
+ * Server will not grant same Byte Range using a different Bucket Seq
+ */
+ lck.in.lock_sequence = 0x010 + 0x2;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 2):\n");
+
+ /*
+ * Server will not grant same Byte Range using a different Bucket Num
+ */
+ lck.in.lock_sequence = 0x020 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* status: still locked */
+
+ /* test with invalid bucket when file is locked */
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 65 (invalid)) [ignored]:\n");
+
+ lck.in.lock_sequence = 0x410 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* status: unlocked */
+
+ /*
+ * Lock again for the unlock replay test
+ */
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 64):\n");
+
+ /*
+ * Server will not grant same Byte Range using a different Bucket Num
+ */
+ lck.in.lock_sequence = 0x400 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /*
+ * Test Unlock replay detection
+ */
+ lck.in.lock_sequence = 0x400 + 0x2;
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK); /* new seq num ==> unlocked */
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK); /* replay detected ==> ignored */
+
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck); /* same seq num ==> ignored */
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* verify it's unlocked: */
+ lck.in.lock_sequence = 0x400 + 0x3;
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* status: not locked */
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/**
+ * Test lock replay detection
+ *
+ * This test check the SMB 3 behaviour of lock sequence checking,
+ * which should be implemented for all handles.
+ *
+ * Make it clear that this test is supposed to pass a
+ * server implementing the specification:
+ *
+ * [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request
+ *
+ * ...
+ *
+ * ... if Open.IsResilient or Open.IsDurable or Open.IsPersistent is
+ * TRUE or if Connection.Dialect belongs to the SMB 3.x dialect family
+ * and Connection.ServerCapabilities includes
+ * SMB2_GLOBAL_CAP_MULTI_CHANNEL bit, the server SHOULD<314>
+ * perform lock sequence verification ...
+ *
+ * ...
+ *
+ * <314> Section 3.3.5.14: Windows 7 and Windows Server 2008 R2 perform
+ * lock sequence verification only when Open.IsResilient is TRUE.
+ * Windows 8 through Windows 10 v1909 and Windows Server 2012 through
+ * Windows Server v1909 perform lock sequence verification only when
+ * Open.IsResilient or Open.IsPersistent is TRUE.
+ *
+ * Note <314> also applies to all versions (at least) up to Windows Server v2004.
+ *
+ * Hopefully this will be fixed in future Windows versions and they
+ * will avoid Note <314>.
+ */
+static bool _test_replay_smb3_specification(struct torture_context *torture,
+ struct smb2_tree *tree,
+ const char *testname,
+ bool use_durable)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create io;
+ struct smb2_handle h;
+ struct smb2_lock lck;
+ struct smb2_lock_element el;
+ char fname[256];
+ struct smb2_transport *transport = tree->session->transport;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(torture, "SMB 3.0.0 Dialect family or above \
+ required for Lock Replay tests\n");
+ }
+
+ snprintf(fname, sizeof(fname), "%s\\%s.dat", BASEDIR, testname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ torture_comment(torture, "%s: Testing Open File:\n", testname);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = use_durable;
+
+ status = smb2_create(tree, torture, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.out.file.handle;
+ CHECK_VALUE(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VALUE(io.out.durable_open, use_durable);
+ CHECK_VALUE(io.out.durable_open_v2, false);
+ CHECK_VALUE(io.out.persistent_open, false);
+
+ /*
+ * Setup initial parameters
+ */
+ el = (struct smb2_lock_element) {
+ .length = 100,
+ .offset = 100,
+ };
+ lck = (struct smb2_lock) {
+ .in.locks = &el,
+ .in.lock_count = 0x0001,
+ .in.file.handle = h
+ };
+
+ torture_comment(torture,
+ "Testing SMB 3 LockSequence for all Handles\n");
+
+ /*
+ * Test with an invalid bucket number (only 1..64 are valid).
+ * With an invalid number, lock replay detection is not performed.
+ */
+ torture_comment(torture, "Testing Lock (ignored) Replay detection "
+ "(Bucket No: 0 (invalid)) [ignored]:\n");
+ lck.in.lock_sequence = 0x000 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 1):\n");
+
+ /*
+ * Obtain Exclusive Lock of length 100 bytes using Bucket Num 1
+ * and Bucket Seq 1.
+ */
+ lck.in.lock_sequence = 0x010 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Server detects Replay of Byte Range locks using the Lock Sequence
+ * Numbers. And ignores the requests completely.
+ */
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* status: still locked */
+
+ /*
+ * Server will not grant same Byte Range using a different Bucket Seq
+ */
+ lck.in.lock_sequence = 0x010 + 0x2;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 2):\n");
+
+ /*
+ * Server will not grant same Byte Range using a different Bucket Num
+ */
+ lck.in.lock_sequence = 0x020 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /* status: still locked */
+
+ /* test with invalid bucket when file is locked */
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 65 (invalid)) [ignored]:\n");
+
+ lck.in.lock_sequence = 0x410 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* status: unlocked */
+
+ /*
+ * Lock again for the unlock replay test
+ */
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Testing Lock Replay detection "
+ "(Bucket No: 64):\n");
+
+ /*
+ * Server will not grant same Byte Range using a different Bucket Num
+ */
+ lck.in.lock_sequence = 0x400 + 0x1;
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ /*
+ * Test Unlock replay detection
+ */
+ lck.in.lock_sequence = 0x400 + 0x2;
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK); /* new seq num ==> unlocked */
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK); /* replay detected ==> ignored */
+
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE | SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck); /* same seq num ==> ignored */
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* verify it's unlocked: */
+ lck.in.lock_sequence = 0x400 + 0x3;
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+ /* status: not locked */
+
+done:
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_replay_smb3_specification_durable(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ const char *testname = "replay_smb3_specification_durable";
+ struct smb2_transport *transport = tree->session->transport;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB2_10) {
+ torture_skip(torture, "SMB 2.1.0 Dialect family or above \
+ required for Lock Replay tests on durable handles\n");
+ }
+
+ return _test_replay_smb3_specification(torture, tree, testname, true);
+}
+
+static bool test_replay_smb3_specification_multi(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ const char *testname = "replay_smb3_specification_multi";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t server_capabilities;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(torture, "SMB 3.0.0 Dialect family or above \
+ required for Lock Replay tests on without durable handles\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(torture, "MULTI_CHANNEL is \
+ required for Lock Replay tests on without durable handles\n");
+ }
+
+ return _test_replay_smb3_specification(torture, tree, testname, false);
+}
+
+/**
+ * Test lock interaction between smbd and ctdb with tombstone records.
+ *
+ * Re-locking an unlocked record could lead to a deadlock between
+ * smbd and ctdb. Make sure we don't regress.
+ *
+ * https://bugzilla.samba.org/show_bug.cgi?id=12005
+ * https://bugzilla.samba.org/show_bug.cgi?id=10008
+ */
+static bool test_deadlock(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ uint8_t buf[200];
+ const char *fname = BASEDIR "\\deadlock.txt";
+
+ if (!lpcfg_clustering(torture->lp_ctx)) {
+ torture_skip(torture, "Test must be run on a ctdb cluster\n");
+ return true;
+ }
+
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ torture_assert_ntstatus_ok(torture, status,
+ "torture_smb2_testdir failed");
+ smb2_util_close(tree, _h);
+
+ status = torture_smb2_testfile(tree, fname, &_h);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "torture_smb2_testfile failed");
+ h = &_h;
+
+ ZERO_STRUCT(buf);
+ status = smb2_util_write(tree, *h, buf, 0, ARRAY_SIZE(buf));
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_util_write failed");
+
+ status = test_smb2_lock(tree, *h, 0, 1, true);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "test_smb2_lock failed");
+
+ status = test_smb2_unlock(tree, *h, 0, 1);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "test_smb2_unlock failed");
+
+ status = test_smb2_lock(tree, *h, 0, 1, true);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "test_smb2_lock failed");
+
+ status = test_smb2_unlock(tree, *h, 0, 1);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "test_smb2_unlock failed");
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/* basic testing of SMB2 locking
+*/
+struct torture_suite *torture_smb2_lock_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "lock");
+ torture_suite_add_1smb2_test(suite, "valid-request",
+ test_valid_request);
+ torture_suite_add_1smb2_test(suite, "rw-none", test_lock_rw_none);
+ torture_suite_add_1smb2_test(suite, "rw-shared", test_lock_rw_shared);
+ torture_suite_add_1smb2_test(suite, "rw-exclusive",
+ test_lock_rw_exclusive);
+ torture_suite_add_1smb2_test(suite, "auto-unlock",
+ test_lock_auto_unlock);
+ torture_suite_add_1smb2_test(suite, "lock", test_lock);
+ torture_suite_add_1smb2_test(suite, "async", test_async);
+ torture_suite_add_1smb2_test(suite, "cancel", test_cancel);
+ torture_suite_add_1smb2_test(suite, "cancel-tdis", test_cancel_tdis);
+ torture_suite_add_1smb2_test(suite, "cancel-logoff",
+ test_cancel_logoff);
+ torture_suite_add_1smb2_test(suite, "errorcode", test_errorcode);
+ torture_suite_add_1smb2_test(suite, "zerobytelength",
+ test_zerobytelength);
+ torture_suite_add_1smb2_test(suite, "zerobyteread",
+ test_zerobyteread);
+ torture_suite_add_1smb2_test(suite, "unlock", test_unlock);
+ torture_suite_add_1smb2_test(suite, "multiple-unlock",
+ test_multiple_unlock);
+ torture_suite_add_1smb2_test(suite, "stacking", test_stacking);
+ torture_suite_add_1smb2_test(suite, "contend", test_contend);
+ torture_suite_add_1smb2_test(suite, "context", test_context);
+ torture_suite_add_1smb2_test(suite, "range", test_range);
+ torture_suite_add_2smb2_test(suite, "overlap", test_overlap);
+ torture_suite_add_1smb2_test(suite, "truncate", test_truncate);
+ torture_suite_add_1smb2_test(suite, "replay_broken_windows",
+ test_replay_broken_windows);
+ torture_suite_add_1smb2_test(suite, "replay_smb3_specification_durable",
+ test_replay_smb3_specification_durable);
+ torture_suite_add_1smb2_test(suite, "replay_smb3_specification_multi",
+ test_replay_smb3_specification_multi);
+ torture_suite_add_1smb2_test(suite, "ctdb-delrec-deadlock", test_deadlock);
+
+ suite->description = talloc_strdup(suite, "SMB2-LOCK tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/mangle.c b/source4/torture/smb2/mangle.c
new file mode 100644
index 0000000..09097ee
--- /dev/null
+++ b/source4/torture/smb2/mangle.c
@@ -0,0 +1,341 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - mangling test
+ Copyright (C) Andrew Tridgell 2002
+ Copyright (C) David Mulder 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/dir.h"
+#include <tdb.h>
+#include "../lib/util/util_tdb.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+#undef strcasecmp
+
+static TDB_CONTEXT *tdb;
+
+#define NAME_LENGTH 20
+
+static unsigned int total, collisions, failures;
+
+static bool test_one(struct torture_context *tctx, struct smb2_tree *tree,
+ const char *name)
+{
+ struct smb2_handle fnum;
+ const char *shortname;
+ const char *name2;
+ NTSTATUS status;
+ TDB_DATA data;
+ struct smb2_create io = {0};
+
+ total++;
+
+ io.in.fname = name;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA |
+ SEC_FILE_EXECUTE;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ status = smb2_create(tree, tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "open of %s failed (%s)\n", name,
+ nt_errstr(status));
+ return false;
+ }
+ fnum = io.out.file.handle;
+
+ status = smb2_util_close(tree, fnum);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx, "close of %s failed (%s)\n", name,
+ nt_errstr(status));
+ return false;
+ }
+
+ /* get the short name */
+ status = smb2_qpathinfo_alt_name(tctx, tree, name, &shortname);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "query altname of %s failed (%s)\n",
+ name, nt_errstr(status));
+ return false;
+ }
+
+ name2 = talloc_asprintf(tctx, "mangle_test\\%s", shortname);
+ status = smb2_util_unlink(tree, name2);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx, "unlink of %s (%s) failed (%s)\n",
+ name2, name, nt_errstr(status));
+ return false;
+ }
+
+ /* recreate by short name */
+ io = (struct smb2_create){0};
+ io.in.fname = name2;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA |
+ SEC_FILE_EXECUTE;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ status = smb2_create(tree, tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "open2 of %s failed (%s)\n", name2,
+ nt_errstr(status));
+ return false;
+ }
+ fnum = io.out.file.handle;
+
+ status = smb2_util_close(tree, fnum);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx, "close of %s failed (%s)\n", name,
+ nt_errstr(status));
+ return false;
+ }
+
+ /* and unlink by long name */
+ status = smb2_util_unlink(tree, name);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_comment(tctx, "unlink2 of %s (%s) failed (%s)\n",
+ name, name2, nt_errstr(status));
+ failures++;
+ smb2_util_unlink(tree, name2);
+ return true;
+ }
+
+ /* see if the short name is already in the tdb */
+ data = tdb_fetch_bystring(tdb, shortname);
+ if (data.dptr) {
+ /* maybe its a duplicate long name? */
+ if (strcasecmp(name, (const char *)data.dptr) != 0) {
+ /* we have a collision */
+ collisions++;
+ torture_comment(tctx, "Collision between %s and %s"
+ " -> %s (coll/tot: %u/%u)\n",
+ name, data.dptr, shortname, collisions,
+ total);
+ }
+ free(data.dptr);
+ } else {
+ TDB_DATA namedata;
+ /* store it for later */
+ namedata.dptr = discard_const_p(uint8_t, name);
+ namedata.dsize = strlen(name)+1;
+ tdb_store_bystring(tdb, shortname, namedata, TDB_REPLACE);
+ }
+
+ return true;
+}
+
+
+static char *gen_name(struct torture_context *tctx)
+{
+ const char *chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-$~...";
+ unsigned int max_idx = strlen(chars);
+ unsigned int len;
+ int i;
+ char *p = NULL;
+ char *name = NULL;
+
+ name = talloc_strdup(tctx, "mangle_test\\");
+ if (!name) {
+ return NULL;
+ }
+
+ len = 1 + random() % NAME_LENGTH;
+
+ name = talloc_realloc(tctx, name, char, strlen(name) + len + 6);
+ if (!name) {
+ return NULL;
+ }
+ p = name + strlen(name);
+
+ for (i=0;i<len;i++) {
+ p[i] = chars[random() % max_idx];
+ }
+
+ p[i] = 0;
+
+ if (ISDOT(p) || ISDOTDOT(p)) {
+ p[0] = '_';
+ }
+
+ /* have a high probability of a common lead char */
+ if (random() % 2 == 0) {
+ p[0] = 'A';
+ }
+
+ /* and a medium probability of a common lead string */
+ if ((len > 5) && (random() % 10 == 0)) {
+ strlcpy(p, "ABCDE", 6);
+ }
+
+ /* and a high probability of a good extension length */
+ if (random() % 2 == 0) {
+ char *s = strrchr(p, '.');
+ if (s) {
+ s[4] = 0;
+ }
+ }
+
+ return name;
+}
+
+
+static bool torture_smb2_mangle(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ extern int torture_numops;
+ int i;
+ bool ok;
+ NTSTATUS status;
+
+ /* we will use an internal tdb to store the names we have used */
+ tdb = tdb_open(NULL, 100000, TDB_INTERNAL, 0, 0);
+ torture_assert(torture, tdb, "ERROR: Failed to open tdb\n");
+
+ ok = smb2_util_setup_dir(torture, tree, "mangle_test");
+ torture_assert(torture, ok, "smb2_util_setup_dir failed\n");
+
+ for (i=0;i<torture_numops;i++) {
+ char *name;
+
+ name = gen_name(torture);
+ torture_assert(torture, name, "Name allocation failed\n");
+
+ ok = test_one(torture, tree, name);
+ torture_assert(torture, ok, talloc_asprintf(torture,
+ "Mangle names failed with %s", name));
+ if (total && total % 100 == 0) {
+ if (torture_setting_bool(torture, "progress", true)) {
+ torture_comment(torture,
+ "collisions %u/%u - %.2f%% (%u failures)\r",
+ collisions, total, (100.0*collisions) / total, failures);
+ }
+ }
+ }
+
+ smb2_util_unlink(tree, "mangle_test\\*");
+ status = smb2_util_rmdir(tree, "mangle_test");
+ torture_assert_ntstatus_ok(torture, status,
+ "ERROR: Failed to remove directory\n");
+
+ torture_comment(torture,
+ "\nTotal collisions %u/%u - %.2f%% (%u failures)\n",
+ collisions, total, (100.0*collisions) / total, failures);
+
+ return (failures == 0);
+}
+
+static bool test_mangled_mask(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ const char *dname = "single_find_with_mangled_name";
+ const char *fname = "single_find_with_mangled_name\\verylongfilename";
+ const char *shortname = NULL;
+ NTSTATUS status;
+ struct smb2_handle dh = {{0}};
+ struct smb2_handle fh = {{0}};
+ struct smb2_find f;
+ union smb_search_data *d;
+ unsigned count, i;
+
+ torture_comment(tctx, "Checking find with mangled search mask\n");
+
+ smb2_deltree(tree, dname);
+
+ status = torture_smb2_testdir(tree, dname, &dh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed");
+
+ status = torture_smb2_testfile(tree, fname, &fh);
+ smb2_util_close(tree, fh);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = dh;
+ f.in.pattern = "*";
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+ smb2_util_close(tree, dh);
+ ZERO_STRUCT(dh);
+
+ for (i = 0; i < count; i++) {
+ const char *found = d[i].both_directory_info.name.s;
+
+ if (!strcmp(found, ".") || !strcmp(found, "..")) {
+ continue;
+ }
+
+ torture_assert_str_equal_goto(tctx, found, "verylongfilename", ret, done,
+ "Bad filename\n");
+ shortname = d[i].both_directory_info.short_name.s;
+ break;
+ }
+
+ torture_assert_not_null_goto(tctx, shortname, ret, done,
+ "shortname is NULL\n");
+
+ torture_comment(tctx, "Got shortname: %s\n", shortname);
+
+ status = torture_smb2_testdir(tree, dname, &dh);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = dh;
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ f.in.pattern = shortname;
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+ smb2_util_close(tree, dh);
+ ZERO_STRUCT(dh);
+
+done:
+ if (!smb2_util_handle_empty(fh)) {
+ smb2_util_close(tree, fh);
+ }
+ if (!smb2_util_handle_empty(dh)) {
+ smb2_util_close(tree, dh);
+ }
+ smb2_deltree(tree, dname);
+ return ret;
+
+}
+
+struct torture_suite *torture_smb2_name_mangling_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = NULL;
+
+ suite = torture_suite_create(ctx, "name-mangling");
+ suite->description = talloc_strdup(suite, "SMB2 name mangling tests");
+
+ torture_suite_add_1smb2_test(suite, "mangle", torture_smb2_mangle);
+ torture_suite_add_1smb2_test(suite, "mangled-mask", test_mangled_mask);
+ return suite;
+}
diff --git a/source4/torture/smb2/max_allowed.c b/source4/torture/smb2/max_allowed.c
new file mode 100644
index 0000000..af8b08a
--- /dev/null
+++ b/source4/torture/smb2/max_allowed.c
@@ -0,0 +1,248 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - deny mode scanning functions
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) David Mulder 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/security/security.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+#define MAXIMUM_ALLOWED_FILE "torture_maximum_allowed"
+static bool torture_smb2_maximum_allowed(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct security_descriptor *sd = NULL, *sd_orig = NULL;
+ struct smb2_create io = {0};
+ TALLOC_CTX *mem_ctx = NULL;
+ struct smb2_handle fnum = {{0}};
+ int i;
+ bool ret = true;
+ NTSTATUS status;
+ union smb_fileinfo q;
+ const char *owner_sid = NULL;
+ bool has_restore_privilege, has_backup_privilege, has_system_security_privilege;
+
+ mem_ctx = talloc_init("torture_maximum_allowed");
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done,
+ "talloc allocation failed\n");
+
+ if (!torture_setting_bool(tctx, "sacl_support", true))
+ torture_warning(tctx, "Skipping SACL related tests!\n");
+
+ sd = security_descriptor_dacl_create(mem_ctx,
+ 0, NULL, NULL,
+ SID_NT_AUTHENTICATED_USERS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_READ,
+ 0, NULL);
+ torture_assert_goto(tctx, sd != NULL, ret, done,
+ "security descriptor creation failed\n");
+
+ /* Blank slate */
+ smb2_util_unlink(tree, MAXIMUM_ALLOWED_FILE);
+
+ /* create initial file with restrictive SD */
+ io.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.fname = MAXIMUM_ALLOWED_FILE;
+ io.in.sec_desc = sd;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ talloc_asprintf(tctx, "Incorrect status %s - should be %s\n",
+ nt_errstr(status), nt_errstr(NT_STATUS_OK)));
+ fnum = io.out.file.handle;
+
+ /* the correct answers for this test depends on whether the
+ user has restore privileges. To find that out we first need
+ to know our SID - get it from the owner_sid of the file we
+ just created */
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = fnum;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ talloc_asprintf(tctx, "Incorrect status %s - should be %s\n",
+ nt_errstr(status), nt_errstr(NT_STATUS_OK)));
+ sd_orig = q.query_secdesc.out.sd;
+
+ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid);
+
+ status = torture_smb2_check_privilege(tree,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_RESTORE));
+ has_restore_privilege = NT_STATUS_IS_OK(status);
+ torture_comment(tctx, "Checked SEC_PRIV_RESTORE for %s - %s\n",
+ owner_sid,
+ has_restore_privilege?"Yes":"No");
+
+ status = torture_smb2_check_privilege(tree,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_BACKUP));
+ has_backup_privilege = NT_STATUS_IS_OK(status);
+ torture_comment(tctx, "Checked SEC_PRIV_BACKUP for %s - %s\n",
+ owner_sid,
+ has_backup_privilege?"Yes":"No");
+
+ status = torture_smb2_check_privilege(tree,
+ owner_sid,
+ sec_privilege_name(SEC_PRIV_SECURITY));
+ has_system_security_privilege = NT_STATUS_IS_OK(status);
+ torture_comment(tctx, "Checked SEC_PRIV_SECURITY for %s - %s\n",
+ owner_sid,
+ has_system_security_privilege?"Yes":"No");
+
+ smb2_util_close(tree, fnum);
+
+ for (i = 0; i < 32; i++) {
+ uint32_t mask = SEC_FLAG_MAXIMUM_ALLOWED | (1u << i);
+ /*
+ * SEC_GENERIC_EXECUTE is a complete subset of
+ * SEC_GENERIC_READ when mapped to specific bits,
+ * so we need to include it in the basic OK mask.
+ */
+ uint32_t ok_mask = SEC_RIGHTS_FILE_READ | SEC_GENERIC_READ | SEC_GENERIC_EXECUTE |
+ SEC_STD_DELETE | SEC_STD_WRITE_DAC;
+
+ /*
+ * Now SEC_RIGHTS_PRIV_RESTORE and SEC_RIGHTS_PRIV_BACKUP
+ * don't include any generic bits (they're used directly
+ * in the fileserver where the generic bits have already
+ * been mapped into file specific bits) we need to add the
+ * generic bits to the ok_mask when we have these privileges.
+ */
+ if (has_restore_privilege) {
+ ok_mask |= SEC_RIGHTS_PRIV_RESTORE|SEC_GENERIC_WRITE;
+ }
+ if (has_backup_privilege) {
+ ok_mask |= SEC_RIGHTS_PRIV_BACKUP|SEC_GENERIC_READ;
+ }
+ if (has_system_security_privilege) {
+ ok_mask |= SEC_FLAG_SYSTEM_SECURITY;
+ }
+
+ /* Skip all SACL related tests. */
+ if ((!torture_setting_bool(tctx, "sacl_support", true)) &&
+ (mask & SEC_FLAG_SYSTEM_SECURITY))
+ continue;
+
+ io = (struct smb2_create){0};
+ io.in.desired_access = mask;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.impersonation_level =
+ NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.in.fname = MAXIMUM_ALLOWED_FILE;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ if (mask & ok_mask ||
+ mask == SEC_FLAG_MAXIMUM_ALLOWED) {
+ torture_assert_ntstatus_ok_goto(tctx, status, ret,
+ done, talloc_asprintf(tctx,
+ "Incorrect status %s - should be %s\n",
+ nt_errstr(status), nt_errstr(NT_STATUS_OK)));
+ } else {
+ if (mask & SEC_FLAG_SYSTEM_SECURITY) {
+ torture_assert_ntstatus_equal_goto(tctx,
+ status, NT_STATUS_PRIVILEGE_NOT_HELD,
+ ret, done, talloc_asprintf(tctx,
+ "Incorrect status %s - should be %s\n",
+ nt_errstr(status),
+ nt_errstr(NT_STATUS_PRIVILEGE_NOT_HELD)));
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx,
+ status, NT_STATUS_ACCESS_DENIED,
+ ret, done, talloc_asprintf(tctx,
+ "Incorrect status %s - should be %s\n",
+ nt_errstr(status),
+ nt_errstr(NT_STATUS_ACCESS_DENIED)));
+ }
+ }
+
+ fnum = io.out.file.handle;
+
+ smb2_util_close(tree, fnum);
+ }
+
+ done:
+ smb2_util_unlink(tree, MAXIMUM_ALLOWED_FILE);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool torture_smb2_read_only_file(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create c;
+ struct smb2_handle h = {{0}};
+ bool ret = true;
+ NTSTATUS status;
+
+ smb2_deltree(tree, MAXIMUM_ALLOWED_FILE);
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_ALL,
+ .in.file_attributes = FILE_ATTRIBUTE_READONLY,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.fname = MAXIMUM_ALLOWED_FILE,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h = c.out.file.handle;
+ smb2_util_close(tree, h);
+ ZERO_STRUCT(h);
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_READONLY,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.fname = MAXIMUM_ALLOWED_FILE,
+ };
+
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ret, done,
+ "Failed to open READ-ONLY file with SEC_FLAG_MAXIMUM_ALLOWED\n");
+ h = c.out.file.handle;
+ smb2_util_close(tree, h);
+ ZERO_STRUCT(h);
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_deltree(tree, MAXIMUM_ALLOWED_FILE);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_max_allowed(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "maximum_allowed");
+
+ torture_suite_add_1smb2_test(suite, "maximum_allowed", torture_smb2_maximum_allowed);
+ torture_suite_add_1smb2_test(suite, "read_only", torture_smb2_read_only_file);
+ return suite;
+}
diff --git a/source4/torture/smb2/maxfid.c b/source4/torture/smb2/maxfid.c
new file mode 100644
index 0000000..5f0b9fe
--- /dev/null
+++ b/source4/torture/smb2/maxfid.c
@@ -0,0 +1,149 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 maxfid test
+
+ Copyright (C) Christof Schmitt 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+bool torture_smb2_maxfid(struct torture_context *tctx)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_tree *tree = NULL;
+ const char *dname = "smb2_maxfid";
+ size_t i, maxfid;
+ struct smb2_handle *handles, dir_handle = { };
+ size_t max_handles;
+
+ /*
+ * We limited this to 65520 as socket_wrapper has a limit of
+ * 65535 (0xfff0) open sockets.
+ *
+ * It could be increased by setting the following env variable:
+ *
+ * SOCKET_WRAPPER_MAX_SOCKETS=100000
+ */
+ max_handles = torture_setting_int(tctx, "maxopenfiles", 65520);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ handles = talloc_array(tctx, struct smb2_handle, max_handles);
+ if (handles == 0) {
+ torture_fail(tctx, "Could not allocate handles array.\n");
+ return false;
+ }
+
+ smb2_deltree(tree, dname);
+
+ status = torture_smb2_testdir(tree, dname, &dir_handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed");
+ smb2_util_close(tree, dir_handle);
+
+ torture_comment(tctx, "Creating subdirectories\n");
+
+ for (i = 0; i < max_handles; i += 1000) {
+ char *name;
+ struct smb2_create create = { };
+ struct smb2_close close = { };
+
+ name = talloc_asprintf(tctx, "%s\\%zu", dname, i / 1000);
+ torture_assert_goto(tctx, (name != NULL), ret, done,
+ "no memory for directory name\n");
+
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = name;
+
+ status = smb2_create(tree, tctx, &create);
+ talloc_free(name);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE directory failed\n");
+
+ close.in.file.handle = create.out.file.handle;
+ status = smb2_close(tree, &close);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE directory failed\n");
+ }
+
+ torture_comment(tctx, "Testing maximum number of open files\n");
+
+ for (i = 0; i < max_handles; i++) {
+ char *name;
+ struct smb2_create create = { };
+
+ name = talloc_asprintf(tctx, "%s\\%zu\\%zu", dname, i / 1000, i);
+ torture_assert_goto(tctx, (name != NULL), ret, done,
+ "no memory for file name\n");
+
+ create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+ create.in.create_options = 0;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.fname = name;
+
+ status = smb2_create(tree, tctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "create of %s failed: %s\n",
+ name, nt_errstr(status));
+ talloc_free(name);
+ break;
+ }
+ talloc_free(name);
+
+ handles[i] = create.out.file.handle;
+ }
+
+ maxfid = i;
+ if (maxfid == max_handles) {
+ torture_comment(tctx, "Reached test limit of %zu open files. "
+ "Adjust to higher test with "
+ "--option=torture:maxopenfiles=NNN\n", maxfid);
+ }
+
+ torture_comment(tctx, "Cleanup open files\n");
+
+ for (i = 0; i < maxfid; i++) {
+ status = smb2_util_close(tree, handles[i]);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE failed\n");
+ }
+
+done:
+ smb2_deltree(tree, dname);
+ talloc_free(handles);
+
+ return ret;
+}
diff --git a/source4/torture/smb2/maxwrite.c b/source4/torture/smb2/maxwrite.c
new file mode 100644
index 0000000..bc52ebc
--- /dev/null
+++ b/source4/torture/smb2/maxwrite.c
@@ -0,0 +1,137 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 write operations
+
+ Copyright (C) Andrew Tridgell 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/security.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+#define FNAME "testmaxwrite.dat"
+
+/*
+ test writing
+*/
+static NTSTATUS torture_smb2_write(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_handle handle)
+{
+ struct smb2_write w;
+ struct smb2_read r;
+ NTSTATUS status;
+ int i, len;
+ int max = 80000000;
+ int min = 1;
+
+ while (max > min) {
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+
+
+ len = 1+(min+max)/2;
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = handle;
+ w.in.offset = 0;
+ w.in.data = data_blob_talloc(tmp_ctx, NULL, len);
+
+ for (i=0;i<len;i++) {
+ w.in.data.data[i] = i % 256;
+ }
+
+ torture_comment(tctx, "trying to write %d bytes (min=%d max=%d)\n",
+ len, min, max);
+
+ status = smb2_write(tree, &w);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "write failed - %s\n", nt_errstr(status));
+ max = len-1;
+ status = smb2_util_close(tree, handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* vista bug */
+ torture_comment(tctx, "coping with server disconnect\n");
+ talloc_free(tree);
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_comment(tctx, "failed to reconnect\n");
+ return NT_STATUS_NET_WRITE_FAULT;
+ }
+ }
+ status = torture_smb2_createfile(tctx, tree, FNAME, &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "failed to create file handle\n");
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ continue;
+ } else {
+ min = len;
+ }
+
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = handle;
+ r.in.length = len;
+ r.in.offset = 0;
+
+ torture_comment(tctx, "reading %d bytes\n", len);
+
+ status = smb2_read(tree, tmp_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "read failed - %s\n", nt_errstr(status));
+ } else if (w.in.data.length != r.out.data.length ||
+ memcmp(w.in.data.data, r.out.data.data, len) != 0) {
+ torture_comment(tctx, "read data mismatch\n");
+ }
+
+ talloc_free(tmp_ctx);
+ }
+
+ torture_comment(tctx, "converged: len=%d\n", max);
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, FNAME);
+
+ return NT_STATUS_OK;
+}
+
+
+
+/*
+ basic testing of SMB2 connection calls
+*/
+bool torture_smb2_maxwrite(struct torture_context *tctx)
+{
+ struct smb2_tree *tree;
+ struct smb2_handle h1;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_smb2_createfile(tctx, tree, FNAME, &h1),
+ "failed to create file handle");
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_smb2_write(tctx, tree, h1),
+ "Write failed");
+
+ return true;
+}
diff --git a/source4/torture/smb2/mkdir.c b/source4/torture/smb2/mkdir.c
new file mode 100644
index 0000000..f797b5c
--- /dev/null
+++ b/source4/torture/smb2/mkdir.c
@@ -0,0 +1,105 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_MKDIR_* and RAW_RMDIR_* individual test suite
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) David Mulder 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "libcli/smb_composite/smb_composite.h"
+
+#define BASEDIR "mkdirtest"
+
+/*
+ test mkdir ops
+*/
+bool torture_smb2_mkdir(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_handle h = {{0}};
+ const char *path = BASEDIR "\\mkdir.dir";
+ NTSTATUS status;
+ bool ret = true;
+
+ ret = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert(tctx, ret, "Failed to setup up test directory: " BASEDIR);
+
+ /*
+ basic mkdir
+ */
+ status = smb2_util_mkdir(tree, path);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Incorrect status");
+
+ torture_comment(tctx, "Testing mkdir collision\n");
+
+ /* 2nd create */
+ status = smb2_util_mkdir(tree, path);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_NAME_COLLISION,
+ ret, done, "Incorrect status");
+
+ /* basic rmdir */
+ status = smb2_util_rmdir(tree, path);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Incorrect status");
+
+ status = smb2_util_rmdir(tree, path);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Incorrect status");
+
+ torture_comment(tctx, "Testing mkdir collision with file\n");
+
+ /* name collision with a file */
+ smb2_create_complex_file(tctx, tree, path, &h);
+ smb2_util_close(tree, h);
+ status = smb2_util_mkdir(tree, path);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_NAME_COLLISION,
+ ret, done, "Incorrect status");
+
+ torture_comment(tctx, "Testing rmdir with file\n");
+
+ /* delete a file with rmdir */
+ status = smb2_util_rmdir(tree, path);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NOT_A_DIRECTORY,
+ ret, done, "Incorrect status");
+
+ smb2_util_unlink(tree, path);
+
+ torture_comment(tctx, "Testing invalid dir\n");
+
+ /* create an invalid dir */
+ status = smb2_util_mkdir(tree, "..\\..\\..");
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+ ret, done, "Incorrect status");
+
+ torture_comment(tctx, "Testing t2mkdir bad path\n");
+ status = smb2_util_mkdir(tree, BASEDIR "\\bad_path\\bad_path");
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_PATH_NOT_FOUND,
+ ret, done, "Incorrect status");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
diff --git a/source4/torture/smb2/multichannel.c b/source4/torture/smb2/multichannel.c
new file mode 100644
index 0000000..6b6e00e
--- /dev/null
+++ b/source4/torture/smb2/multichannel.c
@@ -0,0 +1,2743 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * test SMB2 multichannel operations
+ *
+ * Copyright (C) Guenther Deschner, 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/security/security.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/socket/socket.h"
+#include "lib/param/param.h"
+#include "lib/events/events.h"
+#include "oplock_break_handler.h"
+#include "lease_break_handler.h"
+#include "torture/smb2/block.h"
+
+#define BASEDIR "multichanneltestdir"
+
+#define CHECK_STATUS(status, correct) \
+ torture_assert_ntstatus_equal_goto(tctx, status, correct,\
+ ret, done, "")
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s" \
+ " got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ goto done; \
+ } } while (0)
+
+#define CHECK_VAL_GREATER_THAN(v, gt_val) do { \
+ if ((v) <= (gt_val)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s): wrong value for %s got 0x%x - " \
+ "should be greater than 0x%x\n", \
+ __location__, #v, (int)v, (int)gt_val); \
+ ret = false; \
+ goto done; \
+ } } while (0)
+
+#define CHECK_CREATED(__io, __created, __attribute) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, \
+ NTCREATEX_ACTION_ ## __created); \
+ CHECK_VAL((__io)->out.size, 0); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while (0)
+
+#define CHECK_PTR(ptr, correct) do { \
+ if ((ptr) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
+ "got 0x%p - should be 0x%p\n", \
+ __location__, #ptr, ptr, correct); \
+ ret = false; \
+ goto done; \
+ } } while (0)
+
+#define CHECK_LEASE(__io, __state, __oplevel, __key, __flags) \
+ do { \
+ CHECK_VAL((__io)->out.lease_response.lease_version, 1); \
+ if (__oplevel) { \
+ CHECK_VAL((__io)->out.oplock_level, \
+ SMB2_OPLOCK_LEVEL_LEASE); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
+ (__key)); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
+ ~(__key)); \
+ CHECK_VAL((__io)->out.lease_response.lease_state,\
+ smb2_util_lease_state(__state)); \
+ } else { \
+ CHECK_VAL((__io)->out.oplock_level,\
+ SMB2_OPLOCK_LEVEL_NONE); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[0],\
+ 0); \
+ CHECK_VAL((__io)->out.lease_response.lease_key.data[1],\
+ 0); \
+ CHECK_VAL((__io)->out.lease_response.lease_state, 0); \
+ } \
+ \
+ CHECK_VAL((__io)->out.lease_response.lease_flags, (__flags)); \
+ CHECK_VAL((__io)->out.lease_response.lease_duration, 0); \
+ CHECK_VAL((__io)->out.lease_response.lease_epoch, 0); \
+ } while (0)
+
+#define CHECK_LEASE_V2(__io, __state, __oplevel, __key, __flags, __parent, __epoch) \
+ do { \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_version, 2); \
+ if (__oplevel) { \
+ CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], (__key)); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], ~(__key)); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_state, smb2_util_lease_state(__state)); \
+ } else { \
+ CHECK_VAL((__io)->out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[0], 0); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_key.data[1], 0); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_state, 0); \
+ } \
+ \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_flags, __flags); \
+ if (__flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { \
+ CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[0], (__parent)); \
+ CHECK_VAL((__io)->out.lease_response_v2.parent_lease_key.data[1], ~(__parent)); \
+ } \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_duration, 0); \
+ CHECK_VAL((__io)->out.lease_response_v2.lease_epoch, (__epoch)); \
+ } while(0)
+
+#define CHECK_LEASE_BREAK_V2(__lb, __key, __from, __to, __break_flags, __new_epoch) \
+ do { \
+ CHECK_VAL((__lb).current_lease.lease_key.data[0], (__key)); \
+ CHECK_VAL((__lb).current_lease.lease_key.data[1], ~(__key)); \
+ CHECK_VAL((__lb).current_lease.lease_state, smb2_util_lease_state(__from)); \
+ CHECK_VAL((__lb).new_epoch, (__new_epoch)); \
+ CHECK_VAL((__lb).break_flags, (__break_flags)); \
+ CHECK_VAL((__lb).new_lease_state, smb2_util_lease_state(__to)); \
+ } while(0)
+
+static bool test_ioctl_network_interface_info(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct fsctl_net_iface_info *info)
+{
+ union smb_ioctl ioctl;
+ struct smb2_handle fh;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx,
+ "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
+ }
+
+ ZERO_STRUCT(ioctl);
+
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+
+ fh.data[0] = UINT64_MAX;
+ fh.data[1] = UINT64_MAX;
+
+ ioctl.smb2.in.file.handle = fh;
+ ioctl.smb2.in.function = FSCTL_QUERY_NETWORK_INTERFACE_INFO;
+ /* Windows client sets this to 64KiB */
+ ioctl.smb2.in.max_output_response = 0x10000;
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ torture_assert_ntstatus_ok(tctx,
+ smb2_ioctl(tree, tctx, &ioctl.smb2),
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO failed");
+
+ torture_assert(tctx,
+ (ioctl.smb2.out.out.length != 0),
+ "no interface info returned???");
+
+ torture_assert_ndr_success(tctx,
+ ndr_pull_struct_blob(&ioctl.smb2.out.out, tctx, info,
+ (ndr_pull_flags_fn_t)ndr_pull_fsctl_net_iface_info),
+ "failed to ndr pull");
+
+ if (DEBUGLVL(1)) {
+ NDR_PRINT_DEBUG(fsctl_net_iface_info, info);
+ }
+
+ return true;
+}
+
+static bool test_multichannel_interface_info(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct fsctl_net_iface_info info;
+
+ return test_ioctl_network_interface_info(tctx, tree, &info);
+}
+
+static struct smb2_tree *test_multichannel_create_channel(
+ struct torture_context *tctx,
+ const char *host,
+ const char *share,
+ struct cli_credentials *credentials,
+ const struct smbcli_options *_transport_options,
+ struct smb2_tree *parent_tree
+ )
+{
+ struct smbcli_options transport_options = *_transport_options;
+ NTSTATUS status;
+ struct smb2_transport *transport;
+ struct smb2_session *session;
+ bool ret = true;
+ struct smb2_tree *tree;
+
+ if (parent_tree) {
+ transport_options.only_negprot = true;
+ }
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree,
+ tctx->ev,
+ &transport_options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport = tree->session->transport;
+ transport->oplock.handler = torture_oplock_ack_handler;
+ transport->oplock.private_data = tree;
+ transport->lease.handler = torture_lease_handler;
+ transport->lease.private_data = tree;
+ torture_comment(tctx, "established transport [%p]\n", transport);
+
+ /*
+ * If parent tree is set, bind the session to the parent transport
+ */
+ if (parent_tree) {
+ session = smb2_session_channel(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ parent_tree, parent_tree->session);
+ torture_assert_goto(tctx, session != NULL, ret, done,
+ "smb2_session_channel failed");
+
+ tree->smbXcli = parent_tree->smbXcli;
+ tree->session = session;
+ status = smb2_session_setup_spnego(session,
+ credentials,
+ 0 /* previous_session_id */);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_comment(tctx, "bound new session to parent\n");
+ }
+ /*
+ * We absolutely need to make sure to send something over this
+ * connection to register the oplock break handler with the smb client
+ * connection. If we do not send something (at least a keepalive), we
+ * will *NEVER* receive anything over this transport.
+ */
+ smb2_keepalive(transport);
+
+done:
+ if (ret) {
+ return tree;
+ } else {
+ return NULL;
+ }
+}
+
+bool test_multichannel_create_channel_array(
+ struct torture_context *tctx,
+ const char *host,
+ const char *share,
+ struct cli_credentials *credentials,
+ struct smbcli_options *transport_options,
+ uint8_t num_trees,
+ struct smb2_tree **trees)
+{
+ uint8_t i;
+
+ transport_options->client_guid = GUID_random();
+
+ for (i = 0; i < num_trees; i++) {
+ struct smb2_tree *parent_tree = NULL;
+ struct smb2_tree *tree = NULL;
+ struct smb2_transport *transport = NULL;
+ uint16_t local_port = 0;
+
+ if (i > 0) {
+ parent_tree = trees[0];
+ }
+
+ torture_comment(tctx, "Setting up connection %d\n", i);
+ tree = test_multichannel_create_channel(tctx, host, share,
+ credentials, transport_options,
+ parent_tree);
+ torture_assert(tctx, tree, "failed to created new channel");
+
+ trees[i] = tree;
+ transport = tree->session->transport;
+ local_port = torture_get_local_port_from_transport(transport);
+ torture_comment(tctx, "transport[%d] uses tcp port: %d\n",
+ i, local_port);
+ }
+
+ return true;
+}
+
+bool test_multichannel_create_channels(
+ struct torture_context *tctx,
+ const char *host,
+ const char *share,
+ struct cli_credentials *credentials,
+ struct smbcli_options *transport_options,
+ struct smb2_tree **tree2A,
+ struct smb2_tree **tree2B,
+ struct smb2_tree **tree2C
+ )
+{
+ struct smb2_tree **trees = NULL;
+ size_t num_trees = 0;
+ bool ret;
+
+ torture_assert(tctx, tree2A, "tree2A required!");
+ num_trees += 1;
+ torture_assert(tctx, tree2B, "tree2B required!");
+ num_trees += 1;
+ if (tree2C != NULL) {
+ num_trees += 1;
+ }
+ trees = talloc_zero_array(tctx, struct smb2_tree *, num_trees);
+ torture_assert(tctx, trees, "out of memory");
+
+ ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
+ transport_options,
+ num_trees, trees);
+ if (!ret) {
+ return false;
+ }
+
+ *tree2A = trees[0];
+ *tree2B = trees[1];
+ if (tree2C != NULL) {
+ *tree2C = trees[2];
+ }
+
+ return true;
+}
+
+static void test_multichannel_free_channels(struct smb2_tree *tree2A,
+ struct smb2_tree *tree2B,
+ struct smb2_tree *tree2C)
+{
+ TALLOC_FREE(tree2A);
+ TALLOC_FREE(tree2B);
+ TALLOC_FREE(tree2C);
+}
+
+static bool test_multichannel_initial_checks(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ struct smb2_transport *transport1 = tree1->session->transport;
+ uint32_t server_capabilities;
+ struct fsctl_net_iface_info info;
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip_goto(tctx, fail,
+ "SMB 3.X Dialect family required for "
+ "Multichannel tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip_goto(tctx, fail,
+ "Server does not support multichannel.");
+ }
+
+ torture_assert(tctx,
+ test_ioctl_network_interface_info(tctx, tree1, &info),
+ "failed to retrieve network interface info");
+
+ return true;
+fail:
+ return false;
+}
+
+static void test_multichannel_init_smb_create(struct smb2_create *io)
+{
+ io->in.durable_open = false;
+ io->in.durable_open_v2 = true;
+ io->in.persistent_open = false;
+ io->in.create_guid = GUID_random();
+ io->in.timeout = 0x493E0; /* 300000 */
+ /* windows 2016 returns 300000 0x493E0 */
+}
+
+/* Timer handler function notifies the registering function that time is up */
+static void timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ bool *timesup = (bool *)private_data;
+ *timesup = true;
+}
+
+/*
+ * Oplock break - Test 1
+ * Test to confirm that server sends oplock breaks as expected.
+ * open file1 in session 2A
+ * open file2 in session 2B
+ * open file1 in session 1
+ * oplock break received
+ * open file1 in session 1
+ * oplock break received
+ * Cleanup
+ */
+static bool test_multichannel_oplock_break_test1(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client1_file2 = {{0}};
+ struct smb2_handle h_client1_file3 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_handle h_client2_file2 = {{0}};
+ struct smb2_handle h_client2_file3 = {{0}};
+ struct smb2_create io1, io2, io3;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
+ const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
+ const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
+ struct smb2_tree *tree2A = NULL;
+ struct smb2_tree *tree2B = NULL;
+ struct smb2_tree *tree2C = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Oplock break retry: Test1\n");
+
+ torture_reset_break_info(tctx, &break_info);
+
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io1, fname1,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ test_multichannel_init_smb_create(&io1);
+
+ smb2_oplock_create_share(&io2, fname2,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ test_multichannel_init_smb_create(&io2);
+
+ smb2_oplock_create_share(&io3, fname3,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ test_multichannel_init_smb_create(&io3);
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channels(tctx, host, share,
+ credentials,
+ &transport2_options,
+ &tree2A, &tree2B, NULL);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via session 2A\n");
+ status = smb2_create(tree2A, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ /* 2b opens file2 */
+ torture_comment(tctx, "client2 opens fname2 via session 2B\n");
+ status = smb2_create(tree2B, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+
+ /* 1 opens file1 - batchoplock break? */
+ torture_comment(tctx, "client1 opens fname1 via session 1\n");
+ io1.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+
+ torture_reset_break_info(tctx, &break_info);
+
+ /* 1 opens file2 - batchoplock break? */
+ torture_comment(tctx, "client1 opens fname2 via session 1\n");
+ io2.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree1, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+
+ /* cleanup everything */
+ torture_reset_break_info(tctx, &break_info);
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+ smb2_util_close(tree2A, h_client2_file1);
+ smb2_util_close(tree2A, h_client2_file2);
+ smb2_util_close(tree2A, h_client2_file3);
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ CHECK_VAL(break_info.count, 0);
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ tree2A = tree2B = tree2C = NULL;
+done:
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+ if (tree2A != NULL) {
+ smb2_util_close(tree2A, h_client2_file1);
+ smb2_util_close(tree2A, h_client2_file2);
+ smb2_util_close(tree2A, h_client2_file3);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ smb2_deltree(tree1, BASEDIR);
+
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Oplock Break Test 2
+ * Test to see if oplock break retries are sent by the server.
+ * Also checks to see if new channels can be created and used
+ * after an oplock break retry.
+ * open file1 in 2A
+ * open file2 in 2B
+ * open file1 in session 1
+ * oplock break received
+ * block channel on which oplock break received
+ * open file2 in session 1
+ * oplock break not received. Retry received.
+ * file opened
+ * write to file2 on 2B
+ * Break sent to session 1(which has file2 open)
+ * Break sent to session 2A(which has read oplock)
+ * close file1 in session 1
+ * open file1 with session 1
+ * unblock blocked channel
+ * disconnect blocked channel
+ * connect channel 2D
+ * open file3 in 2D
+ * open file3 in session 1
+ * receive break
+ */
+static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client1_file2 = {{0}};
+ struct smb2_handle h_client1_file3 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_handle h_client2_file2 = {{0}};
+ struct smb2_handle h_client2_file3 = {{0}};
+ struct smb2_create io1, io2, io3;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\oplock_break_test1.dat";
+ const char *fname2 = BASEDIR "\\oplock_break_test2.dat";
+ const char *fname3 = BASEDIR "\\oplock_break_test3.dat";
+ struct smb2_tree *tree2A = NULL;
+ struct smb2_tree *tree2B = NULL;
+ struct smb2_tree *tree2C = NULL;
+ struct smb2_tree *tree2D = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2 = NULL;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+ DATA_BLOB blob;
+ bool block_setup = false;
+ bool block_ok = false;
+ bool unblock_ok = false;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Oplock break retry: Test2\n");
+
+ torture_reset_break_info(tctx, &break_info);
+
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io1, fname1,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ test_multichannel_init_smb_create(&io1);
+
+ smb2_oplock_create_share(&io2, fname2,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ test_multichannel_init_smb_create(&io2);
+
+ smb2_oplock_create_share(&io3, fname3,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ test_multichannel_init_smb_create(&io3);
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channels(tctx, host, share,
+ credentials,
+ &transport2_options,
+ &tree2A, &tree2B, &tree2C);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+
+ torture_comment(tctx, "client2 opens fname1 via session 2A\n");
+ io1.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree2A, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+
+ torture_comment(tctx, "client2 opens fname2 via session 2B\n");
+ io2.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree2B, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+
+ torture_comment(tctx, "client1 opens fname1 via session 1\n");
+ io1.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+
+ /* We use the transport over which this oplock break was received */
+ transport2 = break_info.received_transport;
+ torture_reset_break_info(tctx, &break_info);
+
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+
+ /* block channel */
+ block_ok = test_block_smb2_transport(tctx, transport2);
+
+ torture_comment(tctx, "client1 opens fname2 via session 1\n");
+ io2.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree1, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
+
+ /*
+ * Samba downgrades oplock to a level 2 oplock.
+ * Windows 2016 revokes oplock
+ */
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ torture_reset_break_info(tctx, &break_info);
+
+ torture_comment(tctx, "Trying write to file2 on tree2B\n");
+
+ blob = data_blob_string_const("Here I am");
+ status = smb2_util_write(tree2B,
+ h_client2_file2,
+ blob.data,
+ 0,
+ blob.length);
+ torture_assert_ntstatus_ok(tctx, status,
+ "failed to write file2 via channel 2B");
+
+ /*
+ * Samba: Write triggers 2 oplock breaks
+ * for session 1 which has file2 open
+ * for session 2 which has type 2 oplock
+ * Windows 2016: Only one oplock break for session 1
+ */
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL_GREATER_THAN(break_info.count, 0);
+ torture_reset_break_info(tctx, &break_info);
+
+ torture_comment(tctx, "client1 closes fname2 via session 1\n");
+ smb2_util_close(tree1, h_client1_file2);
+
+ torture_comment(tctx, "client1 opens fname2 via session 1 again\n");
+ io2.in.oplock_level = smb2_util_oplock_level("b");
+ status = smb2_create(tree1, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file2 = io2.out.file.handle;
+ io2.out.alloc_size = 0;
+ io2.out.size = 0;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("s"));
+
+ /*
+ * now add a fourth channel and repeat the test, we need to reestablish
+ * transport2 because the remote end has invalidated our connection
+ */
+ torture_comment(tctx, "Connecting session 2D\n");
+ tree2D = test_multichannel_create_channel(tctx, host, share,
+ credentials, &transport2_options, tree2B);
+ if (!tree2D) {
+ goto done;
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ torture_comment(tctx, "client 2 opening fname3 over transport2D\n");
+ status = smb2_create(tree2D, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ torture_comment(tctx, "client1 opens fname3 via session 1\n");
+ status = smb2_create(tree1, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+
+done:
+ if (block_ok && !unblock_ok) {
+ test_unblock_smb2_transport(tctx, transport2);
+ }
+ test_cleanup_blocked_transports(tctx);
+
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+ if (tree2B != NULL) {
+ smb2_util_close(tree2B, h_client2_file1);
+ smb2_util_close(tree2B, h_client2_file2);
+ smb2_util_close(tree2B, h_client2_file3);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ smb2_deltree(tree1, BASEDIR);
+
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ if (tree2D != NULL) {
+ TALLOC_FREE(tree2D);
+ }
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct test_multichannel_oplock_break_state;
+
+struct test_multichannel_oplock_break_channel {
+ struct test_multichannel_oplock_break_state *state;
+ size_t idx;
+ char name[64];
+ struct smb2_tree *tree;
+ bool blocked;
+ struct timeval break_time;
+ double full_duration;
+ double relative_duration;
+ uint8_t level;
+ size_t break_num;
+};
+
+struct test_multichannel_oplock_break_state {
+ struct torture_context *tctx;
+ struct timeval open_req_time;
+ struct timeval open_rep_time;
+ size_t num_breaks;
+ struct timeval last_break_time;
+ struct test_multichannel_oplock_break_channel channels[32];
+};
+
+static bool test_multichannel_oplock_break_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct test_multichannel_oplock_break_channel *c =
+ (struct test_multichannel_oplock_break_channel *)private_data;
+ struct test_multichannel_oplock_break_state *state = c->state;
+
+ c->break_time = timeval_current();
+ c->full_duration = timeval_elapsed2(&state->open_req_time,
+ &c->break_time);
+ c->relative_duration = timeval_elapsed2(&state->last_break_time,
+ &c->break_time);
+ state->last_break_time = c->break_time;
+ c->level = level;
+ c->break_num = ++state->num_breaks;
+
+ torture_comment(state->tctx, "Got OPLOCK break %zu on %s after %f ( %f)\n",
+ c->break_num, c->name,
+ c->relative_duration,
+ c->full_duration);
+
+ return torture_oplock_ack_handler(transport, handle, level, c->tree);
+}
+
+static bool test_multichannel_oplock_break_test3_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct test_multichannel_oplock_break_state state = {
+ .tctx = tctx,
+ };
+ struct test_multichannel_oplock_break_channel *open2_channel = NULL;
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_create io1;
+ struct smb2_create io2;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\oplock_break_test3w.dat";
+ struct smb2_tree *trees2[32] = { NULL, };
+ size_t i;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+ bool block_setup = false;
+ bool block_ok = false;
+ double open_duration;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Oplock break retry: Test3 (Windows behavior)\n");
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io2, fname1,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
+ &transport2_options,
+ ARRAY_SIZE(trees2), trees2);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+
+ for (i = 0; i < ARRAY_SIZE(trees2); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = trees2[i]->session->transport;
+
+ c->state = &state;
+ c->idx = i+1;
+ c->tree = trees2[i];
+ snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
+
+ t->oplock.handler = test_multichannel_oplock_break_handler;
+ t->oplock.private_data = c;
+ }
+
+ open2_channel = &state.channels[0];
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via %s\n",
+ open2_channel->name);
+ status = smb2_create(open2_channel->tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io2.out.durable_open_v2, false);
+ CHECK_VAL(io2.out.timeout, io2.in.timeout);
+ CHECK_VAL(io2.out.durable_open, false);
+ CHECK_VAL(break_info.count, 0);
+
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = c->tree->session->transport;
+
+ torture_comment(tctx, "Blocking %s\n", c->name);
+ block_ok = _test_block_smb2_transport(tctx, t, c->name);
+ torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
+ c->blocked = true;
+ }
+
+ /* 1 opens file2 */
+ torture_comment(tctx,
+ "Client opens fname1 with session 1 with all %zu blocked\n",
+ ARRAY_SIZE(trees2));
+ smb2_oplock_create_share(&io1, fname1,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ CHECK_VAL(lease_break_info.count, 0);
+ state.open_req_time = timeval_current();
+ state.last_break_time = state.open_req_time;
+ status = smb2_create(tree1, mem_ctx, &io1);
+ state.open_rep_time = timeval_current();
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
+
+ CHECK_VAL(break_info.count, 1);
+
+ open_duration = timeval_elapsed2(&state.open_req_time,
+ &state.open_rep_time);
+ torture_comment(tctx, "open_duration: %f\n", open_duration);
+ CHECK_VAL_GREATER_THAN(open_duration, 35);
+
+ if (break_info.count == 0) {
+ torture_comment(tctx,
+ "Did not receive expected oplock break!!\n");
+ } else {
+ torture_comment(tctx, "Received %d oplock break(s)!!\n",
+ break_info.count);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ size_t expected_break_num = 0;
+
+ /*
+ * Only the latest channel gets a break notification
+ */
+ if (i == (ARRAY_SIZE(state.channels) - 1)) {
+ expected_break_num = 1;
+ }
+
+ torture_comment(tctx, "Verify %s\n", c->name);
+ torture_assert_int_equal(tctx, c->break_num, expected_break_num,
+ "Got oplock break on wrong channel");
+ if (expected_break_num != 0) {
+ CHECK_VAL(c->level, smb2_util_oplock_level("s"));
+ }
+ }
+
+done:
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = NULL;
+
+ if (!c->blocked) {
+ continue;
+ }
+
+ t = c->tree->session->transport;
+
+ torture_comment(tctx, "Unblocking %s\n", c->name);
+ _test_unblock_smb2_transport(tctx, t, c->name);
+ c->blocked = false;
+ }
+ if (block_setup) {
+ test_cleanup_blocked_transports(tctx);
+ }
+
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ if (trees2[0] != NULL) {
+ smb2_util_close(trees2[0], h_client2_file1);
+ }
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_deltree(tree1, BASEDIR);
+
+ for (i = 0; i < ARRAY_SIZE(trees2); i++) {
+ if (trees2[i] == NULL) {
+ continue;
+ }
+ TALLOC_FREE(trees2[i]);
+ }
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_multichannel_oplock_break_test3_specification(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct test_multichannel_oplock_break_state state = {
+ .tctx = tctx,
+ };
+ struct test_multichannel_oplock_break_channel *open2_channel = NULL;
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_create io1;
+ struct smb2_create io2;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\oplock_break_test3s.dat";
+ struct smb2_tree *trees2[32] = { NULL, };
+ size_t i;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+ bool block_setup = false;
+ bool block_ok = false;
+ double open_duration;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Oplock break retry: Test3 (Specification behavior)\n");
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io2, fname1,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
+ &transport2_options,
+ ARRAY_SIZE(trees2), trees2);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+
+ for (i = 0; i < ARRAY_SIZE(trees2); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = trees2[i]->session->transport;
+
+ c->state = &state;
+ c->idx = i+1;
+ c->tree = trees2[i];
+ snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
+
+ t->oplock.handler = test_multichannel_oplock_break_handler;
+ t->oplock.private_data = c;
+ }
+
+ open2_channel = &state.channels[0];
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via %s\n",
+ open2_channel->name);
+ status = smb2_create(open2_channel->tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io2.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io2.out.durable_open_v2, false);
+ CHECK_VAL(io2.out.timeout, io2.in.timeout);
+ CHECK_VAL(io2.out.durable_open, false);
+ CHECK_VAL(break_info.count, 0);
+
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = c->tree->session->transport;
+
+ torture_comment(tctx, "Blocking %s\n", c->name);
+ block_ok = _test_block_smb2_transport(tctx, t, c->name);
+ torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
+ c->blocked = true;
+ }
+
+ /* 1 opens file2 */
+ torture_comment(tctx,
+ "Client opens fname1 with session 1 with all %zu blocked\n",
+ ARRAY_SIZE(trees2));
+ smb2_oplock_create_share(&io1, fname1,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ CHECK_VAL(lease_break_info.count, 0);
+ state.open_req_time = timeval_current();
+ state.last_break_time = state.open_req_time;
+ status = smb2_create(tree1, mem_ctx, &io1);
+ state.open_rep_time = timeval_current();
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+
+ CHECK_VAL_GREATER_THAN(break_info.count, 1);
+
+ open_duration = timeval_elapsed2(&state.open_req_time,
+ &state.open_rep_time);
+ torture_comment(tctx, "open_duration: %f\n", open_duration);
+ if (break_info.count < ARRAY_SIZE(state.channels)) {
+ CHECK_VAL_GREATER_THAN(open_duration, 35);
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("s"));
+ } else {
+ CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ if (break_info.count >= ARRAY_SIZE(state.channels)) {
+ break;
+ }
+ torture_comment(tctx, "Received %d oplock break(s) wait for more!!\n",
+ break_info.count);
+ torture_wait_for_oplock_break(tctx);
+ }
+
+ if (break_info.count == 0) {
+ torture_comment(tctx,
+ "Did not receive expected oplock break!!\n");
+ } else {
+ torture_comment(tctx, "Received %d oplock break(s)!!\n",
+ break_info.count);
+ }
+
+ if (break_info.count < ARRAY_SIZE(state.channels)) {
+ CHECK_VAL_GREATER_THAN(break_info.count, 3);
+ } else {
+ CHECK_VAL(break_info.count, ARRAY_SIZE(state.channels));
+ }
+
+ for (i = 0; i < break_info.count; i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+
+ torture_comment(tctx, "Verify %s\n", c->name);
+ torture_assert_int_equal(tctx, c->break_num, c->idx,
+ "Got oplock break on wrong channel");
+ CHECK_VAL(c->level, smb2_util_oplock_level("s"));
+ }
+
+done:
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_oplock_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = NULL;
+
+ if (!c->blocked) {
+ continue;
+ }
+
+ t = c->tree->session->transport;
+
+ torture_comment(tctx, "Unblocking %s\n", c->name);
+ _test_unblock_smb2_transport(tctx, t, c->name);
+ c->blocked = false;
+ }
+ if (block_setup) {
+ test_cleanup_blocked_transports(tctx);
+ }
+
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ if (trees2[0] != NULL) {
+ smb2_util_close(trees2[0], h_client2_file1);
+ }
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_deltree(tree1, BASEDIR);
+
+ for (i = 0; i < ARRAY_SIZE(trees2); i++) {
+ if (trees2[i] == NULL) {
+ continue;
+ }
+ TALLOC_FREE(trees2[i]);
+ }
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
+static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
+static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
+static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
+static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
+static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
+
+/*
+ * Lease Break Test 1:
+ * Test to check if lease breaks are sent by the server as expected.
+ * open file1 in session 2A
+ * open file2 in session 2B
+ * open file3 in session 2C
+ * open file1 in session 1
+ * lease break sent
+ * open file2 in session 1
+ * lease break sent
+ * open file3 in session 1
+ * lease break sent
+ */
+static bool test_multichannel_lease_break_test1(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client1_file2 = {{0}};
+ struct smb2_handle h_client1_file3 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_handle h_client2_file2 = {{0}};
+ struct smb2_handle h_client2_file3 = {{0}};
+ struct smb2_create io1, io2, io3;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\lease_break_test1.dat";
+ const char *fname2 = BASEDIR "\\lease_break_test2.dat";
+ const char *fname3 = BASEDIR "\\lease_break_test3.dat";
+ struct smb2_tree *tree2A = NULL;
+ struct smb2_tree *tree2B = NULL;
+ struct smb2_tree *tree2C = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_lease ls3;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Lease break retry: Test1\n");
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io1);
+
+ smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io2);
+
+ smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io3);
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channels(tctx, host, share,
+ credentials,
+ &transport2_options,
+ &tree2A, &tree2B, &tree2C);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via session 2A\n");
+ status = smb2_create(tree2A, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* 2b opens file2 */
+ torture_comment(tctx, "client2 opens fname2 via session 2B\n");
+ status = smb2_create(tree2B, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* 2c opens file3 */
+ torture_comment(tctx, "client2 opens fname3 via session 2C\n");
+ smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree2C, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* 1 opens file1 - lease break? */
+ torture_comment(tctx, "client1 opens fname1 via session 1\n");
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* 1 opens file2 - lease break? */
+ torture_comment(tctx, "client1 opens fname2 via session 1\n");
+ smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* 1 opens file3 - lease break? */
+ torture_comment(tctx, "client1 opens fname3 via session 1\n");
+ smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ /* cleanup everything */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+ smb2_util_close(tree2A, h_client2_file1);
+ smb2_util_close(tree2A, h_client2_file2);
+ smb2_util_close(tree2A, h_client2_file3);
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ CHECK_VAL(lease_break_info.count, 0);
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ tree2A = tree2B = tree2C = NULL;
+done:
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+ if (tree2A != NULL) {
+ smb2_util_close(tree2A, h_client2_file1);
+ smb2_util_close(tree2A, h_client2_file2);
+ smb2_util_close(tree2A, h_client2_file3);
+ }
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ smb2_deltree(tree1, BASEDIR);
+
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Lease Break Test 2:
+ * Test for lease break retries being sent by the server.
+ * Connect 2A, 2B
+ * open file1 in session 2A
+ * open file2 in session 2B
+ * block 2A
+ * open file2 in session 1
+ * lease break retry reaches the client?
+ * Connect 2C
+ * open file3 in session 2C
+ * unblock 2A
+ * open file1 in session 1
+ * lease break reaches the client?
+ * open file3 in session 1
+ * lease break reached the client?
+ * Cleanup
+ * On deletion by 1, lease breaks sent for file1, file2 and file3
+ * on 2B
+ * This changes RH lease to R for Session 2.
+ * (This has been disabled while we add support for sending lease
+ * break for handle leases.)
+ */
+static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client1_file2 = {{0}};
+ struct smb2_handle h_client1_file3 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_handle h_client2_file2 = {{0}};
+ struct smb2_handle h_client2_file3 = {{0}};
+ struct smb2_create io1, io2, io3;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\lease_break_test1.dat";
+ const char *fname2 = BASEDIR "\\lease_break_test2.dat";
+ const char *fname3 = BASEDIR "\\lease_break_test3.dat";
+ struct smb2_tree *tree2A = NULL;
+ struct smb2_tree *tree2B = NULL;
+ struct smb2_tree *tree2C = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2A = NULL;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_lease ls3;
+ bool block_setup = false;
+ bool block_ok = false;
+ bool unblock_ok = false;
+
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Lease break retry: Test2\n");
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io1);
+
+ smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io2);
+
+ smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io3);
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channels(tctx, host, share,
+ credentials,
+ &transport2_options,
+ &tree2A, &tree2B, NULL);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+ transport2A = tree2A->session->transport;
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via session 2A\n");
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree2A, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
+ CHECK_VAL(io1.out.durable_open_v2, false); //true);
+ CHECK_VAL(io1.out.timeout, io1.in.timeout);
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* 2b opens file2 */
+ torture_comment(tctx, "client2 opens fname2 via session 2B\n");
+ smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree2B, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
+ CHECK_VAL(io2.out.durable_open_v2, false); //true);
+ CHECK_VAL(io2.out.timeout, io2.in.timeout);
+ CHECK_VAL(io2.out.durable_open, false);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+
+ torture_comment(tctx, "Blocking 2A\n");
+ /* Block 2A */
+ block_ok = test_block_smb2_transport(tctx, transport2A);
+ torture_assert(tctx, block_ok, "we could not block tcp transport");
+
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* 1 opens file2 */
+ torture_comment(tctx,
+ "Client opens fname2 with session1 with 2A blocked\n");
+ smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file2 = io2.out.file.handle;
+ CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
+ CHECK_VAL(io2.out.durable_open_v2, false);
+ CHECK_VAL(io2.out.timeout, 0);
+ CHECK_VAL(io2.out.durable_open, false);
+
+ if (lease_break_info.count == 0) {
+ torture_comment(tctx,
+ "Did not receive expected lease break!!\n");
+ } else {
+ torture_comment(tctx, "Received %d lease break(s)!!\n",
+ lease_break_info.count);
+ }
+
+ /*
+ * We got breaks on both channels
+ * (one failed on the blocked connection)
+ */
+ CHECK_VAL(lease_break_info.count, 2);
+ lease_break_info.count -= 1;
+ CHECK_VAL(lease_break_info.failures, 1);
+ lease_break_info.failures -= 1;
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /* Connect 2C */
+ torture_comment(tctx, "Connecting session 2C\n");
+ talloc_free(tree2C);
+ tree2C = test_multichannel_create_channel(tctx, host, share,
+ credentials, &transport2_options, tree2A);
+ if (!tree2C) {
+ goto done;
+ }
+
+ /* 2c opens file3 */
+ torture_comment(tctx, "client2 opens fname3 via session 2C\n");
+ smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree2C, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
+ CHECK_VAL(io3.out.durable_open_v2, false);
+ CHECK_VAL(io3.out.timeout, io2.in.timeout);
+ CHECK_VAL(io3.out.durable_open, false);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* Unblock 2A */
+ torture_comment(tctx, "Unblocking 2A\n");
+ unblock_ok = test_unblock_smb2_transport(tctx, transport2A);
+ torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
+
+ /* 1 opens file1 */
+ torture_comment(tctx, "Client opens fname1 with session 1\n");
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
+
+ if (lease_break_info.count == 0) {
+ torture_comment(tctx,
+ "Did not receive expected lease break!!\n");
+ } else {
+ torture_comment(tctx,
+ "Received %d lease break(s)!!\n",
+ lease_break_info.count);
+ }
+ CHECK_VAL(lease_break_info.count, 1);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*1 opens file3 */
+ torture_comment(tctx, "client opens fname3 via session 1\n");
+
+ smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io3);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file3 = io3.out.file.handle;
+ CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
+
+ if (lease_break_info.count == 0) {
+ torture_comment(tctx,
+ "Did not receive expected lease break!!\n");
+ } else {
+ torture_comment(tctx,
+ "Received %d lease break(s)!!\n",
+ lease_break_info.count);
+ }
+ CHECK_VAL(lease_break_info.count, 1);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+
+ /*
+ * Session 2 still has RW lease on file 1. Deletion of this file by 1
+ * leads to a lease break call to session 2 file1
+ */
+ smb2_util_unlink(tree1, fname1);
+ /*
+ * Bug - Samba does not revoke Handle lease on unlink
+ * CHECK_BREAK_INFO("RH", "R", LEASE2F1);
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * Session 2 still has RW lease on file 2. Deletion of this file by 1
+ * leads to a lease break call to session 2 file2
+ */
+ smb2_util_unlink(tree1, fname2);
+ /*
+ * Bug - Samba does not revoke Handle lease on unlink
+ * CHECK_BREAK_INFO("RH", "R", LEASE2F2);
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ /*
+ * Session 2 still has RW lease on file 3. Deletion of this file by 1
+ * leads to a lease break call to session 2 file3
+ */
+ smb2_util_unlink(tree1, fname3);
+ /*
+ * Bug - Samba does not revoke Handle lease on unlink
+ * CHECK_BREAK_INFO("RH", "R", LEASE2F3);
+ */
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ smb2_util_close(tree2C, h_client2_file1);
+ smb2_util_close(tree2C, h_client2_file2);
+ smb2_util_close(tree2C, h_client2_file3);
+
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ tree2A = tree2B = tree2C = NULL;
+
+done:
+ if (block_ok && !unblock_ok) {
+ test_unblock_smb2_transport(tctx, transport2A);
+ }
+ if (block_setup) {
+ test_cleanup_blocked_transports(tctx);
+ }
+
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ smb2_util_close(tree1, h_client1_file2);
+ smb2_util_close(tree1, h_client1_file3);
+ if (tree2A != NULL) {
+ smb2_util_close(tree2A, h_client2_file1);
+ smb2_util_close(tree2A, h_client2_file2);
+ smb2_util_close(tree2A, h_client2_file3);
+ }
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+ smb2_util_unlink(tree1, fname3);
+ smb2_deltree(tree1, BASEDIR);
+
+ test_multichannel_free_channels(tree2A, tree2B, tree2C);
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Test 3: Check to see how the server behaves if lease break
+ * response is sent over a different channel to one over which
+ * the break is received.
+ * Connect 2A, 2B
+ * open file1 in session 2A
+ * open file1 in session 1
+ * Lease break sent to 2A
+ * 2B sends back lease break reply.
+ * session 1 allowed to open file
+ */
+static bool test_multichannel_lease_break_test3(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_create io1;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\lease_break_test1.dat";
+ struct smb2_tree *tree2A = NULL;
+ struct smb2_tree *tree2B = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2A = NULL;
+ struct smbcli_options transport2_options;
+ uint16_t local_port = 0;
+ struct smb2_lease ls1;
+ struct tevent_timer *te = NULL;
+ struct timeval ne;
+ bool timesup = false;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Lease break retry: Test3\n");
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+ smb2_util_lease_state("RHW"));
+ test_multichannel_init_smb_create(&io1);
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channels(tctx, host, share,
+ credentials,
+ &transport2_options,
+ &tree2A, &tree2B, NULL);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+ transport2A = tree2A->session->transport;
+ transport2A->lease.private_data = tree2B;
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via session 2A\n");
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree2A, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
+ CHECK_VAL(io1.out.durable_open_v2, false); //true);
+ CHECK_VAL(io1.out.timeout, io1.in.timeout);
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ /* Set a timeout for 5 seconds for session 1 to open file1 */
+ ne = tevent_timeval_current_ofs(0, 5000000);
+ te = tevent_add_timer(tctx->ev, mem_ctx, ne, timeout_cb, &timesup);
+ if (te == NULL) {
+ torture_comment(tctx, "Failed to add timer.");
+ goto done;
+ }
+
+ /* 1 opens file2 */
+ torture_comment(tctx, "Client opens fname1 with session 1\n");
+ smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
+ smb2_util_lease_state("RHW"));
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+ CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
+ CHECK_VAL(io1.out.durable_open_v2, false);
+ CHECK_VAL(io1.out.timeout, 0);
+ CHECK_VAL(io1.out.durable_open, false);
+
+ CHECK_VAL(lease_break_info.count, 1);
+ CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
+
+ /*
+ * Check if timeout handler was fired. This would indicate
+ * that the server didn't receive a reply for the oplock break
+ * from the client and the server let session 1 open the file
+ * only after the oplock break timeout.
+ */
+ CHECK_VAL(timesup, false);
+
+done:
+ smb2_util_close(tree1, h_client1_file1);
+ if (tree2A != NULL) {
+ smb2_util_close(tree2A, h_client2_file1);
+ }
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_deltree(tree1, BASEDIR);
+
+ test_multichannel_free_channels(tree2A, tree2B, NULL);
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Test limits of channels
+ */
+static bool test_multichannel_num_channels(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ bool ret = true;
+ struct smb2_tree **tree2 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport **transport2 = NULL;
+ struct smbcli_options transport2_options;
+ struct smb2_session **session2 = NULL;
+ uint32_t server_capabilities;
+ int i;
+ int max_channels = 33; /* 32 is the W2K12R2 and W2K16 limit */
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_fail(tctx,
+ "SMB 3.X Dialect family required for Multichannel"
+ " tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_fail(tctx,
+ "Server does not support multichannel.");
+ }
+
+ torture_comment(tctx, "Testing max. number of channels\n");
+
+ transport2_options = transport1->options;
+ transport2_options.client_guid = GUID_random();
+
+ tree2 = talloc_zero_array(mem_ctx, struct smb2_tree *,
+ max_channels);
+ transport2 = talloc_zero_array(mem_ctx, struct smb2_transport *,
+ max_channels);
+ session2 = talloc_zero_array(mem_ctx, struct smb2_session *,
+ max_channels);
+ if (tree2 == NULL || transport2 == NULL || session2 == NULL) {
+ torture_fail(tctx, "out of memory");
+ }
+
+ for (i = 0; i < max_channels; i++) {
+
+ NTSTATUS expected_status;
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2[i],
+ tctx->ev,
+ &transport2_options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ ),
+ ret, done, "smb2_connect failed");
+
+ transport2[i] = tree2[i]->session->transport;
+
+ if (i == 0) {
+ /*
+ * done for the 1st channel
+ *
+ * For all remaining channels we do the
+ * session setup on our own.
+ */
+ transport2_options.only_negprot = true;
+ continue;
+ }
+
+ /*
+ * Now bind the session2[i] to the transport2
+ */
+ session2[i] = smb2_session_channel(transport2[i],
+ lpcfg_gensec_settings(tctx,
+ tctx->lp_ctx),
+ tree2[0],
+ tree2[0]->session);
+
+ torture_assert(tctx, session2[i] != NULL,
+ "smb2_session_channel failed");
+
+ torture_comment(tctx, "established transport2 [#%d]\n", i);
+
+ if (i >= 32) {
+ expected_status = NT_STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ expected_status = NT_STATUS_OK;
+ }
+
+ torture_assert_ntstatus_equal_goto(tctx,
+ smb2_session_setup_spnego(session2[i],
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */),
+ expected_status,
+ ret, done,
+ talloc_asprintf(tctx, "failed to establish session "
+ "setup for channel #%d", i));
+
+ torture_comment(tctx, "bound session2 [#%d] to session2 [0]\n",
+ i);
+ }
+
+ done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct test_multichannel_lease_break_state;
+
+struct test_multichannel_lease_break_channel {
+ struct test_multichannel_lease_break_state *state;
+ size_t idx;
+ char name[64];
+ struct smb2_tree *tree;
+ bool blocked;
+ struct timeval break_time;
+ double full_duration;
+ double relative_duration;
+ struct smb2_lease_break lb;
+ size_t break_num;
+};
+
+struct test_multichannel_lease_break_state {
+ struct torture_context *tctx;
+ struct timeval open_req_time;
+ struct timeval open_rep_time;
+ size_t num_breaks;
+ struct timeval last_break_time;
+ struct test_multichannel_lease_break_channel channels[32];
+};
+
+static bool test_multichannel_lease_break_handler(struct smb2_transport *transport,
+ const struct smb2_lease_break *lb,
+ void *private_data)
+{
+ struct test_multichannel_lease_break_channel *c =
+ (struct test_multichannel_lease_break_channel *)private_data;
+ struct test_multichannel_lease_break_state *state = c->state;
+
+ c->break_time = timeval_current();
+ c->full_duration = timeval_elapsed2(&state->open_req_time,
+ &c->break_time);
+ c->relative_duration = timeval_elapsed2(&state->last_break_time,
+ &c->break_time);
+ state->last_break_time = c->break_time;
+ c->lb = *lb;
+ c->break_num = ++state->num_breaks;
+
+ torture_comment(state->tctx, "Got LEASE break epoch[0x%x] %zu on %s after %f ( %f)\n",
+ c->lb.new_epoch, c->break_num, c->name,
+ c->relative_duration,
+ c->full_duration);
+
+ return torture_lease_handler(transport, lb, c->tree);
+}
+
+static bool test_multichannel_lease_break_test4(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct test_multichannel_lease_break_state state = {
+ .tctx = tctx,
+ };
+ struct test_multichannel_lease_break_channel *open2_channel = NULL;
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_handle h_client1_file1 = {{0}};
+ struct smb2_handle h_client2_file1 = {{0}};
+ struct smb2_create io1;
+ struct smb2_create io2;
+ bool ret = true;
+ const char *fname1 = BASEDIR "\\lease_break_test4.dat";
+ struct smb2_tree *trees2[32] = { NULL, };
+ size_t i;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options transport2_options;
+ struct smb2_session *session1 = tree1->session;
+ uint16_t local_port = 0;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ bool block_setup = false;
+ bool block_ok = false;
+ double open_duration;
+
+ if (!test_multichannel_initial_checks(tctx, tree1)) {
+ return true;
+ }
+
+ torture_comment(tctx, "Lease break retry: Test4\n");
+
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ torture_comment(tctx, "transport1 [%p]\n", transport1);
+ local_port = torture_get_local_port_from_transport(transport1);
+ torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname1);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_lease_v2_create(&io2, &ls2, false, fname1,
+ LEASE2F1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x20);
+
+ transport2_options = transport1->options;
+
+ ret = test_multichannel_create_channel_array(tctx, host, share, credentials,
+ &transport2_options,
+ ARRAY_SIZE(trees2), trees2);
+ torture_assert(tctx, ret, "Could not create channels.\n");
+
+ for (i = 0; i < ARRAY_SIZE(trees2); i++) {
+ struct test_multichannel_lease_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = trees2[i]->session->transport;
+
+ c->state = &state;
+ c->idx = i+1;
+ c->tree = trees2[i];
+ snprintf(c->name, sizeof(c->name), "trees2_%zu", c->idx);
+
+ t->lease.handler = test_multichannel_lease_break_handler;
+ t->lease.private_data = c;
+ }
+
+ open2_channel = &state.channels[0];
+
+ /* 2a opens file1 */
+ torture_comment(tctx, "client2 opens fname1 via %s\n",
+ open2_channel->name);
+ status = smb2_create(open2_channel->tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client2_file1 = io2.out.file.handle;
+ CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE_V2(&io2, "RHW", true, LEASE2F1, 0, 0, 0x21);
+ CHECK_VAL(io2.out.durable_open_v2, false);
+ CHECK_VAL(io2.out.timeout, io2.in.timeout);
+ CHECK_VAL(io2.out.durable_open, false);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_lease_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = c->tree->session->transport;
+
+ torture_comment(tctx, "Blocking %s\n", c->name);
+ block_ok = _test_block_smb2_transport(tctx, t, c->name);
+ torture_assert_goto(tctx, block_ok, ret, done, "we could not block tcp transport");
+ c->blocked = true;
+ }
+
+ /* 1 opens file2 */
+ torture_comment(tctx,
+ "Client opens fname1 with session 1 with all %zu blocked\n",
+ ARRAY_SIZE(trees2));
+ smb2_lease_v2_create(&io1, &ls1, false, fname1,
+ LEASE1F1, NULL,
+ smb2_util_lease_state("RHW"),
+ 0x10);
+ CHECK_VAL(lease_break_info.count, 0);
+ state.open_req_time = timeval_current();
+ state.last_break_time = state.open_req_time;
+ status = smb2_create(tree1, mem_ctx, &io1);
+ state.open_rep_time = timeval_current();
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h_client1_file1 = io1.out.file.handle;
+
+ CHECK_VAL_GREATER_THAN(lease_break_info.count, 1);
+
+ open_duration = timeval_elapsed2(&state.open_req_time,
+ &state.open_rep_time);
+ torture_comment(tctx, "open_duration: %f\n", open_duration);
+ if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
+ CHECK_VAL_GREATER_THAN(open_duration, 35);
+ CHECK_LEASE_V2(&io1, "RH", true, LEASE1F1, 0, 0, 0x11);
+ } else {
+ CHECK_LEASE_V2(&io1, "RWH", true, LEASE1F1, 0, 0, 0x11);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ if (lease_break_info.count >= ARRAY_SIZE(state.channels)) {
+ break;
+ }
+ torture_comment(tctx, "Received %d lease break(s) wait for more!!\n",
+ lease_break_info.count);
+ torture_wait_for_lease_break(tctx);
+ }
+
+ if (lease_break_info.count == 0) {
+ torture_comment(tctx,
+ "Did not receive expected lease break!!\n");
+ } else {
+ torture_comment(tctx, "Received %d lease break(s)!!\n",
+ lease_break_info.count);
+ }
+
+ if (lease_break_info.count < ARRAY_SIZE(state.channels)) {
+ CHECK_VAL_GREATER_THAN(lease_break_info.count, 3);
+ } else {
+ CHECK_VAL(lease_break_info.count, ARRAY_SIZE(state.channels));
+ }
+
+ for (i = 0; i < lease_break_info.count; i++) {
+ struct test_multichannel_lease_break_channel *c = &state.channels[i];
+
+ torture_comment(tctx, "Verify %s\n", c->name);
+ torture_assert_int_equal(tctx, c->break_num, c->idx,
+ "Got lease break in wrong order");
+ CHECK_LEASE_BREAK_V2(c->lb, LEASE2F1, "RWH", "RH",
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED,
+ 0x22);
+ }
+
+done:
+ for (i = 0; i < ARRAY_SIZE(state.channels); i++) {
+ struct test_multichannel_lease_break_channel *c = &state.channels[i];
+ struct smb2_transport *t = NULL;
+
+ if (!c->blocked) {
+ continue;
+ }
+
+ t = c->tree->session->transport;
+
+ torture_comment(tctx, "Unblocking %s\n", c->name);
+ _test_unblock_smb2_transport(tctx, t, c->name);
+ c->blocked = false;
+ }
+ if (block_setup) {
+ test_cleanup_blocked_transports(tctx);
+ }
+
+ tree1->session = session1;
+
+ smb2_util_close(tree1, h_client1_file1);
+ if (trees2[0] != NULL) {
+ smb2_util_close(trees2[0], h_client2_file1);
+ }
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_deltree(tree1, BASEDIR);
+
+ for (i = 0; i < ARRAY_SIZE(trees2); i++) {
+ if (trees2[i] == NULL) {
+ continue;
+ }
+ TALLOC_FREE(trees2[i]);
+ }
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Test channel merging race
+ * This is a regression test for
+ * https://bugzilla.samba.org/show_bug.cgi?id=15346
+ */
+struct test_multichannel_bug_15346_conn;
+
+struct test_multichannel_bug_15346_state {
+ struct torture_context *tctx;
+ struct test_multichannel_bug_15346_conn *conns;
+ size_t num_conns;
+ size_t num_ready;
+ bool asserted;
+ bool looping;
+};
+
+struct test_multichannel_bug_15346_conn {
+ struct test_multichannel_bug_15346_state *state;
+ size_t idx;
+ struct smbXcli_conn *smbXcli;
+ struct tevent_req *nreq;
+ struct tevent_req *ereq;
+};
+
+static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq);
+static void test_multichannel_bug_15346_edone(struct tevent_req *subreq);
+
+static void test_multichannel_bug_15346_ndone(struct tevent_req *subreq)
+{
+ struct test_multichannel_bug_15346_conn *conn =
+ (struct test_multichannel_bug_15346_conn *)
+ tevent_req_callback_data_void(subreq);
+ struct test_multichannel_bug_15346_state *state = conn->state;
+ struct torture_context *tctx = state->tctx;
+ struct timeval current_time;
+ struct tm tm_buf;
+ struct tm *current_tm = NULL;
+ char time_str[sizeof "10000-01-01T00:00:00"];
+ size_t time_str_len;
+ NTSTATUS status;
+ bool ok = false;
+
+ SMB_ASSERT(conn->nreq == subreq);
+ conn->nreq = NULL;
+
+ status = smbXcli_negprot_recv(subreq, NULL, NULL);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
+ "smbXcli_negprot_recv failed");
+
+ current_time = tevent_timeval_current();
+ current_tm = gmtime_r(&current_time.tv_sec, &tm_buf);
+ torture_assert_not_null_goto(tctx, current_tm, ok, asserted,
+ "gmtime_r failed");
+
+ time_str_len = strftime(time_str, sizeof time_str, "%FT%T", current_tm);
+ torture_assert_size_not_equal_goto(tctx, time_str_len, 0, ok, asserted,
+ "strftime failed");
+
+ torture_comment(tctx,
+ "%s.%ldZ: conn[%zu]: negprot done\n",
+ time_str,
+ (long)current_time.tv_usec,
+ conn->idx);
+
+ conn->ereq = smb2cli_echo_send(conn->smbXcli,
+ tctx->ev,
+ conn->smbXcli,
+ state->num_conns * 2 * 1000);
+ torture_assert_goto(tctx, conn->ereq != NULL, ok, asserted,
+ "smb2cli_echo_send");
+ tevent_req_set_callback(conn->ereq,
+ test_multichannel_bug_15346_edone,
+ conn);
+
+ return;
+
+asserted:
+ SMB_ASSERT(!ok);
+ state->asserted = true;
+ state->looping = false;
+ return;
+}
+
+static void test_multichannel_bug_15346_edone(struct tevent_req *subreq)
+{
+ struct test_multichannel_bug_15346_conn *conn =
+ (struct test_multichannel_bug_15346_conn *)
+ tevent_req_callback_data_void(subreq);
+ struct test_multichannel_bug_15346_state *state = conn->state;
+ struct torture_context *tctx = state->tctx;
+ struct timeval current_time;
+ struct tm tm_buf;
+ struct tm *current_tm = NULL;
+ char time_str[sizeof "10000-01-01T00:00:00"];
+ size_t time_str_len;
+ const char *outcome = NULL;
+ NTSTATUS status;
+ bool ok = false;
+
+ SMB_ASSERT(conn->ereq == subreq);
+ conn->ereq = NULL;
+
+ current_time = tevent_timeval_current();
+ current_tm = gmtime_r(&current_time.tv_sec, &tm_buf);
+ torture_assert_not_null_goto(tctx, current_tm, ok, asserted,
+ "gmtime_r failed");
+
+ time_str_len = strftime(time_str, sizeof time_str, "%FT%T", current_tm);
+ torture_assert_size_not_equal_goto(tctx, time_str_len, 0, ok, asserted,
+ "strftime failed");
+
+ status = smb2cli_echo_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ outcome = "timed out";
+ } else if (!NT_STATUS_IS_OK(status)) {
+ outcome = "failed";
+ } else {
+ outcome = "done";
+ }
+ torture_comment(tctx,
+ "%s.%ldZ: conn[%zu]: echo %s\n",
+ time_str,
+ (long)current_time.tv_usec,
+ conn->idx,
+ outcome);
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, asserted,
+ "smb2cli_echo_recv failed");
+
+ state->num_ready += 1;
+ if (state->num_ready < state->num_conns) {
+ return;
+ }
+
+ state->looping = false;
+ return;
+
+asserted:
+ SMB_ASSERT(!ok);
+ state->asserted = true;
+ state->looping = false;
+ return;
+}
+
+static bool test_multichannel_bug_15346(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct resolve_context *resolve_ctx = lpcfg_resolve_context(tctx->lp_ctx);
+ const char *socket_options = lpcfg_socket_options(tctx->lp_ctx);
+ struct gensec_settings *gsettings = NULL;
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct test_multichannel_bug_15346_state *state = NULL;
+ uint32_t server_capabilities;
+ struct smb2_handle root_handle = {{0}};
+ size_t i;
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_fail(tctx,
+ "SMB 3.X Dialect family required for Multichannel"
+ " tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_fail(tctx,
+ "Server does not support multichannel.");
+ }
+
+ torture_comment(tctx, "Testing for BUG 15346\n");
+
+ state = talloc_zero(tctx, struct test_multichannel_bug_15346_state);
+ torture_assert_goto(tctx, state != NULL, ret, done,
+ "talloc_zero");
+ state->tctx = tctx;
+
+ gsettings = lpcfg_gensec_settings(state, tctx->lp_ctx);
+ torture_assert_goto(tctx, gsettings != NULL, ret, done,
+ "lpcfg_gensec_settings");
+
+ /*
+ * 32 is the W2K12R2 and W2K16 limit
+ * add 31 additional connections
+ */
+ state->num_conns = 31;
+ state->conns = talloc_zero_array(state,
+ struct test_multichannel_bug_15346_conn,
+ state->num_conns);
+ torture_assert_goto(tctx, state->conns != NULL, ret, done,
+ "talloc_zero_array");
+
+ /*
+ * First we open the additional tcp connections
+ */
+
+ for (i = 0; i < state->num_conns; i++) {
+ struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+ struct socket_context *sock = NULL;
+ uint16_t port = 445;
+ struct smbcli_options options = transport1->options;
+
+ conn->state = state;
+ conn->idx = i;
+
+ status = socket_connect_multi(state->conns,
+ host,
+ 1, &port,
+ resolve_ctx,
+ tctx->ev,
+ &sock,
+ &port);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "socket_connect_multi failed");
+
+ conn->smbXcli = smbXcli_conn_create(state->conns,
+ sock->fd,
+ host,
+ SMB_SIGNING_OFF,
+ 0,
+ &options.client_guid,
+ options.smb2_capabilities,
+ &options.smb3_capabilities);
+ torture_assert_goto(tctx, conn->smbXcli != NULL, ret, done,
+ "smbXcli_conn_create failed");
+ sock->fd = -1;
+ TALLOC_FREE(sock);
+ }
+
+ /*
+ * Now prepare the async SMB2 Negotiate requests
+ */
+ for (i = 0; i < state->num_conns; i++) {
+ struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+
+ conn->nreq = smbXcli_negprot_send(conn->smbXcli,
+ tctx->ev,
+ conn->smbXcli,
+ state->num_conns * 2 * 1000,
+ smbXcli_conn_protocol(transport1->conn),
+ smbXcli_conn_protocol(transport1->conn),
+ 33, /* max_credits */
+ NULL);
+ torture_assert_goto(tctx, conn->nreq != NULL, ret, done, "smbXcli_negprot_send");
+ tevent_req_set_callback(conn->nreq,
+ test_multichannel_bug_15346_ndone,
+ conn);
+ }
+
+ /*
+ * now we loop until all negprot and the first round
+ * of echos are done.
+ */
+ state->looping = true;
+ while (state->looping) {
+ torture_assert_goto(tctx, tevent_loop_once(tctx->ev) == 0,
+ ret, done, "tevent_loop_once");
+ }
+
+ if (state->asserted) {
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Now we check that the connections are still usable
+ */
+ for (i = 0; i < state->num_conns; i++) {
+ struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+
+ torture_comment(tctx, "conn[%zu]: checking echo again1\n", conn->idx);
+
+ status = smb2cli_echo(conn->smbXcli, 1000);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2cli_echo failed");
+ }
+
+ status = smb2_util_roothandle(tree1, &root_handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_roothandle failed");
+
+ /*
+ * Now we check that the connections are still usable
+ */
+ for (i = 0; i < state->num_conns; i++) {
+ struct test_multichannel_bug_15346_conn *conn = &state->conns[i];
+ struct smbcli_options options = transport1->options;
+ struct smb2_session *session = NULL;
+ struct smb2_tree *tree = NULL;
+ union smb_fileinfo io;
+
+ torture_comment(tctx, "conn[%zu]: checking session bind\n", conn->idx);
+
+ /*
+ * Prepare smb2_{tree,session,transport} structures
+ * for the existing connection.
+ */
+ options.only_negprot = true;
+ status = smb2_connect_ext(state->conns,
+ host,
+ NULL, /* ports */
+ share,
+ resolve_ctx,
+ samba_cmdline_get_creds(),
+ &conn->smbXcli,
+ 0, /* previous_session_id */
+ &tree,
+ tctx->ev,
+ &options,
+ socket_options,
+ gsettings);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect_ext failed");
+ conn->smbXcli = tree->session->transport->conn;
+
+ session = smb2_session_channel(tree->session->transport,
+ lpcfg_gensec_settings(tree, tctx->lp_ctx),
+ tree,
+ tree1->session);
+ torture_assert_goto(tctx, session != NULL, ret, done,
+ "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /*
+ * Fix up the bound smb2_tree
+ */
+ tree->session = session;
+ tree->smbXcli = tree1->smbXcli;
+
+ ZERO_STRUCT(io);
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = root_handle;
+
+ status = smb2_getinfo_file(tree, tree, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ }
+
+ done:
+ talloc_free(state);
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_multichannel_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "multichannel");
+ struct torture_suite *suite_generic = torture_suite_create(ctx,
+ "generic");
+ struct torture_suite *suite_oplocks = torture_suite_create(ctx,
+ "oplocks");
+ struct torture_suite *suite_leases = torture_suite_create(ctx,
+ "leases");
+ struct torture_suite *suite_bugs = torture_suite_create(ctx,
+ "bugs");
+
+ torture_suite_add_suite(suite, suite_generic);
+ torture_suite_add_suite(suite, suite_oplocks);
+ torture_suite_add_suite(suite, suite_leases);
+ torture_suite_add_suite(suite, suite_bugs);
+
+ torture_suite_add_1smb2_test(suite_generic, "interface_info",
+ test_multichannel_interface_info);
+ torture_suite_add_1smb2_test(suite_generic, "num_channels",
+ test_multichannel_num_channels);
+ torture_suite_add_1smb2_test(suite_oplocks, "test1",
+ test_multichannel_oplock_break_test1);
+ torture_suite_add_1smb2_test(suite_oplocks, "test2",
+ test_multichannel_oplock_break_test2);
+ torture_suite_add_1smb2_test(suite_oplocks, "test3_windows",
+ test_multichannel_oplock_break_test3_windows);
+ torture_suite_add_1smb2_test(suite_oplocks, "test3_specification",
+ test_multichannel_oplock_break_test3_specification);
+ torture_suite_add_1smb2_test(suite_leases, "test1",
+ test_multichannel_lease_break_test1);
+ torture_suite_add_1smb2_test(suite_leases, "test2",
+ test_multichannel_lease_break_test2);
+ torture_suite_add_1smb2_test(suite_leases, "test3",
+ test_multichannel_lease_break_test3);
+ torture_suite_add_1smb2_test(suite_leases, "test4",
+ test_multichannel_lease_break_test4);
+ torture_suite_add_1smb2_test(suite_bugs, "bug_15346",
+ test_multichannel_bug_15346);
+
+ suite->description = talloc_strdup(suite, "SMB2 Multichannel tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c
new file mode 100644
index 0000000..0aadc50
--- /dev/null
+++ b/source4/torture/smb2/notify.c
@@ -0,0 +1,2786 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 notify test suite
+
+ Copyright (C) Stefan Metzmacher 2006
+ Copyright (C) Andrew Tridgell 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "torture/util.h"
+
+#include "system/filesys.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/security.h"
+
+#include "lib/events/events.h"
+
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "(%s) wrong value for %s 0x%x should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_WIRE_STR(field, value) do { \
+ if (!field.s || strcmp(field.s, value)) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "(%s) %s [%s] != %s\n", __location__, #field, \
+ field.s, value); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define WAIT_FOR_ASYNC_RESPONSE(req) \
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
+ if (tevent_loop_once(torture->ev) != 0) { \
+ break; \
+ } \
+ }
+
+#define BASEDIR "test_notify"
+#define FNAME "smb2-notify01.dat"
+
+static bool test_valid_request(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle dh;
+ struct smb2_notify n;
+ struct smb2_request *req;
+ uint32_t max_buffer_size;
+
+ torture_comment(torture, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
+
+ smb2_transport_credits_ask_num(tree->session->transport, 256);
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = smb2_util_roothandle(tree, &dh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ max_buffer_size =
+ smb2cli_conn_max_trans_size(tree->session->transport->conn);
+
+ n.in.recursive = 0x0000;
+ n.in.buffer_size = max_buffer_size;
+ n.in.file.handle = dh;
+ n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
+ n.in.unknown = 0x00000000;
+ req = smb2_notify_send(tree, &n);
+
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
+ if (tevent_loop_once(torture->ev) != 0) {
+ break;
+ }
+ }
+
+ status = torture_setup_simple_file(torture, tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &n);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(n.out.num_changes, 1);
+ CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
+
+ /*
+ * if the change response doesn't fit in the buffer
+ * NOTIFY_ENUM_DIR is returned.
+ */
+ n.in.buffer_size = 0x00000000;
+ req = smb2_notify_send(tree, &n);
+
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
+ if (tevent_loop_once(torture->ev) != 0) {
+ break;
+ }
+ }
+
+ status = torture_setup_simple_file(torture, tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &n);
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
+
+ /*
+ * if the change response fits in the buffer we get
+ * NT_STATUS_OK again
+ */
+ n.in.buffer_size = max_buffer_size;
+ req = smb2_notify_send(tree, &n);
+
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
+ if (tevent_loop_once(torture->ev) != 0) {
+ break;
+ }
+ }
+
+ status = torture_setup_simple_file(torture, tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &n);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(n.out.num_changes, 3);
+ CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
+ CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
+ CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
+ CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
+
+ /* if the first notify returns NOTIFY_ENUM_DIR, all do */
+ status = smb2_util_close(tree, dh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_roothandle(tree, &dh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ n.in.recursive = 0x0000;
+ n.in.buffer_size = 0x00000001;
+ n.in.file.handle = dh;
+ n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
+ n.in.unknown = 0x00000000;
+ req = smb2_notify_send(tree, &n);
+
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
+ if (tevent_loop_once(torture->ev) != 0) {
+ break;
+ }
+ }
+
+ status = torture_setup_simple_file(torture, tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &n);
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
+
+ n.in.buffer_size = max_buffer_size;
+ req = smb2_notify_send(tree, &n);
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
+ if (tevent_loop_once(torture->ev) != 0) {
+ break;
+ }
+ }
+
+ status = torture_setup_simple_file(torture, tree, FNAME);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &n);
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
+
+ /* if the buffer size is too large, we get invalid parameter */
+ n.in.recursive = 0x0000;
+ n.in.buffer_size = max_buffer_size + 1;
+ n.in.file.handle = dh;
+ n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
+ n.in.unknown = 0x00000000;
+ req = smb2_notify_send(tree, &n);
+ status = smb2_notify_recv(req, torture, &n);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+done:
+ return ret;
+}
+
+/*
+ basic testing of change notify on directories
+*/
+
+#define BASEDIR_DIR BASEDIR "_DIR"
+
+static bool torture_smb2_notify_dir(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ union smb_close cl;
+ int i, count;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_request *req, *req2;
+ const char *fname = BASEDIR_DIR "\\subdir-name";
+ extern int torture_numops;
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
+
+ smb2_deltree(tree1, BASEDIR_DIR);
+ smb2_util_rmdir(tree1, BASEDIR_DIR);
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_DIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ;
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ torture_comment(torture, "Testing notify cancel\n");
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_cancel(req);
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ torture_comment(torture, "Testing notify mkdir\n");
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_util_mkdir(tree2, fname);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "Testing notify rmdir\n");
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_util_rmdir(tree2, fname);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture,
+ "Testing notify mkdir - rmdir - mkdir - rmdir\n");
+
+ smb2_util_mkdir(tree2, fname);
+ smb2_util_rmdir(tree2, fname);
+ smb2_util_mkdir(tree2, fname);
+ smb2_util_rmdir(tree2, fname);
+ smb_msleep(200);
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 4);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+ CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name");
+ CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name");
+ CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name");
+
+ count = torture_numops;
+ torture_comment(torture,
+ "Testing buffered notify on create of %d files\n", count);
+ for (i=0;i<count;i++) {
+ struct smb2_handle h12;
+ char *fname2 = talloc_asprintf(torture,
+ BASEDIR_DIR "\\test%d.txt",
+ i);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options =
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname2;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(torture, "Failed to create %s \n",
+ fname);
+ ret = false;
+ goto done;
+ }
+ h12 = io.smb2.out.file.handle;
+ talloc_free(fname2);
+ smb2_util_close(tree1, h12);
+ }
+
+ /* (1st notify) setup a new notify on a different directory handle.
+ This new notify won't see the events above. */
+ notify.smb2.in.file.handle = h2;
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+
+ /* (2nd notify) whereas this notify will see the above buffered events,
+ and it directly returns the buffered events */
+ notify.smb2.in.file.handle = h1;
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /* (1st unlink) as the 2nd notify directly returns,
+ this unlink is only seen by the 1st notify and
+ the 3rd notify (later) */
+ torture_comment(torture,
+ "Testing notify on unlink for the first file\n");
+ status = smb2_util_unlink(tree2, BASEDIR_DIR "\\test0.txt");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* receive the reply from the 2nd notify */
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, count);
+ for (i=1;i<count;i++) {
+ CHECK_VAL(notify.smb2.out.changes[i].action,
+ NOTIFY_ACTION_ADDED);
+ }
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
+
+ torture_comment(torture, "and now from the 1st notify\n");
+ status = smb2_notify_recv(req2, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
+
+ torture_comment(torture,
+ "(3rd notify) this notify will only see the 1st unlink\n");
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ status = smb2_util_unlink(tree1, BASEDIR_DIR "\\nonexistent.txt");
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ for (i=1;i<count;i++) {
+ char *fname2 = talloc_asprintf(torture,
+ BASEDIR_DIR "\\test%d.txt", i);
+ status = smb2_util_unlink(tree2, fname2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ talloc_free(fname2);
+ }
+
+ /* receive the 3rd notify */
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "test0.txt");
+
+ /* and we now see the rest of the unlink calls on both
+ * directory handles */
+ notify.smb2.in.file.handle = h1;
+ sleep(3);
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, count-1);
+ for (i=0;i<notify.smb2.out.num_changes;i++) {
+ CHECK_VAL(notify.smb2.out.changes[i].action,
+ NOTIFY_ACTION_REMOVED);
+ }
+ notify.smb2.in.file.handle = h2;
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, count-1);
+ for (i=0;i<notify.smb2.out.num_changes;i++) {
+ CHECK_VAL(notify.smb2.out.changes[i].action,
+ NOTIFY_ACTION_REMOVED);
+ }
+
+ torture_comment(torture,
+ "Testing if a close() on the dir handle triggers the notify reply\n");
+
+ notify.smb2.in.file.handle = h1;
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
+ CHECK_VAL(notify.smb2.out.num_changes, 9);
+
+done:
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h2);
+ smb2_deltree(tree1, BASEDIR_DIR);
+ return ret;
+}
+
+static struct smb2_handle custom_smb2_create(struct smb2_tree *tree,
+ struct torture_context *torture,
+ struct smb2_create *smb2)
+{
+ struct smb2_handle h1;
+ bool ret = true;
+ NTSTATUS status;
+ smb2_deltree(tree, smb2->in.fname);
+ status = smb2_create(tree, torture, smb2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = smb2->out.file.handle;
+done:
+ if (!ret) {
+ h1 = (struct smb2_handle) {
+ .data = { 0 , 0},
+ };
+ }
+ return h1;
+}
+
+/*
+ testing of recursive change notify
+*/
+
+#define BASEDIR_REC BASEDIR "_REC"
+
+static bool torture_smb2_notify_recursive(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io, io1;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle h1;
+ struct smb2_request *req1, *req2;
+
+ smb2_deltree(tree1, BASEDIR_REC);
+ smb2_util_rmdir(tree1, BASEDIR_REC);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY WITH RECURSION\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_REC;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify, on file or directory name
+ changes. Setup both with and without recursion */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_CREATION;
+ notify.smb2.in.file.handle = h1;
+
+ notify.smb2.in.recursive = true;
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_cancel(req1);
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ notify.smb2.in.recursive = false;
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_cancel(req2);
+ status = smb2_notify_recv(req2, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ ZERO_STRUCT(io1.smb2);
+ io1.generic.level = RAW_OPEN_SMB2;
+ io1.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_ALL;
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io1.smb2.in.alloc_size = 0;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io1.smb2.in.security_flags = 0;
+ io1.smb2.in.fname = BASEDIR_REC "\\subdir-name";
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree2, io1.smb2.out.file.handle);
+
+ io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname1";
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR_REC "\\subdir-name\\subname1-r";
+ status = smb2_setinfo_file(tree2, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io1.smb2.in.fname = BASEDIR_REC "\\subdir-name\\subname2";
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname2-r";
+ status = smb2_setinfo_file(tree2, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io1.smb2.in.fname = BASEDIR_REC "\\subname2-r";
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = BASEDIR_REC "\\subname3-r";
+ status = smb2_setinfo_file(tree2, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ notify.smb2.in.completion_filter = 0;
+ notify.smb2.in.recursive = true;
+ smb_msleep(200);
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+
+ status = smb2_util_rmdir(tree2,
+ BASEDIR_REC "\\subdir-name\\subname1-r");
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_rmdir(tree2,
+ BASEDIR_REC "\\subdir-name");
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_unlink(tree2, BASEDIR_REC "\\subname3-r");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ notify.smb2.in.recursive = false;
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 9);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+ CHECK_VAL(notify.smb2.out.changes[1].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[1].name, "subdir-name\\subname1");
+ CHECK_VAL(notify.smb2.out.changes[2].action, NOTIFY_ACTION_OLD_NAME);
+ CHECK_WIRE_STR(notify.smb2.out.changes[2].name, "subdir-name\\subname1");
+ CHECK_VAL(notify.smb2.out.changes[3].action, NOTIFY_ACTION_NEW_NAME);
+ CHECK_WIRE_STR(notify.smb2.out.changes[3].name, "subdir-name\\subname1-r");
+ CHECK_VAL(notify.smb2.out.changes[4].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[4].name, "subdir-name\\subname2");
+ CHECK_VAL(notify.smb2.out.changes[5].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[5].name, "subdir-name\\subname2");
+ CHECK_VAL(notify.smb2.out.changes[6].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[6].name, "subname2-r");
+ CHECK_VAL(notify.smb2.out.changes[7].action, NOTIFY_ACTION_OLD_NAME);
+ CHECK_WIRE_STR(notify.smb2.out.changes[7].name, "subname2-r");
+ CHECK_VAL(notify.smb2.out.changes[8].action, NOTIFY_ACTION_NEW_NAME);
+ CHECK_WIRE_STR(notify.smb2.out.changes[8].name, "subname3-r");
+
+done:
+ smb2_deltree(tree1, BASEDIR_REC);
+ return ret;
+}
+
+/*
+ testing of change notify mask change
+*/
+
+#define BASEDIR_MC BASEDIR "_MC"
+
+static bool torture_smb2_notify_mask_change(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io, io1;
+ struct smb2_handle h1;
+ struct smb2_request *req1, *req2;
+ union smb_setfileinfo sinfo;
+
+ smb2_deltree(tree1, BASEDIR_MC);
+ smb2_util_rmdir(tree1, BASEDIR_MC);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_MC;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify, on file or directory name
+ changes. Setup both with and without recursion */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ notify.smb2.in.file.handle = h1;
+
+ notify.smb2.in.recursive = true;
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+
+ smb2_cancel(req1);
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+
+ notify.smb2.in.recursive = false;
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+
+ smb2_cancel(req2);
+ status = smb2_notify_recv(req2, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ notify.smb2.in.recursive = true;
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+
+ /* Set to hidden then back again. */
+ ZERO_STRUCT(io1.smb2);
+ io1.generic.level = RAW_OPEN_SMB2;
+ io1.smb2.in.create_flags = 0;
+ io1.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_ALL;
+ io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io1.smb2.in.security_flags = 0;
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io1.smb2.in.fname = BASEDIR_MC "\\tname1";
+
+ smb2_util_close(tree1,
+ custom_smb2_create(tree1, torture, &(io1.smb2)));
+ status = smb2_util_setatr(tree1, BASEDIR_MC "\\tname1",
+ FILE_ATTRIBUTE_HIDDEN);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_unlink(tree1, BASEDIR_MC "\\tname1");
+
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
+
+ /* Now try and change the mask to include other events.
+ * This should not work - once the mask is set on a directory
+ * h1 it seems to be fixed until the fnum is closed. */
+
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_CREATION;
+ notify.smb2.in.recursive = true;
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+
+ notify.smb2.in.recursive = false;
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io1.smb2.in.fname = BASEDIR_MC "\\subdir-name";
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree2, io1.smb2.out.file.handle);
+
+ ZERO_STRUCT(sinfo);
+ io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname1";
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR_MC "\\subdir-name\\subname1-r";
+ status = smb2_setinfo_file(tree2, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io1.smb2.in.fname = BASEDIR_MC "\\subdir-name\\subname2";
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
+ sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname2-r";
+ status = smb2_setinfo_file(tree2, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree2, io1.smb2.out.file.handle);
+
+ io1.smb2.in.fname = BASEDIR_MC "\\subname2-r";
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, torture, &(io1.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ sinfo.rename_information.in.file.handle = io1.smb2.out.file.handle;
+ sinfo.rename_information.in.new_name = BASEDIR_MC "\\subname3-r";
+ status = smb2_setinfo_file(tree2, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree2, io1.smb2.out.file.handle);
+
+ status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name\\subname1-r");
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_rmdir(tree2, BASEDIR_MC "\\subdir-name");
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_unlink(tree2, BASEDIR_MC "\\subname3-r");
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname2-r");
+
+ status = smb2_notify_recv(req2, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subname3-r");
+
+ if (!ret) {
+ goto done;
+ }
+
+done:
+ smb2_deltree(tree1, BASEDIR_MC);
+ return ret;
+}
+
+/*
+ testing of mask bits for change notify
+*/
+
+#define BASEDIR_MSK BASEDIR "_MSK"
+
+static bool torture_smb2_notify_mask(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io, io1;
+ struct smb2_handle h1, h2;
+ int i;
+ char c = 1;
+ union smb_setfileinfo sinfo;
+
+ smb2_deltree(tree1, BASEDIR_MSK);
+ smb2_util_rmdir(tree1, BASEDIR_MSK);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
+
+
+ ZERO_STRUCT(h1);
+ ZERO_STRUCT(h2);
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_MSK;
+
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.recursive = true;
+
+#define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
+ expected, nchanges) \
+ do { \
+ do { for (i=0;i<32;i++) { \
+ struct smb2_request *req; \
+ status = smb2_create(tree1, torture, &(io.smb2)); \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ h1 = io.smb2.out.file.handle; \
+ setup \
+ notify.smb2.in.file.handle = h1; \
+ notify.smb2.in.completion_filter = ((uint32_t)1<<i); \
+ /* cancel initial requests so the buffer is setup */ \
+ req = smb2_notify_send(tree1, &(notify.smb2)); \
+ smb2_cancel(req); \
+ status = smb2_notify_recv(req, torture, &(notify.smb2)); \
+ CHECK_STATUS(status, NT_STATUS_CANCELLED); \
+ /* send the change notify request */ \
+ req = smb2_notify_send(tree1, &(notify.smb2)); \
+ op \
+ smb_msleep(200); smb2_cancel(req); \
+ status = smb2_notify_recv(req, torture, &(notify.smb2)); \
+ cleanup \
+ smb2_util_close(tree1, h1); \
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
+ CHECK_STATUS(status, NT_STATUS_OK); \
+ /* special case to cope with file rename behaviour */ \
+ if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
+ notify.smb2.out.changes[0].action == \
+ NOTIFY_ACTION_MODIFIED && \
+ ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
+ Action == NOTIFY_ACTION_OLD_NAME) { \
+ torture_comment(torture, \
+ "(rename file special handling OK)\n"); \
+ } else if (nchanges != notify.smb2.out.num_changes) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "ERROR: nchanges=%d expected=%d "\
+ "action=%d filter=0x%08x\n", \
+ notify.smb2.out.num_changes, \
+ nchanges, \
+ notify.smb2.out.changes[0].action, \
+ notify.smb2.in.completion_filter); \
+ ret = false; \
+ } else if (notify.smb2.out.changes[0].action != Action) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "ERROR: nchanges=%d action=%d " \
+ "expectedAction=%d filter=0x%08x\n", \
+ notify.smb2.out.num_changes, \
+ notify.smb2.out.changes[0].action, \
+ Action, \
+ notify.smb2.in.completion_filter); \
+ ret = false; \
+ } else if (strcmp(notify.smb2.out.changes[0].name.s, \
+ "tname1") != 0) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "ERROR: nchanges=%d action=%d " \
+ "filter=0x%08x name=%s\n", \
+ notify.smb2.out.num_changes, \
+ notify.smb2.out.changes[0].action, \
+ notify.smb2.in.completion_filter, \
+ notify.smb2.out.changes[0].name.s); \
+ ret = false; \
+ } \
+ } \
+ } while (0); \
+ } while (0);
+
+ torture_comment(torture, "Testing mkdir\n");
+ NOTIFY_MASK_TEST("Testing mkdir",;,
+ smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
+ smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
+ NOTIFY_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_DIR_NAME, 1);
+
+ torture_comment(torture, "Testing create file\n");
+ ZERO_STRUCT(io1.smb2);
+ io1.generic.level = RAW_OPEN_SMB2;
+ io1.smb2.in.create_flags = 0;
+ io1.smb2.in.desired_access = SEC_FILE_ALL;
+ io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io1.smb2.in.security_flags = 0;
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io1.smb2.in.fname = BASEDIR_MSK "\\tname1";
+
+ NOTIFY_MASK_TEST("Testing create file",;,
+ smb2_util_close(tree2, custom_smb2_create(tree2,
+ torture, &(io1.smb2)));,
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
+ NOTIFY_ACTION_ADDED,
+ FILE_NOTIFY_CHANGE_FILE_NAME, 1);
+
+ torture_comment(torture, "Testing unlink\n");
+ NOTIFY_MASK_TEST("Testing unlink",
+ smb2_util_close(tree2, custom_smb2_create(tree2,
+ torture, &(io1.smb2)));,
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
+ ;,
+ NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_FILE_NAME, 1);
+
+ torture_comment(torture, "Testing rmdir\n");
+ NOTIFY_MASK_TEST("Testing rmdir",
+ smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
+ smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname1");,
+ ;,
+ NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_DIR_NAME, 1);
+
+ torture_comment(torture, "Testing rename file\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
+ NOTIFY_MASK_TEST("Testing rename file",
+ smb2_util_close(tree2, custom_smb2_create(tree2,
+ torture, &(io1.smb2)));,
+ smb2_setinfo_file(tree2, &sinfo);,
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname2");,
+ NOTIFY_ACTION_OLD_NAME,
+ FILE_NOTIFY_CHANGE_FILE_NAME, 2);
+
+ torture_comment(torture, "Testing rename dir\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = BASEDIR_MSK "\\tname2";
+ NOTIFY_MASK_TEST("Testing rename dir",
+ smb2_util_mkdir(tree2, BASEDIR_MSK "\\tname1");,
+ smb2_setinfo_file(tree2, &sinfo);,
+ smb2_util_rmdir(tree2, BASEDIR_MSK "\\tname2");,
+ NOTIFY_ACTION_OLD_NAME,
+ FILE_NOTIFY_CHANGE_DIR_NAME, 2);
+
+ torture_comment(torture, "Testing set path attribute\n");
+ NOTIFY_MASK_TEST("Testing set path attribute",
+ smb2_util_close(tree2, custom_smb2_create(tree2,
+ torture, &(io.smb2)));,
+ smb2_util_setatr(tree2, BASEDIR_MSK "\\tname1",
+ FILE_ATTRIBUTE_HIDDEN);,
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
+
+ torture_comment(torture, "Testing set path write time\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sinfo.generic.in.file.handle = h1;
+ sinfo.basic_info.in.write_time = 1000;
+ NOTIFY_MASK_TEST("Testing set path write time",
+ smb2_util_close(tree2, custom_smb2_create(tree2,
+ torture, &(io1.smb2)));,
+ smb2_setinfo_file(tree2, &sinfo);,
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1");,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
+
+ if (torture_setting_bool(torture, "samba3", false)) {
+ torture_comment(torture,
+ "Samba3 does not yet support create times "
+ "everywhere\n");
+ }
+ else {
+ ZERO_STRUCT(sinfo);
+ sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sinfo.generic.in.file.handle = h1;
+ sinfo.basic_info.in.create_time = 0;
+ torture_comment(torture, "Testing set file create time\n");
+ NOTIFY_MASK_TEST("Testing set file create time",
+ smb2_create_complex_file(torture, tree2,
+ BASEDIR_MSK "\\tname1", &h2);,
+ smb2_setinfo_file(tree2, &sinfo);,
+ (smb2_util_close(tree2, h2),
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_CREATION, 1);
+ }
+
+ ZERO_STRUCT(sinfo);
+ sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sinfo.generic.in.file.handle = h1;
+ sinfo.basic_info.in.access_time = 0;
+ torture_comment(torture, "Testing set file access time\n");
+ NOTIFY_MASK_TEST("Testing set file access time",
+ smb2_create_complex_file(torture,
+ tree2,
+ BASEDIR_MSK "\\tname1",
+ &h2);,
+ smb2_setinfo_file(tree2, &sinfo);,
+ (smb2_util_close(tree2, h2),
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
+
+ ZERO_STRUCT(sinfo);
+ sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sinfo.generic.in.file.handle = h1;
+ sinfo.basic_info.in.change_time = 0;
+ torture_comment(torture, "Testing set file change time\n");
+ NOTIFY_MASK_TEST("Testing set file change time",
+ smb2_create_complex_file(torture,
+ tree2,
+ BASEDIR_MSK "\\tname1",
+ &h2);,
+ smb2_setinfo_file(tree2, &sinfo);,
+ (smb2_util_close(tree2, h2),
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ 0, 1);
+
+
+ torture_comment(torture, "Testing write\n");
+ NOTIFY_MASK_TEST("Testing write",
+ smb2_create_complex_file(torture,
+ tree2,
+ BASEDIR_MSK "\\tname1",
+ &h2);,
+ smb2_util_write(tree2, h2, &c, 10000, 1);,
+ (smb2_util_close(tree2, h2),
+ smb2_util_unlink(tree2, BASEDIR_MSK "\\tname1"));,
+ NOTIFY_ACTION_MODIFIED,
+ 0, 1);
+
+done:
+ smb2_deltree(tree1, BASEDIR_MSK);
+ return ret;
+}
+
+#define BASEDIR_FL BASEDIR "_FL"
+/*
+ basic testing of change notify on files
+*/
+static bool torture_smb2_notify_file(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_close cl;
+ union smb_notify notify;
+ struct smb2_request *req;
+ struct smb2_handle h1;
+ const char *fname = BASEDIR_FL "\\file.txt";
+
+ smb2_deltree(tree, BASEDIR_FL);
+ smb2_util_rmdir(tree, BASEDIR_FL);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
+ status = torture_smb2_testdir(tree, BASEDIR_FL, &h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
+ notify.smb2.in.recursive = false;
+
+ torture_comment(torture,
+ "Testing if notifies on file handles are invalid (should be)\n");
+
+ req = smb2_notify_send(tree, &(notify.smb2));
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ ZERO_STRUCT(cl.smb2);
+ cl.close.level = RAW_CLOSE_SMB2;
+ cl.close.in.file.handle = h1;
+ status = smb2_close(tree, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_deltree(tree, BASEDIR_FL);
+ return ret;
+}
+/*
+ basic testing of change notifies followed by a tdis
+*/
+
+#define BASEDIR_TD BASEDIR "_TD"
+
+static bool torture_smb2_notify_tree_disconnect(
+ struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+
+ smb2_deltree(tree, BASEDIR_TD);
+ smb2_util_rmdir(tree, BASEDIR_TD);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
+ "TREE-DISCONNECT\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_TD;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_cancel(req);
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+
+ status = smb2_tdis(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ req = smb2_notify_send(tree, &(notify.smb2));
+
+ smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+ smb2_deltree(tree, BASEDIR_TD);
+ return ret;
+}
+
+/*
+ testing of change notifies followed by a tdis - no cancel
+*/
+
+#define BASEDIR_NTDIS BASEDIR "_NTDIS"
+
+static bool torture_smb2_notify_tree_disconnect_1(
+ struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+
+ smb2_deltree(tree, BASEDIR_NTDIS);
+ smb2_util_rmdir(tree, BASEDIR_NTDIS);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
+ "TREE-DISCONNECT\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_NTDIS;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree, &(notify.smb2));
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ status = smb2_tdis(tree);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+ smb2_deltree(tree, BASEDIR_NTDIS);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by a close
+*/
+
+#define BASEDIR_CNC BASEDIR "_CNC"
+
+static bool torture_smb2_notify_close(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+
+ smb2_deltree(tree1, BASEDIR_CNC);
+ smb2_util_rmdir(tree1, BASEDIR_CNC);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_CNC;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ status = smb2_util_close(tree1, h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+ smb2_deltree(tree1, BASEDIR_CNC);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by a ulogoff
+*/
+
+#define BASEDIR_NUL BASEDIR "_NUL"
+static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+
+ smb2_deltree(tree1, BASEDIR_NUL);
+ smb2_util_rmdir(tree1, BASEDIR_NUL);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_NUL;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ status = smb2_logoff(tree1->session);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+ smb2_deltree(tree1, BASEDIR_NUL);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by a session reconnect
+*/
+
+#define BASEDIR_NSR BASEDIR "_NSR"
+
+static bool torture_smb2_notify_session_reconnect(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+ uint64_t previous_session_id = 0;
+ struct smb2_session *session2 = NULL;
+
+ smb2_deltree(tree1, BASEDIR_NSR);
+ smb2_util_rmdir(tree1, BASEDIR_NSR);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY SESSION RECONNECT\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_NSR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ previous_session_id = smb2cli_session_current_id(tree1->session->smbXcli);
+ torture_assert(torture, torture_smb2_session_setup(torture,
+ tree1->session->transport,
+ previous_session_id,
+ torture, &session2),
+ "session setup with previous_session_id failed");
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+ status = smb2_logoff(tree1->session);
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+
+ status = smb2_logoff(session2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+done:
+ smb2_deltree(tree1, BASEDIR_NSR);
+ return ret;
+}
+
+/*
+ basic testing of change notifies followed by an invalid reauth
+*/
+
+#define BASEDIR_IR BASEDIR "_IR"
+
+static bool torture_smb2_notify_invalid_reauth(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+ struct cli_credentials *invalid_creds;
+
+ smb2_deltree(tree2, BASEDIR_IR);
+ smb2_util_rmdir(tree2, BASEDIR_IR);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY invalid REAUTH\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_IR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ invalid_creds = cli_credentials_init(torture);
+ torture_assert(torture, (invalid_creds != NULL), "talloc error");
+ cli_credentials_set_username(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
+ cli_credentials_set_domain(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
+ cli_credentials_set_password(invalid_creds, "__none__invalid__none__", CRED_SPECIFIED);
+ cli_credentials_set_realm(invalid_creds, NULL, CRED_SPECIFIED);
+ cli_credentials_set_workstation(invalid_creds, "", CRED_UNINITIALISED);
+
+ status = smb2_session_setup_spnego(tree1->session,
+ invalid_creds,
+ 0 /* previous_session_id */);
+ CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_CLEANUP);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+ /*
+ * Demonstrate that the session is no longer valid.
+ */
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED);
+done:
+ smb2_deltree(tree2, BASEDIR_IR);
+ return ret;
+}
+
+static void tcp_dis_handler(struct smb2_transport *t, void *p)
+{
+ struct smb2_tree *tree = (struct smb2_tree *)p;
+ smb2_transport_dead(tree->session->transport,
+ NT_STATUS_LOCAL_DISCONNECT);
+ t = NULL;
+ tree = NULL;
+}
+
+/*
+ basic testing of change notifies followed by tcp disconnect
+*/
+
+#define BASEDIR_NTCPD BASEDIR "_NTCPD"
+
+static bool torture_smb2_notify_tcp_disconnect(
+ struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+
+ smb2_deltree(tree, BASEDIR_NTCPD);
+ smb2_util_rmdir(tree, BASEDIR_NTCPD);
+
+ torture_comment(torture,
+ "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_NTCPD;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_cancel(req);
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ notify.smb2.in.recursive = true;
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_transport_idle_handler(tree->session->transport,
+ tcp_dis_handler, 250000, tree);
+ tree = NULL;
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
+
+done:
+ return ret;
+}
+
+/*
+ test setting up two change notify requests on one handle
+*/
+
+#define BASEDIR_NDOH BASEDIR "_NDOH"
+
+static bool torture_smb2_notify_double(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req1, *req2;
+
+ smb2_deltree(tree1, BASEDIR_NDOH);
+ smb2_util_rmdir(tree1, BASEDIR_NDOH);
+
+ torture_comment(torture,
+ "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
+ SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_NDOH;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_cancel(req1);
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+ smb2_cancel(req2);
+ status = smb2_notify_recv(req2, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name");
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+ req2 = smb2_notify_send(tree1, &(notify.smb2));
+
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ smb2_util_mkdir(tree2, BASEDIR_NDOH "\\subdir-name2");
+
+ status = smb2_notify_recv(req2, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
+
+done:
+ smb2_deltree(tree1, BASEDIR_NDOH);
+ return ret;
+}
+
+
+/*
+ test multiple change notifies at different depths and with/without recursion
+*/
+
+#define BASEDIR_TREE BASEDIR "_TREE"
+
+static bool torture_smb2_notify_tree(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_request *req;
+ struct timeval tv;
+ struct {
+ const char *path;
+ bool recursive;
+ uint32_t filter;
+ int expected;
+ struct smb2_handle h1;
+ int counted;
+ } dirs[] = {
+ {
+ .path = BASEDIR_TREE "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 30,
+ },
+ {
+ .path = BASEDIR_TREE "\\zqy",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 8,
+ },
+ {
+ .path = BASEDIR_TREE "\\atsy",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 4,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\foo",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\blah",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 13,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\blah",
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 7,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\blah\\a",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\blah\\b",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\blah\\c",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc\\fooblah",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\zqy\\xx",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\zqy\\yyy",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 2,
+ },
+ {
+ .path = BASEDIR_TREE "\\zqy\\..",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 40,
+ },
+ {
+ .path = BASEDIR_TREE,
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 40,
+ },
+ {
+ .path = BASEDIR_TREE,
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 6,
+ },
+ {
+ .path = BASEDIR_TREE "\\atsy",
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 4,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 24,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc",
+ .recursive = false,
+ .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
+ .expected = 0,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
+ .expected = 0,
+ },
+ {
+ .path = BASEDIR_TREE "\\abc",
+ .recursive = true,
+ .filter = FILE_NOTIFY_CHANGE_NAME,
+ .expected = 24,
+ },
+ };
+ int i;
+ NTSTATUS status;
+ bool all_done = false;
+
+ smb2_deltree(tree, BASEDIR_TREE);
+ smb2_util_rmdir(tree, BASEDIR_TREE);
+
+ torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_TREE;
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 20000;
+
+ /*
+ setup the directory tree, and the notify buffer on each directory
+ */
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ io.smb2.in.fname = dirs[i].path;
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dirs[i].h1 = io.smb2.out.file.handle;
+
+ notify.smb2.in.completion_filter = dirs[i].filter;
+ notify.smb2.in.file.handle = dirs[i].h1;
+ notify.smb2.in.recursive = dirs[i].recursive;
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_cancel(req);
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+ }
+
+ /* trigger 2 events in each dir */
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ char *path = talloc_asprintf(torture, "%s\\test.dir",
+ dirs[i].path);
+ smb2_util_mkdir(tree, path);
+ smb2_util_rmdir(tree, path);
+ talloc_free(path);
+ }
+
+ /* give a bit of time for the events to propagate */
+ tv = timeval_current();
+
+ do {
+ /* count events that have happened in each dir */
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ notify.smb2.in.completion_filter = dirs[i].filter;
+ notify.smb2.in.file.handle = dirs[i].h1;
+ notify.smb2.in.recursive = dirs[i].recursive;
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_cancel(req);
+ notify.smb2.out.num_changes = 0;
+ status = smb2_notify_recv(req, torture,
+ &(notify.smb2));
+ dirs[i].counted += notify.smb2.out.num_changes;
+ }
+
+ all_done = true;
+
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ if (dirs[i].counted != dirs[i].expected) {
+ all_done = false;
+ }
+ }
+ } while (!all_done && timeval_elapsed(&tv) < 20);
+
+ torture_comment(torture, "took %.4f seconds to propagate all events\n",
+ timeval_elapsed(&tv));
+
+ for (i=0;i<ARRAY_SIZE(dirs);i++) {
+ if (dirs[i].counted != dirs[i].expected) {
+ torture_comment(torture,
+ "ERROR: i=%d expected %d got %d for '%s'\n",
+ i, dirs[i].expected, dirs[i].counted,
+ dirs[i].path);
+ ret = false;
+ }
+ }
+
+ /*
+ run from the back, closing and deleting
+ */
+ for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
+ smb2_util_close(tree, dirs[i].h1);
+ smb2_util_rmdir(tree, dirs[i].path);
+ }
+
+done:
+ smb2_deltree(tree, BASEDIR_TREE);
+ smb2_util_rmdir(tree, BASEDIR_TREE);
+ return ret;
+}
+
+/*
+ Test response when cached server events exceed single NT NOTFIY response
+ packet size.
+*/
+
+#define BASEDIR_OVF BASEDIR "_OVF"
+
+static bool torture_smb2_notify_overflow(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1, h2;
+ int count = 100;
+ struct smb2_request *req1;
+ int i;
+
+ smb2_deltree(tree, BASEDIR_OVF);
+ smb2_util_rmdir(tree, BASEDIR_OVF);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
+
+ /* get a handle on the directory */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_OVF;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify, on name changes. */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_NTTRANS;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+
+ notify.smb2.in.recursive = true;
+ req1 = smb2_notify_send(tree, &(notify.smb2));
+
+ /* cancel initial requests so the buffer is setup */
+ smb2_cancel(req1);
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ /* open a lot of files, filling up the server side notify buffer */
+ torture_comment(torture,
+ "Testing overflowed buffer notify on create of %d files\n",
+ count);
+
+ for (i=0;i<count;i++) {
+ char *fname = talloc_asprintf(torture,
+ BASEDIR_OVF "\\test%d.txt", i);
+ union smb_open io1;
+ ZERO_STRUCT(io1.smb2);
+ io1.generic.level = RAW_OPEN_SMB2;
+ io1.smb2.in.create_flags = 0;
+ io1.smb2.in.desired_access = SEC_FILE_ALL;
+ io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io1.smb2.in.alloc_size = 0;
+ io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io1.smb2.in.security_flags = 0;
+ io1.smb2.in.fname = fname;
+
+ h2 = custom_smb2_create(tree, torture, &(io1.smb2));
+ talloc_free(fname);
+ smb2_util_close(tree, h2);
+ }
+
+ req1 = smb2_notify_send(tree, &(notify.smb2));
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOTIFY_ENUM_DIR);
+ CHECK_VAL(notify.smb2.out.num_changes, 0);
+
+done:
+ smb2_deltree(tree, BASEDIR_OVF);
+ return ret;
+}
+
+/*
+ Test if notifications are returned for changes to the base directory.
+ They shouldn't be.
+*/
+
+#define BASEDIR_BAS BASEDIR "_BAS"
+
+static bool torture_smb2_notify_basedir(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req1;
+
+ smb2_deltree(tree1, BASEDIR_BAS);
+ smb2_util_rmdir(tree1, BASEDIR_BAS);
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
+
+ /* get a handle on the directory */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_BAS;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* create a test file that will also be modified */
+ io.smb2.in.fname = BASEDIR_BAS "\\tname1";
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ status = smb2_create(tree2, torture, &(io.smb2));
+ CHECK_STATUS(status,NT_STATUS_OK);
+ smb2_util_close(tree2, io.smb2.out.file.handle);
+
+ /* ask for a change notify, on attribute changes. */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req1 = smb2_notify_send(tree1, &(notify.smb2));
+
+ /* set attribute on the base dir */
+ smb2_util_setatr(tree2, BASEDIR_BAS, FILE_ATTRIBUTE_HIDDEN);
+
+ /* set attribute on a file to assure we receive a notification */
+ smb2_util_setatr(tree2, BASEDIR_BAS "\\tname1", FILE_ATTRIBUTE_HIDDEN);
+ smb_msleep(200);
+
+ /* check how many responses were given, expect only 1 for the file */
+ status = smb2_notify_recv(req1, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
+
+done:
+ smb2_deltree(tree1, BASEDIR_BAS);
+ return ret;
+}
+
+/*
+ very simple change notify test
+*/
+
+#define BASEDIR_TCON BASEDIR "_TCON"
+
+static bool torture_smb2_notify_tcon(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_request *req = NULL;
+ struct smb2_tree *tree1 = NULL;
+ const char *fname = BASEDIR_TCON "\\subdir-name";
+
+ smb2_deltree(tree, BASEDIR_TCON);
+ smb2_util_rmdir(tree, BASEDIR_TCON);
+
+ torture_comment(torture, "TESTING SIMPLE CHANGE NOTIFY\n");
+
+ /*
+ get a handle on the directory
+ */
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_TCON;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ torture_comment(torture, "Testing notify mkdir\n");
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_cancel(req);
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ notify.smb2.in.recursive = true;
+ req = smb2_notify_send(tree, &(notify.smb2));
+ status = smb2_util_mkdir(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "Testing notify rmdir\n");
+ req = smb2_notify_send(tree, &(notify.smb2));
+ status = smb2_util_rmdir(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "SIMPLE CHANGE NOTIFY OK\n");
+
+ torture_comment(torture, "TESTING WITH SECONDARY TCON\n");
+ if (!torture_smb2_tree_connect(torture, tree->session, tree, &tree1)) {
+ torture_warning(torture, "couldn't reconnect to share, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(torture, "tid1=%d tid2=%d\n",
+ smb2cli_tcon_current_id(tree->smbXcli),
+ smb2cli_tcon_current_id(tree1->smbXcli));
+
+ torture_comment(torture, "Testing notify mkdir\n");
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_util_mkdir(tree1, fname);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "Testing notify rmdir\n");
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_util_rmdir(tree, fname);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "CHANGE NOTIFY WITH TCON OK\n");
+
+ torture_comment(torture, "Disconnecting secondary tree\n");
+ status = smb2_tdis(tree1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ talloc_free(tree1);
+
+ torture_comment(torture, "Testing notify mkdir\n");
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_util_mkdir(tree, fname);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_ADDED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "Testing notify rmdir\n");
+ req = smb2_notify_send(tree, &(notify.smb2));
+ smb2_util_rmdir(tree, fname);
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(notify.smb2.out.num_changes, 1);
+ CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_REMOVED);
+ CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
+
+ torture_comment(torture, "CHANGE NOTIFY WITH TDIS OK\n");
+done:
+ smb2_util_close(tree, h1);
+ smb2_deltree(tree, BASEDIR_TCON);
+
+ return ret;
+}
+
+#define BASEDIR_RMD BASEDIR "_RMD"
+
+static bool torture_smb2_notify_rmdir(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2,
+ bool initial_delete_on_close)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify = {};
+ union smb_setfileinfo sfinfo = {};
+ union smb_open io = {};
+ struct smb2_handle h = {};
+ struct smb2_request *req;
+
+ torture_comment(torture, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
+
+ smb2_deltree(tree1, BASEDIR_RMD);
+ smb2_util_rmdir(tree1, BASEDIR_RMD);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE ;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_RMD;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h;
+ notify.smb2.in.recursive = false;
+
+ io.smb2.in.desired_access |= SEC_STD_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ req = smb2_notify_send(tree1, &(notify.smb2));
+
+ if (initial_delete_on_close) {
+ status = smb2_util_rmdir(tree2, BASEDIR_RMD);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ } else {
+ status = smb2_create(tree2, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = io.smb2.out.file.handle;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb2_setinfo_file(tree2, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree2, io.smb2.out.file.handle);
+ }
+
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
+
+done:
+
+ smb2_util_close(tree1, h);
+ smb2_deltree(tree1, BASEDIR_RMD);
+
+ return ret;
+}
+
+static bool torture_smb2_notify_rmdir1(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ return torture_smb2_notify_rmdir(torture, tree, tree, false);
+}
+
+static bool torture_smb2_notify_rmdir2(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ return torture_smb2_notify_rmdir(torture, tree, tree, true);
+}
+
+static bool torture_smb2_notify_rmdir3(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return torture_smb2_notify_rmdir(torture, tree1, tree2, false);
+}
+
+static bool torture_smb2_notify_rmdir4(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return torture_smb2_notify_rmdir(torture, tree1, tree2, true);
+}
+
+static void notify_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct smb2_request *req = talloc_get_type_abort(
+ private_data, struct smb2_request);
+
+ smb2_cancel(req);
+}
+
+#define BASEDIR_INR BASEDIR "_INR"
+
+static bool torture_smb2_inotify_rename(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ struct smb2_notify notify;
+ struct notify_changes change1 = {0};
+ struct notify_changes change2 = {0};
+ struct smb2_create create;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_request *req;
+ struct tevent_timer *te = NULL;
+ bool ok = false;
+
+ smb2_deltree(tree1, BASEDIR_INR);
+
+ torture_comment(torture, "Testing change notify of a rename with inotify\n");
+
+ status = torture_smb2_testdir(tree1, BASEDIR_INR, &h1);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "torture_smb2_testdir failed");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_ALL;
+ create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = BASEDIR_INR "\\subdir-name";
+
+ status = smb2_create(tree2, torture, &create);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_create failed\n");
+ h2 = create.out.file.handle;
+
+ ZERO_STRUCT(notify);
+ notify.level = RAW_NOTIFY_SMB2;
+ notify.in.buffer_size = 4096;
+ notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.in.file.handle = h1;
+ notify.in.recursive = true;
+ req = smb2_notify_send(tree1, &notify);
+ torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
+
+ while (!NT_STATUS_EQUAL(req->status, NT_STATUS_PENDING)) {
+ if (tevent_loop_once(torture->ev) != 0) {
+ goto done;
+ }
+ }
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h2;
+ sinfo.rename_information.in.new_name = BASEDIR_INR "\\subdir-name-r";
+
+ status = smb2_setinfo_file(tree2, &sinfo);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_setinfo_file failed\n");
+
+ smb2_util_close(tree2, h2);
+
+ te = tevent_add_timer(torture->ev,
+ tree1,
+ tevent_timeval_current_ofs(1, 0),
+ notify_timeout,
+ req);
+ torture_assert_not_null_goto(torture, te, ok, done, "tevent_add_timer failed\n");
+
+ status = smb2_notify_recv(req, torture, &notify);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
+
+ torture_assert_goto(torture, notify.out.num_changes == 1 || notify.out.num_changes == 2,
+ ok, done, "bad notify\n");
+
+ change1 = notify.out.changes[0];
+ if (notify.out.num_changes == 2) {
+ change2 = notify.out.changes[1];
+ } else {
+ /*
+ * We may only get one event at a time, so check for the
+ * matching second event for the oldname/newname or
+ * removed/added pair.
+ */
+ ZERO_STRUCT(notify);
+ notify.level = RAW_NOTIFY_SMB2;
+ notify.in.buffer_size = 4096;
+ notify.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.in.file.handle = h1;
+ notify.in.recursive = true;
+ req = smb2_notify_send(tree1, &notify);
+ torture_assert_not_null_goto(torture, req, ok, done, "smb2_notify_send failed\n");
+
+ status = smb2_notify_recv(req, torture, &notify);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "smb2_notify_recv failed\n");
+
+ torture_assert_goto(torture, notify.out.num_changes == 1, ok, done,
+ "bad notify\n");
+
+ change2 = notify.out.changes[0];
+ }
+
+ if ((change1.action != NOTIFY_ACTION_OLD_NAME) &&
+ (change1.action != NOTIFY_ACTION_REMOVED))
+ {
+ torture_fail_goto(torture, done, "bad change notification\n");
+ }
+ torture_assert_str_equal_goto(torture, change1.name.s, "subdir-name",
+ ok, done, "bad change notification\n");
+
+ if ((change2.action != NOTIFY_ACTION_NEW_NAME) &&
+ (change2.action != NOTIFY_ACTION_ADDED))
+ {
+ torture_fail_goto(torture, done, "bad change notification\n");
+ }
+ torture_assert_str_equal_goto(torture, change2.name.s, "subdir-name-r",
+ ok, done, "bad change notification\n");
+
+ ok = true;
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree1, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree2, h2);
+ }
+
+ smb2_deltree(tree1, BASEDIR_INR);
+ return ok;
+}
+
+/*
+ Test asking for a change notify on a handle without permissions.
+*/
+
+#define BASEDIR_HPERM BASEDIR "_HPERM"
+
+static bool torture_smb2_notify_handle_permissions(
+ struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_request *req;
+
+ smb2_deltree(tree, BASEDIR_HPERM);
+ smb2_util_rmdir(tree, BASEDIR_HPERM);
+
+ torture_comment(torture,
+ "TESTING CHANGE NOTIFY "
+ "ON A HANDLE WITHOUT PERMISSIONS\n");
+
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR_HPERM;
+
+ status = smb2_create(tree, torture, &io.smb2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree, &notify.smb2);
+ torture_assert_goto(torture,
+ req != NULL,
+ ret,
+ done,
+ "smb2_notify_send failed\n");
+
+ /*
+ * Cancel it, we don't really want to wait.
+ */
+ smb2_cancel(req);
+ status = smb2_notify_recv(req, torture, &notify.smb2);
+ /* Handle h1 doesn't have permissions for ChangeNotify. */
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_deltree(tree, BASEDIR_HPERM);
+ return ret;
+}
+
+/*
+ basic testing of SMB2 change notify
+*/
+struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "notify");
+
+ torture_suite_add_1smb2_test(suite, "valid-req", test_valid_request);
+ torture_suite_add_1smb2_test(suite, "tcon", torture_smb2_notify_tcon);
+ torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir);
+ torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask);
+ torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect);
+ torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1);
+ torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change);
+ torture_suite_add_1smb2_test(suite, "close", torture_smb2_notify_close);
+ torture_suite_add_1smb2_test(suite, "logoff", torture_smb2_notify_ulogoff);
+ torture_suite_add_1smb2_test(suite, "session-reconnect", torture_smb2_notify_session_reconnect);
+ torture_suite_add_2smb2_test(suite, "invalid-reauth", torture_smb2_notify_invalid_reauth);
+ torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree);
+ torture_suite_add_2smb2_test(suite, "basedir", torture_smb2_notify_basedir);
+ torture_suite_add_2smb2_test(suite, "double", torture_smb2_notify_double);
+ torture_suite_add_1smb2_test(suite, "file", torture_smb2_notify_file);
+ torture_suite_add_1smb2_test(suite, "tcp", torture_smb2_notify_tcp_disconnect);
+ torture_suite_add_2smb2_test(suite, "rec", torture_smb2_notify_recursive);
+ torture_suite_add_1smb2_test(suite, "overflow", torture_smb2_notify_overflow);
+ torture_suite_add_1smb2_test(suite, "rmdir1",
+ torture_smb2_notify_rmdir1);
+ torture_suite_add_1smb2_test(suite, "rmdir2",
+ torture_smb2_notify_rmdir2);
+ torture_suite_add_2smb2_test(suite, "rmdir3",
+ torture_smb2_notify_rmdir3);
+ torture_suite_add_2smb2_test(suite, "rmdir4",
+ torture_smb2_notify_rmdir4);
+ torture_suite_add_1smb2_test(suite,
+ "handle-permissions",
+ torture_smb2_notify_handle_permissions);
+
+ suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");
+
+ return suite;
+}
+
+/*
+ basic testing of SMB2 change notify
+*/
+struct torture_suite *torture_smb2_notify_inotify_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "notify-inotify");
+
+ suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests that use inotify");
+
+ torture_suite_add_2smb2_test(suite, "inotify-rename", torture_smb2_inotify_rename);
+
+ return suite;
+}
diff --git a/source4/torture/smb2/notify_disabled.c b/source4/torture/smb2/notify_disabled.c
new file mode 100644
index 0000000..f38941c
--- /dev/null
+++ b/source4/torture/smb2/notify_disabled.c
@@ -0,0 +1,120 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 notify test suite
+
+ Copyright (C) Stefan Metzmacher 2006
+ Copyright (C) Andrew Tridgell 2009
+ Copyright (C) Ralph Boehme 2015
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "torture/util.h"
+
+#include "system/filesys.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/cmdline.h"
+#include "librpc/gen_ndr/security.h"
+
+#include "lib/events/events.h"
+
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+
+#define BASEDIR "test_notify_disabled"
+
+/*
+ basic testing of change notify on directories
+*/
+static bool torture_smb2_notify_disabled(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_notify notify;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_request *req;
+
+ torture_comment(torture, "TESTING CHANGE NOTIFY DISABLED\n");
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+ /*
+ get a handle on the directory
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OK,
+ ret, done, "smb2_create");
+ h1 = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(notify.smb2);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = h1;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ status = smb2_notify_recv(req, torture, &(notify.smb2));
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_NOT_IMPLEMENTED,
+ ret, done, "smb2_notify_recv");
+
+ status = smb2_util_close(tree1, h1);
+ torture_assert_ntstatus_equal_goto(torture, status, NT_STATUS_OK,
+ ret, done, "smb2_create");
+
+done:
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of SMB2 change notify
+*/
+struct torture_suite *torture_smb2_notify_disabled_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx,
+ "change_notify_disabled");
+
+ torture_suite_add_1smb2_test(suite, "notfiy_disabled", torture_smb2_notify_disabled);
+ suite->description = talloc_strdup(suite, "SMB2-CHANGE-NOTIFY-DISABLED tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c
new file mode 100644
index 0000000..90bf4d2
--- /dev/null
+++ b/source4/torture/smb2/oplock.c
@@ -0,0 +1,5405 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 oplocks
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan Metzmacher 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/smb/smbXcli_base.h"
+
+#include "lib/cmdline/cmdline.h"
+#include "lib/events/events.h"
+
+#include "param/param.h"
+#include "system/filesys.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/smb2/block.h"
+
+#include "lib/util/sys_rw.h"
+#include "libcli/security/security.h"
+
+#define CHECK_RANGE(v, min, max) do { \
+ if ((v) < (min) || (v) > (max)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
+ "got %d - should be between %d and %d\n", \
+ __location__, #v, (int)v, (int)min, (int)max); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STRMATCH(v, correct) do { \
+ if (!v || strstr((v),(correct)) == NULL) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s "\
+ "got '%s' - should be '%s'\n", \
+ __location__, #v, v?v:"NULL", correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
+ "got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define BASEDIR "oplock_test"
+
+static struct {
+ struct smb2_handle handle;
+ uint8_t level;
+ struct smb2_break br;
+ int count;
+ int failures;
+ NTSTATUS failure_status;
+} break_info;
+
+static void torture_oplock_break_callback(struct smb2_request *req)
+{
+ NTSTATUS status;
+ struct smb2_break br;
+
+ ZERO_STRUCT(br);
+ status = smb2_break_recv(req, &break_info.br);
+ if (!NT_STATUS_IS_OK(status)) {
+ break_info.failures++;
+ break_info.failure_status = status;
+ }
+
+ return;
+}
+
+/* A general oplock break notification handler. This should be used when a
+ * test expects to break from batch or exclusive to a lower level. */
+static bool torture_oplock_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ const char *name;
+ struct smb2_request *req;
+ ZERO_STRUCT(break_info.br);
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ switch (level) {
+ case SMB2_OPLOCK_LEVEL_II:
+ name = "level II";
+ break;
+ case SMB2_OPLOCK_LEVEL_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break_info.failures++;
+ }
+ printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
+
+ break_info.br.in.file.handle = *handle;
+ break_info.br.in.oplock_level = level;
+ break_info.br.in.reserved = 0;
+ break_info.br.in.reserved2 = 0;
+
+ req = smb2_break_send(tree, &break_info.br);
+ req->async.fn = torture_oplock_break_callback;
+ req->async.private_data = NULL;
+ return true;
+}
+
+/*
+ A handler function for oplock break notifications. Send a break to none
+ request.
+*/
+static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ struct smb2_request *req;
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ printf("Acking to none in oplock handler\n");
+
+ ZERO_STRUCT(break_info.br);
+ break_info.br.in.file.handle = *handle;
+ break_info.br.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+ break_info.br.in.reserved = 0;
+ break_info.br.in.reserved2 = 0;
+
+ req = smb2_break_send(tree, &break_info.br);
+ req->async.fn = torture_oplock_break_callback;
+ req->async.private_data = NULL;
+
+ return true;
+}
+
+/*
+ A handler function for oplock break notifications. Break from level II to
+ none. SMB2 requires that the client does not send an oplock break request to
+ the server in this case.
+*/
+static bool torture_oplock_handler_level2_to_none(
+ struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ printf("Break from level II to none in oplock handler\n");
+
+ return true;
+}
+
+/* A handler function for oplock break notifications. This should be used when
+ * test expects two break notifications, first to level II, then to none. */
+static bool torture_oplock_handler_two_notifications(
+ struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ const char *name;
+ struct smb2_request *req;
+ ZERO_STRUCT(break_info.br);
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ switch (level) {
+ case SMB2_OPLOCK_LEVEL_II:
+ name = "level II";
+ break;
+ case SMB2_OPLOCK_LEVEL_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break_info.failures++;
+ }
+ printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
+
+ if (level == SMB2_OPLOCK_LEVEL_NONE)
+ return true;
+
+ break_info.br.in.file.handle = *handle;
+ break_info.br.in.oplock_level = level;
+ break_info.br.in.reserved = 0;
+ break_info.br.in.reserved2 = 0;
+
+ req = smb2_break_send(tree, &break_info.br);
+ req->async.fn = torture_oplock_break_callback;
+ req->async.private_data = NULL;
+ return true;
+}
+static void torture_oplock_handler_close_recv(struct smb2_request *req)
+{
+ if (!smb2_request_receive(req)) {
+ printf("close failed in oplock_handler_close\n");
+ break_info.failures++;
+ }
+}
+
+/*
+ a handler function for oplock break requests - close the file
+*/
+static bool torture_oplock_handler_close(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_close io;
+ struct smb2_tree *tree = private_data;
+ struct smb2_request *req;
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ ZERO_STRUCT(io);
+ io.in.file.handle = *handle;
+ io.in.flags = RAW_CLOSE_SMB2;
+ req = smb2_close_send(tree, &io);
+ if (req == NULL) {
+ printf("failed to send close in oplock_handler_close\n");
+ return false;
+ }
+
+ req->async.fn = torture_oplock_handler_close_recv;
+ req->async.private_data = NULL;
+
+ return true;
+}
+
+/*
+ a handler function for oplock break requests. Let it timeout
+*/
+static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ printf("Let oplock break timeout\n");
+ return true;
+}
+
+static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
+ struct smb2_tree **tree)
+{
+ NTSTATUS status;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct smbcli_options options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ options.use_level2_oplocks = false;
+
+ status = smb2_connect(tctx, host,
+ lpcfg_smb_ports(tctx->lp_ctx), share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ tree, tctx->ev, &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to connect to SMB2 share "
+ "\\\\%s\\%s - %s\n", host, share,
+ nt_errstr(status));
+ return false;
+ }
+ return true;
+}
+
+static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_exclusive1.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h1;
+ struct smb2_handle h;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
+ "oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ torture_comment(tctx, "a 2nd open should not cause a break\n");
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "unlink it - should also be no break\n");
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_exclusive2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
+ "oplock (share mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h2 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ ZERO_STRUCT(break_info);
+
+ /* now we have 2 level II oplocks... */
+ torture_comment(tctx, "try to unlink it - should cause a break\n");
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "close both handles\n");
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_exclusive3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
+ "oplock (share mode: none)\n");
+
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ torture_comment(tctx, "setpathinfo EOF should trigger a break to "
+ "none\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 100;
+
+ status = smb2_composite_setpathinfo(tree2, &sfi);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_exclusive4.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "second open with attributes only shouldn't "
+ "cause oplock break\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_exclusive5.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and "
+ "NTCREATEX_DISP_OVERWRITE_IF disposition causes "
+ "oplock break\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
+ const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sinfo;
+ struct smb2_close closeio;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree2, fname2);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname1;
+
+ torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
+ "oplock (share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ torture_comment(tctx, "rename with the parent directory handle open "
+ "for DELETE should not generate a break but get "
+ "a sharing violation\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.new_name = fname2;
+ status = smb2_setinfo_file(tree1, &sinfo);
+
+ torture_comment(tctx, "trying rename while parent handle open for delete.\n");
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Close the parent directory handle. */
+ ZERO_STRUCT(closeio);
+ closeio.in.file.handle = h;
+ status = smb2_close(tree1, &closeio);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+ "Incorrect status");
+
+ /* Re-open without DELETE access. */
+ ZERO_STRUCT(io);
+ io.smb2.in.oplock_level = 0;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL & (~SEC_STD_DELETE);
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the base directory");
+
+ torture_comment(tctx, "rename with the parent directory handle open "
+ "without DELETE should succeed without a break\n");
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.new_name = fname2;
+ status = smb2_setinfo_file(tree1, &sinfo);
+
+ torture_comment(tctx, "trying rename while parent handle open without delete\n");
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+ "Incorrect status");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_exclusive9(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_exclusive9.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h1, h2;
+ int i;
+
+ struct {
+ uint32_t create_disposition;
+ uint32_t break_level;
+ } levels[] = {
+ { NTCREATEX_DISP_SUPERSEDE, SMB2_OPLOCK_LEVEL_NONE },
+ { NTCREATEX_DISP_OPEN, SMB2_OPLOCK_LEVEL_II },
+ { NTCREATEX_DISP_OVERWRITE_IF, SMB2_OPLOCK_LEVEL_NONE },
+ { NTCREATEX_DISP_OPEN_IF, SMB2_OPLOCK_LEVEL_II },
+ };
+
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h1);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+ smb2_util_close(tree1, h1);
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ for (i=0; i<ARRAY_SIZE(levels); i++) {
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status,
+ "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level,
+ SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_disposition = levels[i].create_disposition;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status,
+ "Error opening the file");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, levels[i].break_level);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h1);
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch1(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch1.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+ char c = 0;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH1: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "unlink should generate a break\n");
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "2nd unlink should not generate a break\n");
+ ZERO_STRUCT(break_info);
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ torture_comment(tctx, "writing should generate a self break to none\n");
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ smb2_util_write(tree1, h1, &c, 0, 1);
+
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch2(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ char c = 0;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH2: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "unlink should generate a break, which we ack "
+ "as break to none\n");
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_ack_to_none;
+ tree1->session->transport->oplock.private_data = tree1;
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ torture_comment(tctx, "2nd unlink should not generate a break\n");
+ ZERO_STRUCT(break_info);
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ torture_comment(tctx, "writing should not generate a break\n");
+ smb2_util_write(tree1, h1, &c, 0, 1);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch3(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH3: if we close on break then the unlink "
+ "can succeed\n");
+ ZERO_STRUCT(break_info);
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_close;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch4(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch4.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_read r;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
+ ZERO_STRUCT(break_info);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = h1;
+ r.in.offset = 0;
+
+ status = smb2_read(tree1, tree1, &r);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch5(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch5.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch6(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch6.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+ char c = 0;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
+ "level II if the first open allowed shared read\n");
+ ZERO_STRUCT(break_info);
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none on both\n");
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ tree2->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ smb2_util_write(tree1, h1, &c, 0, 1);
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch7(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch7.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
+ "we close instead of ack\n");
+ ZERO_STRUCT(break_info);
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_close;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h2.data[0]);
+ CHECK_VAL(break_info.level, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree2, h1);
+ smb2_util_close(tree2, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch8(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch8.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH8: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "second open with attributes only shouldn't "
+ "cause oplock break\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch9(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch9.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+ char c = 0;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH9: open with attributes only can create "
+ "file\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "Subsequent normal open should break oplock on "
+ "attribute only open to level II\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ smb2_util_close(tree2, h2);
+
+ torture_comment(tctx, "third oplocked open should grant level2 without "
+ "break\n");
+ ZERO_STRUCT(break_info);
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none on both\n");
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ tree2->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ smb2_util_write(tree2, h2, &c, 0, 1);
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch9a(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch9a.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2, h3;
+ char c = 0;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH9: open with attributes only can create "
+ "file\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error creating the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.create_action, FILE_WAS_CREATED);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "Subsequent attributes open should not break\n");
+
+ ZERO_STRUCT(break_info);
+
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h3 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(io.smb2.out.create_action, FILE_WAS_OPENED);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+ smb2_util_close(tree2, h3);
+
+ torture_comment(tctx, "Subsequent normal open should break oplock on "
+ "attribute only open to level II\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ smb2_util_close(tree2, h2);
+
+ torture_comment(tctx, "third oplocked open should grant level2 without "
+ "break\n");
+ ZERO_STRUCT(break_info);
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none on both\n");
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ tree2->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ smb2_util_write(tree2, h2, &c, 0, 1);
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+
+static bool test_smb2_oplock_batch10(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch10.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
+ "open should grant level2\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, 0);
+
+ tree2->session->transport->oplock.handler =
+ torture_oplock_handler_level2_to_none;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_comment(tctx, "write should trigger a break to none\n");
+ {
+ struct smb2_write wr;
+ DATA_BLOB data;
+ data = data_blob_talloc_zero(tree1, UINT16_MAX);
+ data.data[0] = (const uint8_t)'x';
+ ZERO_STRUCT(wr);
+ wr.in.file.handle = h1;
+ wr.in.offset = 0;
+ wr.in.data = data;
+ status = smb2_write(tree1, &wr);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ }
+
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h2.data[0]);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch11(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch11.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_two_notifications;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /* Test if a set-eof on pathname breaks an exclusive oplock. */
+ torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
+ "oplocks.\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h1 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.end_of_file_info.in.size = 100;
+
+ status = smb2_composite_setpathinfo(tree2, &sfi);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch12(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch12.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_setfileinfo sfi;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_two_notifications;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /* Test if a set-allocation size on pathname breaks an exclusive
+ * oplock. */
+ torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
+ "breaks oplocks.\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h1 = io.smb2.out.file.handle;
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
+ sfi.generic.in.file.path = fname;
+ sfi.allocation_info.in.alloc_size = 65536 * 8;
+
+ status = smb2_composite_setpathinfo(tree2, &sfi);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ /* We expect two breaks */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ CHECK_VAL(break_info.count, 2);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch13(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch13.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH13: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and "
+ "NTCREATEX_DISP_OVERWRITE disposition causes "
+ "oplock break\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+
+ return ret;
+}
+
+static bool test_smb2_oplock_batch14(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch14.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH14: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and "
+ "NTCREATEX_DISP_SUPERSEDE disposition causes "
+ "oplock break\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch15(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch15.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
+ torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
+ "a batch oplock (should not).\n");
+
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ qfi.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree2, tctx, &qfi);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch16(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch16.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH16: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "second open with attributes only and "
+ "NTCREATEX_DISP_OVERWRITE_IF disposition causes "
+ "oplock break\n");
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_STD_SYNCHRONIZE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
+ * SMB2 doesn't have a RENAME command this test isn't applicable. However,
+ * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
+ * test numbers in sync. */
+#if 0
+static bool test_raw_oplock_batch17(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return true;
+}
+#endif
+
+/* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
+ * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
+ * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
+ * test numbers in sync. */
+#if 0
+static bool test_raw_oplock_batch18(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return true;
+}
+#endif
+
+static bool test_smb2_oplock_batch19(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *fname1 = BASEDIR "\\test_batch19_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch19_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname1;
+
+ torture_comment(tctx, "BATCH19: open a file with an batch oplock "
+ "(share mode: none)\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "setfileinfo rename info should not trigger "
+ "a break but should cause a sharing violation\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.generic.in.file.path = fname1;
+ sfi.rename_information.in.file.handle = h1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.root_fid = 0;
+ sfi.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree1, &sfi);
+
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ qfi.generic.in.file.handle = h1;
+
+ status = smb2_getinfo_file(tree1, tctx, &qfi);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, fname1);
+ smb2_deltree(tree1, fname2);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch20(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname1 = BASEDIR "\\test_batch20_1.dat";
+ const char *fname2 = BASEDIR "\\test_batch20_2.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ union smb_fileinfo qfi;
+ union smb_setfileinfo sfi;
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname1;
+
+ torture_comment(tctx, "BATCH20: open a file with an batch oplock "
+ "(share mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "setfileinfo rename info should not trigger "
+ "a break but should cause a sharing violation\n");
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.rename_information.in.file.handle = h1;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree1, &sfi);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ qfi.generic.in.file.handle = h1;
+
+ status = smb2_getinfo_file(tree1, tctx, &qfi);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
+
+ torture_comment(tctx, "open the file a second time requesting batch "
+ "(share mode: all)\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.fname = fname1;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_comment(tctx, "setfileinfo rename info should not trigger "
+ "a break but should cause a sharing violation\n");
+ ZERO_STRUCT(break_info);
+ ZERO_STRUCT(sfi);
+ sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfi.rename_information.in.file.handle = h2;
+ sfi.rename_information.in.overwrite = 0;
+ sfi.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree2, &sfi);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ qfi.generic.in.file.handle = h1;
+
+ status = smb2_getinfo_file(tree1, tctx, &qfi);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
+
+ ZERO_STRUCT(qfi);
+ qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ qfi.generic.in.file.handle = h2;
+
+ status = smb2_getinfo_file(tree2, tctx, &qfi);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, fname1);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch21(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *fname = BASEDIR "\\test_batch21.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+ char c = 0;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH21: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "writing should not generate a break\n");
+ status = smb2_util_write(tree1, h1, &c, 0, 1);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch22a(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *fname = BASEDIR "\\test_batch22a.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+ struct timeval tv;
+ int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
+ int te;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH22: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "a 2nd open should succeed after the oplock "
+ "break timeout\n");
+ tv = timeval_current();
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_timeout;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ te = (int)timeval_elapsed(&tv);
+ CHECK_RANGE(te, timeout - 1, timeout + 15);
+ torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h2);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch22b(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch22b.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2 = {{0}};
+ struct timeval tv;
+ int timeout = torture_setting_int(tctx, "oplocktimeout", 35);
+ struct smb2_transport *transport1 = tree1->session->transport;
+ bool block_setup = false;
+ bool block_ok = false;
+ int te;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "BATCH22: open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "a 2nd open should succeed after the oplock "
+ "break timeout\n");
+ tv = timeval_current();
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_timeout;
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+ block_ok = test_block_smb2_transport(tctx, transport1);
+ torture_assert(tctx, block_ok, "test_block_smb2_transport");
+
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_wait_for_oplock_break(tctx);
+ te = (int)timeval_elapsed(&tv);
+ CHECK_RANGE(te, 0, timeout);
+ torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+done:
+ if (block_ok) {
+ test_unblock_smb2_transport(tctx, transport1);
+ }
+ test_cleanup_blocked_transports(tctx);
+
+ smb2_util_close(tree1, h1);
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree1, h2);
+ }
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch23(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch23.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2, h3;
+ struct smb2_tree *tree3 = NULL;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
+ CHECK_VAL(ret, true);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ tree3->session->transport->oplock.handler = torture_oplock_handler;
+ tree3->session->transport->oplock.private_data = tree3;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 2nd open without level2 oplock support "
+ "should generate a break to level2\n");
+ status = smb2_create(tree3, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h3 = io.smb2.out.file.handle;
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 3rd open with level2 oplock support should "
+ "not generate a break\n");
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree3, h3);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch24(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch24.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2;
+ struct smb2_tree *tree3 = NULL;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
+ CHECK_VAL(ret, true);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ tree3->session->transport->oplock.handler = torture_oplock_handler;
+ tree3->session->transport->oplock.private_data = tree3;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH24: a open without level support and "
+ "ask for a batch oplock\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree3, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a 2nd open with level2 oplock support should "
+ "generate a break\n");
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.handle.data[0], h2.data[0]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree3, h2);
+ smb2_util_close(tree2, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch25(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *fname = BASEDIR "\\test_batch25.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "BATCH25: open a file with an batch oplock "
+ "(share mode: none)\n");
+
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
+ torture_assert_ntstatus_ok(tctx, status, "Setting attributes "
+ "shouldn't trigger an oplock break");
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, fname);
+ return ret;
+}
+
+static bool test_smb2_oplock_batch26(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1, h2, h3;
+ const char *fname_base = BASEDIR "\\test_oplock.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = 0x120089;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname_base;
+
+ /*
+ Open base file with a batch oplock.
+ */
+ torture_comment(tctx, "Open the base file with batch oplock\n");
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening base file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "Got batch oplock on base file\n");
+
+ torture_comment(tctx, "Opening stream file with batch oplock..\n");
+
+ io.smb2.in.fname = fname_stream;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening stream file");
+ h2 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "Got batch oplock on stream file\n");
+
+ torture_comment(tctx, "Open base file again with batch oplock\n");
+
+ io.smb2.in.fname = fname_base;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h3 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h2);
+ smb2_util_close(tree1, h3);
+ smb2_util_close(tree1, h);
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+
+}
+
+/* Test how oplocks work on streams. */
+static bool test_raw_oplock_stream1(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname_base = BASEDIR "\\test_stream1.txt";
+ const char *fname_stream, *fname_default_stream;
+ const char *default_stream = "::$DATA";
+ const char *stream = "Stream One:$DATA";
+ bool ret = true;
+ struct smb2_handle h, h_base, h_stream;
+ int i;
+
+#define NSTREAM_OPLOCK_RESULTS 8
+ struct {
+ const char **fname;
+ bool open_base_file;
+ uint32_t oplock_req;
+ uint32_t oplock_granted;
+ } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
+ /* Request oplock on stream without the base file open. */
+ {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
+ {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
+ {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
+ {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
+
+ /* Request oplock on stream with the base file open. */
+ {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
+ {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
+ {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
+ {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
+ };
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
+ fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
+ default_stream);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* Initialize handles to "closed". Using -1 in the first 64-bytes
+ * as the sentry for this */
+ h_stream.data[0] = -1;
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname_base);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ tree2->session->transport->oplock.handler = torture_oplock_handler;
+ tree2->session->transport->oplock.private_data = tree2;
+
+ /* Setup generic open parameters. */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_STD_READ_CONTROL);
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+
+ /* Create the file with a stream */
+ io.smb2.in.fname = fname_stream;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error creating file");
+ smb2_util_close(tree1, io.smb2.out.file.handle);
+
+ /* Change the disposition to open now that the file has been created. */
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ /* Try some permutations of taking oplocks on streams. */
+ for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
+ const char *fname = *stream_oplock_results[i].fname;
+ bool open_base_file = stream_oplock_results[i].open_base_file;
+ uint32_t oplock_req = stream_oplock_results[i].oplock_req;
+ uint32_t oplock_granted =
+ stream_oplock_results[i].oplock_granted;
+
+ if (open_base_file) {
+ torture_comment(tctx, "Opening base file: %s with "
+ "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
+ io.smb2.in.fname = fname_base;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status,
+ "Error opening file");
+ CHECK_VAL(io.smb2.out.oplock_level,
+ SMB2_OPLOCK_LEVEL_BATCH);
+ h_base = io.smb2.out.file.handle;
+ }
+
+ torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
+ fname, oplock_req);
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = oplock_req;
+
+ /* Do the open with the desired oplock on the stream. */
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening file");
+ CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
+ smb2_util_close(tree1, io.smb2.out.file.handle);
+
+ /* Cleanup the base file if it was opened. */
+ if (open_base_file)
+ smb2_util_close(tree2, h_base);
+ }
+
+ /* Open the stream with an exclusive oplock. */
+ torture_comment(tctx, "Opening stream: %s with %d\n",
+ fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+ io.smb2.in.fname = fname_stream;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening file");
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+ h_stream = io.smb2.out.file.handle;
+
+ /* Open the base file and see if it contends. */
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "Opening base file: %s with %d\n",
+ fname_base, SMB2_OPLOCK_LEVEL_BATCH);
+ io.smb2.in.fname = fname_base;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening file");
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ smb2_util_close(tree2, io.smb2.out.file.handle);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Open the stream again to see if it contends. */
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "Opening stream again: %s with "
+ "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
+ io.smb2.in.fname = fname_stream;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening file");
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+ smb2_util_close(tree2, io.smb2.out.file.handle);
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Close the stream. */
+ if (h_stream.data[0] != -1) {
+ smb2_util_close(tree1, h_stream);
+ }
+
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_oplock_doc.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+ union smb_setfileinfo sfinfo;
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+ smb2_util_close(tree, h);
+
+ /* cleanup */
+ smb2_util_unlink(tree, fname);
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "open a file with a batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ torture_comment(tctx, "Set delete on close\n");
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ torture_comment(tctx, "2nd open should not break and get "
+ "DELETE_PENDING\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree2, tctx, &io.smb2);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_DELETE_PENDING,
+ "Incorrect status");
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree, h1);
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/* Open a file with a batch oplock, then open it again from a second client
+ * requesting no oplock. Having two open file handles should break our own
+ * oplock during BRL acquisition.
+ */
+static bool test_smb2_oplock_brl1(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ /*int fname, f;*/
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ struct smb2_lock lck;
+ struct smb2_lock_element lock[1];
+ struct smb2_handle h, h1, h2;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_two_notifications;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "open with batch oplock\n");
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+
+ status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Failed to create file\n");
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(tctx, "a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = 0;
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ h2 = io.smb2.out.file.handle;
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a self BRL acquisition should break to none\n");
+
+ ZERO_STRUCT(lock);
+
+ lock[0].offset = 0;
+ lock[0].length = 4;
+ lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ ZERO_STRUCT(lck);
+ lck.in.file.handle = h1;
+ lck.in.locks = &lock[0];
+ lck.in.lock_count = 1;
+ status = smb2_lock(tree1, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* expect no oplock break */
+ ZERO_STRUCT(break_info);
+ lock[0].offset = 2;
+ status = smb2_lock(tree1, &lck);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree2, h2);
+ smb2_util_close(tree1, h);
+
+done:
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+
+}
+
+/* Open a file with a batch oplock on one tree and then acquire a brl.
+ * We should not contend our own oplock.
+ */
+static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ /*int fname, f;*/
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ struct smb2_handle h, h1;
+ struct smb2_lock lck;
+ struct smb2_lock_element lock[1];
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "open with batch oplock\n");
+ ZERO_STRUCT(break_info);
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+
+ status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Failed to create file\n");
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a self BRL acquisition should not break to "
+ "none\n");
+
+ ZERO_STRUCT(lock);
+
+ lock[0].offset = 0;
+ lock[0].length = 4;
+ lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ ZERO_STRUCT(lck);
+ lck.in.file.handle = h1;
+ lck.in.locks = &lock[0];
+ lck.in.lock_count = 1;
+ status = smb2_lock(tree1, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ lock[0].offset = 2;
+ status = smb2_lock(tree1, &lck);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
+ "Incorrect status");
+
+ /* With one file handle open a BRL should not contend our oplock.
+ * Thus, no oplock break will be received and the entire break_info
+ * struct will be 0 */
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+done:
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/* Open a file with a batch oplock twice from one tree and then acquire a
+ * brl. BRL acquisition should break our own oplock.
+ */
+static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ const char *fname = BASEDIR "\\test_batch_brl.dat";
+ bool ret = true;
+ uint8_t buf[1000];
+ union smb_open io;
+ NTSTATUS status;
+ struct smb2_handle h, h1, h2;
+ struct smb2_lock lck;
+ struct smb2_lock_element lock[1];
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+ tree1->session->transport->oplock.handler =
+ torture_oplock_handler_two_notifications;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ with a batch oplock we get a break
+ */
+ torture_comment(tctx, "open with batch oplock\n");
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* create a file with bogus data */
+ memset(buf, 0, sizeof(buf));
+ status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Failed to create file\n");
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(tctx, "a 2nd open should give a break\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = 0;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ h2 = io.smb2.out.file.handle;
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "a self BRL acquisition should break to none\n");
+
+ ZERO_STRUCT(lock);
+
+ lock[0].offset = 0;
+ lock[0].length = 4;
+ lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ ZERO_STRUCT(lck);
+ lck.in.file.handle = h1;
+ lck.in.locks = &lock[0];
+ lck.in.lock_count = 1;
+ status = smb2_lock(tree1, &lck);
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
+ CHECK_VAL(break_info.handle.data[0], h1.data[0]);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* expect no oplock break */
+ ZERO_STRUCT(break_info);
+ lock[0].offset = 2;
+ status = smb2_lock(tree1, &lck);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
+ "Incorrect status");
+
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h2);
+ smb2_util_close(tree1, h);
+
+done:
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+
+}
+
+/* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
+ * tests in sync with an identically numbered SMB2 test */
+
+/* Test whether the server correctly returns an error when we send
+ * a response to a levelII to none oplock notification. */
+static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ const char *fname = BASEDIR "\\test_levelII500.dat";
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+ struct smb2_handle h, h1;
+ char c = 0;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ tree1->session->transport->oplock.handler = torture_oplock_handler;
+ tree1->session->transport->oplock.private_data = tree1;
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
+ "none should return an error\n");
+ ZERO_STRUCT(break_info);
+
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ h1 = io.smb2.out.file.handle;
+ CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
+
+ ZERO_STRUCT(break_info);
+
+ torture_comment(tctx, "write should trigger a break to none and when "
+ "we reply, an oplock break failure\n");
+ smb2_util_write(tree1, h1, &c, 0, 1);
+
+ /* Wait several times to receive both the break notification, and the
+ * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+
+ /* There appears to be a race condition in W2K8 and W2K8R2 where
+ * sometimes the server will happily reply to our break response with
+ * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
+ * error. As the MS-SMB2 doc states that a client should not reply to
+ * a level2 to none break notification, I'm leaving the protocol error
+ * as the expected behavior. */
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 1);
+ torture_assert_ntstatus_equal(tctx, break_info.failure_status,
+ NT_STATUS_INVALID_OPLOCK_PROTOCOL,
+ "Incorrect status");
+
+ smb2_util_close(tree1, h1);
+ smb2_util_close(tree1, h);
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/*
+ * Test a double-break. Open a file with exclusive. Send off a second open
+ * request with OPEN_IF, triggering a break to level2. This should respond
+ * with level2. Before replying to the break to level2, fire off a third open
+ * with OVERWRITE_IF. The expected sequence would be that the 3rd opener gets
+ * a level2 immediately triggered by a break to none, but that seems not the
+ * case. Still investigating what the right behaviour should be.
+ */
+
+struct levelII501_state {
+ struct torture_context *tctx;
+ struct smb2_tree *tree1;
+ struct smb2_tree *tree2;
+ struct smb2_tree *tree3;
+ struct smb2_handle h;
+ struct smb2_handle h1;
+ union smb_open io;
+
+ struct smb2_handle break_handle;
+ uint8_t break_to;
+ struct smb2_break br;
+
+ bool done;
+};
+
+static bool torture_oplock_break_delay(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data);
+static void levelII501_break_done(struct smb2_request *req);
+static void levelII501_open1_done(struct smb2_request *req);
+static void levelII501_open2_done(struct smb2_request *req);
+static void levelII501_2ndopen_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+static void levelII501_break_timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+static void levelII501_timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data);
+
+static bool test_smb2_oplock_levelII501(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\test_levelII501.dat";
+ NTSTATUS status;
+ bool ret = true;
+ struct levelII501_state *state;
+ struct smb2_request *req;
+ struct tevent_timer *te;
+
+ state = talloc(tctx, struct levelII501_state);
+ state->tctx = tctx;
+ state->done = false;
+ state->tree1 = tree1;
+ state->tree2 = tree2;
+
+ if (!torture_smb2_connection(tctx, &state->tree3)) {
+ torture_fail(tctx, "Establishing SMB2 connection failed\n");
+ return false;
+ }
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &state->h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(state->io.smb2);
+ state->io.generic.level = RAW_OPEN_SMB2;
+ state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ state->io.smb2.in.alloc_size = 0;
+ state->io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ state->io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ state->io.smb2.in.create_options = 0;
+ state->io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ state->io.smb2.in.security_flags = 0;
+ state->io.smb2.in.fname = fname;
+
+ torture_comment(tctx, "LEVELII501: Test double break sequence\n");
+ ZERO_STRUCT(break_info);
+
+ state->io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ state->io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ state->io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ state->io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ tree1->session->transport->oplock.handler = torture_oplock_break_delay;
+ tree1->session->transport->oplock.private_data = state;
+
+ status = smb2_create(tree1, tctx, &(state->io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ state->h1 = state->io.smb2.out.file.handle;
+ CHECK_VAL(state->io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ /*
+ * Trigger a break to level2
+ */
+
+ req = smb2_create_send(tree2, &state->io.smb2);
+ req->async.fn = levelII501_open1_done;
+ req->async.private_data = state;
+
+ te = tevent_add_timer(
+ tctx->ev, tctx, tevent_timeval_current_ofs(0, 200000),
+ levelII501_2ndopen_cb, state);
+ torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
+
+ te = tevent_add_timer(
+ tctx->ev, tctx, tevent_timeval_current_ofs(2, 0),
+ levelII501_timeout_cb, state);
+ torture_assert(tctx, te != NULL, "tevent_add_timer failed\n");
+
+ while (!state->done) {
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_comment(tctx, "tevent_loop_once failed\n");
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Fire off a second open after a little timeout
+ */
+
+static void levelII501_2ndopen_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct levelII501_state *state = talloc_get_type_abort(
+ private_data, struct levelII501_state);
+ struct smb2_request *req;
+
+ state->io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ req = smb2_create_send(state->tree3, &state->io.smb2);
+ req->async.fn = levelII501_open2_done;
+ req->async.private_data = state;
+}
+
+/*
+ * Postpone the break response by 500 msec
+ */
+static bool torture_oplock_break_delay(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data)
+{
+ struct levelII501_state *state = talloc_get_type_abort(
+ private_data, struct levelII501_state);
+ const char *name;
+ struct tevent_timer *te;
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ state->break_handle = *handle;
+ state->break_to = level;
+
+ switch(level) {
+ case SMB2_OPLOCK_LEVEL_II:
+ name = "level II";
+ break;
+ case SMB2_OPLOCK_LEVEL_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break;
+ }
+ printf("Got break to %s [0x%02X] in oplock handler, postponing "
+ "break response for 500msec\n", name, level);
+
+ te = tevent_add_timer(
+ state->tctx->ev, state->tctx,
+ tevent_timeval_current_ofs(0, 500000),
+ levelII501_break_timeout_cb, state);
+ torture_assert(state->tctx, te != NULL, "tevent_add_timer failed\n");
+
+ return true;
+}
+
+static void levelII501_break_timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct levelII501_state *state = talloc_get_type_abort(
+ private_data, struct levelII501_state);
+ struct smb2_request *req;
+
+ talloc_free(te);
+
+ ZERO_STRUCT(state->br);
+ state->br.in.file.handle = state->break_handle;
+ state->br.in.oplock_level = state->break_to;
+
+ req = smb2_break_send(state->tree1, &state->br);
+ req->async.fn = levelII501_break_done;
+ req->async.private_data = state;
+}
+
+static void levelII501_break_done(struct smb2_request *req)
+{
+ struct smb2_break io;
+ NTSTATUS status;
+
+ status = smb2_break_recv(req, &io);
+ printf("break done: %s\n", nt_errstr(status));
+}
+
+static void levelII501_open1_done(struct smb2_request *req)
+{
+ struct levelII501_state *state = talloc_get_type_abort(
+ req->async.private_data, struct levelII501_state);
+ struct smb2_create io;
+ NTSTATUS status;
+
+ status = smb2_create_recv(req, state, &io);
+ printf("open1 done: %s\n", nt_errstr(status));
+}
+
+static void levelII501_open2_done(struct smb2_request *req)
+{
+ struct levelII501_state *state = talloc_get_type_abort(
+ req->async.private_data, struct levelII501_state);
+ struct smb2_create io;
+ NTSTATUS status;
+
+ status = smb2_create_recv(req, state, &io);
+ printf("open2 done: %s\n", nt_errstr(status));
+}
+
+static void levelII501_timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct levelII501_state *state = talloc_get_type_abort(
+ private_data, struct levelII501_state);
+ talloc_free(te);
+ state->done = true;
+}
+
+static bool test_smb2_oplock_levelII502(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+
+{
+ const char *fname = BASEDIR "\\test_levelII502.dat";
+ NTSTATUS status;
+ union smb_open io;
+ struct smb2_close closeio;
+ struct smb2_handle h;
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ /* cleanup */
+ smb2_util_unlink(tree1, fname);
+
+ /*
+ base ntcreatex parms
+ */
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ torture_comment(
+ tctx,
+ "LEVELII502: Open a stale LEVEL2 oplock with OVERWRITE");
+
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
+ status = smb2_create(tree1, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ torture_assert(tctx,
+ io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_II,
+ "Did not get LEVEL_II oplock\n");
+
+ status = smbXcli_conn_samba_suicide(
+ tree1->session->transport->conn, 93);
+ torture_assert_ntstatus_ok(tctx, status, "suicide failed");
+
+ sleep(1);
+
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+
+ status = smb2_create(tree2, tctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
+ torture_assert(tctx,
+ io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_BATCH,
+ "Did not get BATCH oplock\n");
+
+ closeio = (struct smb2_close) {
+ .in.file.handle = io.smb2.out.file.handle,
+ };
+ status = smb2_close(tree2, &closeio);
+ torture_assert_ntstatus_equal(
+ tctx, status, NT_STATUS_OK, "close failed");
+
+ return true;
+}
+
+static bool test_oplock_statopen1_do(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ uint32_t access_mask,
+ bool expect_stat_open)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create cr;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ const char *fname = "oplock_statopen1.dat";
+ bool ret = true;
+
+ /* Open file with exclusive oplock. */
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = fname,
+ .in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH,
+ };
+ status = smb2_create(tree, mem_ctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = cr.out.file.handle;
+ CHECK_VAL(cr.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+
+ /* Stat open */
+ cr = (struct smb2_create) {
+ .in.desired_access = access_mask,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = fname,
+ };
+ status = smb2_create(tree, mem_ctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h2 = cr.out.file.handle;
+
+ if (expect_stat_open) {
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.level, 0);
+ CHECK_VAL(break_info.failures, 0);
+ if (!ret) {
+ goto done;
+ }
+ } else {
+ CHECK_VAL(break_info.count, 1);
+ }
+
+done:
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_smb2_oplock_statopen1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "oplock_statopen1.dat";
+ size_t i;
+ bool ret = true;
+ struct {
+ uint32_t access_mask;
+ bool expect_stat_open;
+ } tests[] = {
+ {
+ .access_mask = FILE_READ_DATA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_WRITE_DATA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_READ_EA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_WRITE_EA,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_EXECUTE,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = FILE_READ_ATTRIBUTES,
+ .expect_stat_open = true,
+ },
+ {
+ .access_mask = FILE_WRITE_ATTRIBUTES,
+ .expect_stat_open = true,
+ },
+ {
+ .access_mask = DELETE_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = READ_CONTROL_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = WRITE_DAC_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = WRITE_OWNER_ACCESS,
+ .expect_stat_open = false,
+ },
+ {
+ .access_mask = SYNCHRONIZE_ACCESS,
+ .expect_stat_open = true,
+ },
+ };
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ ZERO_STRUCT(break_info);
+
+ ret = test_oplock_statopen1_do(tctx,
+ tree,
+ tests[i].access_mask,
+ tests[i].expect_stat_open);
+ if (ret == true) {
+ continue;
+ }
+ torture_result(tctx, TORTURE_FAIL,
+ "test %zu: access_mask: %s, "
+ "expect_stat_open: %s\n",
+ i,
+ get_sec_mask_str(tree, tests[i].access_mask),
+ tests[i].expect_stat_open ? "yes" : "no");
+ goto done;
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "oplock");
+
+ torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
+ torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
+ torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
+ torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
+ torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
+ torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
+ torture_suite_add_2smb2_test(suite, "exclusive9",
+ test_smb2_oplock_exclusive9);
+ torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
+ torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
+ torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
+ torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
+ torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
+ torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
+ torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
+ torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
+ torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
+ torture_suite_add_2smb2_test(suite, "batch9a", test_smb2_oplock_batch9a);
+ torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
+ torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
+ torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
+ torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
+ torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
+ torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
+ torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
+ torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
+ torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
+ torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
+ torture_suite_add_1smb2_test(suite, "batch22a", test_smb2_oplock_batch22a);
+ torture_suite_add_2smb2_test(suite, "batch22b", test_smb2_oplock_batch22b);
+ torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
+ torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
+ torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
+ torture_suite_add_1smb2_test(suite, "batch26", test_smb2_oplock_batch26);
+ torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
+ torture_suite_add_2smb2_test(suite, "doc", test_smb2_oplock_doc);
+ torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
+ torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
+ torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
+ torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
+ torture_suite_add_2smb2_test(suite, "levelii501",
+ test_smb2_oplock_levelII501);
+ torture_suite_add_2smb2_test(suite, "levelii502",
+ test_smb2_oplock_levelII502);
+ torture_suite_add_1smb2_test(suite, "statopen1", test_smb2_oplock_statopen1);
+ suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
+
+ return suite;
+}
+
+/*
+ stress testing of oplocks
+*/
+bool test_smb2_bench_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_tree **trees;
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+ int i, count=0;
+ int timelimit = torture_setting_int(tctx, "timelimit", 10);
+ union smb_open io;
+ struct timeval tv;
+ struct smb2_handle h;
+
+ trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
+
+ torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
+ for (i=0;i<torture_nprocs;i++) {
+ if (!torture_smb2_connection(tctx, &trees[i])) {
+ return false;
+ }
+ talloc_steal(mem_ctx, trees[i]);
+ trees[i]->session->transport->oplock.handler =
+ torture_oplock_handler_close;
+ trees[i]->session->transport->oplock.private_data = trees[i];
+ }
+
+ status = torture_smb2_testdir(trees[0], BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\test.dat";
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ tv = timeval_current();
+
+ /*
+ we open the same file with SHARE_ACCESS_NONE from all the
+ connections in a round robin fashion. Each open causes an
+ oplock break on the previous connection, which is answered
+ by the oplock_handler_close() to close the file.
+
+ This measures how fast we can pass on oplocks, and stresses
+ the oplock handling code
+ */
+ torture_comment(tctx, "Running for %d seconds\n", timelimit);
+ while (timeval_elapsed(&tv) < timelimit) {
+ for (i=0;i<torture_nprocs;i++) {
+ status = smb2_create(trees[i], mem_ctx, &(io.smb2));
+ torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
+ count++;
+ }
+
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%.2f ops/second\r",
+ count/timeval_elapsed(&tv));
+ }
+ }
+
+ torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
+ smb2_util_close(trees[0], io.smb2.out.file.handle);
+ smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
+ smb2_deltree(trees[0], BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static struct hold_oplock_info {
+ const char *fname;
+ bool close_on_break;
+ uint32_t share_access;
+ struct smb2_handle handle;
+} hold_info[] = {
+ {
+ .fname = BASEDIR "\\notshared_close",
+ .close_on_break = true,
+ .share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ },
+ {
+ .fname = BASEDIR "\\notshared_noclose",
+ .close_on_break = false,
+ .share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ },
+ {
+ .fname = BASEDIR "\\shared_close",
+ .close_on_break = true,
+ .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ },
+ {
+ .fname = BASEDIR "\\shared_noclose",
+ .close_on_break = false,
+ .share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE,
+ },
+};
+
+static bool torture_oplock_handler_hold(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data)
+{
+ struct hold_oplock_info *info;
+ int i;
+
+ for (i=0;i<ARRAY_SIZE(hold_info);i++) {
+ if (smb2_util_handle_equal(hold_info[i].handle, *handle))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(hold_info)) {
+ printf("oplock break for unknown handle 0x%llx%llx\n",
+ (unsigned long long) handle->data[0],
+ (unsigned long long) handle->data[1]);
+ return false;
+ }
+
+ info = &hold_info[i];
+
+ if (info->close_on_break) {
+ printf("oplock break on %s - closing\n", info->fname);
+ torture_oplock_handler_close(transport, handle,
+ level, private_data);
+ return true;
+ }
+
+ printf("oplock break on %s - acking break\n", info->fname);
+ printf("Acking to none in oplock handler\n");
+
+ torture_oplock_handler_ack_to_none(transport, handle,
+ level, private_data);
+ return true;
+}
+
+/*
+ used for manual testing of oplocks - especially interaction with
+ other filesystems (such as NFS and local access)
+*/
+bool test_smb2_hold_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct torture_context *mem_ctx = talloc_new(tctx);
+ struct tevent_context *ev = tctx->ev;
+ int i;
+ struct smb2_handle h;
+ NTSTATUS status;
+
+ torture_comment(tctx, "Setting up open files with oplocks in %s\n",
+ BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
+
+ tree->session->transport->oplock.handler = torture_oplock_handler_hold;
+ tree->session->transport->oplock.private_data = tree;
+
+ /* setup the files */
+ for (i=0;i<ARRAY_SIZE(hold_info);i++) {
+ union smb_open io;
+ char c = 1;
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = hold_info[i].share_access;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = hold_info[i].fname;
+ io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ torture_comment(tctx, "opening %s\n", hold_info[i].fname);
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to open %s - %s\n",
+ hold_info[i].fname, nt_errstr(status));
+ return false;
+ }
+
+ if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
+ torture_comment(tctx, "Oplock not granted for %s - "
+ "expected %d but got %d\n",
+ hold_info[i].fname,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ io.smb2.out.oplock_level);
+ return false;
+ }
+ hold_info[i].handle = io.smb2.out.file.handle;
+
+ /* make the file non-zero size */
+ status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "Failed to write to file\n");
+ return false;
+ }
+ }
+
+ torture_comment(tctx, "Waiting for oplock events\n");
+ tevent_loop_wait(ev);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return true;
+}
+
+
+static bool test_smb2_kernel_oplocks1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_kernel_oplock1.dat";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "Open didn't return NT_STATUS_SHARING_VIOLATION\n");
+ h2 = create.out.file.handle;
+
+ torture_wait_for_oplock_break(tctx);
+ if (break_info.count != 0) {
+ torture_warning(tctx, "Open caused oplock break\n");
+ }
+
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+static bool test_smb2_kernel_oplocks2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_kernel_oplock2.dat";
+ const char *sname = "test_kernel_oplock2.dat:foo";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+
+ smb2_util_unlink(tree, fname);
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h2 = create.out.file.handle;
+
+ torture_wait_for_oplock_break(tctx);
+ if (break_info.count != 0) {
+ torture_warning(tctx, "Stream open caused oplock break\n");
+ }
+
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/**
+ * 1. 1st client opens file with oplock
+ * 2. 2nd client opens file
+ *
+ * Verify 2 triggers an oplock break
+ **/
+static bool test_smb2_kernel_oplocks3(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ const char *fname = "test_kernel_oplock3.dat";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating testfile\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+
+ /* 1 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
+
+ /* 2 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+
+ status = smb2_create(tree2, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h2 = create.out.file.handle;
+
+ torture_wait_for_oplock_break(tctx);
+ torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/**
+ * 1) create testfile with stream
+ * 2) open file r/w with batch oplock, sharing read/delete
+ * 3) open stream on file for reading
+ *
+ * Verify 3) doesn't trigger an oplock break
+ **/
+static bool test_smb2_kernel_oplocks4(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_kernel_oplock4.dat";
+ const char *sname = "test_kernel_oplock4.dat:foo";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+ smb2_util_unlink(tree, fname);
+
+ /* 1 */
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating testfile\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /* 2 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h2 = create.out.file.handle;
+
+ torture_wait_for_oplock_break(tctx);
+ if (break_info.count != 0) {
+ torture_warning(tctx, "Stream open caused oplock break\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/**
+ * 1) create testfile with stream
+ * 2) open stream r/w with batch oplock -> batch oplock granted
+ * 3) open stream r/o with batch oplock
+ *
+ * Verify 3) does trigger an oplock break
+ **/
+static bool test_smb2_kernel_oplocks5(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_kernel_oplock4.dat";
+ const char *sname = "test_kernel_oplock4.dat:foo";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+ smb2_util_unlink(tree, fname);
+
+ /* 1 */
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating testfile\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /* 2 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_BATCH, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_BATCH\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h2 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
+
+ torture_wait_for_oplock_break(tctx);
+ if (break_info.count != 1) {
+ torture_warning(tctx, "Stream open didn't cause oplock break\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/**
+ * 1) create testfile with stream
+ * 2) 1st client opens stream r/w with batch oplock -> batch oplock granted
+ * 3) 2nd client opens stream r/o with batch oplock
+ *
+ * Verify 3) does trigger an oplock break
+ **/
+static bool test_smb2_kernel_oplocks6(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ const char *fname = "test_kernel_oplock6.dat";
+ const char *sname = "test_kernel_oplock6.dat:foo";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating testfile\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+
+ /* 1 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /* 2 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h1 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_EXCLUSIVE\n");
+
+ /* 3 */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_READ;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+
+ status = smb2_create(tree2, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "Error opening the file\n");
+ h2 = create.out.file.handle;
+
+ torture_assert_goto(tctx, create.out.oplock_level == SMB2_OPLOCK_LEVEL_NONE, ret, done,
+ "Oplock level is not SMB2_OPLOCK_LEVEL_NONE\n");
+
+ torture_wait_for_oplock_break(tctx);
+ torture_assert_goto(tctx, break_info.count == 1, ret, done, "Expected 1 oplock break\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+/**
+ * Recreate regression test from bug:
+ *
+ * https://bugzilla.samba.org/show_bug.cgi?id=13058
+ *
+ * 1. smbd-1 opens the file and sets the oplock
+ * 2. smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred.
+ * 3. smbd-1 sends oplock break request to the client.
+ * 4. smbd-1 closes the file.
+ * 5. smbd-1 opens the file and sets the oplock.
+ * 6. smbd-2 calls defer_open_done(), and should re-break the oplock.
+ **/
+
+static bool test_smb2_kernel_oplocks7(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ const char *fname = "test_kernel_oplock7.dat";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+ struct smb2_create create_2;
+ struct smb2_create io;
+ struct smb2_request *req;
+
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating testfile\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /* Close the open file on break. */
+ tree->session->transport->oplock.handler = torture_oplock_handler_close;
+ tree->session->transport->oplock.private_data = tree;
+ ZERO_STRUCT(break_info);
+
+ /* 1 - open file with oplock */
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = fname;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error opening the file\n");
+ CHECK_VAL(create.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
+
+ /* 2 - open file to break oplock */
+ ZERO_STRUCT(create_2);
+ create_2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create_2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create_2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create_2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create_2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create_2.in.fname = fname;
+ create_2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ /* Open on tree2 - should cause a break on tree */
+ req = smb2_create_send(tree2, &create_2);
+ torture_assert(tctx, req != NULL, "smb2_create_send");
+
+ /* The oplock break handler should close the file. */
+ /* Steps 3 & 4. */
+ torture_wait_for_oplock_break(tctx);
+
+ tree->session->transport->oplock.handler = torture_oplock_handler;
+
+ /*
+ * 5 - re-open on tree. NB. There is a race here
+ * depending on which smbd goes first. We either get
+ * an oplock level of SMB2_OPLOCK_LEVEL_EXCLUSIVE if
+ * the close and re-open on tree is processed first, or
+ * SMB2_OPLOCK_LEVEL_NONE if the pending create on
+ * tree2 is processed first.
+ */
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error opening the file\n");
+
+ h1 = create.out.file.handle;
+ if (create.out.oplock_level != SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
+ create.out.oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
+ torture_result(tctx,
+ TORTURE_FAIL,
+ "(%s): wrong value for oplock got 0x%x\n",
+ __location__,
+ (unsigned int)create.out.oplock_level);
+ ret = false;
+ goto done;
+
+ }
+
+ /* 6 - retrieve the second open. */
+ status = smb2_create_recv(req, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error opening the file\n");
+ h2 = io.out.file.handle;
+ CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree2, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+#ifdef HAVE_KERNEL_OPLOCKS_LINUX
+
+#ifndef RT_SIGNAL_LEASE
+#define RT_SIGNAL_LEASE (SIGRTMIN+1)
+#endif
+
+static int got_break;
+
+/*
+ * Signal handler.
+ */
+
+static void got_rt_break(int sig)
+{
+ got_break = 1;
+}
+
+static int got_alarm;
+
+/*
+ * Signal handler.
+ */
+
+static void got_alarm_fn(int sig)
+{
+ got_alarm = 1;
+}
+
+/*
+ * Child process function.
+ */
+
+static int do_child_process(int pipefd, const char *name)
+{
+ int ret = 0;
+ int fd = -1;
+ char c = 0;
+ struct sigaction act;
+ sigset_t set;
+ sigset_t empty_set;
+
+ /* Block RT_SIGNAL_LEASE and SIGALRM. */
+ sigemptyset(&set);
+ sigemptyset(&empty_set);
+ sigaddset(&set, RT_SIGNAL_LEASE);
+ sigaddset(&set, SIGALRM);
+ ret = sigprocmask(SIG_SETMASK, &set, NULL);
+ if (ret == -1) {
+ return 11;
+ }
+
+ /* Set up a signal handler for RT_SIGNAL_LEASE. */
+ ZERO_STRUCT(act);
+ act.sa_handler = got_rt_break;
+ ret = sigaction(RT_SIGNAL_LEASE, &act, NULL);
+ if (ret == -1) {
+ return 1;
+ }
+ /* Set up a signal handler for SIGALRM. */
+ ZERO_STRUCT(act);
+ act.sa_handler = got_alarm_fn;
+ ret = sigaction(SIGALRM, &act, NULL);
+ if (ret == -1) {
+ return 1;
+ }
+ /* Open the passed in file and get a kernel oplock. */
+ fd = open(name, O_RDWR, 0666);
+ if (fd == -1) {
+ return 2;
+ }
+
+ ret = fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE);
+ if (ret == -1) {
+ close(fd);
+ return 3;
+ }
+
+ ret = fcntl(fd, F_SETLEASE, F_WRLCK);
+ if (ret == -1) {
+ close(fd);
+ return 4;
+ }
+
+ /* Tell the parent we're ready. */
+ ret = sys_write(pipefd, &c, 1);
+ if (ret != 1) {
+ close(fd);
+ return 5;
+ }
+
+ /* Ensure the pause doesn't hang forever. */
+ alarm(5);
+
+ /* Wait for RT_SIGNAL_LEASE or SIGALRM. */
+ ret = sigsuspend(&empty_set);
+ if (ret != -1 || errno != EINTR) {
+ close(fd);
+ return 6;
+ }
+
+ if (got_alarm == 1) {
+ close(fd);
+ return 10;
+ }
+
+ if (got_break != 1) {
+ close(fd);
+ return 7;
+ }
+
+ /* Cancel any pending alarm. */
+ alarm(0);
+
+ /* Force the server to wait for 3 seconds. */
+ sleep(3);
+
+ /* Remove our lease. */
+ ret = fcntl(fd, F_SETLEASE, F_UNLCK);
+ if (ret == -1) {
+ close(fd);
+ return 8;
+ }
+
+ ret = close(fd);
+ if (ret == -1) {
+ return 9;
+ }
+
+ /* All is well. */
+ return 0;
+}
+
+static bool wait_for_child_oplock(struct torture_context *tctx,
+ const char *localdir,
+ const char *fname)
+{
+ int fds[2];
+ int ret;
+ pid_t pid;
+ char *name = talloc_asprintf(tctx,
+ "%s/%s",
+ localdir,
+ fname);
+
+ torture_assert(tctx, name != NULL, "talloc failed");
+
+ ret = pipe(fds);
+ torture_assert(tctx, ret != -1, "pipe failed");
+
+ pid = fork();
+ torture_assert(tctx, pid != (pid_t)-1, "fork failed");
+
+ if (pid != (pid_t)0) {
+ char c;
+ /* Parent. */
+ TALLOC_FREE(name);
+ close(fds[1]);
+ ret = sys_read(fds[0], &c, 1);
+ torture_assert(tctx, ret == 1, "read failed");
+ return true;
+ }
+
+ /* Child process. */
+ close(fds[0]);
+ ret = do_child_process(fds[1], name);
+ _exit(ret);
+ /* Notreached. */
+}
+#else
+static bool wait_for_child_oplock(struct torture_context *tctx,
+ const char *localdir,
+ const char *fname)
+{
+ return false;
+}
+#endif
+
+static void child_sig_term_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ int *pstatus = (int *)private_data;
+ int status = 0;
+
+ wait(&status);
+ if (WIFEXITED(status)) {
+ *pstatus = WEXITSTATUS(status);
+ } else {
+ *pstatus = status;
+ }
+}
+
+/*
+ * Deal with a non-smbd process holding a kernel oplock.
+ */
+
+static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_kernel_oplock8.dat";
+ const char *fname1 = "tmp_test_kernel_oplock8.dat";
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create io;
+ struct smb2_request *req = NULL;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ const char *localdir = torture_setting_string(tctx, "localdir", NULL);
+ struct tevent_signal *se = NULL;
+ int child_exit_code = -1;
+ time_t start;
+ time_t end;
+
+#ifndef HAVE_KERNEL_OPLOCKS_LINUX
+ torture_skip(tctx, "Need kernel oplocks for test");
+#endif
+
+ if (localdir == NULL) {
+ torture_skip(tctx, "Need localdir for test");
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname1);
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating testfile\n");
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ se = tevent_add_signal(tctx->ev,
+ tctx,
+ SIGCHLD,
+ 0,
+ child_sig_term_handler,
+ &child_exit_code);
+ torture_assert(tctx, se != NULL, "tevent_add_signal failed\n");
+
+ /* Take the oplock locally in a sub-process. */
+ ret = wait_for_child_oplock(tctx, localdir, fname);
+ torture_assert_goto(tctx, ret, ret, done,
+ "Wait for child process failed.\n");
+
+ /*
+ * Now try and open. This should block for 3 seconds.
+ * while the child process is still alive.
+ */
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+
+ req = smb2_create_send(tree, &io);
+ torture_assert_goto(tctx, req != NULL,
+ ret, done, "smb2_create_send");
+
+ /* Ensure while the open is blocked the smbd is
+ still serving other requests. */
+ io.in.fname = fname1;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+
+ /* Time the start -> end of the request. */
+ start = time(NULL);
+ status = smb2_create(tree, tctx, &io);
+ end = time(NULL);
+
+ /* Should succeed. */
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error opening the second file\n");
+ h1 = io.out.file.handle;
+
+ /* in less than 2 seconds. Otherwise the server blocks. */
+ torture_assert_goto(tctx, end - start < 2,
+ ret, done, "server was blocked !");
+
+ /* Pick up the return for the initial blocking open. */
+ status = smb2_create_recv(req, tctx, &io);
+
+ /* Which should also have succeeded. */
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error opening the file\n");
+ h2 = io.out.file.handle;
+
+ /* Wait for the exit code from the child. */
+ while (child_exit_code == -1) {
+ int rval = tevent_loop_once(tctx->ev);
+ torture_assert_goto(tctx, rval == 0, ret,
+ done, "tevent_loop_once error\n");
+ }
+
+ torture_assert_int_equal_goto(tctx, child_exit_code, 0,
+ ret, done, "Bad child exit code");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname1);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "kernel-oplocks");
+
+ torture_suite_add_1smb2_test(suite, "kernel_oplocks1", test_smb2_kernel_oplocks1);
+ torture_suite_add_1smb2_test(suite, "kernel_oplocks2", test_smb2_kernel_oplocks2);
+ torture_suite_add_2smb2_test(suite, "kernel_oplocks3", test_smb2_kernel_oplocks3);
+ torture_suite_add_1smb2_test(suite, "kernel_oplocks4", test_smb2_kernel_oplocks4);
+ torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5);
+ torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6);
+ torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7);
+ torture_suite_add_1smb2_test(suite, "kernel_oplocks8", test_smb2_kernel_oplocks8);
+
+ suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/oplock_break_handler.c b/source4/torture/smb2/oplock_break_handler.c
new file mode 100644
index 0000000..c17d32a
--- /dev/null
+++ b/source4/torture/smb2/oplock_break_handler.c
@@ -0,0 +1,169 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * test suite for SMB2 replay
+ *
+ * Copyright (C) Anubhav Rakshit 2014
+ * Copyright (C) Stefan Metzmacher 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "oplock_break_handler.h"
+#include "lib/events/events.h"
+
+struct break_info break_info;
+
+static void torture_oplock_ack_callback(struct smb2_request *req)
+{
+ NTSTATUS status;
+
+ status = smb2_break_recv(req, &break_info.br);
+ if (!NT_STATUS_IS_OK(status)) {
+ break_info.failures++;
+ break_info.failure_status = status;
+ }
+}
+
+/**
+ * A general oplock break notification handler. This should be used when a
+ * test expects to break from batch or exclusive to a lower level.
+ */
+
+bool torture_oplock_ack_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data)
+{
+ struct smb2_tree *tree = private_data;
+ const char *name;
+ struct smb2_request *req;
+
+ ZERO_STRUCT(break_info.br);
+
+ break_info.handle = *handle;
+ break_info.level = level;
+ break_info.count++;
+
+ switch (level) {
+ case SMB2_OPLOCK_LEVEL_II:
+ name = "level II";
+ break;
+ case SMB2_OPLOCK_LEVEL_NONE:
+ name = "none";
+ break;
+ default:
+ name = "unknown";
+ break_info.failures++;
+ }
+
+ break_info.br.in.file.handle = *handle;
+ break_info.br.in.oplock_level = level;
+ break_info.br.in.reserved = 0;
+ break_info.br.in.reserved2 = 0;
+ break_info.received_transport = tree->session->transport;
+ SMB_ASSERT(tree->session->transport == transport);
+
+ if (break_info.oplock_skip_ack) {
+ torture_comment(break_info.tctx,
+ "transport[%p] skip acking to %s [0x%02X] in oplock handler\n",
+ transport, name, level);
+ return true;
+ }
+
+ torture_comment(break_info.tctx,
+ "transport[%p] Acking to %s [0x%02X] in oplock handler\n",
+ transport, name, level);
+
+ req = smb2_break_send(tree, &break_info.br);
+ req->async.fn = torture_oplock_ack_callback;
+ req->async.private_data = NULL;
+
+ return true;
+}
+
+/**
+ * A oplock break handler designed to ignore incoming break requests.
+ * This is used when incoming oplock break requests need to be ignored
+ */
+bool torture_oplock_ignore_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level, void *private_data)
+{
+ return true;
+}
+
+/*
+ * Timer handler function notifies the registering function that time is up
+ */
+static void timeout_cb(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ bool *timesup = (bool *)private_data;
+ *timesup = true;
+}
+
+/*
+ * Wait a short period of time to receive a single oplock break request
+ */
+void torture_wait_for_oplock_break(struct torture_context *tctx)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct tevent_timer *te = NULL;
+ struct timeval ne;
+ bool timesup = false;
+ int old_count = break_info.count;
+
+ /* Wait 1 second for an oplock break */
+ ne = tevent_timeval_current_ofs(0, 1000000);
+
+ te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
+ if (te == NULL) {
+ torture_comment(tctx, "Failed to wait for an oplock break. "
+ "test results may not be accurate.\n");
+ goto done;
+ }
+
+ torture_comment(tctx, "Waiting for a potential oplock break...\n");
+ while (!timesup && break_info.count < old_count + 1) {
+ if (tevent_loop_once(tctx->ev) != 0) {
+ torture_comment(tctx, "Failed to wait for an oplock "
+ "break. test results may not be "
+ "accurate\n.");
+ goto done;
+ }
+ }
+ if (timesup) {
+ torture_comment(tctx, "... waiting for an oplock break timed out\n");
+ } else {
+ torture_comment(tctx, "Got %u oplock breaks\n",
+ break_info.count - old_count);
+ }
+
+done:
+ /* We don't know if the timed event fired and was freed, we received
+ * our oplock break, or some other event triggered the loop. Thus,
+ * we create a tmp_ctx to be able to safely free/remove the timed
+ * event in all 3 cases.
+ */
+ talloc_free(tmp_ctx);
+}
diff --git a/source4/torture/smb2/oplock_break_handler.h b/source4/torture/smb2/oplock_break_handler.h
new file mode 100644
index 0000000..c576782
--- /dev/null
+++ b/source4/torture/smb2/oplock_break_handler.h
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * test suite for SMB2 replay
+ *
+ * Copyright (C) Anubhav Rakshit 2014
+ * Copyright (C) Stefan Metzmacher 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OPLOCK_BREAK_HANDLER_H__
+#define __OPLOCK_BREAK_HANDLER_H__
+
+struct break_info {
+ struct torture_context *tctx;
+ bool oplock_skip_ack;
+ struct smb2_handle handle;
+ uint8_t level;
+ struct smb2_break br;
+ int count;
+ int failures;
+ NTSTATUS failure_status;
+ struct smb2_transport *received_transport;
+};
+
+extern struct break_info break_info;
+
+bool torture_oplock_ack_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data);
+bool torture_oplock_ignore_handler(struct smb2_transport *transport,
+ const struct smb2_handle *handle,
+ uint8_t level,
+ void *private_data);
+void torture_wait_for_oplock_break(struct torture_context *tctx);
+
+static inline void torture_reset_break_info(struct torture_context *tctx,
+ struct break_info *r)
+{
+ ZERO_STRUCTP(r);
+ r->tctx = tctx;
+}
+
+#endif /* __OPLOCK_BREAK_HANDLER_H__ */
diff --git a/source4/torture/smb2/read.c b/source4/torture/smb2/read.c
new file mode 100644
index 0000000..2bc0dc9
--- /dev/null
+++ b/source4/torture/smb2/read.c
@@ -0,0 +1,573 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 read test suite
+
+ Copyright (C) Andrew Tridgell 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include <tevent.h>
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+
+
+#define CHECK_STATUS(_status, _expected) \
+ torture_assert_ntstatus_equal_goto(torture, _status, _expected, \
+ ret, done, "Incorrect status")
+
+#define CHECK_VALUE(v, correct) \
+ torture_assert_int_equal_goto(torture, v, correct, \
+ ret, done, "Incorrect value")
+
+#define FNAME "smb2_readtest.dat"
+#define DNAME "smb2_readtest.dir"
+
+static bool test_read_eof(struct torture_context *torture, struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[64*1024];
+ struct smb2_read rd;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ ZERO_STRUCT(buf);
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 5;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 10;
+ rd.in.offset = 0;
+ rd.in.min_count = 1;
+
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 10);
+
+ rd.in.min_count = 0;
+ rd.in.length = 10;
+ rd.in.offset = sizeof(buf);
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = sizeof(buf);
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 0);
+
+ rd.in.min_count = 1;
+ rd.in.length = 0;
+ rd.in.offset = sizeof(buf);
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 0;
+ rd.in.length = 2;
+ rd.in.offset = sizeof(buf) - 1;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 1);
+
+ rd.in.min_count = 2;
+ rd.in.length = 1;
+ rd.in.offset = sizeof(buf) - 1;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 0x10000;
+ rd.in.length = 1;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 0x10000 - 2;
+ rd.in.length = 1;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 10;
+ rd.in.length = 5;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+static bool test_read_position(struct torture_context *torture, struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[64*1024];
+ struct smb2_read rd;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ union smb_fileinfo info;
+
+ ZERO_STRUCT(buf);
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 10;
+ rd.in.offset = 0;
+ rd.in.min_count = 1;
+
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 10);
+
+ info.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ info.generic.in.file.handle = h;
+
+ status = smb2_getinfo_file(tree, tmp_ctx, &info);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (torture_setting_bool(torture, "windows", false)) {
+ CHECK_VALUE(info.all_info2.out.position, 0);
+ } else {
+ CHECK_VALUE(info.all_info2.out.position, 10);
+ }
+
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static bool test_read_dir(struct torture_context *torture, struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ struct smb2_read rd;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf(__location__ " Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status));
+ return false;
+ }
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 10;
+ rd.in.offset = 0;
+ rd.in.min_count = 1;
+
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
+
+ rd.in.min_count = 11;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
+
+ rd.in.length = 0;
+ rd.in.min_count = 2592;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ if (torture_setting_bool(torture, "windows", false)) {
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
+ }
+
+ rd.in.length = 0;
+ rd.in.min_count = 0;
+ rd.in.channel = 0;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ if (torture_setting_bool(torture, "windows", false)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static bool test_read_access(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[64 * 1024];
+ struct smb2_read rd;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ ZERO_STRUCT(buf);
+
+ /* create a file */
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* open w/ READ access - success */
+ status = torture_smb2_testfile_access(
+ tree, FNAME, &h, SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_DATA);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 5;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* open w/ EXECUTE access - success */
+ status = torture_smb2_testfile_access(
+ tree, FNAME, &h, SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 5;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* open without READ or EXECUTE access - access denied */
+ status = torture_smb2_testfile_access(tree, FNAME, &h,
+ SEC_FILE_READ_ATTRIBUTE);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 5;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ basic regression test for BUG 14607
+ https://bugzilla.samba.org/show_bug.cgi?id=14607
+*/
+static bool test_read_bug14607(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[64 * 1024];
+ struct smb2_read rd;
+ uint32_t timeout_msec;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ uint8_t *data = NULL;
+ uint32_t data_length = 0;
+
+ memset(buf, 0x1f, ARRAY_SIZE(buf));
+
+ /* create a file */
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = ARRAY_SIZE(buf);
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, rd.out.data.data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content smb2_read");
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ status = smb2cli_read(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ rd.in.length,
+ rd.in.offset,
+ h.data[0],
+ h.data[1],
+ rd.in.min_count,
+ rd.in.remaining,
+ tmp_ctx,
+ &data, &data_length);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(data_length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content smb2cli_read");
+
+ status = smb2cli_ioctl(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ tmp_ctx,
+ &out_input_buffer,
+ &out_output_buffer);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST))
+ {
+ torture_comment(torture,
+ "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8: %s\n",
+ nt_errstr(status));
+ torture_skip(torture, "server doesn't support FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8\n");
+ }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8");
+
+ torture_assert_int_equal(torture, out_output_buffer.length, 0,
+ "output length");
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = ARRAY_SIZE(buf);
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, rd.out.data.data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content after padding smb2_read");
+
+ status = smb2cli_read(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ rd.in.length,
+ rd.in.offset,
+ h.data[0],
+ h.data[1],
+ rd.in.min_count,
+ rd.in.remaining,
+ tmp_ctx,
+ &data, &data_length);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(data_length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content after padding smb2cli_read");
+
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ basic testing of SMB2 read
+*/
+struct torture_suite *torture_smb2_read_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "read");
+
+ torture_suite_add_1smb2_test(suite, "eof", test_read_eof);
+ torture_suite_add_1smb2_test(suite, "position", test_read_position);
+ torture_suite_add_1smb2_test(suite, "dir", test_read_dir);
+ torture_suite_add_1smb2_test(suite, "access", test_read_access);
+ torture_suite_add_1smb2_test(suite, "bug14607",
+ test_read_bug14607);
+
+ suite->description = talloc_strdup(suite, "SMB2-READ tests");
+
+ return suite;
+}
+
+static bool test_aio_cancel(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle h;
+ uint8_t buf[64 * 1024];
+ struct smb2_read r;
+ struct smb2_request *req = NULL;
+ int rc;
+ NTSTATUS status;
+ bool ret = true;
+
+ ZERO_STRUCT(buf);
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "torture_smb2_testfile failed\n");
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "smb2_util_write failed\n");
+
+ status = smb2_util_close(tree, h);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "smb2_util_close failed\n");
+
+ status = torture_smb2_testfile_access(
+ tree, FNAME, &h, SEC_RIGHTS_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "torture_smb2_testfile_access failed\n");
+
+ r = (struct smb2_read) {
+ .in.file.handle = h,
+ .in.length = 1,
+ .in.offset = 0,
+ .in.min_count = 1,
+ };
+
+ req = smb2_read_send(tree, &r);
+ torture_assert_goto(
+ tctx,
+ req != NULL,
+ ret,
+ done,
+ "smb2_read_send failed\n");
+
+ while (!req->cancel.can_cancel) {
+ rc = tevent_loop_once(tctx->ev);
+ torture_assert_goto(
+ tctx,
+ rc == 0,
+ ret,
+ done,
+ "tevent_loop_once failed\n");
+ }
+
+ status = smb2_cancel(req);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "smb2_cancel failed\n");
+
+ status = smb2_read_recv(req, tree, &r);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "smb2_read_recv failed\n");
+
+ status = smb2_util_close(tree, h);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "smb2_util_close failed\n");
+
+done:
+ smb2_util_unlink(tree, FNAME);
+ return ret;
+}
+
+/*
+ * aio testing against share with VFS module "delay_inject"
+ */
+struct torture_suite *torture_smb2_aio_delay_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "aio_delay");
+
+ torture_suite_add_1smb2_test(suite, "aio_cancel", test_aio_cancel);
+
+ suite->description = talloc_strdup(suite, "SMB2 delayed aio tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/read_write.c b/source4/torture/smb2/read_write.c
new file mode 100644
index 0000000..707a49b
--- /dev/null
+++ b/source4/torture/smb2/read_write.c
@@ -0,0 +1,361 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB read/write torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) David Mulder 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+#define CHECK_STATUS(_status, _expected) \
+ torture_assert_ntstatus_equal_goto(torture, _status, _expected, \
+ ret, done, "Incorrect status")
+
+#define CHECK_VALUE(v, correct) \
+ torture_assert_int_equal_goto(torture, v, correct, \
+ ret, done, "Incorrect value")
+
+#define FNAME "smb2_writetest.dat"
+
+static bool run_smb2_readwritetest(struct torture_context *tctx,
+ struct smb2_tree *t1, struct smb2_tree *t2)
+{
+ const char *lockfname = "torture2.lck";
+ struct smb2_create f1 = {0};
+ struct smb2_create f2 = {0};
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ int i;
+ uint8_t buf[131072];
+ bool correct = true;
+ NTSTATUS status;
+ int ret = 0;
+
+ ret = smb2_deltree(t1, lockfname);
+ torture_assert(tctx, ret != -1, "unlink failed");
+
+ f1.in.desired_access = SEC_FILE_ALL;
+ f1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ f1.in.create_disposition = FILE_CREATE;
+ f1.in.fname = lockfname;
+
+ status = smb2_create(t1, tctx, &f1);
+ torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
+ talloc_asprintf(tctx, "first open read/write of %s failed (%s)",
+ lockfname, nt_errstr(status)));
+ h1 = f1.out.file.handle;
+
+ f2.in.desired_access = SEC_FILE_READ_DATA;
+ f2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ f2.in.create_disposition = FILE_OPEN;
+ f2.in.fname = lockfname;
+
+ status = smb2_create(t2, tctx, &f2);
+ torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
+ talloc_asprintf(tctx, "second open read-only of %s failed (%s)",
+ lockfname, nt_errstr(status)));
+ h2 = f2.out.file.handle;
+
+ torture_comment(tctx, "Checking data integrity over %d ops\n",
+ torture_numops);
+
+ for (i = 0; i < torture_numops; i++) {
+ struct smb2_write w = {0};
+ struct smb2_read r = {0};
+ size_t buf_size = ((unsigned int)random()%(sizeof(buf)-1))+ 1;
+
+ if (i % 10 == 0) {
+ if (torture_setting_bool(tctx, "progress", true)) {
+ torture_comment(tctx, "%d\r", i); fflush(stdout);
+ }
+ }
+
+ generate_random_buffer(buf, buf_size);
+
+ w.in.file.handle = h1;
+ w.in.offset = 0;
+ w.in.data.data = buf;
+ w.in.data.length = buf_size;
+
+ status = smb2_write(t1, &w);
+ if (!NT_STATUS_IS_OK(status) || w.out.nwritten != buf_size) {
+ torture_comment(tctx, "write failed (%s)\n",
+ nt_errstr(status));
+ torture_result(tctx, TORTURE_FAIL,
+ "wrote %d, expected %d\n",
+ (int)w.out.nwritten, (int)buf_size);
+ correct = false;
+ goto done;
+ }
+
+ r.in.file.handle = h2;
+ r.in.offset = 0;
+ r.in.length = buf_size;
+ status = smb2_read(t2, tctx, &r);
+ if (!NT_STATUS_IS_OK(status) || r.out.data.length != buf_size) {
+ torture_comment(tctx, "read failed (%s)\n",
+ nt_errstr(status));
+ torture_result(tctx, TORTURE_FAIL,
+ "read %d, expected %d\n",
+ (int)r.out.data.length, (int)buf_size);
+ correct = false;
+ goto done;
+ }
+
+ torture_assert_mem_equal_goto(tctx, r.out.data.data, buf,
+ buf_size, correct, done, "read/write compare failed\n");
+ }
+
+ status = smb2_util_close(t2, h2);
+ torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
+ talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
+ ZERO_STRUCT(h2);
+
+ status = smb2_util_close(t1, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
+ talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
+ ZERO_STRUCT(h1);
+
+done:
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(t2, h2);
+ }
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(t1, h1);
+ }
+
+ status = smb2_util_unlink(t1, lockfname);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "unlink failed (%s)", nt_errstr(status));
+ }
+
+ return correct;
+}
+
+
+static bool run_smb2_wrap_readwritetest(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return run_smb2_readwritetest(tctx, tree1, tree1);
+}
+
+static bool test_rw_invalid(struct torture_context *torture, struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[64*1024];
+ struct smb2_read rd;
+ struct smb2_write w = {0};
+ union smb_setfileinfo sfinfo;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+
+ ZERO_STRUCT(buf);
+
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* set delete-on-close */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.in.file.handle = h;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = 10;
+ rd.in.offset = 0;
+ rd.in.min_count = 1;
+
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 10);
+
+ rd.in.min_count = 0;
+ rd.in.length = 10;
+ rd.in.offset = sizeof(buf);
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = sizeof(buf);
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 0);
+
+ rd.in.min_count = 0;
+ rd.in.length = 1;
+ rd.in.offset = INT64_MAX - 1;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = INT64_MAX;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, 0);
+
+ rd.in.min_count = 0;
+ rd.in.length = 1;
+ rd.in.offset = INT64_MAX;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = (uint64_t)INT64_MAX + 1;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = (uint64_t)INT64_MIN;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = (uint64_t)(int64_t)-1;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = (uint64_t)(int64_t)-2;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ rd.in.min_count = 0;
+ rd.in.length = 0;
+ rd.in.offset = (uint64_t)(int64_t)-3;
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = (int64_t)-1;
+ w.in.data.data = buf;
+ w.in.data.length = ARRAY_SIZE(buf);
+
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = (int64_t)-2;
+ w.in.data.data = buf;
+ w.in.data.length = ARRAY_SIZE(buf);
+
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = INT64_MIN;
+ w.in.data.data = buf;
+ w.in.data.length = 1;
+
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = INT64_MIN;
+ w.in.data.data = buf;
+ w.in.data.length = 0;
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = INT64_MAX;
+ w.in.data.data = buf;
+ w.in.data.length = 0;
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(w.out.nwritten, 0);
+
+ w.in.file.handle = h;
+ w.in.offset = INT64_MAX;
+ w.in.data.data = buf;
+ w.in.data.length = 1;
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = (uint64_t)INT64_MAX + 1;
+ w.in.data.data = buf;
+ w.in.data.length = 0;
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
+ w.in.data.data = buf;
+ w.in.data.length = 1;
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ w.in.file.handle = h;
+ w.in.offset = 0xfffffff0000 - 1; /* MAXFILESIZE - 1 */
+ w.in.data.data = buf;
+ w.in.data.length = 1;
+ status = smb2_write(tree, &w);
+ if (TARGET_IS_SAMBA3(torture) || TARGET_IS_SAMBA4(torture)) {
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(w.out.nwritten, 1);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_DISK_FULL);
+ }
+
+ w.in.file.handle = h;
+ w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
+ w.in.data.data = buf;
+ w.in.data.length = 0;
+ status = smb2_write(tree, &w);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(w.out.nwritten, 0);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_readwrite_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "rw");
+
+ torture_suite_add_2smb2_test(suite, "rw1", run_smb2_readwritetest);
+ torture_suite_add_2smb2_test(suite, "rw2", run_smb2_wrap_readwritetest);
+ torture_suite_add_1smb2_test(suite, "invalid", test_rw_invalid);
+
+ suite->description = talloc_strdup(suite, "SMB2 Samba4 Read/Write");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/rename.c b/source4/torture/smb2/rename.c
new file mode 100644
index 0000000..12636c4
--- /dev/null
+++ b/source4/torture/smb2/rename.c
@@ -0,0 +1,1751 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 rename test suite
+
+ Copyright (C) Christian Ambach 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+#include "librpc/gen_ndr/security.h"
+
+#define CHECK_VAL(v, correct) \
+ do { \
+ if ((v) != (correct)) { \
+ torture_result(torture, \
+ TORTURE_FAIL, \
+ "(%s): wrong value for %s got " \
+ "0x%llx - should be 0x%llx\n", \
+ __location__, #v, \
+ (unsigned long long)v, \
+ (unsigned long long)correct); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_CREATED(__io, __created, __attribute) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
+ CHECK_VAL((__io)->out.size, 0); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while(0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(torture, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define BASEDIR "test_rename"
+
+/*
+ * basic testing of rename: open file with DELETE access
+ * this should pass
+ */
+
+static bool torture_smb2_rename_simple(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ union smb_fileinfo fi;
+ struct smb2_handle h1;
+
+ ZERO_STRUCT(h1);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL|SEC_STD_DELETE;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Checking for new filename\n");
+
+ ZERO_STRUCT(fi);
+ fi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ fi.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree1, torture, &fi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(h1);
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (h1.data[0] || h1.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/*
+ * basic testing of rename, this time do not request DELETE access
+ * for the file, this should fail
+ */
+
+static bool torture_smb2_rename_simple2(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle h1;
+
+ ZERO_STRUCT(h1);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(h1);
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (h1.data[0] || h1.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+
+/*
+ * testing of rename with no sharing allowed on file
+ * this should work
+ */
+
+static bool torture_smb2_rename_no_sharemode(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ union smb_fileinfo fi;
+ struct smb2_handle h1;
+
+ ZERO_STRUCT(h1);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = io.smb2.out.file.handle;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Checking for new filename\n");
+
+ ZERO_STRUCT(fi);
+ fi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ fi.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree1, torture, &fi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(h1);
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (h1.data[0] || h1.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/*
+ * testing of rename when opening parent dir with delete access and delete
+ * sharing allowed
+ * should result in sharing violation
+ */
+
+static bool torture_smb2_rename_with_delete_access(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle fh, dh;
+
+ ZERO_STRUCT(fh);
+ ZERO_STRUCT(dh);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Opening parent directory\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_STD_DELETE | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE | SEC_FILE_WRITE_EA |
+ SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dh = io.smb2.out.file.handle;
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_STD_DELETE | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_WRITE_EA | SEC_FILE_READ_EA |
+ SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fh = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = fh;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(fh);
+
+ torture_comment(torture, "Closing directory\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(dh);
+
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (fh.data[0] || fh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ if (dh.data[0] || dh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+
+/*
+ * testing of rename with delete access on parent dir
+ * this is a variation of the test above: parent dir is opened
+ * without share_delete, so rename must fail
+ */
+
+static bool torture_smb2_rename_with_delete_access2(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle fh, dh;
+
+ ZERO_STRUCT(fh);
+ ZERO_STRUCT(dh);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Opening parent directory\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_STD_DELETE | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE | SEC_FILE_WRITE_EA |
+ SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dh = io.smb2.out.file.handle;
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_STD_DELETE | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_WRITE_EA | SEC_FILE_READ_EA |
+ SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fh = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = fh;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(fh);
+
+ torture_comment(torture, "Closing directory\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(dh);
+
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (fh.data[0] || fh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ if (dh.data[0] || dh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/*
+ * testing of rename when opening parent dir with no delete access and delete
+ * sharing allowed
+ * this should pass
+ */
+
+static bool torture_smb2_rename_no_delete_access(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ union smb_fileinfo fi;
+ struct smb2_handle fh, dh;
+
+ ZERO_STRUCT(fh);
+ ZERO_STRUCT(dh);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Opening parent directory\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE | SEC_FILE_WRITE_EA |
+ SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dh = io.smb2.out.file.handle;
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_STD_DELETE | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_WRITE_EA | SEC_FILE_READ_EA |
+ SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fh = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = fh;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Checking for new filename\n");
+
+ ZERO_STRUCT(fi);
+ fi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ fi.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree1, torture, &fi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(fh);
+
+ torture_comment(torture, "Closing directory\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(dh);
+
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (fh.data[0] || fh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ if (dh.data[0] || dh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+
+/*
+ * testing of rename with no delete access on parent dir
+ * this is the negative case of the test above: parent dir is opened
+ * without share_delete, so rename must fail
+ */
+
+static bool torture_smb2_rename_no_delete_access2(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle fh, dh;
+
+ ZERO_STRUCT(fh);
+ ZERO_STRUCT(dh);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Opening parent directory\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE | SEC_FILE_WRITE_EA |
+ SEC_FILE_READ_EA | SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dh = io.smb2.out.file.handle;
+
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_STD_WRITE_DAC |
+ SEC_STD_READ_CONTROL | SEC_STD_DELETE | SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_ATTRIBUTE | SEC_FILE_WRITE_EA | SEC_FILE_READ_EA |
+ SEC_FILE_APPEND_DATA | SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fh = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = fh;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(fh);
+
+ torture_comment(torture, "Closing directory\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(dh);
+
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (fh.data[0] || fh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ if (dh.data[0] || dh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+/*
+ * this is a replay of how Word 2010 saves a file
+ * this should pass
+ */
+
+static bool torture_smb2_rename_msword(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ union smb_fileinfo fi;
+ struct smb2_handle fh, dh;
+
+ ZERO_STRUCT(fh);
+ ZERO_STRUCT(dh);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ smb2_util_mkdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.create_options = 0x60;
+ io.smb2.in.file_attributes = 0;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ fh = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Opening parent directory\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x00100080;
+ io.smb2.in.create_options = 0x00800021;
+ io.smb2.in.file_attributes = 0;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dh = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming test file\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = fh;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "\\newname.txt";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(torture, "Checking for new filename\n");
+
+ ZERO_STRUCT(fi);
+ fi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ fi.generic.in.file.handle = fh;
+ status = smb2_getinfo_file(tree1, torture, &fi);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+
+ torture_comment(torture, "Closing test file\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(fh);
+
+ torture_comment(torture, "Closing directory\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(dh);
+
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (fh.data[0] || fh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = fh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ if (dh.data[0] || dh.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = dh;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool torture_smb2_rename_dir_openfile(struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle d1, h1;
+
+ ZERO_STRUCT(d1);
+ ZERO_STRUCT(h1);
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_rmdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating base directory\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ d1 = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Creating test file\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree1, torture, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ torture_comment(torture, "Renaming directory\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = d1;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name =
+ BASEDIR "-new";
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+ torture_comment(torture, "Closing directory\n");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = d1;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(d1);
+
+ torture_comment(torture, "Closing test file\n");
+
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(h1);
+
+done:
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (h1.data[0] || h1.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree1, &(cl.smb2));
+ }
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+struct rename_one_dir_cycle_state {
+ struct tevent_context *ev;
+ struct smb2_tree *tree;
+ struct smb2_handle file;
+ const char *base_name;
+ char *new_name;
+ unsigned *rename_counter;
+
+ unsigned current;
+ unsigned max;
+ union smb_setfileinfo sinfo;
+};
+
+static void rename_one_dir_cycle_done(struct smb2_request *subreq);
+
+static struct tevent_req *rename_one_dir_cycle_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smb2_tree *tree,
+ struct smb2_handle file,
+ unsigned max_renames,
+ const char *base_name,
+ unsigned *rename_counter)
+{
+ struct tevent_req *req;
+ struct rename_one_dir_cycle_state *state;
+ struct smb2_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct rename_one_dir_cycle_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->tree = tree;
+ state->file = file;
+ state->base_name = base_name;
+ state->rename_counter = rename_counter;
+ state->current = 0;
+ state->max = max_renames;
+
+ ZERO_STRUCT(state->sinfo);
+ state->sinfo.rename_information.level =
+ RAW_SFILEINFO_RENAME_INFORMATION;
+ state->sinfo.rename_information.in.file.handle = state->file;
+ state->sinfo.rename_information.in.overwrite = 0;
+ state->sinfo.rename_information.in.root_fid = 0;
+
+ state->new_name = talloc_asprintf(
+ state, "%s-%u", state->base_name, state->current);
+ if (tevent_req_nomem(state->new_name, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->sinfo.rename_information.in.new_name = state->new_name;
+
+ subreq = smb2_setinfo_file_send(state->tree, &state->sinfo);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq->async.fn = rename_one_dir_cycle_done;
+ subreq->async.private_data = req;
+ return req;
+}
+
+static void rename_one_dir_cycle_done(struct smb2_request *subreq)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ subreq->async.private_data, struct tevent_req);
+ struct rename_one_dir_cycle_state *state = tevent_req_data(
+ req, struct rename_one_dir_cycle_state);
+ NTSTATUS status;
+
+ status = smb2_setinfo_recv(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ TALLOC_FREE(state->new_name);
+
+ *state->rename_counter += 1;
+
+ state->current += 1;
+ if (state->current >= state->max) {
+ tevent_req_done(req);
+ return;
+ }
+
+ ZERO_STRUCT(state->sinfo);
+ state->sinfo.rename_information.level =
+ RAW_SFILEINFO_RENAME_INFORMATION;
+ state->sinfo.rename_information.in.file.handle = state->file;
+ state->sinfo.rename_information.in.overwrite = 0;
+ state->sinfo.rename_information.in.root_fid = 0;
+
+ state->new_name = talloc_asprintf(
+ state, "%s-%u", state->base_name, state->current);
+ if (tevent_req_nomem(state->new_name, req)) {
+ return;
+ }
+ state->sinfo.rename_information.in.new_name = state->new_name;
+
+ subreq = smb2_setinfo_file_send(state->tree, &state->sinfo);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ subreq->async.fn = rename_one_dir_cycle_done;
+ subreq->async.private_data = req;
+}
+
+static NTSTATUS rename_one_dir_cycle_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+struct rename_dir_bench_state {
+ struct tevent_context *ev;
+ struct smb2_tree *tree;
+ const char *base_name;
+ unsigned max_renames;
+ unsigned *rename_counter;
+
+ struct smb2_create io;
+ union smb_setfileinfo sinfo;
+ struct smb2_close cl;
+
+ struct smb2_handle file;
+};
+
+static void rename_dir_bench_opened(struct smb2_request *subreq);
+static void rename_dir_bench_renamed(struct tevent_req *subreq);
+static void rename_dir_bench_set_doc(struct smb2_request *subreq);
+static void rename_dir_bench_closed(struct smb2_request *subreq);
+
+static struct tevent_req *rename_dir_bench_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smb2_tree *tree,
+ const char *base_name,
+ unsigned max_renames,
+ unsigned *rename_counter)
+{
+ struct tevent_req *req;
+ struct rename_dir_bench_state *state;
+ struct smb2_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct rename_dir_bench_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->tree = tree;
+ state->base_name = base_name;
+ state->max_renames = max_renames;
+ state->rename_counter = rename_counter;
+
+ ZERO_STRUCT(state->io);
+ state->io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ state->io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ state->io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ state->io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ state->io.in.fname = state->base_name;
+
+ subreq = smb2_create_send(state->tree, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq->async.fn = rename_dir_bench_opened;
+ subreq->async.private_data = req;
+ return req;
+}
+
+static void rename_dir_bench_opened(struct smb2_request *subreq)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ subreq->async.private_data, struct tevent_req);
+ struct rename_dir_bench_state *state = tevent_req_data(
+ req, struct rename_dir_bench_state);
+ struct smb2_create *io;
+ struct tevent_req *subreq2;
+ NTSTATUS status;
+
+ io = talloc(state, struct smb2_create);
+ if (tevent_req_nomem(io, req)) {
+ return;
+ }
+
+ status = smb2_create_recv(subreq, io, io);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ state->file = io->out.file.handle;
+ TALLOC_FREE(io);
+
+ subreq2 = rename_one_dir_cycle_send(
+ state, state->ev, state->tree, state->file,
+ state->max_renames, state->base_name,
+ state->rename_counter);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq2, rename_dir_bench_renamed, req);
+}
+
+static void rename_dir_bench_renamed(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct rename_dir_bench_state *state = tevent_req_data(
+ req, struct rename_dir_bench_state);
+ struct smb2_request *subreq2;
+ NTSTATUS status;
+
+ status = rename_one_dir_cycle_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ ZERO_STRUCT(state->sinfo);
+ state->sinfo.disposition_info.level =
+ RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ state->sinfo.disposition_info.in.file.handle = state->file;
+ state->sinfo.disposition_info.in.delete_on_close = true;
+
+ subreq2 = smb2_setinfo_file_send(state->tree, &state->sinfo);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ subreq2->async.fn = rename_dir_bench_set_doc;
+ subreq2->async.private_data = req;
+}
+
+static void rename_dir_bench_set_doc(struct smb2_request *subreq)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ subreq->async.private_data, struct tevent_req);
+ struct rename_dir_bench_state *state = tevent_req_data(
+ req, struct rename_dir_bench_state);
+ NTSTATUS status;
+
+ status = smb2_setinfo_recv(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ ZERO_STRUCT(state->cl);
+ state->cl.in.file.handle = state->file;
+
+ subreq = smb2_close_send(state->tree, &state->cl);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ subreq->async.fn = rename_dir_bench_closed;
+ subreq->async.private_data = req;
+}
+
+static void rename_dir_bench_closed(struct smb2_request *subreq)
+{
+ struct tevent_req *req = talloc_get_type_abort(
+ subreq->async.private_data, struct tevent_req);
+ struct smb2_close cl;
+ NTSTATUS status;
+
+ status = smb2_close_recv(subreq, &cl);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS rename_dir_bench_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+struct rename_dirs_bench_state {
+ unsigned num_reqs;
+ unsigned num_done;
+};
+
+static void rename_dirs_bench_done(struct tevent_req *subreq);
+
+static struct tevent_req *rename_dirs_bench_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smb2_tree *tree,
+ const char *base_name,
+ unsigned num_parallel,
+ unsigned max_renames,
+ unsigned *rename_counter)
+{
+ struct tevent_req *req;
+ struct rename_dirs_bench_state *state;
+ unsigned i;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct rename_dirs_bench_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->num_reqs = num_parallel;
+ state->num_done = 0;
+
+ for (i=0; i<num_parallel; i++) {
+ struct tevent_req *subreq;
+ char *sub_base;
+
+ sub_base = talloc_asprintf(state, "%s-%u", base_name, i);
+ if (tevent_req_nomem(sub_base, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = rename_dir_bench_send(state, ev, tree, sub_base,
+ max_renames, rename_counter);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, rename_dirs_bench_done, req);
+ }
+ return req;
+}
+
+static void rename_dirs_bench_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct rename_dirs_bench_state *state = tevent_req_data(
+ req, struct rename_dirs_bench_state);
+ NTSTATUS status;
+
+ status = rename_dir_bench_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->num_done += 1;
+ if (state->num_done >= state->num_reqs) {
+ tevent_req_done(req);
+ }
+}
+
+static NTSTATUS rename_dirs_bench_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static bool torture_smb2_rename_dir_bench(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct tevent_req *req;
+ NTSTATUS status;
+ unsigned counter = 0;
+ bool ret;
+
+ req = rename_dirs_bench_send(tctx, tctx->ev, tree, "dir", 3, 10,
+ &counter);
+ torture_assert(tctx, req != NULL, "rename_dirs_bench_send failed");
+
+ ret = tevent_req_poll(req, tctx->ev);
+ torture_assert(tctx, ret, "tevent_req_poll failed");
+
+ status = rename_dirs_bench_recv(req);
+ torture_comment(tctx, "rename_dirs_bench returned %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(req);
+ torture_assert_ntstatus_ok(tctx, status, "bench failed");
+ return true;
+}
+
+/*
+ * This test basically verifies that modify and change timestamps are preserved
+ * after file rename with outstanding open file handles.
+ */
+
+static bool torture_smb2_rename_simple_modtime(
+ struct torture_context *torture,
+ struct smb2_tree *tree1)
+{
+ struct smb2_create c1, c2;
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree1, BASEDIR);
+ smb2_util_mkdir(tree1, BASEDIR);
+
+ torture_comment(torture, "Creating test file: file1.txt\n");
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL|SEC_STD_DELETE,
+ .in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = BASEDIR "\\file1.txt",
+ };
+
+ status = smb2_create(tree1, torture, &c1);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ torture_comment(torture, "Waitig for 5 secs..\n");
+ sleep(5);
+
+ torture_comment(torture, "Creating test file: file2.txt\n");
+
+ c2 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL|SEC_STD_DELETE,
+ .in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = BASEDIR "\\file2.txt",
+ };
+
+ status = smb2_create(tree1, torture, &c2);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_create failed\n");
+ h2 = c2.out.file.handle;
+
+ torture_comment(torture, "Renaming file1.txt --> tmp1.txt\n");
+
+ si = (union smb_setfileinfo) {
+ .rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION,
+ .rename_information.in.file.handle = h1,
+ .rename_information.in.new_name =
+ BASEDIR "\\tmp1.txt",
+ };
+
+ status = smb2_setinfo_file(tree1, &si);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ torture_comment(torture, "GetInfo of tmp1.txt\n");
+
+ gi = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree1, torture, &gi);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(torture, "Check if timestamps are good after rename(file1.txt --> tmp1.txt).\n");
+
+ torture_assert_nttime_equal(
+ torture, c1.out.write_time, gi.all_info.out.write_time,
+ "Bad timestamp\n");
+ torture_assert_nttime_equal(
+ torture, c1.out.change_time, gi.all_info.out.change_time,
+ "Bad timestamp\n");
+
+ torture_comment(torture, "Renaming file2.txt --> file1.txt\n");
+
+ si = (union smb_setfileinfo) {
+ .rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION,
+ .rename_information.in.file.handle = h2,
+ .rename_information.in.new_name =
+ BASEDIR "\\file1.txt",
+ };
+ status = smb2_setinfo_file(tree1, &si);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ torture_comment(torture, "GetInfo of file1.txt\n");
+
+ gi = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h2,
+ };
+
+ status = smb2_getinfo_file(tree1, torture, &gi);
+ torture_assert_ntstatus_ok_goto(torture, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(torture, "Check if timestamps are good after rename(file2.txt --> file1.txt).\n");
+
+ torture_assert_nttime_equal(
+ torture, c2.out.write_time, gi.all_info.out.write_time,
+ "Bad timestamp\n");
+ torture_assert_nttime_equal(
+ torture, c2.out.change_time, gi.all_info.out.change_time,
+ "Bad timestamp\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree1, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree1, h2);
+ }
+ smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+static bool test_smb2_close_full_information(struct torture_context *torture,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ union smb_close cl;
+ struct smb2_create io = {0};
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ union smb_setfileinfo sinfo;
+ NTSTATUS status;
+ const char *fname_src = "request.dat";
+ const char *fname_dst = "renamed.dat";
+ bool ret = true;
+
+ /* Start with a tidy share. */
+ smb2_util_unlink(tree1, fname_src);
+ smb2_util_unlink(tree1, fname_dst);
+
+ /* Create the test file, and leave it open. */
+ io.in.fname = fname_src;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tree1, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.out.file.handle;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ /* Open the test file on the second connection. */
+ ZERO_STRUCT(io);
+ io.in.fname = fname_src;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree2, tree2, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.out.file.handle;
+
+ /* Now open for rename on the first connection. */
+ ZERO_STRUCT(io);
+ io.in.fname = fname_src;
+ io.in.desired_access = SEC_STD_DELETE | SEC_FILE_READ_ATTRIBUTE;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree1, tree1, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+
+ /* Do the rename. */
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h3;
+ sinfo.rename_information.in.new_name = fname_dst;
+ status = smb2_setinfo_file(tree1, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* And close h3. */
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h3;
+ status = smb2_close(tree1, &cl.smb2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(h3);
+
+ /*
+ * Close h1 with SMB2_CLOSE_FLAGS_FULL_INFORMATION.
+ * Ensure we get data.
+ */
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ cl.smb2.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
+ status = smb2_close(tree1, &cl.smb2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(h1);
+ CHECK_VAL(cl.smb2.out.file_attr, 0x20);
+
+ /*
+ * Wait 3 seconds for name change to propagate
+ * to the other connection.
+ */
+ sleep(3);
+
+ /*
+ * Close h2 with SMB2_CLOSE_FLAGS_FULL_INFORMATION.
+ * This is on connection2.
+ * Ensure we get data.
+ */
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h2;
+ cl.smb2.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
+ status = smb2_close(tree2, &cl.smb2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ZERO_STRUCT(h2);
+ CHECK_VAL(cl.smb2.out.file_attr, 0x20);
+
+ done:
+
+ if (h1.data[0] != 0 || h1.data[1] != 0) {
+ smb2_util_close(tree1, h1);
+ }
+ if (h2.data[0] != 0 || h2.data[1] != 0) {
+ smb2_util_close(tree2, h2);
+ }
+ if (h3.data[0] != 0 || h3.data[1] != 0) {
+ smb2_util_close(tree1, h3);
+ }
+
+ smb2_util_unlink(tree1, fname_src);
+ smb2_util_unlink(tree1, fname_dst);
+
+ return ret;
+}
+
+/*
+ basic testing of SMB2 rename
+ */
+struct torture_suite *torture_smb2_rename_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "rename");
+
+ torture_suite_add_1smb2_test(suite, "simple",
+ torture_smb2_rename_simple);
+
+ torture_suite_add_1smb2_test(suite, "simple_modtime",
+ torture_smb2_rename_simple_modtime);
+
+ torture_suite_add_1smb2_test(suite, "simple_nodelete",
+ torture_smb2_rename_simple2);
+
+ torture_suite_add_1smb2_test(suite, "no_sharing",
+ torture_smb2_rename_no_sharemode);
+
+ torture_suite_add_1smb2_test(suite,
+ "share_delete_and_delete_access",
+ torture_smb2_rename_with_delete_access);
+
+ torture_suite_add_1smb2_test(suite,
+ "no_share_delete_but_delete_access",
+ torture_smb2_rename_with_delete_access2);
+
+ torture_suite_add_1smb2_test(suite,
+ "share_delete_no_delete_access",
+ torture_smb2_rename_no_delete_access);
+
+ torture_suite_add_1smb2_test(suite,
+ "no_share_delete_no_delete_access",
+ torture_smb2_rename_no_delete_access2);
+
+ torture_suite_add_1smb2_test(suite,
+ "msword",
+ torture_smb2_rename_msword);
+
+ torture_suite_add_1smb2_test(
+ suite, "rename_dir_openfile",
+ torture_smb2_rename_dir_openfile);
+
+ torture_suite_add_1smb2_test(suite,
+ "rename_dir_bench",
+ torture_smb2_rename_dir_bench);
+
+ torture_suite_add_2smb2_test(suite,
+ "close-full-information",
+ test_smb2_close_full_information);
+
+ suite->description = talloc_strdup(suite, "smb2.rename tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c
new file mode 100644
index 0000000..d84ced8
--- /dev/null
+++ b/source4/torture/smb2/replay.c
@@ -0,0 +1,5515 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 replay
+
+ Copyright (C) Anubhav Rakshit 2014
+ Copyright (C) Stefan Metzmacher 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/security/security.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/param/param.h"
+#include "lib/events/events.h"
+#include "oplock_break_handler.h"
+#include "lease_break_handler.h"
+
+#define CHECK_VAL(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
+ nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_CREATED(__io, __created, __attribute) \
+ do { \
+ CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
+ CHECK_VAL((__io)->out.size, 0); \
+ CHECK_VAL((__io)->out.file_attr, (__attribute)); \
+ CHECK_VAL((__io)->out.reserved2, 0); \
+ } while(0)
+
+#define CHECK_HANDLE(__h1, __h2) \
+ do { \
+ CHECK_VAL((__h1)->data[0], (__h2)->data[0]); \
+ CHECK_VAL((__h1)->data[1], (__h2)->data[1]); \
+ } while(0)
+
+#define __IO_OUT_VAL(__io1, __io2, __m) \
+ CHECK_VAL((__io1)->out.__m, (__io2)->out.__m)
+
+#define CHECK_CREATE_OUT(__io1, __io2) \
+ do { \
+ CHECK_HANDLE(&(__io1)->out.file.handle, \
+ &(__io2)->out.file.handle); \
+ __IO_OUT_VAL(__io1, __io2, oplock_level); \
+ __IO_OUT_VAL(__io1, __io2, create_action); \
+ __IO_OUT_VAL(__io1, __io2, create_time); \
+ __IO_OUT_VAL(__io1, __io2, access_time); \
+ __IO_OUT_VAL(__io1, __io2, write_time); \
+ __IO_OUT_VAL(__io1, __io2, change_time); \
+ __IO_OUT_VAL(__io1, __io2, alloc_size); \
+ __IO_OUT_VAL(__io1, __io2, size); \
+ __IO_OUT_VAL(__io1, __io2, file_attr); \
+ __IO_OUT_VAL(__io1, __io2, durable_open); \
+ __IO_OUT_VAL(__io1, __io2, durable_open_v2); \
+ __IO_OUT_VAL(__io1, __io2, persistent_open); \
+ __IO_OUT_VAL(__io1, __io2, timeout); \
+ __IO_OUT_VAL(__io1, __io2, blobs.num_blobs); \
+ if ((__io1)->out.oplock_level == SMB2_OPLOCK_LEVEL_LEASE) { \
+ __IO_OUT_VAL(__io1, __io2, lease_response.lease_state);\
+ __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[0]);\
+ __IO_OUT_VAL(__io1, __io2, lease_response.lease_key.data[1]);\
+ } \
+ } while(0)
+
+#define WAIT_FOR_ASYNC_RESPONSE(__tctx, __req) do { \
+ torture_comment((__tctx), "Waiting for async response: %s\n", #__req); \
+ while (!(__req)->cancel.can_cancel && (__req)->state <= SMB2_REQUEST_RECV) { \
+ if (tevent_loop_once((__tctx)->ev) != 0) { \
+ break; \
+ } \
+ } \
+} while(0)
+
+#define BASEDIR "replaytestdir"
+
+/**
+ * Test what happens when SMB2_FLAGS_REPLAY_OPERATION is enabled for various
+ * commands. We want to verify if the server returns an error code or not.
+ */
+static bool test_replay_commands(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[200];
+ struct smb2_read rd;
+ union smb_setfileinfo sfinfo;
+ union smb_fileinfo qfinfo;
+ union smb_ioctl ioctl;
+ struct smb2_lock lck;
+ struct smb2_lock_element el[2];
+ struct smb2_flush f;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ const char *fname = BASEDIR "\\replay_commands.dat";
+ struct smb2_transport *transport = tree->session->transport;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "Replay tests\n");
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+
+ torture_comment(tctx, "Try Commands with Replay Flags Enabled\n");
+
+ torture_comment(tctx, "Trying create\n");
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 0);
+ /*
+ * Wireshark shows that the response has SMB2_FLAGS_REPLAY_OPERATION
+ * flags set. The server should ignore this flag.
+ */
+
+ torture_comment(tctx, "Trying write\n");
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ f = (struct smb2_flush) {
+ .in.file.handle = h
+ };
+ torture_comment(tctx, "Trying flush\n");
+ status = smb2_flush(tree, &f);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ rd = (struct smb2_read) {
+ .in.file.handle = h,
+ .in.length = 10,
+ .in.offset = 0,
+ .in.min_count = 1
+ };
+ torture_comment(tctx, "Trying read\n");
+ status = smb2_read(tree, tmp_ctx, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(rd.out.data.length, 10);
+
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.position_information.in.file.handle = h;
+ sfinfo.position_information.in.position = 0x1000;
+ torture_comment(tctx, "Trying setinfo\n");
+ status = smb2_setinfo_file(tree, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ qfinfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
+ .generic.in.file.handle = h
+ };
+ torture_comment(tctx, "Trying getinfo\n");
+ status = smb2_getinfo_file(tree, tmp_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
+
+ ioctl = (union smb_ioctl) {
+ .smb2.level = RAW_IOCTL_SMB2,
+ .smb2.in.file.handle = h,
+ .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
+ .smb2.in.max_output_response = 64,
+ .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL
+ };
+ torture_comment(tctx, "Trying ioctl\n");
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck = (struct smb2_lock) {
+ .in.locks = el,
+ .in.lock_count = 0x0001,
+ .in.lock_sequence = 0x00000000,
+ .in.file.handle = h
+ };
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+
+ torture_comment(tctx, "Trying lock\n");
+ el[0].offset = 0x0000000000000000;
+ el[0].length = 0x0000000000000100;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ lck.in.file.handle = h;
+ el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ CHECK_VAL(break_info.count, 0);
+done:
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+/**
+ * Test replay detection without create GUID on single channel.
+ * Regular creates can not be replayed.
+ * The return code is unaffected of the REPLAY_OPERATION flag.
+ */
+static bool test_replay_regular(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ uint32_t perms = 0;
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay_regular.dat";
+ struct smb2_transport *transport = tree->session->transport;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ CHECK_VAL(break_info.count, 0);
+
+ torture_comment(tctx, "No replay detection for regular create\n");
+
+ perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE |
+ SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE |
+ SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA |
+ SEC_FILE_WRITE_DATA;
+
+ io = (struct smb2_create) {
+ .in.desired_access = perms,
+ .in.file_attributes = 0,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_DELETE,
+ .in.create_options = 0x0,
+ .in.fname = fname
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, tctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree, *h);
+ h = NULL;
+ smb2_util_unlink(tree, fname);
+
+ /*
+ * Same experiment with different create disposition.
+ */
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, tctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_util_close(tree, *h);
+ h = NULL;
+ smb2_util_unlink(tree, fname);
+
+ /*
+ * Now with more generous share mode.
+ */
+ io.in.share_access = smb2_util_share_access("RWD");
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 0);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, tctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(break_info.count, 0);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Durability V2 Create Replay Detection on Single Channel.
+ */
+static bool test_replay_dhv2_oplock1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io, ref1;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+ "Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ref1 = io;
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+
+ /*
+ * Replay Durable V2 Create on single channel
+ */
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io, &ref1);
+ CHECK_VAL(break_info.count, 0);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Durability V2 Create Replay Detection on Single Channel.
+ * Hand in a different oplock level in the replay.
+ * Server responds with the handed in oplock level and
+ * corresponding durable status, but does not change the
+ * oplock level or durable status of the opened file.
+ */
+static bool test_replay_dhv2_oplock2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io, ref1, ref2;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay_dhv2_oplock2.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+ "Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ref1 = io;
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+
+ /*
+ * Replay durable v2 create on single channel:
+ *
+ * Replay the create with a different oplock (none).
+ * The server replies with the requested oplock level
+ * and also only replies with durable handle based
+ * on whether it could have been granted based on
+ * the requested oplock type.
+ */
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level(""));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ /*
+ * Adapt the response to the expected values
+ */
+ ref2 = ref1;
+ ref2.out.oplock_level = smb2_util_oplock_level("");
+ ref2.out.durable_open_v2 = false;
+ ref2.out.timeout = 0;
+ ref2.out.blobs.num_blobs = 0;
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io, &ref2);
+ CHECK_VAL(break_info.count, 0);
+
+ /*
+ * Prove that the open file still has a batch oplock
+ * by breaking it with another open.
+ */
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = GUID_random();
+ io.in.timeout = UINT32_MAX;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ if (!share_is_so) {
+ CHECK_VAL(break_info.count, 1);
+ CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
+ CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
+ torture_reset_break_info(tctx, &break_info);
+ }
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Durability V2 Create Replay Detection on Single Channel.
+ * Replay with a different share mode. The share mode of
+ * the opened file is not changed by this.
+ */
+static bool test_replay_dhv2_oplock3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io, ref1;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay_dhv2_oplock3.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+ "Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ref1 = io;
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+
+ /*
+ * Replay durable v2 create on single channel:
+ *
+ * Replay the create with a different share mode.
+ * The server replies with the requested share
+ * mode instead of that which is associated to
+ * the handle.
+ */
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io, &ref1);
+ CHECK_VAL(break_info.count, 0);
+
+ /*
+ * In order to prove that the different share mode in the
+ * replayed create had no effect on the open file handle,
+ * show that a new create yields NT_STATUS_SHARING_VIOLATION.
+ */
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = GUID_random();
+ io.in.timeout = UINT32_MAX;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ if (!share_is_so) {
+ CHECK_VAL(break_info.count, 1);
+ CHECK_HANDLE(&break_info.handle, &ref1.out.file.handle);
+ CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
+ torture_reset_break_info(tctx, &break_info);
+ }
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Durability V2 Create Replay Detection on Single Channel.
+ * Create with an oplock, and replay with a lease.
+ */
+static bool test_replay_dhv2_oplock_lease(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay_dhv2_oplock1.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+ struct smb2_lease ls;
+ uint64_t lease_key;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 on Single "
+ "Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+
+ /*
+ * Replay Durable V2 Create on single channel
+ * but replay it with a lease instead of an oplock.
+ */
+ lease_key = random();
+ smb2_lease_create(&io, &ls, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RH"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * Test durability v2 create replay detection on single channel.
+ * Variant with leases instead of oplocks:
+ * - open a file with a rh lease
+ * - upgrade to a rwh lease with a second create
+ * - replay the first create.
+ * ==> it gets back the upgraded lease level
+ */
+static bool test_replay_dhv2_lease1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h2;
+ struct smb2_handle *h2 = NULL;
+ struct smb2_create io1, io2, ref1;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay2_lease1.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+ struct smb2_lease ls1, ls2;
+ uint64_t lease_key;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+ "on Single Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key = random();
+
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RH"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ref1 = io1;
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+ if (share_is_so) {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("R"));
+ CHECK_VAL(io1.out.durable_open_v2, false);
+ CHECK_VAL(io1.out.timeout, 0);
+ } else {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+ }
+
+ /*
+ * Upgrade the lease to RWH
+ */
+ smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RHW"));
+ io2.in.durable_open = false;
+ io2.in.durable_open_v2 = true;
+ io2.in.persistent_open = false;
+ io2.in.create_guid = GUID_random(); /* new guid... */
+ io2.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h2 = io2.out.file.handle;
+ h2 = &_h2;
+
+ /*
+ * Replay Durable V2 Create on single channel.
+ * We get the io from open #1 but with the
+ * upgraded lease.
+ */
+
+ /* adapt expected lease in response */
+ if (!share_is_so) {
+ ref1.out.lease_response.lease_state =
+ smb2_util_lease_state("RHW");
+ }
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io1);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io1, &ref1);
+ CHECK_VAL(break_info.count, 0);
+
+done:
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+ if (h2 != NULL) {
+ smb2_util_close(tree, *h2);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test durability v2 create replay detection on single channel.
+ * Variant with leases instead of oplocks, where the
+ * replay does not specify the original lease level but
+ * just a "R" lease. This still gives the upgraded lease
+ * level in the reply.
+ * - open a file with a rh lease
+ * - upgrade to a rwh lease with a second create
+ * - replay the first create.
+ * ==> it gets back the upgraded lease level
+ */
+static bool test_replay_dhv2_lease2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h2;
+ struct smb2_handle *h2 = NULL;
+ struct smb2_create io1, io2, ref1;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay2_lease2.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+ struct smb2_lease ls1, ls2;
+ uint64_t lease_key;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+ "on Single Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key = random();
+
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RH"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+ if (share_is_so) {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("R"));
+ CHECK_VAL(io1.out.durable_open_v2, false);
+ CHECK_VAL(io1.out.timeout, 0);
+ } else {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+ }
+ ref1 = io1;
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+
+ /*
+ * Upgrade the lease to RWH
+ */
+ smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RHW"));
+ io2.in.durable_open = false;
+ io2.in.durable_open_v2 = true;
+ io2.in.persistent_open = false;
+ io2.in.create_guid = GUID_random(); /* new guid... */
+ io2.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h2 = io2.out.file.handle;
+ h2 = &_h2;
+
+ /*
+ * Replay Durable V2 Create on single channel.
+ * Changing the requested lease level to "R"
+ * does not change the response:
+ * We get the reply from open #1 but with the
+ * upgraded lease.
+ */
+
+ /* adapt the expected response */
+ if (!share_is_so) {
+ ref1.out.lease_response.lease_state =
+ smb2_util_lease_state("RHW");
+ }
+
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("R"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid;
+ io1.in.timeout = UINT32_MAX;
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io1);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io1, &ref1);
+ CHECK_VAL(break_info.count, 0);
+
+done:
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+ if (h2 != NULL) {
+ smb2_util_close(tree, *h2);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test durability v2 create replay detection on single channel.
+ * create with a lease, and replay with a different lease key
+ */
+static bool test_replay_dhv2_lease3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h2;
+ struct smb2_handle *h2 = NULL;
+ struct smb2_create io1, io2;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay2_lease2.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+ struct smb2_lease ls1, ls2;
+ uint64_t lease_key;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+ "on Single Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key = random();
+
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RH"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+ if (share_is_so) {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("R"));
+ CHECK_VAL(io1.out.durable_open_v2, false);
+ CHECK_VAL(io1.out.timeout, 0);
+ } else {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+ }
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+
+ /*
+ * Upgrade the lease to RWH
+ */
+ smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RHW"));
+ io2.in.durable_open = false;
+ io2.in.durable_open_v2 = true;
+ io2.in.persistent_open = false;
+ io2.in.create_guid = GUID_random(); /* new guid... */
+ io2.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h2 = io2.out.file.handle;
+ h2 = &_h2;
+
+ /*
+ * Replay Durable V2 Create on single channel.
+ * use a different lease key.
+ */
+
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ random() /* lease key */,
+ smb2_util_lease_state("RH"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid;
+ io1.in.timeout = UINT32_MAX;
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io1);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+ if (h2 != NULL) {
+ smb2_util_close(tree, *h2);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test durability v2 create replay detection on single channel.
+ * Do the original create with a lease, and do the replay
+ * with an oplock.
+ */
+static bool test_replay_dhv2_lease_oplock(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h2;
+ struct smb2_handle *h2 = NULL;
+ struct smb2_create io1, io2, ref1;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay2_lease1.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+ struct smb2_lease ls1, ls2;
+ uint64_t lease_key;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 with Lease "
+ "on Single Channel\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key = random();
+
+ smb2_lease_create(&io1, &ls1, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RH"));
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ref1 = io1;
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease_key);
+ CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease_key);
+ if (share_is_so) {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("R"));
+ CHECK_VAL(io1.out.durable_open_v2, false);
+ CHECK_VAL(io1.out.timeout, 0);
+ } else {
+ CHECK_VAL(io1.out.lease_response.lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+ }
+
+ /*
+ * Upgrade the lease to RWH
+ */
+ smb2_lease_create(&io2, &ls2, false /* dir */, fname,
+ lease_key, smb2_util_lease_state("RHW"));
+ io2.in.durable_open = false;
+ io2.in.durable_open_v2 = true;
+ io2.in.persistent_open = false;
+ io2.in.create_guid = GUID_random(); /* new guid... */
+ io2.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h2 = io2.out.file.handle;
+ h2 = &_h2;
+
+ /*
+ * Replay Durable V2 Create on single channel.
+ * We get the io from open #1 but with the
+ * upgraded lease.
+ */
+
+ smb2_oplock_create_share(&io2, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io2.in.durable_open = false;
+ io2.in.durable_open_v2 = true;
+ io2.in.persistent_open = false;
+ io2.in.create_guid = create_guid;
+ io2.in.timeout = UINT32_MAX;
+
+ /* adapt expected lease in response */
+ if (!share_is_so) {
+ ref1.out.lease_response.lease_state =
+ smb2_util_lease_state("RHW");
+ }
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io1);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io1, &ref1);
+ CHECK_VAL(break_info.count, 0);
+
+done:
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+ if (h2 != NULL) {
+ smb2_util_close(tree, *h2);
+ }
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel. It tests the case where the client2 open
+ * is deferred because it conflicts with a HANDLE lease,
+ * which is broken because the operation should otherwise
+ * return NT_STATUS_SHARING_VIOLATION.
+ *
+ * With a durablev2 request containing a create_guid:
+ * - client2_level = NONE:
+ * but without asking for an oplock nor a lease.
+ * - client2_level = BATCH:
+ * and asking for a batch oplock.
+ * - client2_level = LEASE
+ * and asking for an RWH lease.
+ *
+ * While another client holds a batch oplock or
+ * RWH lease. (client1_level => LEASE or BATCH).
+ *
+ * There are two modes of this test one, with releaseing
+ * the oplock/lease of client1 via close or ack.
+ * (release_op SMB2_OP_CLOSE/SMB2_OP_BREAK).
+ *
+ * Windows doesn't detect replays in this case and
+ * always result in NT_STATUS_SHARING_VIOLATION.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ */
+static bool _test_dhv2_pending1_vs_violation(struct torture_context *tctx,
+ const char *testname,
+ struct smb2_tree *tree1,
+ uint8_t client1_level,
+ uint8_t release_op,
+ struct smb2_tree *tree2,
+ uint8_t client2_level,
+ NTSTATUS orig21_reject_status,
+ NTSTATUS replay22_reject_status,
+ NTSTATUS replay23_reject_status)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle *h2f = NULL;
+ struct smb2_handle _h21;
+ struct smb2_handle *h21 = NULL;
+ struct smb2_handle _h23;
+ struct smb2_handle *h23 = NULL;
+ struct smb2_handle _h24;
+ struct smb2_handle *h24 = NULL;
+ struct smb2_create io1, io21, io22, io23, io24;
+ struct GUID create_guid1 = GUID_random();
+ struct GUID create_guid2 = GUID_random();
+ struct smb2_request *req21 = NULL;
+ struct smb2_request *req22 = NULL;
+ bool ret = true;
+ char fname[256];
+ struct smb2_transport *transport1 = tree1->session->transport;
+ uint32_t server_capabilities;
+ uint32_t share_capabilities;
+ struct smb2_lease ls1;
+ uint64_t lease_key1;
+ uint16_t lease_epoch1 = 0;
+ struct smb2_break op_ack1;
+ struct smb2_lease_break_ack lb_ack1;
+ struct smb2_lease ls2;
+ uint64_t lease_key2;
+ uint16_t lease_epoch2 = 0;
+ bool share_is_so;
+ struct smb2_transport *transport2 = tree2->session->transport;
+ int request_timeout2 = transport2->options.request_timeout;
+ struct smb2_session *session2 = tree2->session;
+ const char *hold_name = NULL;
+
+ switch (client1_level) {
+ case SMB2_OPLOCK_LEVEL_LEASE:
+ hold_name = "RWH Lease";
+ break;
+ case SMB2_OPLOCK_LEVEL_BATCH:
+ hold_name = "BATCH Oplock";
+ break;
+ default:
+ smb_panic(__location__);
+ break;
+ }
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
+ client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_skip(tctx, "leases are not supported");
+ }
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+ if (share_is_so) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "%s not supported on SCALEOUT share",
+ hold_name));
+ }
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
+ BASEDIR, testname, generate_random_str(tctx, 8));
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ ZERO_STRUCT(op_ack1);
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ ZERO_STRUCT(lb_ack1);
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ smb2_keepalive(transport1);
+ transport2->oplock.handler = torture_oplock_ack_handler;
+ transport2->oplock.private_data = tree2;
+ transport2->lease.handler = torture_lease_handler;
+ transport2->lease.private_data = tree2;
+ smb2_keepalive(transport2);
+
+ smb2_util_unlink(tree1, fname);
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key1 = random();
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
+ lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
+ } else {
+ smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ io1.in.share_access = 0;
+ io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid1;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RWH"));
+ } else {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+
+ lease_key2 = random();
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
+ lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
+ } else {
+ smb2_oplock_create(&io21, fname, client2_level);
+ }
+ io21.in.share_access = 0;
+ io21.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io21.in.desired_access = SEC_RIGHTS_FILE_READ;
+ io21.in.durable_open = false;
+ io21.in.durable_open_v2 = true;
+ io21.in.persistent_open = false;
+ io21.in.create_guid = create_guid2;
+ io21.in.timeout = UINT32_MAX;
+ io24 = io23 = io22 = io21;
+
+ req21 = smb2_create_send(tree2, &io21);
+ torture_assert(tctx, req21 != NULL, "req21");
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ const struct smb2_lease_break *lb =
+ &lease_break_info.lease_break;
+ const struct smb2_lease *l = &lb->current_lease;
+ const struct smb2_lease_key *k = &l->lease_key;
+
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ torture_assert(tctx,
+ lease_break_info.lease_transport == transport1,
+ "expect lease break on transport1\n");
+ CHECK_VAL(k->data[0], lease_key1);
+ CHECK_VAL(k->data[1], ~lease_key1);
+ /*
+ * With share none the handle lease
+ * is broken.
+ */
+ CHECK_VAL(lb->new_lease_state,
+ smb2_util_lease_state("RW"));
+ CHECK_VAL(lb->break_flags,
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
+ CHECK_VAL(lb->new_epoch, lease_epoch1+1);
+ lease_epoch1 += 1;
+
+ lb_ack1.in.lease.lease_key = lb->current_lease.lease_key;
+ lb_ack1.in.lease.lease_state = lb->new_lease_state;
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_assert(tctx,
+ break_info.received_transport == transport1,
+ "expect oplock break on transport1\n");
+ CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
+ CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+
+ op_ack1.in = break_info.br.in;
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ if (NT_STATUS_EQUAL(replay22_reject_status, NT_STATUS_SHARING_VIOLATION)) {
+ /*
+ * The server is broken and doesn't
+ * detect a replay, so we start an async
+ * request and send a lease break ack
+ * after 5 seconds in order to avoid
+ * the 35 second delay.
+ */
+ torture_comment(tctx, "Starting ASYNC Replay req22 expecting %s\n",
+ nt_errstr(replay22_reject_status));
+ smb2cli_session_start_replay(session2->smbXcli);
+ transport2->options.request_timeout = 15;
+ req22 = smb2_create_send(tree2, &io22);
+ torture_assert(tctx, req22 != NULL, "req22");
+ transport2->options.request_timeout = request_timeout2;
+ smb2cli_session_stop_replay(session2->smbXcli);
+
+ WAIT_FOR_ASYNC_RESPONSE(tctx, req22);
+ } else {
+ torture_comment(tctx, "SYNC Replay io22 expecting %s\n",
+ nt_errstr(replay22_reject_status));
+ smb2cli_session_start_replay(session2->smbXcli);
+ transport2->options.request_timeout = 5;
+ status = smb2_create(tree2, tctx, &io22);
+ CHECK_STATUS(status, replay22_reject_status);
+ transport2->options.request_timeout = request_timeout2;
+ smb2cli_session_stop_replay(session2->smbXcli);
+ }
+
+ /*
+ * We don't expect any action for 35 seconds
+ *
+ * But we sleep just 5 seconds before we
+ * ack the break.
+ */
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ if (release_op == SMB2_OP_CLOSE) {
+ torture_comment(tctx, "Closing h1\n");
+ smb2_util_close(tree1, _h1);
+ h1 = NULL;
+ } else {
+ torture_comment(tctx, "Acking lease_key1\n");
+ status = smb2_lease_break_ack(tree1, &lb_ack1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(lb_ack1.out.lease.lease_flags, 0);
+ CHECK_VAL(lb_ack1.out.lease.lease_state, lb_ack1.in.lease.lease_state);
+ CHECK_VAL(lb_ack1.out.lease.lease_key.data[0], lease_key1);
+ CHECK_VAL(lb_ack1.out.lease.lease_key.data[1], ~lease_key1);
+ CHECK_VAL(lb_ack1.out.lease.lease_duration, 0);
+ }
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ if (release_op == SMB2_OP_CLOSE) {
+ torture_comment(tctx, "Closing h1\n");
+ smb2_util_close(tree1, _h1);
+ h1 = NULL;
+ } else {
+ torture_comment(tctx, "Acking break h1\n");
+ status = smb2_break(tree1, &op_ack1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(op_ack1.out.oplock_level, op_ack1.in.oplock_level);
+ }
+ }
+
+ torture_comment(tctx, "Checking req21 expecting %s\n",
+ nt_errstr(orig21_reject_status));
+ status = smb2_create_recv(req21, tctx, &io21);
+ CHECK_STATUS(status, orig21_reject_status);
+ if (NT_STATUS_IS_OK(orig21_reject_status)) {
+ _h21 = io21.out.file.handle;
+ h21 = &_h21;
+ if (h2f == NULL) {
+ h2f = h21;
+ }
+ CHECK_VAL(h21->data[0], h2f->data[0]);
+ CHECK_VAL(h21->data[1], h2f->data[1]);
+ CHECK_CREATED(&io21, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io21.out.oplock_level, client2_level);
+ CHECK_VAL(io21.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io21.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io21.out.durable_open_v2, true);
+ CHECK_VAL(io21.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io21.out.durable_open_v2, true);
+ CHECK_VAL(io21.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io21.out.durable_open_v2, false);
+ }
+ }
+
+ if (NT_STATUS_EQUAL(replay22_reject_status, NT_STATUS_SHARING_VIOLATION)) {
+ torture_comment(tctx, "Checking req22 expecting %s\n",
+ nt_errstr(replay22_reject_status));
+ status = smb2_create_recv(req22, tctx, &io22);
+ CHECK_STATUS(status, replay22_reject_status);
+ }
+
+ torture_comment(tctx, "SYNC Replay io23 expecting %s\n",
+ nt_errstr(replay23_reject_status));
+ smb2cli_session_start_replay(session2->smbXcli);
+ transport2->options.request_timeout = 5;
+ status = smb2_create(tree2, tctx, &io23);
+ transport2->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, replay23_reject_status);
+ smb2cli_session_stop_replay(session2->smbXcli);
+ if (NT_STATUS_IS_OK(replay23_reject_status)) {
+ _h23 = io23.out.file.handle;
+ h23 = &_h23;
+ if (h2f == NULL) {
+ h2f = h23;
+ }
+ CHECK_VAL(h23->data[0], h2f->data[0]);
+ CHECK_VAL(h23->data[1], h2f->data[1]);
+ CHECK_CREATED(&io23, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io23.out.oplock_level, client2_level);
+ CHECK_VAL(io23.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io23.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io23.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io23.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io23.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io23.out.durable_open_v2, true);
+ CHECK_VAL(io23.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io23.out.durable_open_v2, true);
+ CHECK_VAL(io23.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io23.out.durable_open_v2, false);
+ }
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ if (h1 != NULL) {
+ torture_comment(tctx, "Closing h1\n");
+ smb2_util_close(tree1, _h1);
+ h1 = NULL;
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_comment(tctx, "SYNC Replay io24 expecting %s\n",
+ nt_errstr(NT_STATUS_OK));
+ smb2cli_session_start_replay(session2->smbXcli);
+ transport2->options.request_timeout = 5;
+ status = smb2_create(tree2, tctx, &io24);
+ transport2->options.request_timeout = request_timeout2;
+ smb2cli_session_stop_replay(session2->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h24 = io24.out.file.handle;
+ h24 = &_h24;
+ if (h2f == NULL) {
+ h2f = h24;
+ }
+ CHECK_VAL(h24->data[0], h2f->data[0]);
+ CHECK_VAL(h24->data[1], h2f->data[1]);
+ CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io24.out.oplock_level, client2_level);
+ CHECK_VAL(io24.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io24.out.durable_open_v2, false);
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+ status = smb2_util_close(tree2, *h24);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h24 = NULL;
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+done:
+
+ smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+
+ TALLOC_FREE(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * This tests replay with a pending open on a single
+ * channel. It tests the case where the client2 open
+ * is deferred because it conflicts with a HANDLE lease,
+ * which is broken because the operation should otherwise
+ * return NT_STATUS_SHARING_VIOLATION.
+ *
+ * With a durablev2 request containing a create_guid,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease,
+ * which is released by a close.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_SHARING_VIOLATION to the replay (after
+ * 35 seconds), and this tests reports NT_STATUS_IO_TIMEOUT,
+ * as it expects a NT_STATUS_FILE_NOT_AVAILABLE within 5 seconds.
+ * see test_dhv2_pending1n_vs_violation_lease_close_windows().
+ */
+static bool test_dhv2_pending1n_vs_violation_lease_close_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_violation(tctx, __func__,
+ tree1,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OP_CLOSE,
+ tree2,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_OK,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ NT_STATUS_OK);
+}
+
+/*
+ * This tests replay with a pending open on a single
+ * channel. It tests the case where the client2 open
+ * is deferred because it conflicts with a HANDLE lease,
+ * which is broken because the operation should otherwise
+ * return NT_STATUS_SHARING_VIOLATION.
+ *
+ * With a durablev2 request containing a create_guid,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease,
+ * which is released by a close.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange behavior of ignoring the
+ * replay, which is returned done by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE
+ * see test_dhv2_pending1n_vs_violation_lease_close_sane().
+ */
+static bool test_dhv2_pending1n_vs_violation_lease_close_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_violation(tctx, __func__,
+ tree1,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OP_CLOSE,
+ tree2,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_OK,
+ NT_STATUS_SHARING_VIOLATION,
+ NT_STATUS_OK);
+}
+
+/*
+ * This tests replay with a pending open on a single
+ * channel. It tests the case where the client2 open
+ * is deferred because it conflicts with a HANDLE lease,
+ * which is broken because the operation should otherwise
+ * return NT_STATUS_SHARING_VIOLATION.
+ *
+ * With a durablev2 request containing a create_guid,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease,
+ * which is released by a lease break ack.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_SHARING_VIOLATION to the replay (after
+ * 35 seconds), and this tests reports NT_STATUS_IO_TIMEOUT,
+ * as it expects a NT_STATUS_FILE_NOT_AVAILABLE within 5 seconds.
+ * see test_dhv2_pending1n_vs_violation_lease_ack_windows().
+ */
+static bool test_dhv2_pending1n_vs_violation_lease_ack_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_violation(tctx, __func__,
+ tree1,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OP_BREAK,
+ tree2,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_SHARING_VIOLATION,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ NT_STATUS_SHARING_VIOLATION);
+}
+
+/*
+ * This tests replay with a pending open on a single
+ * channel. It tests the case where the client2 open
+ * is deferred because it conflicts with a HANDLE lease,
+ * which is broken because the operation should otherwise
+ * return NT_STATUS_SHARING_VIOLATION.
+ *
+ * With a durablev2 request containing a create_guid,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease,
+ * which is released by a close.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange behavior of ignoring the
+ * replay, which is returned done by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE
+ * see test_dhv2_pending1n_vs_violation_lease_ack_sane().
+ */
+static bool test_dhv2_pending1n_vs_violation_lease_ack_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_violation(tctx, __func__,
+ tree1,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OP_BREAK,
+ tree2,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_SHARING_VIOLATION,
+ NT_STATUS_SHARING_VIOLATION,
+ NT_STATUS_SHARING_VIOLATION);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid and
+ * a share_access of READ/WRITE/DELETE:
+ * - client2_level = NONE:
+ * but without asking for an oplock nor a lease.
+ * - client2_level = BATCH:
+ * and asking for a batch oplock.
+ * - client2_level = LEASE
+ * and asking for an RWH lease.
+ *
+ * While another client holds a batch oplock or
+ * RWH lease. (client1_level => LEASE or BATCH).
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ */
+static bool _test_dhv2_pending1_vs_hold(struct torture_context *tctx,
+ const char *testname,
+ uint8_t client1_level,
+ uint8_t client2_level,
+ NTSTATUS reject_status,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h21;
+ struct smb2_handle *h21 = NULL;
+ struct smb2_handle _h24;
+ struct smb2_handle *h24 = NULL;
+ struct smb2_create io1, io21, io22, io23, io24;
+ struct GUID create_guid1 = GUID_random();
+ struct GUID create_guid2 = GUID_random();
+ struct smb2_request *req21 = NULL;
+ bool ret = true;
+ char fname[256];
+ struct smb2_transport *transport1 = tree1->session->transport;
+ uint32_t server_capabilities;
+ uint32_t share_capabilities;
+ struct smb2_lease ls1;
+ uint64_t lease_key1;
+ uint16_t lease_epoch1 = 0;
+ struct smb2_lease ls2;
+ uint64_t lease_key2;
+ uint16_t lease_epoch2 = 0;
+ bool share_is_so;
+ struct smb2_transport *transport2 = tree2->session->transport;
+ int request_timeout2 = transport2->options.request_timeout;
+ struct smb2_session *session2 = tree2->session;
+ const char *hold_name = NULL;
+
+ switch (client1_level) {
+ case SMB2_OPLOCK_LEVEL_LEASE:
+ hold_name = "RWH Lease";
+ break;
+ case SMB2_OPLOCK_LEVEL_BATCH:
+ hold_name = "BATCH Oplock";
+ break;
+ default:
+ smb_panic(__location__);
+ break;
+ }
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
+ client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_skip(tctx, "leases are not supported");
+ }
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+ if (share_is_so) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "%s not supported on SCALEOUT share",
+ hold_name));
+ }
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
+ BASEDIR, testname, generate_random_str(tctx, 8));
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ smb2_keepalive(transport1);
+ transport2->oplock.handler = torture_oplock_ack_handler;
+ transport2->oplock.private_data = tree2;
+ transport2->lease.handler = torture_lease_handler;
+ transport2->lease.private_data = tree2;
+ smb2_keepalive(transport2);
+
+ smb2_util_unlink(tree1, fname);
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key1 = random();
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
+ lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
+ } else {
+ smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ io1.in.share_access = smb2_util_share_access("RWD");
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid1;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ } else {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+
+ lease_key2 = random();
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
+ lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
+ } else {
+ smb2_oplock_create(&io21, fname, client2_level);
+ }
+ io21.in.share_access = smb2_util_share_access("RWD");
+ io21.in.durable_open = false;
+ io21.in.durable_open_v2 = true;
+ io21.in.persistent_open = false;
+ io21.in.create_guid = create_guid2;
+ io21.in.timeout = UINT32_MAX;
+ io24 = io23 = io22 = io21;
+
+ req21 = smb2_create_send(tree2, &io21);
+ torture_assert(tctx, req21 != NULL, "req21");
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ const struct smb2_lease_break *lb =
+ &lease_break_info.lease_break;
+ const struct smb2_lease *l = &lb->current_lease;
+ const struct smb2_lease_key *k = &l->lease_key;
+
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ torture_assert(tctx,
+ lease_break_info.lease_transport == transport1,
+ "expect lease break on transport1\n");
+ CHECK_VAL(k->data[0], lease_key1);
+ CHECK_VAL(k->data[1], ~lease_key1);
+ CHECK_VAL(lb->new_lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(lb->break_flags,
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
+ CHECK_VAL(lb->new_epoch, lease_epoch1+1);
+ lease_epoch1 += 1;
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_assert(tctx,
+ break_info.received_transport == transport1,
+ "expect oplock break on transport1\n");
+ CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
+ CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2cli_session_start_replay(session2->smbXcli);
+ transport2->options.request_timeout = 5;
+ status = smb2_create(tree2, tctx, &io22);
+ transport2->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, reject_status);
+ smb2cli_session_stop_replay(session2->smbXcli);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2cli_session_start_replay(session2->smbXcli);
+ transport2->options.request_timeout = 5;
+ status = smb2_create(tree2, tctx, &io23);
+ transport2->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, reject_status);
+ smb2cli_session_stop_replay(session2->smbXcli);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_util_close(tree1, _h1);
+ h1 = NULL;
+
+ status = smb2_create_recv(req21, tctx, &io21);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h21 = io21.out.file.handle;
+ h21 = &_h21;
+ CHECK_CREATED(&io21, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io21.out.oplock_level, client2_level);
+ CHECK_VAL(io21.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io21.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io21.out.durable_open_v2, true);
+ CHECK_VAL(io21.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io21.out.durable_open_v2, true);
+ CHECK_VAL(io21.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io21.out.durable_open_v2, false);
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2cli_session_start_replay(session2->smbXcli);
+ status = smb2_create(tree2, tctx, &io24);
+ smb2cli_session_stop_replay(session2->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h24 = io24.out.file.handle;
+ h24 = &_h24;
+ CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(h24->data[0], h21->data[0]);
+ CHECK_VAL(h24->data[1], h21->data[1]);
+ CHECK_VAL(io24.out.oplock_level, client2_level);
+ CHECK_VAL(io24.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io24.out.durable_open_v2, false);
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+ status = smb2_util_close(tree2, *h24);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h24 = NULL;
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+done:
+
+ smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+
+ TALLOC_FREE(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending1n_vs_oplock_windows().
+ */
+static bool test_dhv2_pending1n_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending1n_vs_oplock_sane.
+ */
+static bool test_dhv2_pending1n_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending1n_vs_lease_windows().
+ */
+static bool test_dhv2_pending1n_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending1n_vs_lease_sane.
+ */
+static bool test_dhv2_pending1n_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending1l_vs_oplock_windows().
+ */
+static bool test_dhv2_pending1l_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending1l_vs_oplock_sane.
+ */
+static bool test_dhv2_pending1l_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending1l_vs_lease_windows().
+ */
+static bool test_dhv2_pending1l_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending1l_vs_lease_sane.
+ */
+static bool test_dhv2_pending1l_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending1o_vs_oplock_windows().
+ */
+static bool test_dhv2_pending1o_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending1o_vs_oplock_sane.
+ */
+static bool test_dhv2_pending1o_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending1o_vs_lease_windows().
+ */
+static bool test_dhv2_pending1o_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open on a single
+ * channel.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending1o_vs_lease_sane.
+ */
+static bool test_dhv2_pending1o_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ return _test_dhv2_pending1_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid and
+ * a share_access of READ/WRITE/DELETE:
+ * - client2_level = NONE:
+ * but without asking for an oplock nor a lease.
+ * - client2_level = BATCH:
+ * and asking for a batch oplock.
+ * - client2_level = LEASE
+ * and asking for an RWH lease.
+ *
+ * While another client holds a batch oplock or
+ * RWH lease. (client1_level => LEASE or BATCH).
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ */
+static bool _test_dhv2_pending2_vs_hold(struct torture_context *tctx,
+ const char *testname,
+ uint8_t client1_level,
+ uint8_t client2_level,
+ NTSTATUS reject_status,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h24;
+ struct smb2_handle *h24 = NULL;
+ struct smb2_create io1, io21, io22, io23, io24;
+ struct GUID create_guid1 = GUID_random();
+ struct GUID create_guid2 = GUID_random();
+ struct smb2_request *req21 = NULL;
+ bool ret = true;
+ char fname[256];
+ struct smb2_transport *transport1 = tree1->session->transport;
+ uint32_t server_capabilities;
+ uint32_t share_capabilities;
+ struct smb2_lease ls1;
+ uint64_t lease_key1;
+ uint16_t lease_epoch1 = 0;
+ struct smb2_lease ls2;
+ uint64_t lease_key2;
+ uint16_t lease_epoch2 = 0;
+ bool share_is_so;
+ struct smb2_transport *transport2_1 = tree2_1->session->transport;
+ int request_timeout2 = transport2_1->options.request_timeout;
+ struct smbcli_options options2x;
+ struct smb2_tree *tree2_2 = NULL;
+ struct smb2_tree *tree2_3 = NULL;
+ struct smb2_tree *tree2_4 = NULL;
+ struct smb2_transport *transport2_2 = NULL;
+ struct smb2_transport *transport2_3 = NULL;
+ struct smb2_transport *transport2_4 = NULL;
+ struct smb2_session *session2_1 = tree2_1->session;
+ struct smb2_session *session2_2 = NULL;
+ struct smb2_session *session2_3 = NULL;
+ struct smb2_session *session2_4 = NULL;
+ uint16_t csn2 = 1;
+ const char *hold_name = NULL;
+
+ switch (client1_level) {
+ case SMB2_OPLOCK_LEVEL_LEASE:
+ hold_name = "RWH Lease";
+ break;
+ case SMB2_OPLOCK_LEVEL_BATCH:
+ hold_name = "BATCH Oplock";
+ break;
+ default:
+ smb_panic(__location__);
+ break;
+ }
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx, "MULTI_CHANNEL are not supported");
+ }
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
+ client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_skip(tctx, "leases are not supported");
+ }
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+ if (share_is_so) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "%s not supported on SCALEOUT share",
+ hold_name));
+ }
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
+ BASEDIR, testname, generate_random_str(tctx, 8));
+
+ options2x = transport2_1->options;
+ options2x.only_negprot = true;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_2,
+ tctx->ev,
+ &options2x,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2_2 = tree2_2->session->transport;
+
+ session2_2 = smb2_session_channel(transport2_2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx,
+ session2_1);
+ torture_assert(tctx, session2_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_2,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2_2->smbXcli = tree2_1->smbXcli;
+ tree2_2->session = session2_2;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_3,
+ tctx->ev,
+ &options2x,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2_3 = tree2_3->session->transport;
+
+ session2_3 = smb2_session_channel(transport2_3,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx,
+ session2_1);
+ torture_assert(tctx, session2_3 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_3,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2_3->smbXcli = tree2_1->smbXcli;
+ tree2_3->session = session2_3;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_4,
+ tctx->ev,
+ &options2x,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2_4 = tree2_4->session->transport;
+
+ session2_4 = smb2_session_channel(transport2_4,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx,
+ session2_1);
+ torture_assert(tctx, session2_4 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_4,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2_4->smbXcli = tree2_1->smbXcli;
+ tree2_4->session = session2_4;
+
+ smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ smb2_keepalive(transport1);
+ transport2_1->oplock.handler = torture_oplock_ack_handler;
+ transport2_1->oplock.private_data = tree2_1;
+ transport2_1->lease.handler = torture_lease_handler;
+ transport2_1->lease.private_data = tree2_1;
+ smb2_keepalive(transport2_1);
+ transport2_2->oplock.handler = torture_oplock_ack_handler;
+ transport2_2->oplock.private_data = tree2_2;
+ transport2_2->lease.handler = torture_lease_handler;
+ transport2_2->lease.private_data = tree2_2;
+ smb2_keepalive(transport2_2);
+ transport2_3->oplock.handler = torture_oplock_ack_handler;
+ transport2_3->oplock.private_data = tree2_3;
+ transport2_3->lease.handler = torture_lease_handler;
+ transport2_3->lease.private_data = tree2_3;
+ smb2_keepalive(transport2_3);
+ transport2_4->oplock.handler = torture_oplock_ack_handler;
+ transport2_4->oplock.private_data = tree2_4;
+ transport2_4->lease.handler = torture_lease_handler;
+ transport2_4->lease.private_data = tree2_4;
+ smb2_keepalive(transport2_4);
+
+ smb2_util_unlink(tree1, fname);
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key1 = random();
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
+ lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
+ } else {
+ smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid1;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ } else {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+
+ lease_key2 = random();
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
+ lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
+ } else {
+ smb2_oplock_create(&io21, fname, client2_level);
+ }
+ io21.in.durable_open = false;
+ io21.in.durable_open_v2 = true;
+ io21.in.persistent_open = false;
+ io21.in.create_guid = create_guid2;
+ io21.in.timeout = UINT32_MAX;
+ io24 = io23 = io22 = io21;
+
+ req21 = smb2_create_send(tree2_1, &io21);
+ torture_assert(tctx, req21 != NULL, "req21");
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ const struct smb2_lease_break *lb =
+ &lease_break_info.lease_break;
+ const struct smb2_lease *l = &lb->current_lease;
+ const struct smb2_lease_key *k = &l->lease_key;
+
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ torture_assert(tctx,
+ lease_break_info.lease_transport == transport1,
+ "expect lease break on transport1\n");
+ CHECK_VAL(k->data[0], lease_key1);
+ CHECK_VAL(k->data[1], ~lease_key1);
+ CHECK_VAL(lb->new_lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(lb->break_flags,
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
+ CHECK_VAL(lb->new_epoch, lease_epoch1+1);
+ lease_epoch1 += 1;
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_assert(tctx,
+ break_info.received_transport == transport1,
+ "expect oplock break on transport1\n");
+ CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
+ CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smbXcli_conn_disconnect(transport2_1->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smb2cli_session_reset_channel_sequence(session2_1->smbXcli, csn2++);
+
+ smb2cli_session_start_replay(session2_2->smbXcli);
+ transport2_2->options.request_timeout = 5;
+ status = smb2_create(tree2_2, tctx, &io22);
+ transport2_2->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, reject_status);
+ smb2cli_session_stop_replay(session2_2->smbXcli);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smbXcli_conn_disconnect(transport2_2->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
+
+ smb2cli_session_start_replay(session2_3->smbXcli);
+ transport2_3->options.request_timeout = 5;
+ status = smb2_create(tree2_3, tctx, &io23);
+ transport2_3->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, reject_status);
+ smb2cli_session_stop_replay(session2_3->smbXcli);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_util_close(tree1, _h1);
+ h1 = NULL;
+
+ status = smb2_create_recv(req21, tctx, &io21);
+ CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smbXcli_conn_disconnect(transport2_3->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smb2cli_session_reset_channel_sequence(session2_3->smbXcli, csn2++);
+
+ smb2cli_session_start_replay(session2_4->smbXcli);
+ status = smb2_create(tree2_4, tctx, &io24);
+ smb2cli_session_stop_replay(session2_4->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h24 = io24.out.file.handle;
+ h24 = &_h24;
+ CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io24.out.oplock_level, client2_level);
+ CHECK_VAL(io24.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io24.out.durable_open_v2, false);
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+ status = smb2_util_close(tree2_4, *h24);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h24 = NULL;
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+done:
+
+ smbXcli_conn_disconnect(transport2_1->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2_2->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2_3->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2_4->conn, NT_STATUS_LOCAL_DISCONNECT);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+
+ TALLOC_FREE(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending2n_vs_lease_windows().
+ */
+static bool test_dhv2_pending2n_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending2n_vs_lease_sane().
+ */
+static bool test_dhv2_pending2n_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending2n_vs_oplock_windows().
+ */
+static bool test_dhv2_pending2n_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending2n_vs_oplock_sane().
+ */
+static bool test_dhv2_pending2n_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending2l_vs_oplock_windows().
+ */
+static bool test_dhv2_pending2l_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending2l_vs_oplock_sane().
+ */
+static bool test_dhv2_pending2l_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending2l_vs_oplock_windows().
+ */
+static bool test_dhv2_pending2l_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending2l_vs_oplock_sane().
+ */
+static bool test_dhv2_pending2l_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending2o_vs_oplock_windows().
+ */
+static bool test_dhv2_pending2o_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending2o_vs_oplock_sane().
+ */
+static bool test_dhv2_pending2o_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending2o_vs_lease_windows().
+ */
+static bool test_dhv2_pending2o_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and closed transports on the client and server side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending2o_vs_lease_sane().
+ */
+static bool test_dhv2_pending2o_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending2_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid and
+ * a share_access of READ/WRITE/DELETE:
+ * - client2_level = NONE:
+ * but without asking for an oplock nor a lease.
+ * - client2_level = BATCH:
+ * and asking for a batch oplock.
+ * - client2_level = LEASE
+ * and asking for an RWH lease.
+ *
+ * While another client holds a batch oplock or
+ * RWH lease. (client1_level => LEASE or BATCH).
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ */
+static bool _test_dhv2_pending3_vs_hold(struct torture_context *tctx,
+ const char *testname,
+ uint8_t client1_level,
+ uint8_t client2_level,
+ NTSTATUS reject_status,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h21;
+ struct smb2_handle *h21 = NULL;
+ struct smb2_handle _h24;
+ struct smb2_handle *h24 = NULL;
+ struct smb2_create io1, io21, io22, io23, io24;
+ struct GUID create_guid1 = GUID_random();
+ struct GUID create_guid2 = GUID_random();
+ struct smb2_request *req21 = NULL;
+ bool ret = true;
+ char fname[256];
+ struct smb2_transport *transport1 = tree1->session->transport;
+ uint32_t server_capabilities;
+ uint32_t share_capabilities;
+ struct smb2_lease ls1;
+ uint64_t lease_key1;
+ uint16_t lease_epoch1 = 0;
+ struct smb2_lease ls2;
+ uint64_t lease_key2;
+ uint16_t lease_epoch2 = 0;
+ bool share_is_so;
+ struct smb2_transport *transport2_1 = tree2_1->session->transport;
+ int request_timeout2 = transport2_1->options.request_timeout;
+ struct smbcli_options options2x;
+ struct smb2_tree *tree2_2 = NULL;
+ struct smb2_tree *tree2_3 = NULL;
+ struct smb2_tree *tree2_4 = NULL;
+ struct smb2_transport *transport2_2 = NULL;
+ struct smb2_transport *transport2_3 = NULL;
+ struct smb2_transport *transport2_4 = NULL;
+ struct smb2_session *session2_1 = tree2_1->session;
+ struct smb2_session *session2_2 = NULL;
+ struct smb2_session *session2_3 = NULL;
+ struct smb2_session *session2_4 = NULL;
+ bool block_setup = false;
+ bool blocked2_1 = false;
+ bool blocked2_2 = false;
+ bool blocked2_3 = false;
+ uint16_t csn2 = 1;
+ const char *hold_name = NULL;
+
+ switch (client1_level) {
+ case SMB2_OPLOCK_LEVEL_LEASE:
+ hold_name = "RWH Lease";
+ break;
+ case SMB2_OPLOCK_LEVEL_BATCH:
+ hold_name = "BATCH Oplock";
+ break;
+ default:
+ smb_panic(__location__);
+ break;
+ }
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx, "MULTI_CHANNEL are not supported");
+ }
+ if (!(server_capabilities & SMB2_CAP_LEASING)) {
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE ||
+ client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_skip(tctx, "leases are not supported");
+ }
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+ if (share_is_so) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "%s not supported on SCALEOUT share",
+ hold_name));
+ }
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s\\%s_%s.dat",
+ BASEDIR, testname, generate_random_str(tctx, 8));
+
+ options2x = transport2_1->options;
+ options2x.only_negprot = true;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_2,
+ tctx->ev,
+ &options2x,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2_2 = tree2_2->session->transport;
+
+ session2_2 = smb2_session_channel(transport2_2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx,
+ session2_1);
+ torture_assert(tctx, session2_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_2,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2_2->smbXcli = tree2_1->smbXcli;
+ tree2_2->session = session2_2;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_3,
+ tctx->ev,
+ &options2x,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2_3 = tree2_3->session->transport;
+
+ session2_3 = smb2_session_channel(transport2_3,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx,
+ session2_1);
+ torture_assert(tctx, session2_3 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_3,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2_3->smbXcli = tree2_1->smbXcli;
+ tree2_3->session = session2_3;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_4,
+ tctx->ev,
+ &options2x,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2_4 = tree2_4->session->transport;
+
+ session2_4 = smb2_session_channel(transport2_4,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx,
+ session2_1);
+ torture_assert(tctx, session2_4 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_4,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2_4->smbXcli = tree2_1->smbXcli;
+ tree2_4->session = session2_4;
+
+ smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+ transport1->lease.handler = torture_lease_handler;
+ transport1->lease.private_data = tree1;
+ smb2_keepalive(transport1);
+ transport2_1->oplock.handler = torture_oplock_ack_handler;
+ transport2_1->oplock.private_data = tree2_1;
+ transport2_1->lease.handler = torture_lease_handler;
+ transport2_1->lease.private_data = tree2_1;
+ smb2_keepalive(transport2_1);
+ transport2_2->oplock.handler = torture_oplock_ack_handler;
+ transport2_2->oplock.private_data = tree2_2;
+ transport2_2->lease.handler = torture_lease_handler;
+ transport2_2->lease.private_data = tree2_2;
+ smb2_keepalive(transport2_2);
+ transport2_3->oplock.handler = torture_oplock_ack_handler;
+ transport2_3->oplock.private_data = tree2_3;
+ transport2_3->lease.handler = torture_lease_handler;
+ transport2_3->lease.private_data = tree2_3;
+ smb2_keepalive(transport2_3);
+ transport2_4->oplock.handler = torture_oplock_ack_handler;
+ transport2_4->oplock.private_data = tree2_4;
+ transport2_4->lease.handler = torture_lease_handler;
+ transport2_4->lease.private_data = tree2_4;
+ smb2_keepalive(transport2_4);
+
+ smb2_util_unlink(tree1, fname);
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h1);
+ CHECK_VAL(break_info.count, 0);
+
+ lease_key1 = random();
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io1, &ls1, false /* dir */, fname,
+ lease_key1, NULL, smb2_util_lease_state("RWH"), lease_epoch1++);
+ } else {
+ smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ io1.in.durable_open = false;
+ io1.in.durable_open_v2 = true;
+ io1.in.persistent_open = false;
+ io1.in.create_guid = create_guid1;
+ io1.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io1.out.durable_open, false);
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[0], lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_key.data[1], ~lease_key1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_epoch, lease_epoch1);
+ CHECK_VAL(io1.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ } else {
+ CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
+ }
+ CHECK_VAL(io1.out.durable_open_v2, true);
+ CHECK_VAL(io1.out.timeout, 300*1000);
+
+ lease_key2 = random();
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ smb2_lease_v2_create(&io21, &ls2, false /* dir */, fname,
+ lease_key2, NULL, smb2_util_lease_state("RWH"), lease_epoch2++);
+ } else {
+ smb2_oplock_create(&io21, fname, client2_level);
+ }
+ io21.in.durable_open = false;
+ io21.in.durable_open_v2 = true;
+ io21.in.persistent_open = false;
+ io21.in.create_guid = create_guid2;
+ io21.in.timeout = UINT32_MAX;
+ io24 = io23 = io22 = io21;
+
+ req21 = smb2_create_send(tree2_1, &io21);
+ torture_assert(tctx, req21 != NULL, "req21");
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ const struct smb2_lease_break *lb =
+ &lease_break_info.lease_break;
+ const struct smb2_lease *l = &lb->current_lease;
+ const struct smb2_lease_key *k = &l->lease_key;
+
+ torture_wait_for_lease_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 1);
+
+ torture_assert(tctx,
+ lease_break_info.lease_transport == transport1,
+ "expect lease break on transport1\n");
+ CHECK_VAL(k->data[0], lease_key1);
+ CHECK_VAL(k->data[1], ~lease_key1);
+ CHECK_VAL(lb->new_lease_state,
+ smb2_util_lease_state("RH"));
+ CHECK_VAL(lb->break_flags,
+ SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
+ CHECK_VAL(lb->new_epoch, lease_epoch1+1);
+ lease_epoch1 += 1;
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ torture_assert(tctx,
+ break_info.received_transport == transport1,
+ "expect oplock break on transport1\n");
+ CHECK_VAL(break_info.handle.data[0], _h1.data[0]);
+ CHECK_VAL(break_info.handle.data[1], _h1.data[1]);
+ CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ break_info.oplock_skip_ack = true;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ WAIT_FOR_ASYNC_RESPONSE(tctx, req21);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ block_setup = test_setup_blocked_transports(tctx);
+ torture_assert(tctx, block_setup, "test_setup_blocked_transports");
+
+ blocked2_1 = _test_block_smb2_transport(tctx, transport2_1, "transport2_1");
+ torture_assert_goto(tctx, blocked2_1, ret, done, "we could not block tcp transport");
+ smb2cli_session_reset_channel_sequence(session2_1->smbXcli, csn2++);
+
+ smb2cli_session_start_replay(session2_2->smbXcli);
+ transport2_2->options.request_timeout = 5;
+ status = smb2_create(tree2_2, tctx, &io22);
+ transport2_2->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, reject_status);
+ smb2cli_session_stop_replay(session2_2->smbXcli);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ blocked2_2 = _test_block_smb2_transport(tctx, transport2_2, "transport2_2");
+ torture_assert_goto(tctx, blocked2_2, ret, done, "we could not block tcp transport");
+ smb2cli_session_reset_channel_sequence(session2_2->smbXcli, csn2++);
+
+ smb2cli_session_start_replay(session2_3->smbXcli);
+ transport2_3->options.request_timeout = 5;
+ status = smb2_create(tree2_3, tctx, &io23);
+ transport2_3->options.request_timeout = request_timeout2;
+ CHECK_STATUS(status, reject_status);
+ smb2cli_session_stop_replay(session2_3->smbXcli);
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ smb2_util_close(tree1, _h1);
+ h1 = NULL;
+
+ status = smb2_create_recv(req21, tctx, &io21);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h21 = io21.out.file.handle;
+ h21 = &_h21;
+ CHECK_CREATED(&io21, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io21.out.oplock_level, client2_level);
+ CHECK_VAL(io21.out.durable_open, false);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io21.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io21.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io21.out.durable_open_v2, true);
+ CHECK_VAL(io21.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io21.out.durable_open_v2, true);
+ CHECK_VAL(io21.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io21.out.durable_open_v2, false);
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+ blocked2_3 = _test_block_smb2_transport(tctx, transport2_3, "transport2_3");
+ torture_assert_goto(tctx, blocked2_3, ret, done, "we could not block tcp transport");
+ smb2cli_session_reset_channel_sequence(session2_3->smbXcli, csn2++);
+
+ smb2cli_session_start_replay(session2_4->smbXcli);
+ status = smb2_create(tree2_4, tctx, &io24);
+ smb2cli_session_stop_replay(session2_4->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h24 = io24.out.file.handle;
+ h24 = &_h24;
+ CHECK_CREATED(&io24, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(h24->data[0], h21->data[0]);
+ CHECK_VAL(h24->data[1], h21->data[1]);
+ if (client2_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[0], lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_key.data[1], ~lease_key2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_epoch, lease_epoch2);
+ CHECK_VAL(io24.out.lease_response_v2.lease_state,
+ smb2_util_lease_state("RHW"));
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else if (client2_level == SMB2_OPLOCK_LEVEL_BATCH) {
+ CHECK_VAL(io24.out.durable_open_v2, true);
+ CHECK_VAL(io24.out.timeout, 300*1000);
+ } else {
+ CHECK_VAL(io24.out.durable_open_v2, false);
+ }
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+ status = smb2_util_close(tree2_4, *h24);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h24 = NULL;
+
+ if (client1_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ torture_wait_for_lease_break(tctx);
+ } else {
+ torture_wait_for_oplock_break(tctx);
+ }
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(lease_break_info.count, 0);
+
+done:
+
+ if (blocked2_3) {
+ _test_unblock_smb2_transport(tctx, transport2_3, "transport2_3");
+ }
+ if (blocked2_2) {
+ _test_unblock_smb2_transport(tctx, transport2_2, "transport2_2");
+ }
+ if (blocked2_1) {
+ _test_unblock_smb2_transport(tctx, transport2_1, "transport2_1");
+ }
+ if (block_setup) {
+ test_cleanup_blocked_transports(tctx);
+ }
+
+ smbXcli_conn_disconnect(transport2_1->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2_2->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2_3->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2_4->conn, NT_STATUS_LOCAL_DISCONNECT);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_deltree(tree1, BASEDIR);
+
+ TALLOC_FREE(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending3n_vs_lease_windows().
+ */
+static bool test_dhv2_pending3n_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending3n_vs_lease_sane.
+ */
+static bool test_dhv2_pending3n_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending3n_vs_oplock_windows().
+ */
+static bool test_dhv2_pending3n_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * but without asking for an oplock nor a lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending3n_vs_oplock_sane.
+ */
+static bool test_dhv2_pending3n_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_NONE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending3l_vs_oplock_windows().
+ */
+static bool test_dhv2_pending3l_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending3l_vs_oplock_sane.
+ */
+static bool test_dhv2_pending3l_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending3l_vs_lease_windows().
+ */
+static bool test_dhv2_pending3l_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a v2 lease.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending3l_vs_lease_sane().
+ */
+static bool test_dhv2_pending3l_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending3o_vs_oplock_windows().
+ */
+static bool test_dhv2_pending3o_vs_oplock_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds a batch oplock.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending3o_vs_oplock_sane().
+ */
+static bool test_dhv2_pending3o_vs_oplock_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the sane reject status of
+ * NT_STATUS_FILE_NOT_AVAILABLE.
+ *
+ * It won't pass against Windows as it returns
+ * NT_STATUS_ACCESS_DENIED see
+ * test_dhv2_pending3o_vs_lease_windows().
+ */
+static bool test_dhv2_pending3o_vs_lease_sane(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_FILE_NOT_AVAILABLE,
+ tree1, tree2_1);
+}
+
+/**
+ * This tests replay with a pending open with 4 channels
+ * and blocked transports on the client side.
+ *
+ * With a durablev2 request containing a create_guid,
+ * a share_access of READ/WRITE/DELETE,
+ * and asking for a batch oplock.
+ *
+ * While another client holds an RWH lease.
+ * And allows share_access of READ/WRITE/DELETE.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14449
+ *
+ * This expects the strange reject status of
+ * NT_STATUS_ACCESS_DENIED, which is returned
+ * by Windows Servers.
+ *
+ * It won't pass against Samba as it returns
+ * NT_STATUS_FILE_NOT_AVAILABLE. see
+ * test_dhv2_pending3o_vs_lease_sane().
+ */
+static bool test_dhv2_pending3o_vs_lease_windows(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2_1)
+{
+ return _test_dhv2_pending3_vs_hold(tctx, __func__,
+ SMB2_OPLOCK_LEVEL_LEASE,
+ SMB2_OPLOCK_LEVEL_BATCH,
+ NT_STATUS_ACCESS_DENIED,
+ tree1, tree2_1);
+}
+
+static bool test_channel_sequence_table(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ bool do_replay,
+ uint16_t opcode)
+{
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle handle;
+ struct smb2_handle *phandle = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\channel_sequence.dat";
+ uint16_t csn = 0;
+ uint16_t limit = UINT16_MAX - 0x7fff;
+ int i;
+ struct {
+ uint16_t csn;
+ bool csn_rand_low;
+ bool csn_rand_high;
+ NTSTATUS expected_status;
+ } tests[] = {
+ {
+ .csn = 0,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 0x7fff + 1,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = 0x7fff + 2,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = -1,
+ .csn_rand_high = true,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = 0xffff,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = 0x7fff,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 0x7ffe,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = 0,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = -1,
+ .csn_rand_low = true,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = 0x7fff + 1,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 0xffff,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 0,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 1,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 0,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ },{
+ .csn = 1,
+ .expected_status = NT_STATUS_OK,
+ },{
+ .csn = 0xffff,
+ .expected_status = NT_STATUS_FILE_NOT_AVAILABLE,
+ }
+ };
+
+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
+
+ csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli);
+ torture_comment(tctx, "Testing create with channel sequence number: 0x%04x\n", csn);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ smb2_create(tree, mem_ctx, &io),
+ ret, done, "failed to call smb2_create");
+
+ handle = io.out.file.handle;
+ phandle = &handle;
+
+ for (i=0; i <ARRAY_SIZE(tests); i++) {
+
+ const char *opstr = "";
+ union smb_fileinfo qfinfo;
+
+ csn = tests[i].csn;
+
+ if (tests[i].csn_rand_low) {
+ csn = rand() % limit;
+ } else if (tests[i].csn_rand_high) {
+ csn = rand() % limit + 0x7fff;
+ }
+
+ switch (opcode) {
+ case SMB2_OP_WRITE:
+ opstr = "write";
+ break;
+ case SMB2_OP_IOCTL:
+ opstr = "ioctl";
+ break;
+ case SMB2_OP_SETINFO:
+ opstr = "setinfo";
+ break;
+ default:
+ break;
+ }
+
+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, csn);
+ csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli);
+
+ torture_comment(tctx, "Testing %s (replay: %s) with CSN 0x%04x, expecting: %s\n",
+ opstr, do_replay ? "true" : "false", csn,
+ nt_errstr(tests[i].expected_status));
+
+ if (do_replay) {
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ }
+
+ switch (opcode) {
+ case SMB2_OP_WRITE: {
+ DATA_BLOB blob = data_blob_talloc(tctx, NULL, 255);
+
+ generate_random_buffer(blob.data, blob.length);
+
+ status = smb2_util_write(tree, handle, blob.data, 0, blob.length);
+ if (NT_STATUS_IS_OK(status)) {
+ struct smb2_read rd;
+
+ rd = (struct smb2_read) {
+ .in.file.handle = handle,
+ .in.length = blob.length,
+ .in.offset = 0
+ };
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ smb2_read(tree, tree, &rd),
+ ret, done, "failed to read after write");
+
+ torture_assert_data_blob_equal(tctx,
+ rd.out.data, blob,
+ "read/write mismatch");
+ }
+ break;
+ }
+ case SMB2_OP_IOCTL: {
+ union smb_ioctl ioctl;
+ ioctl = (union smb_ioctl) {
+ .smb2.level = RAW_IOCTL_SMB2,
+ .smb2.in.file.handle = handle,
+ .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID,
+ .smb2.in.max_output_response = 64,
+ .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL
+ };
+ status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2);
+ break;
+ }
+ case SMB2_OP_SETINFO: {
+ union smb_setfileinfo sfinfo;
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = handle;
+ sfinfo.position_information.in.position = 0x1000;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ break;
+ }
+ default:
+ break;
+ }
+
+ qfinfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
+ .generic.in.file.handle = handle
+ };
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ smb2_getinfo_file(tree, mem_ctx, &qfinfo),
+ ret, done, "failed to read after write");
+
+ if (do_replay) {
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ }
+
+ torture_assert_ntstatus_equal_goto(tctx,
+ status, tests[i].expected_status,
+ ret, done, "got unexpected failure code");
+
+ }
+done:
+ if (phandle != NULL) {
+ smb2_util_close(tree, *phandle);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ return ret;
+}
+
+static bool test_channel_sequence(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ bool ret = true;
+ const char *fname = BASEDIR "\\channel_sequence.dat";
+ struct smb2_transport *transport1 = tree->session->transport;
+ struct smb2_handle handle;
+ uint16_t opcodes[] = { SMB2_OP_WRITE, SMB2_OP_IOCTL, SMB2_OP_SETINFO };
+ int i;
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "Replay tests\n");
+ }
+
+ torture_comment(tctx, "Testing channel sequence numbers\n");
+
+ smbXcli_conn_set_force_channel_sequence(transport1->conn, true);
+
+ torture_assert_ntstatus_ok_goto(tctx,
+ torture_smb2_testdir(tree, BASEDIR, &handle),
+ ret, done, "failed to setup test directory");
+
+ smb2_util_close(tree, handle);
+ smb2_util_unlink(tree, fname);
+
+ for (i=0; i <ARRAY_SIZE(opcodes); i++) {
+ torture_assert(tctx,
+ test_channel_sequence_table(tctx, tree, false, opcodes[i]),
+ "failed to test CSN without replay flag");
+ torture_assert(tctx,
+ test_channel_sequence_table(tctx, tree, true, opcodes[i]),
+ "failed to test CSN with replay flag");
+ }
+
+done:
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Durability V2 Create Replay Detection on Multi Channel
+ */
+static bool test_replay3(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay3.dat";
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2 = NULL;
+ struct smb2_session *session1_1 = tree1->session;
+ struct smb2_session *session1_2 = NULL;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "Replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx,
+ "Server does not support multi-channel.");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+
+ torture_comment(tctx, "Replay of DurableHandleReqV2 on Multi "
+ "Channel\n");
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h);
+ smb2_util_unlink(tree1, fname);
+ CHECK_VAL(break_info.count, 0);
+
+ /*
+ * use the 1st channel, 1st session
+ */
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ tree1->session = session1_1;
+ status = smb2_create(tree1, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(break_info.count, 0);
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree2,
+ tctx->ev,
+ &transport1->options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2 = tree2->session->transport;
+
+ transport2->oplock.handler = torture_oplock_ack_handler;
+ transport2->oplock.private_data = tree2;
+
+ /*
+ * Now bind the 1st session to 2nd transport channel
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2, session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_2,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * use the 2nd channel, 1st session
+ */
+ tree1->session = session1_2;
+ smb2cli_session_start_replay(tree1->session->smbXcli);
+ status = smb2_create(tree1, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree1->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(break_info.count, 0);
+
+ tree1->session = session1_1;
+ smb2_util_close(tree1, *h);
+ h = NULL;
+
+done:
+ talloc_free(tree2);
+ tree1->session = session1_1;
+
+ if (h != NULL) {
+ smb2_util_close(tree1, *h);
+ }
+
+ smb2_util_unlink(tree1, fname);
+ smb2_deltree(tree1, BASEDIR);
+
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Multichannel IO Ordering using ChannelSequence/Channel Epoch number
+ */
+static bool test_replay4(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ uint8_t buf[64];
+ struct smb2_read rd;
+ union smb_setfileinfo sfinfo;
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay4.dat";
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2 = NULL;
+ struct smb2_session *session1_1 = tree1->session;
+ struct smb2_session *session1_2 = NULL;
+ uint16_t curr_cs;
+ uint32_t share_capabilities;
+ bool share_is_so;
+ uint32_t server_capabilities;
+
+ if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "Replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(
+ tree1->session->transport->conn);
+ if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx,
+ "Server does not support multi-channel.");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree1->smbXcli);
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+
+ torture_reset_break_info(tctx, &break_info);
+ transport1->oplock.handler = torture_oplock_ack_handler;
+ transport1->oplock.private_data = tree1;
+
+ torture_comment(tctx, "IO Ordering for Multi Channel\n");
+ status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree1, _h1);
+ smb2_util_unlink(tree1, fname);
+ CHECK_VAL(break_info.count, 0);
+
+ /*
+ * use the 1st channel, 1st session
+ */
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ tree1->session = session1_1;
+ status = smb2_create(tree1, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h1 = io.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ if (share_is_so) {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s"));
+ CHECK_VAL(io.out.durable_open_v2, false);
+ CHECK_VAL(io.out.timeout, 0);
+ } else {
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ }
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(break_info.count, 0);
+
+ status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Increment ChannelSequence so that server thinks that there's a
+ * Channel Failure
+ */
+ smb2cli_session_increment_channel_sequence(tree1->session->smbXcli);
+
+ /*
+ * Perform a Read with incremented ChannelSequence
+ */
+ rd = (struct smb2_read) {
+ .in.file.handle = *h1,
+ .in.length = sizeof(buf),
+ .in.offset = 0
+ };
+ status = smb2_read(tree1, tree1, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Performing a Write with Stale ChannelSequence is not allowed by
+ * server
+ */
+ curr_cs = smb2cli_session_reset_channel_sequence(
+ tree1->session->smbXcli, 0);
+ status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
+
+ /*
+ * Performing a Write Replay with Stale ChannelSequence is not allowed
+ * by server
+ */
+ smb2cli_session_start_replay(tree1->session->smbXcli);
+ smb2cli_session_reset_channel_sequence(tree1->session->smbXcli, 0);
+ status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
+ smb2cli_session_stop_replay(tree1->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
+
+ /*
+ * Performing a SetInfo with stale ChannelSequence is not allowed by
+ * server
+ */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = *h1;
+ sfinfo.position_information.in.position = 0x1000;
+ status = smb2_setinfo_file(tree1, &sfinfo);
+ CHECK_STATUS(status, NT_STATUS_FILE_NOT_AVAILABLE);
+
+ /*
+ * Performing a Read with stale ChannelSequence is allowed
+ */
+ rd = (struct smb2_read) {
+ .in.file.handle = *h1,
+ .in.length = ARRAY_SIZE(buf),
+ .in.offset = 0
+ };
+ status = smb2_read(tree1, tree1, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree2,
+ tctx->ev,
+ &transport1->options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport2 = tree2->session->transport;
+
+ transport2->oplock.handler = torture_oplock_ack_handler;
+ transport2->oplock.private_data = tree2;
+
+ /*
+ * Now bind the 1st session to 2nd transport channel
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2, session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_2,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * use the 2nd channel, 1st session
+ */
+ tree1->session = session1_2;
+
+ /*
+ * Write Replay with Correct ChannelSequence is allowed by the server
+ */
+ smb2cli_session_start_replay(tree1->session->smbXcli);
+ smb2cli_session_reset_channel_sequence(tree1->session->smbXcli,
+ curr_cs);
+ status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2cli_session_stop_replay(tree1->session->smbXcli);
+
+ /*
+ * See what happens if we change the Buffer and perform a Write Replay.
+ * This is to show that Write Replay does not really care about the data
+ */
+ memset(buf, 'r', ARRAY_SIZE(buf));
+ smb2cli_session_start_replay(tree1->session->smbXcli);
+ status = smb2_util_write(tree1, *h1, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2cli_session_stop_replay(tree1->session->smbXcli);
+
+ /*
+ * Read back from File to verify what was written
+ */
+ rd = (struct smb2_read) {
+ .in.file.handle = *h1,
+ .in.length = ARRAY_SIZE(buf),
+ .in.offset = 0
+ };
+ status = smb2_read(tree1, tree1, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if ((rd.out.data.length != ARRAY_SIZE(buf)) ||
+ memcmp(rd.out.data.data, buf, ARRAY_SIZE(buf))) {
+ torture_comment(tctx, "Write Replay Data Mismatch\n");
+ }
+
+ tree1->session = session1_1;
+ smb2_util_close(tree1, *h1);
+ h1 = NULL;
+
+ if (share_is_so) {
+ CHECK_VAL(break_info.count, 1);
+ } else {
+ CHECK_VAL(break_info.count, 0);
+ }
+done:
+ talloc_free(tree2);
+ tree1->session = session1_1;
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_util_unlink(tree1, fname);
+ smb2_deltree(tree1, BASEDIR);
+
+ talloc_free(tree1);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * Test Durability V2 Persistent Create Replay on a Single Channel
+ */
+static bool test_replay5(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ uint32_t share_capabilities;
+ bool share_is_ca;
+ bool share_is_so;
+ uint32_t server_capabilities;
+ const char *fname = BASEDIR "\\replay5.dat";
+ struct smb2_transport *transport = tree->session->transport;
+ struct smbcli_options options = tree->session->transport->options;
+ uint8_t expect_oplock = smb2_util_oplock_level("b");
+ NTSTATUS expect_status = NT_STATUS_DUPLICATE_OBJECTID;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "Replay tests\n");
+ }
+
+ server_capabilities = smb2cli_conn_server_capabilities(
+ tree->session->transport->conn);
+ if (!(server_capabilities & SMB2_CAP_PERSISTENT_HANDLES)) {
+ torture_skip(tctx,
+ "Server does not support persistent handles.");
+ }
+
+ share_capabilities = smb2cli_tcon_capabilities(tree->smbXcli);
+
+ share_is_ca = share_capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
+ if (!share_is_ca) {
+ torture_skip(tctx, "Share is not continuously available.");
+ }
+
+ share_is_so = share_capabilities & SMB2_SHARE_CAP_SCALEOUT;
+ if (share_is_so) {
+ expect_oplock = smb2_util_oplock_level("s");
+ expect_status = NT_STATUS_FILE_NOT_AVAILABLE;
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ transport->oplock.handler = torture_oplock_ack_handler;
+ transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Replay of Persistent DurableHandleReqV2 on Single "
+ "Channel\n");
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ smb2_util_unlink(tree, fname);
+ CHECK_VAL(break_info.count, 0);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = true;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, expect_oplock);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+ CHECK_VAL(io.out.persistent_open, true);
+ CHECK_VAL(io.out.timeout, 300*1000);
+ CHECK_VAL(break_info.count, 0);
+
+ /* disconnect, leaving the durable open */
+ TALLOC_FREE(tree);
+
+ if (!torture_smb2_connection_ext(tctx, 0, &options, &tree)) {
+ torture_warning(tctx, "couldn't reconnect, bailing\n");
+ ret = false;
+ goto done;
+ }
+
+ /* a re-open of a persistent handle causes an error */
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, expect_status);
+
+ /* SMB2_FLAGS_REPLAY_OPERATION must be set to open the Persistent Handle */
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ smb2cli_session_increment_channel_sequence(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.persistent_open, true);
+ CHECK_VAL(io.out.oplock_level, expect_oplock);
+ _h = io.out.file.handle;
+ h = &_h;
+
+ smb2_util_close(tree, *h);
+ h = NULL;
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+/**
+ * Test Error Codes when a DurableHandleReqV2 with matching CreateGuid is
+ * re-sent with or without SMB2_FLAGS_REPLAY_OPERATION
+ */
+static bool test_replay6(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle _h;
+ struct smb2_handle *h = NULL;
+ struct smb2_create io, ref1;
+ union smb_fileinfo qfinfo;
+ struct GUID create_guid = GUID_random();
+ bool ret = true;
+ const char *fname = BASEDIR "\\replay6.dat";
+ struct smb2_transport *transport = tree->session->transport;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ torture_reset_break_info(tctx, &break_info);
+ tree->session->transport->oplock.handler = torture_oplock_ack_handler;
+ tree->session->transport->oplock.private_data = tree;
+
+ torture_comment(tctx, "Error Codes for DurableHandleReqV2 Replay\n");
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &_h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, _h);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ torture_reset_break_info(tctx, &break_info);
+
+ smb2_oplock_create_share(&io, fname,
+ smb2_util_share_access("RWD"),
+ smb2_util_oplock_level("b"));
+ io.in.durable_open = false;
+ io.in.durable_open_v2 = true;
+ io.in.persistent_open = false;
+ io.in.create_guid = create_guid;
+ io.in.timeout = UINT32_MAX;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ref1 = io;
+ _h = io.out.file.handle;
+ h = &_h;
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+ CHECK_VAL(io.out.durable_open, false);
+ CHECK_VAL(io.out.durable_open_v2, true);
+
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATE_OUT(&io, &ref1);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ torture_reset_break_info(tctx, &break_info);
+
+ qfinfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
+ .generic.in.file.handle = *h
+ };
+ torture_comment(tctx, "Trying getinfo\n");
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VAL(qfinfo.position_information.out.position, 0);
+
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_assert_u64_not_equal_goto(tctx,
+ io.out.file.handle.data[0],
+ ref1.out.file.handle.data[0],
+ ret, done, "data 0");
+ torture_assert_u64_not_equal_goto(tctx,
+ io.out.file.handle.data[1],
+ ref1.out.file.handle.data[1],
+ ret, done, "data 1");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, smb2_util_oplock_level("s"));
+ torture_reset_break_info(tctx, &break_info);
+
+ /*
+ * Resend the matching Durable V2 Create without
+ * SMB2_FLAGS_REPLAY_OPERATION. This triggers an oplock break and still
+ * gets NT_STATUS_DUPLICATE_OBJECTID
+ */
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_DUPLICATE_OBJECTID);
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+ torture_reset_break_info(tctx, &break_info);
+
+ /*
+ * According to MS-SMB2 3.3.5.9.10 if Durable V2 Create is replayed and
+ * FileAttributes or CreateDisposition do not match the earlier Create
+ * request the Server fails request with
+ * NT_STATUS_INVALID_PARAMETER. But through this test we see that server
+ * does not really care about changed FileAttributes or
+ * CreateDisposition.
+ */
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ smb2cli_session_start_replay(tree->session->smbXcli);
+ status = smb2_create(tree, mem_ctx, &io);
+ smb2cli_session_stop_replay(tree->session->smbXcli);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ torture_assert_u64_not_equal_goto(tctx,
+ io.out.file.handle.data[0],
+ ref1.out.file.handle.data[0],
+ ret, done, "data 0");
+ torture_assert_u64_not_equal_goto(tctx,
+ io.out.file.handle.data[1],
+ ref1.out.file.handle.data[1],
+ ret, done, "data 1");
+ torture_wait_for_oplock_break(tctx);
+ CHECK_VAL(break_info.count, 0);
+
+done:
+ if (h != NULL) {
+ smb2_util_close(tree, *h);
+ }
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_replay7(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_transport *transport = tree->session->transport;
+ NTSTATUS status;
+ struct smb2_handle _dh;
+ struct smb2_handle *dh = NULL;
+ struct smb2_notify notify;
+ struct smb2_request *req;
+ union smb_fileinfo qfinfo;
+ bool ret = false;
+
+ if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx, "SMB 3.X Dialect family required for "
+ "replay tests\n");
+ }
+
+ torture_comment(tctx, "Notify across increment/decrement of csn\n");
+
+ smbXcli_conn_set_force_channel_sequence(transport->conn, true);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &_dh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ dh = &_dh;
+
+ notify.in.recursive = 0x0000;
+ notify.in.buffer_size = 0xffff;
+ notify.in.file.handle = _dh;
+ notify.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ notify.in.unknown = 0x00000000;
+
+ /*
+ * This posts a long-running request with csn==0 to "dh". Now
+ * op->request_count==1 in smb2_server.c.
+ */
+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
+ req = smb2_notify_send(tree, &notify);
+
+ qfinfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
+ .generic.in.file.handle = _dh
+ };
+
+ /*
+ * This sequence of 2 dummy requests moves
+ * op->request_count==1 to op->pre_request_count. The numbers
+ * used avoid int16 overflow.
+ */
+
+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 30000);
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 60000);
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * This final request turns the op->global->channel_sequence
+ * to the same as we had when sending the notify above. The
+ * notify's request count has in the meantime moved to
+ * op->pre_request_count.
+ */
+
+ smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * At this point op->request_count==0.
+ *
+ * The next cancel makes us reply to the notify. Because the
+ * csn we currently use is the same as we used when sending
+ * the notify, smbd thinks it must decrement op->request_count
+ * and not op->pre_request_count.
+ */
+
+ status = smb2_cancel(req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_notify_recv(req, mem_ctx, &notify);
+ CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+ ret = true;
+
+done:
+ if (dh != NULL) {
+ smb2_util_close(tree, _dh);
+ }
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(tree);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "replay");
+
+ torture_suite_add_1smb2_test(suite, "replay-commands", test_replay_commands);
+ torture_suite_add_1smb2_test(suite, "replay-regular", test_replay_regular);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock1", test_replay_dhv2_oplock1);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock2", test_replay_dhv2_oplock2);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock3", test_replay_dhv2_oplock3);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-oplock-lease", test_replay_dhv2_oplock_lease);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-lease1", test_replay_dhv2_lease1);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-lease2", test_replay_dhv2_lease2);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-lease3", test_replay_dhv2_lease3);
+ torture_suite_add_1smb2_test(suite, "replay-dhv2-lease-oplock", test_replay_dhv2_lease_oplock);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-close-sane", test_dhv2_pending1n_vs_violation_lease_close_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-ack-sane", test_dhv2_pending1n_vs_violation_lease_ack_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-close-windows", test_dhv2_pending1n_vs_violation_lease_close_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-violation-lease-ack-windows", test_dhv2_pending1n_vs_violation_lease_ack_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-oplock-sane", test_dhv2_pending1n_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-oplock-windows", test_dhv2_pending1n_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-lease-sane", test_dhv2_pending1n_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1n-vs-lease-windows", test_dhv2_pending1n_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-oplock-sane", test_dhv2_pending1l_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-oplock-windows", test_dhv2_pending1l_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-lease-sane", test_dhv2_pending1l_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1l-vs-lease-windows", test_dhv2_pending1l_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-oplock-sane", test_dhv2_pending1o_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-oplock-windows", test_dhv2_pending1o_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-lease-sane", test_dhv2_pending1o_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending1o-vs-lease-windows", test_dhv2_pending1o_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-oplock-sane", test_dhv2_pending2n_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-oplock-windows", test_dhv2_pending2n_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-lease-sane", test_dhv2_pending2n_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2n-vs-lease-windows", test_dhv2_pending2n_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-oplock-sane", test_dhv2_pending2l_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-oplock-windows", test_dhv2_pending2l_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-lease-sane", test_dhv2_pending2l_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2l-vs-lease-windows", test_dhv2_pending2l_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-oplock-sane", test_dhv2_pending2o_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-oplock-windows", test_dhv2_pending2o_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-lease-sane", test_dhv2_pending2o_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending2o-vs-lease-windows", test_dhv2_pending2o_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-oplock-sane", test_dhv2_pending3n_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-oplock-windows", test_dhv2_pending3n_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-lease-sane", test_dhv2_pending3n_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3n-vs-lease-windows", test_dhv2_pending3n_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-oplock-sane", test_dhv2_pending3l_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-oplock-windows", test_dhv2_pending3l_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-lease-sane", test_dhv2_pending3l_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3l-vs-lease-windows", test_dhv2_pending3l_vs_lease_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-oplock-sane", test_dhv2_pending3o_vs_oplock_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-oplock-windows", test_dhv2_pending3o_vs_oplock_windows);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-lease-sane", test_dhv2_pending3o_vs_lease_sane);
+ torture_suite_add_2smb2_test(suite, "dhv2-pending3o-vs-lease-windows", test_dhv2_pending3o_vs_lease_windows);
+ torture_suite_add_1smb2_test(suite, "channel-sequence", test_channel_sequence);
+ torture_suite_add_1smb2_test(suite, "replay3", test_replay3);
+ torture_suite_add_1smb2_test(suite, "replay4", test_replay4);
+ torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
+ torture_suite_add_1smb2_test(suite, "replay6", test_replay6);
+ torture_suite_add_1smb2_test(suite, "replay7", test_replay7);
+
+ suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/samba3misc.c b/source4/torture/smb2/samba3misc.c
new file mode 100644
index 0000000..6696c06
--- /dev/null
+++ b/source4/torture/smb2/samba3misc.c
@@ -0,0 +1,189 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Test some misc Samba3 code paths
+
+ Copyright (C) Volker Lendecke 2006
+ Copyright (C) Stefan Metzmacher 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "torture/util.h"
+#include "lib/events/events.h"
+#include "param/param.h"
+
+#define CHECK_STATUS(status, correct) do { \
+ const char *_cmt = "(" __location__ ")"; \
+ torture_assert_ntstatus_equal_goto(tctx,status,correct, \
+ ret,done,_cmt); \
+ } while (0)
+
+#define BASEDIR "samba3misc.smb2"
+
+#define WAIT_FOR_ASYNC_RESPONSE(req) \
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
+ if (tevent_loop_once(tctx->ev) != 0) { \
+ break; \
+ } \
+ }
+
+static void torture_smb2_tree_disconnect_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval now,
+ void *private_data)
+{
+ struct smb2_tree *tree =
+ talloc_get_type_abort(private_data,
+ struct smb2_tree);
+
+ smbXcli_conn_disconnect(tree->session->transport->conn,
+ NT_STATUS_CTX_CLIENT_QUERY_TIMEOUT);
+}
+
+/*
+ * Check that Samba3 correctly deals with conflicting local posix byte range
+ * locks on an underlying file via "normal" SMB2 (without posix extensions).
+ *
+ * Note: This test depends on "posix locking = yes".
+ * Note: To run this test, use "--option=torture:localdir=<LOCALDIR>"
+ */
+static bool torture_samba3_localposixlock1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ bool ret = true;
+ int rc;
+ const char *fname = "posixtimedlock.dat";
+ const char *fpath;
+ const char *localdir;
+ const char *localname;
+ struct smb2_handle h = {{0}};
+ struct smb2_lock lck = {0};
+ struct smb2_lock_element el[1] = {{0}};
+ struct smb2_request *req = NULL;
+ int fd = -1;
+ struct flock posix_lock;
+ struct tevent_timer *te;
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ status = torture_smb2_testfile(tree, fname, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fname);
+ torture_assert(tctx, fpath != NULL, "fpath\n");
+
+ status = torture_smb2_testfile(tree, fpath, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ localdir = torture_setting_string(tctx, "localdir", NULL);
+ torture_assert(tctx, localdir != NULL,
+ "--option=torture:localdir=<LOCALDIR> required\n");
+
+ localname = talloc_asprintf(tctx, "%s/%s/%s",
+ localdir, BASEDIR, fname);
+ torture_assert(tctx, localname != NULL, "localname\n");
+
+ /*
+ * Lock a byte range from posix
+ */
+
+ torture_comment(tctx, " local open(%s)\n", localname);
+ fd = open(localname, O_RDWR);
+ if (fd == -1) {
+ torture_warning(tctx, "open(%s) failed: %s\n",
+ localname, strerror(errno));
+ torture_assert(tctx, fd != -1, "open localname\n");
+ }
+
+ posix_lock.l_type = F_WRLCK;
+ posix_lock.l_whence = SEEK_SET;
+ posix_lock.l_start = 0;
+ posix_lock.l_len = 1;
+
+ torture_comment(tctx, " local fcntl\n");
+ rc = fcntl(fd, F_SETLK, &posix_lock);
+ if (rc == -1) {
+ torture_warning(tctx, "fcntl failed: %s\n", strerror(errno));
+ torture_assert_goto(tctx, rc != -1, ret, done,
+ "fcntl lock\n");
+ }
+
+ el[0].offset = 0;
+ el[0].length = 1;
+ el[0].reserved = 0x00000000;
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ lck.in.locks = el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = h;
+
+ torture_comment(tctx, " remote non-blocking lock\n");
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+ torture_comment(tctx, " remote async blocking lock\n");
+ el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
+ req = smb2_lock_send(tree, &lck);
+ torture_assert_goto(tctx, req != NULL, ret, done, "smb2_lock_send()\n");
+
+ te = tevent_add_timer(tctx->ev,
+ tctx, timeval_current_ofs(5, 0),
+ torture_smb2_tree_disconnect_timer,
+ tree);
+ torture_assert_goto(tctx, te != NULL, ret, done, "tevent_add_timer\n");
+
+ torture_comment(tctx, " remote wait for STATUS_PENDING\n");
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ torture_comment(tctx, " local close file\n");
+ close(fd);
+ fd = -1;
+
+ torture_comment(tctx, " remote lock should now succeed\n");
+ status = smb2_lock_recv(req, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ if (fd != -1) {
+ close(fd);
+ }
+ smb2_util_close(tree, h);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_samba3misc_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "samba3misc");
+
+ torture_suite_add_1smb2_test(suite, "localposixlock1",
+ torture_samba3_localposixlock1);
+
+ suite->description = talloc_strdup(suite, "SMB2 Samba3 MISC");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/scan.c b/source4/torture/smb2/scan.c
new file mode 100644
index 0000000..086cc75
--- /dev/null
+++ b/source4/torture/smb2/scan.c
@@ -0,0 +1,265 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 opcode scanner
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/torture.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+
+#include "torture/smb2/proto.h"
+
+/*
+ scan for valid SMB2 getinfo levels
+*/
+static bool torture_smb2_getinfo_scan(struct torture_context *tctx)
+{
+ struct smb2_tree *tree;
+ NTSTATUS status;
+ struct smb2_getinfo io;
+ struct smb2_handle fhandle, dhandle;
+ int c, i;
+
+ static const char *FNAME = "scan-getinfo.dat";
+ static const char *FNAME2 = "scan-getinfo.dat:2ndstream";
+ static const char *DNAME = "scan-getinfo.dir";
+ static const char *DNAME2 = "scan-getinfo.dir:2ndstream";
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ status = torture_setup_complex_file(tctx, tree, FNAME);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to setup complex file '%s': %s\n",
+ FNAME, nt_errstr(status));
+ return false;
+ }
+ torture_setup_complex_file(tctx, tree, FNAME2);
+
+ status = torture_setup_complex_dir(tctx, tree, DNAME);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to setup complex dir '%s': %s\n",
+ DNAME, nt_errstr(status));
+ smb2_util_unlink(tree, FNAME);
+ return false;
+ }
+ torture_setup_complex_file(tctx, tree, DNAME2);
+
+ torture_smb2_testfile(tree, FNAME, &fhandle);
+ torture_smb2_testdir(tree, DNAME, &dhandle);
+
+
+ ZERO_STRUCT(io);
+ io.in.output_buffer_length = 0xFFFF;
+
+ for (c=1;c<5;c++) {
+ for (i=0;i<0x100;i++) {
+ io.in.info_type = c;
+ io.in.info_class = i;
+
+ io.in.file.handle = fhandle;
+ status = smb2_getinfo(tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ torture_comment(tctx, "file level 0x%02x:%02x %u is %ld bytes - %s\n",
+ io.in.info_type, io.in.info_class,
+ (unsigned)io.in.info_class,
+ (long)io.out.blob.length, nt_errstr(status));
+ dump_data(1, io.out.blob.data, io.out.blob.length);
+ }
+
+ io.in.file.handle = dhandle;
+ status = smb2_getinfo(tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ torture_comment(tctx, "dir level 0x%02x:%02x %u is %ld bytes - %s\n",
+ io.in.info_type, io.in.info_class,
+ (unsigned)io.in.info_class,
+ (long)io.out.blob.length, nt_errstr(status));
+ dump_data(1, io.out.blob.data, io.out.blob.length);
+ }
+ }
+ }
+
+ smb2_util_unlink(tree, FNAME);
+ smb2_util_rmdir(tree, DNAME);
+ return true;
+}
+
+/*
+ scan for valid SMB2 setinfo levels
+*/
+static bool torture_smb2_setinfo_scan(struct torture_context *tctx)
+{
+ static const char *FNAME = "scan-setinfo.dat";
+ static const char *FNAME2 = "scan-setinfo.dat:2ndstream";
+
+ struct smb2_tree *tree;
+ NTSTATUS status;
+ struct smb2_setinfo io;
+ struct smb2_handle handle;
+ int c, i;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ status = torture_setup_complex_file(tctx, tree, FNAME);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to setup complex file '%s': %s\n",
+ FNAME, nt_errstr(status));
+ return false;
+ }
+ torture_setup_complex_file(tctx, tree, FNAME2);
+
+ torture_smb2_testfile(tree, FNAME, &handle);
+
+ ZERO_STRUCT(io);
+ io.in.blob = data_blob_talloc_zero(tctx, 1024);
+
+ for (c=1;c<5;c++) {
+ for (i=0;i<0x100;i++) {
+ io.in.level = (i<<8) | c;
+ io.in.file.handle = handle;
+ status = smb2_setinfo(tree, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+ torture_comment(tctx, "file level 0x%04x - %s\n",
+ io.in.level, nt_errstr(status));
+ }
+ }
+ }
+
+ smb2_util_unlink(tree, FNAME);
+ return true;
+}
+
+
+/*
+ scan for valid SMB2 scan levels
+*/
+static bool torture_smb2_find_scan(struct torture_context *tctx)
+{
+ struct smb2_tree *tree;
+ NTSTATUS status;
+ struct smb2_find io;
+ struct smb2_handle handle;
+ int i;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+ torture_assert_ntstatus_ok(tctx,
+ smb2_util_roothandle(tree, &handle),
+ "Failed to open roothandle");
+
+ ZERO_STRUCT(io);
+ io.in.file.handle = handle;
+ io.in.pattern = "*";
+ io.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
+ io.in.max_response_size = 0x10000;
+
+ for (i=1;i<0x100;i++) {
+ io.in.level = i;
+
+ io.in.file.handle = handle;
+ status = smb2_find(tree, tctx, &io);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ torture_comment(tctx, "find level 0x%04x is %ld bytes - %s\n",
+ io.in.level, (long)io.out.blob.length, nt_errstr(status));
+ dump_data(1, io.out.blob.data, io.out.blob.length);
+ }
+ }
+
+ return true;
+}
+
+/*
+ scan for valid SMB2 opcodes
+*/
+static bool torture_smb2_scan(struct torture_context *tctx)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_tree *tree;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ NTSTATUS status;
+ int opcode;
+ struct smb2_request *req;
+ struct smbcli_options options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ status = smb2_connect(mem_ctx, host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree, tctx->ev, &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "Connection failed");
+
+ tree->session->transport->options.request_timeout = 3;
+
+ for (opcode=0;opcode<1000;opcode++) {
+ req = smb2_request_init_tree(tree, opcode, 2, false, 0);
+ SSVAL(req->out.body, 0, 0);
+ smb2_transport_send(req);
+ if (!smb2_request_receive(req)) {
+ talloc_free(tree);
+ status = smb2_connect(mem_ctx, host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ &tree, tctx->ev, &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(mem_ctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "Connection failed");
+ tree->session->transport->options.request_timeout = 3;
+ } else {
+ status = smb2_request_destroy(req);
+ torture_comment(tctx, "active opcode %4d gave status %s\n", opcode, nt_errstr(status));
+ }
+ }
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+
+struct torture_suite *torture_smb2_scan_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "scan");
+
+ torture_suite_add_simple_test(suite, "scan", torture_smb2_scan);
+ torture_suite_add_simple_test(suite, "getinfo", torture_smb2_getinfo_scan);
+ torture_suite_add_simple_test(suite, "setinfo", torture_smb2_setinfo_scan);
+ torture_suite_add_simple_test(suite, "find", torture_smb2_find_scan);
+
+ suite->description = talloc_strdup(suite, "scan target (not a test)");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/secleak.c b/source4/torture/smb2/secleak.c
new file mode 100644
index 0000000..ca709ed
--- /dev/null
+++ b/source4/torture/smb2/secleak.c
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ find security related memory leaks
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) David Mulder 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "system/time.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+static bool try_failed_login(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct cli_credentials *credentials = NULL;
+ uint32_t sessid = 0;
+ struct smb2_session *session = NULL;
+ bool result = true;
+
+ session = smb2_session_init(tree->session->transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, session, "Session initialization failed");
+
+ sessid = smb2cli_session_current_id(tree->session->smbXcli);
+ credentials = cli_credentials_init(session);
+ torture_assert_goto(tctx, credentials, result, done,
+ "Credential allocation failed");
+
+ cli_credentials_set_conf(credentials, tctx->lp_ctx);
+ cli_credentials_set_domain(credentials, "INVALID-DOMAIN", CRED_SPECIFIED);
+ cli_credentials_set_username(credentials, "INVALID-USERNAME", CRED_SPECIFIED);
+ cli_credentials_set_password(credentials, "INVALID-PASSWORD", CRED_SPECIFIED);
+
+ status = smb2_session_setup_spnego(session, credentials, sessid);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_LOGON_FAILURE, result, done,
+ "Allowed session setup with invalid credentials?!\n");
+
+done:
+ /* smb2_session_init() steals the transport, and if we don't steal it
+ * back before freeing session, then we segfault on the next iteration
+ * because the transport pointer in the tree is now invalid.
+ */
+ tree->session->transport = talloc_steal(tree->session, session->transport);
+ talloc_free(session);
+
+ return result;
+}
+
+bool torture_smb2_sec_leak(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ time_t t1 = time_mono(NULL);
+ int timelimit = torture_setting_int(tctx, "timelimit", 20);
+ bool result;
+
+ while (time_mono(NULL) < t1+timelimit) {
+ result = try_failed_login(tctx, tree);
+ torture_assert(tctx, result,
+ "Invalid credentials should have failed");
+
+ talloc_report(NULL, stdout);
+ }
+
+ return true;
+}
diff --git a/source4/torture/smb2/sessid.c b/source4/torture/smb2/sessid.c
new file mode 100644
index 0000000..bdcec05
--- /dev/null
+++ b/source4/torture/smb2/sessid.c
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) David Mulder 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/events/events.h"
+#include "param/param.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/smb2/proto.h"
+#include "libcli/smb/smbXcli_base.h"
+
+
+static void smb2cli_session_set_id(struct smbXcli_session *session,
+ uint64_t session_id)
+{
+ smb2cli_session_set_id_and_flags(session, session_id,
+ smb2cli_session_get_flags(session));
+}
+
+/**
+ Try with a wrong session id and check error message.
+ */
+
+bool run_sessidtest(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ const char *fname = "sessid.tst";
+ struct smb2_handle fnum;
+ struct smb2_create io = {0};
+ uint32_t session_id;
+ union smb_fileinfo finfo;
+
+ NTSTATUS status;
+
+ smb2_util_unlink(tree, fname);
+
+ io.in.fname = fname;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree, tree, &io);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_result(tctx, TORTURE_FAIL, "open of %s failed (%s)\n",
+ fname, nt_errstr(status));
+ return false;
+ }
+ fnum = io.out.file.handle;
+
+ session_id = smb2cli_session_current_id(tree->session->smbXcli);
+ smb2cli_session_set_id(tree->session->smbXcli, session_id+1234);
+
+ torture_comment(tctx, "Testing qfileinfo with wrong sessid\n");
+
+ finfo.all_info2.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ finfo.all_info2.in.file.handle = fnum;
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_fail(tctx, "smb2_getinfo_file passed with wrong sessid");
+ }
+
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_USER_SESSION_DELETED,
+ "smb2_getinfo_file should have returned "
+ "NT_STATUS_USER_SESSION_DELETED");
+
+ smb2cli_session_set_id(tree->session->smbXcli, session_id);
+
+ status = smb2_util_close(tree, fnum);
+ torture_assert_ntstatus_ok(tctx, status,
+ talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
+
+ smb2_util_unlink(tree, fname);
+
+ return true;
+}
diff --git a/source4/torture/smb2/session.c b/source4/torture/smb2/session.c
new file mode 100644
index 0000000..823304f
--- /dev/null
+++ b/source4/torture/smb2/session.c
@@ -0,0 +1,5670 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 session setups
+
+ Copyright (C) Michael Adam 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "libcli/security/security.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/param/param.h"
+#include "lib/util/tevent_ntstatus.h"
+
+/* Ticket lifetime we want to request in seconds */
+#define KRB5_TICKET_LIFETIME 5
+/* Allowed clock skew in seconds */
+#define KRB5_CLOCKSKEW 5
+/* Time till ticket fully expired in seconds */
+#define KRB5_TICKET_EXPIRETIME KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW
+
+#define texpand(x) #x
+#define GENSEC_GSSAPI_REQUESTED_LIFETIME(x) \
+ "gensec_gssapi:requested_life_time=" texpand(x)
+
+#define CHECK_CREATED(tctx, __io, __created, __attribute) \
+ do { \
+ torture_assert_int_equal(tctx, (__io)->out.create_action, \
+ NTCREATEX_ACTION_ ## __created, \
+ "out.create_action incorrect"); \
+ torture_assert_int_equal(tctx, (__io)->out.size, 0, \
+ "out.size incorrect"); \
+ torture_assert_int_equal(tctx, (__io)->out.file_attr, \
+ (__attribute), \
+ "out.file_attr incorrect"); \
+ torture_assert_int_equal(tctx, (__io)->out.reserved2, 0, \
+ "out.reserverd2 incorrect"); \
+ } while(0)
+
+#define WAIT_FOR_ASYNC_RESPONSE(req) \
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
+ if (tevent_loop_once(tctx->ev) != 0) { \
+ break; \
+ } \
+ }
+
+static void sleep_remaining(struct torture_context *tctx,
+ const struct timeval *endtime)
+{
+ struct timeval current = tevent_timeval_current();
+ double remaining_secs = timeval_elapsed2(&current, endtime);
+
+ remaining_secs = remaining_secs < 1.0 ? 1.0 : remaining_secs;
+ torture_comment(
+ tctx,
+ "sleep for %2.f second(s) that the krb5 ticket expires",
+ remaining_secs);
+ smb_msleep((int)(remaining_secs * 1000));
+}
+
+/**
+ * basic test for doing a session reconnect
+ */
+bool test_session_reconnect1(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_handle _h2;
+ struct smb2_handle *h2 = NULL;
+ struct smb2_create io1, io2;
+ uint64_t previous_session_id;
+ bool ret = true;
+ struct smb2_tree *tree2 = NULL;
+ union smb_fileinfo qfinfo;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reconnect_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* disconnect, reconnect and then do durable reopen */
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ torture_assert_goto(tctx, torture_smb2_connection_ext(tctx, previous_session_id,
+ &tree->session->transport->options, &tree2),
+ ret, done,
+ "session reconnect failed\n");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_USER_SESSION_DELETED,
+ ret, done, "smb2_getinfo_file "
+ "returned unexpected status");
+ h1 = NULL;
+
+ smb2_oplock_create_share(&io2, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree2, mem_ctx, &io2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+
+ CHECK_CREATED(tctx, &io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+ _h2 = io2.out.file.handle;
+ h2 = &_h2;
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+ if (h2 != NULL) {
+ smb2_util_close(tree2, *h2);
+ }
+
+ if (tree2 != NULL) {
+ smb2_util_unlink(tree2, fname);
+ }
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+ talloc_free(tree2);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * basic test for doing a session reconnect on one connection
+ */
+bool test_session_reconnect2(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ uint64_t previous_session_id;
+ bool ret = true;
+ struct smb2_session *session2 = NULL;
+ union smb_fileinfo qfinfo;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reconnect_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* disconnect, reconnect and then do durable reopen */
+ previous_session_id = smb2cli_session_current_id(tree->session->smbXcli);
+
+ torture_assert(tctx, torture_smb2_session_setup(tctx, tree->session->transport,
+ previous_session_id, tctx, &session2),
+ "session reconnect (on the same connection) failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_USER_SESSION_DELETED,
+ ret, done, "smb2_getinfo_file "
+ "returned unexpected status");
+ h1 = NULL;
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ talloc_free(tree);
+ talloc_free(session2);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+bool test_session_reauth1(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ bool ret = true;
+ union smb_fileinfo qfinfo;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reauth1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+bool test_session_reauth2(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ bool ret = true;
+ union smb_fileinfo qfinfo;
+ struct cli_credentials *anon_creds = NULL;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reauth2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+ torture_assert(tctx, (anon_creds != NULL), "talloc error");
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* re-authenticate as original user again */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * test getting security descriptor after reauth
+ */
+bool test_session_reauth3(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ bool ret = true;
+ union smb_fileinfo qfinfo;
+ struct cli_credentials *anon_creds = NULL;
+ uint32_t secinfo_flags = SECINFO_OWNER
+ | SECINFO_GROUP
+ | SECINFO_DACL
+ | SECINFO_PROTECTED_DACL
+ | SECINFO_UNPROTECTED_DACL;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reauth3_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+ torture_assert(tctx, (anon_creds != NULL), "talloc error");
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* re-authenticate as original user again */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * test setting security descriptor after reauth.
+ */
+bool test_session_reauth4(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ bool ret = true;
+ union smb_fileinfo qfinfo;
+ union smb_setfileinfo sfinfo;
+ struct cli_credentials *anon_creds = NULL;
+ uint32_t secinfo_flags = SECINFO_OWNER
+ | SECINFO_GROUP
+ | SECINFO_DACL
+ | SECINFO_PROTECTED_DACL
+ | SECINFO_UNPROTECTED_DACL;
+ struct security_descriptor *sd1;
+ struct security_ace ace;
+ struct dom_sid *extra_sid;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reauth4_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ sd1 = qfinfo.query_secdesc.out.sd;
+
+ /* re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+ torture_assert(tctx, (anon_creds != NULL), "talloc error");
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* give full access on the file to anonymous */
+
+ extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS);
+
+ ZERO_STRUCT(ace);
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_STD_ALL | SEC_FILE_ALL;
+ ace.trustee = *extra_sid;
+
+ status = security_descriptor_dacl_add(sd1, &ace);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "security_descriptor_dacl_add failed");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ sfinfo.set_secdesc.in.file.handle = _h1;
+ sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ sfinfo.set_secdesc.in.sd = sd1;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed");
+
+ /* re-authenticate as original user again */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* re-get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ ret = true;
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * test renaming after reauth.
+ * compare security descriptors before and after rename/reauth
+ */
+bool test_session_reauth5(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char dname[128];
+ char fname[256];
+ char fname2[256];
+ struct smb2_handle _dh1;
+ struct smb2_handle *dh1 = NULL;
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ bool ret = true;
+ bool ok;
+ union smb_fileinfo qfinfo;
+ union smb_setfileinfo sfinfo;
+ struct cli_credentials *anon_creds = NULL;
+ uint32_t secinfo_flags = SECINFO_OWNER
+ | SECINFO_GROUP
+ | SECINFO_DACL
+ | SECINFO_PROTECTED_DACL
+ | SECINFO_UNPROTECTED_DACL;
+ struct security_descriptor *f_sd1;
+ struct security_descriptor *d_sd1 = NULL;
+ struct security_ace ace;
+ struct dom_sid *extra_sid;
+
+ /* Add some random component to the file name. */
+ snprintf(dname, sizeof(dname), "session_reauth5_%s.d",
+ generate_random_str(tctx, 8));
+ snprintf(fname, sizeof(fname), "%s\\file.dat", dname);
+
+ ok = smb2_util_setup_dir(tctx, tree, dname);
+ torture_assert(tctx, ok, "smb2_util_setup_dir not ok");
+
+ status = torture_smb2_testdir(tree, dname, &_dh1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed");
+ dh1 = &_dh1;
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ f_sd1 = qfinfo.query_secdesc.out.sd;
+
+ /* re-authenticate as anonymous */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+ torture_assert(tctx, (anon_creds != NULL), "talloc error");
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to rename the file: fails */
+
+ snprintf(fname2, sizeof(fname2), "%s\\file2.dat", dname);
+
+ status = smb2_util_unlink(tree, fname2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed");
+
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfinfo.rename_information.in.file.handle = _h1;
+ sfinfo.rename_information.in.overwrite = true;
+ sfinfo.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_ACCESS_DENIED,
+ ret, done, "smb2_setinfo_file "
+ "returned unexpected status");
+
+ /* re-authenticate as original user again */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* give full access on the file to anonymous */
+
+ extra_sid = dom_sid_parse_talloc(tctx, SID_NT_ANONYMOUS);
+
+ ZERO_STRUCT(ace);
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_RIGHTS_FILE_ALL;
+ ace.trustee = *extra_sid;
+
+ status = security_descriptor_dacl_add(f_sd1, &ace);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "security_descriptor_dacl_add failed");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ sfinfo.set_secdesc.in.file.handle = _h1;
+ sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags;
+ sfinfo.set_secdesc.in.sd = f_sd1;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed");
+
+ /* re-get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* re-authenticate as anonymous - again */
+
+ anon_creds = cli_credentials_init_anon(mem_ctx);
+ torture_assert(tctx, (anon_creds != NULL), "talloc error");
+
+ status = smb2_session_setup_spnego(tree->session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* try to rename the file: fails */
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfinfo.rename_information.in.file.handle = _h1;
+ sfinfo.rename_information.in.overwrite = true;
+ sfinfo.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_ACCESS_DENIED,
+ ret, done, "smb2_setinfo_file "
+ "returned unexpected status");
+
+ /* give full access on the parent dir to anonymous */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _dh1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ d_sd1 = qfinfo.query_secdesc.out.sd;
+
+ ZERO_STRUCT(ace);
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_RIGHTS_FILE_ALL;
+ ace.trustee = *extra_sid;
+
+ status = security_descriptor_dacl_add(d_sd1, &ace);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "security_descriptor_dacl_add failed");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ sfinfo.set_secdesc.in.file.handle = _dh1;
+ sfinfo.set_secdesc.in.secinfo_flags = secinfo_flags;
+ sfinfo.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ sfinfo.set_secdesc.in.sd = d_sd1;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed");
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _dh1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ status = smb2_util_close(tree, _dh1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+ dh1 = NULL;
+
+ /* try to rename the file: still fails */
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfinfo.rename_information.in.file.handle = _h1;
+ sfinfo.rename_information.in.overwrite = true;
+ sfinfo.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_ACCESS_DENIED,
+ ret, done, "smb2_setinfo_file "
+ "returned unexpected status");
+
+ /* re-authenticate as original user - again */
+
+ status = smb2_session_setup_spnego(tree->session,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* rename the file - for verification that it works */
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sfinfo.rename_information.in.file.handle = _h1;
+ sfinfo.rename_information.in.overwrite = true;
+ sfinfo.rename_information.in.new_name = fname2;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed");
+
+ /* closs the file, check it is gone and reopen under the new name */
+
+ status = smb2_util_close(tree, _h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+ ZERO_STRUCT(io1);
+
+ smb2_generic_create_share(&io1,
+ NULL /* lease */, false /* dir */,
+ fname,
+ NTCREATEX_DISP_OPEN,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"),
+ 0 /* leasekey */, 0 /* leasestate */);
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "smb2_create "
+ "returned unexpected status");
+
+ ZERO_STRUCT(io1);
+
+ smb2_generic_create_share(&io1,
+ NULL /* lease */, false /* dir */,
+ fname2,
+ NTCREATEX_DISP_OPEN,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"),
+ 0 /* leasekey */, 0 /* leasestate */);
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* try to access the file via the old handle */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ qfinfo.query_secdesc.in.file.handle = _h1;
+ qfinfo.query_secdesc.in.secinfo_flags = secinfo_flags;
+
+ status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+done:
+ if (dh1 != NULL) {
+ smb2_util_close(tree, *dh1);
+ }
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ smb2_deltree(tree, dname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/**
+ * do reauth with wrong credentials,
+ * hence triggering the error path in reauth.
+ * The invalid reauth deletes the session.
+ */
+bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ bool ret = true;
+ char *corrupted_password;
+ struct cli_credentials *broken_creds;
+ bool ok;
+ bool encrypted;
+ NTSTATUS expected;
+ enum credentials_use_kerberos krb_state;
+
+ krb_state = cli_credentials_get_kerberos_state(
+ samba_cmdline_get_creds());
+ if (krb_state == CRED_USE_KERBEROS_REQUIRED) {
+ torture_skip(tctx,
+ "Can't test failing session setup with kerberos.");
+ }
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree->smbXcli);
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_reauth1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /*
+ * reauthentication with invalid credentials:
+ */
+
+ broken_creds = cli_credentials_shallow_copy(mem_ctx,
+ samba_cmdline_get_creds());
+ torture_assert(tctx, (broken_creds != NULL), "talloc error");
+
+ corrupted_password = talloc_asprintf(mem_ctx, "%s%s",
+ cli_credentials_get_password(broken_creds),
+ "corrupt");
+ torture_assert(tctx, (corrupted_password != NULL), "talloc error");
+
+ ok = cli_credentials_set_password(broken_creds, corrupted_password,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_password not ok");
+
+ status = smb2_session_setup_spnego(tree->session,
+ broken_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_LOGON_FAILURE, ret, done,
+ "smb2_session_setup_spnego "
+ "returned unexpected status");
+
+ torture_comment(tctx, "did failed reauth\n");
+ /*
+ * now verify that the invalid session reauth has closed our session
+ */
+
+ if (encrypted) {
+ expected = NT_STATUS_CONNECTION_DISCONNECTED;
+ } else {
+ expected = NT_STATUS_USER_SESSION_DELETED;
+ }
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree, mem_ctx, &io1);
+ torture_assert_ntstatus_equal_goto(tctx, status, expected,
+ ret, done, "smb2_create "
+ "returned unexpected status");
+
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ talloc_free(tree);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+static bool test_session_expire1i(struct torture_context *tctx,
+ bool force_signing,
+ bool force_encryption)
+{
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ struct smb2_tree *tree = NULL;
+ enum credentials_use_kerberos use_kerberos;
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo;
+ size_t i;
+ struct timeval endtime;
+ bool ticket_expired = false;
+
+ use_kerberos = cli_credentials_get_kerberos_state(credentials);
+ if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) {
+ torture_warning(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ torture_skip(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ }
+
+ torture_assert_int_equal(tctx,
+ use_kerberos,
+ CRED_USE_KERBEROS_REQUIRED,
+ "please use --use-kerberos=required");
+
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ lpcfg_set_option(
+ tctx->lp_ctx,
+ GENSEC_GSSAPI_REQUESTED_LIFETIME(KRB5_TICKET_LIFETIME));
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ if (force_signing) {
+ options.signing = SMB_SIGNING_REQUIRED;
+ }
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ /*
+ * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds.
+ * Give the server at least KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW + a
+ * few more milliseconds for this to kick in.
+ */
+ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+
+ if (force_encryption) {
+ status = smb2cli_session_encryption_on(tree->session->smbXcli);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2cli_session_encryption_on failed");
+ }
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_expire1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, tctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ qfinfo.access_information.in.file.handle = _h1;
+
+ for (i=0; i < 2; i++) {
+ torture_comment(tctx, "%s: query info => OK\n",
+ current_timestring(tctx, true));
+
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_comment(tctx, "%s: %s:%s: after smb2_getinfo_file() => %s\n",
+ current_timestring(tctx, true),
+ __location__, __func__,
+ nt_errstr(status));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ sleep_remaining(tctx, &endtime);
+
+ torture_comment(tctx, "%s: query info => EXPIRED\n",
+ current_timestring(tctx, true));
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_comment(tctx, "%s: %s:%s: after smb2_getinfo_file() => %s\n",
+ current_timestring(tctx, true),
+ __location__, __func__,
+ nt_errstr(status));
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_getinfo_file "
+ "returned unexpected status");
+
+ /*
+ * the krb5 library may not handle expired creds
+ * well, lets start with an empty ccache.
+ */
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ if (!force_encryption) {
+ smb2cli_session_require_signed_response(
+ tree->session->smbXcli, true);
+ }
+
+ torture_comment(tctx, "%s: reauth => OK\n",
+ current_timestring(tctx, true));
+ status = smb2_session_setup_spnego(tree->session,
+ credentials,
+ 0 /* previous_session_id */);
+ /*
+ * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds.
+ * Give the server at least KRB5_TICKET_LIFETIME +
+ * KRB5_CLOCKSKEW + a few more milliseconds for this to kick in.
+ */
+ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME,
+ 500 * 1000);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ smb2cli_session_require_signed_response(
+ tree->session->smbXcli, false);
+ }
+
+ ticket_expired = timeval_expired(&endtime);
+ if (ticket_expired) {
+ struct timeval current = timeval_current();
+ double remaining_secs = timeval_elapsed2(&current, &endtime);
+ remaining_secs = remaining_secs < 0.0 ? remaining_secs * -1.0
+ : remaining_secs;
+ torture_warning(
+ tctx,
+ "The ticket already expired %.2f seconds ago. "
+ "You might want to increase KRB5_TICKET_LIFETIME.",
+ remaining_secs);
+ }
+ torture_assert(tctx,
+ ticket_expired == false,
+ "The kerberos ticket already expired");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ torture_comment(tctx, "%s: %s:%s: before smb2_getinfo_file()\n",
+ current_timestring(tctx, true),
+ __location__, __func__);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_comment(tctx, "%s: %s:%s: after smb2_getinfo_file() => %s\n",
+ current_timestring(tctx, true),
+ __location__, __func__,
+ nt_errstr(status));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ ret = true;
+done:
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ talloc_free(tree);
+ lpcfg_set_option(tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(0));
+ return ret;
+}
+
+static bool test_session_expire1n(struct torture_context *tctx)
+{
+ return test_session_expire1i(tctx,
+ false, /* force_signing */
+ false); /* force_encryption */
+}
+
+static bool test_session_expire1s(struct torture_context *tctx)
+{
+ return test_session_expire1i(tctx,
+ true, /* force_signing */
+ false); /* force_encryption */
+}
+
+static bool test_session_expire1e(struct torture_context *tctx)
+{
+ return test_session_expire1i(tctx,
+ true, /* force_signing */
+ true); /* force_encryption */
+}
+
+static bool test_session_expire2i(struct torture_context *tctx,
+ bool force_encryption)
+{
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ struct smb2_tree *tree = NULL;
+ const char *unc = NULL;
+ struct smb2_tree *tree2 = NULL;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ enum credentials_use_kerberos use_kerberos;
+ uint32_t caps;
+ char fname[256];
+ struct smb2_handle dh;
+ struct smb2_handle dh2;
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo;
+ union smb_setfileinfo sfinfo;
+ struct smb2_flush flsh;
+ struct smb2_read rd;
+ const uint8_t wd = 0;
+ struct smb2_lock lck;
+ struct smb2_lock_element el;
+ struct smb2_ioctl ctl;
+ struct smb2_break oack;
+ struct smb2_lease_break_ack lack;
+ struct smb2_find fnd;
+ union smb_search_data *d = NULL;
+ unsigned int count;
+ struct smb2_request *req = NULL;
+ struct smb2_notify ntf1;
+ struct smb2_notify ntf2;
+ struct timeval endtime;
+
+ use_kerberos = cli_credentials_get_kerberos_state(credentials);
+ if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) {
+ torture_warning(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ torture_skip(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ }
+
+ torture_assert_int_equal(tctx,
+ use_kerberos,
+ CRED_USE_KERBEROS_REQUIRED,
+ "please use --use-kerberos=required");
+
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ lpcfg_set_option(
+ tctx->lp_ctx,
+ GENSEC_GSSAPI_REQUESTED_LIFETIME(KRB5_TICKET_LIFETIME));
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ options.signing = SMB_SIGNING_REQUIRED;
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ /*
+ * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds.
+ * Give the server at least KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW + a
+ * few more milliseconds for this to kick in.
+ */
+ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+
+ if (force_encryption) {
+ status = smb2cli_session_encryption_on(tree->session->smbXcli);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2cli_session_encryption_on failed");
+ }
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_expire2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ status = smb2_util_roothandle(tree, &dh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_roothandle failed");
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, tctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ qfinfo.access_information.in.file.handle = _h1;
+
+ torture_comment(tctx, "query info => OK\n");
+
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ torture_comment(tctx, "lock => OK\n");
+ ZERO_STRUCT(lck);
+ lck.in.locks = &el;
+ lck.in.lock_count = 0x0001;
+ lck.in.lock_sequence = 0x00000000;
+ lck.in.file.handle = *h1;
+ ZERO_STRUCT(el);
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ el.offset = 0x0000000000000000;
+ el.length = 0x0000000000000001;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_lock lock failed");
+
+ torture_comment(tctx, "1st notify => PENDING\n");
+ ZERO_STRUCT(ntf1);
+ ntf1.in.file.handle = dh;
+ ntf1.in.recursive = 0x0000;
+ ntf1.in.buffer_size = 128;
+ ntf1.in.completion_filter= FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ ntf1.in.unknown = 0x00000000;
+ req = smb2_notify_send(tree, &ntf1);
+
+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
+ if (tevent_loop_once(tctx->ev) != 0) {
+ break;
+ }
+ }
+
+ torture_assert_goto(tctx, req->state <= SMB2_REQUEST_RECV, ret, done,
+ "smb2_notify finished");
+
+ sleep_remaining(tctx, &endtime);
+
+ torture_comment(tctx, "query info => EXPIRED\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_getinfo_file "
+ "returned unexpected status");
+
+
+ torture_comment(tctx, "set info => EXPIRED\n");
+ ZERO_STRUCT(sfinfo);
+ sfinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.end_of_file_info.in.file.handle = *h1;
+ sfinfo.end_of_file_info.in.size = 1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_setinfo_file "
+ "returned unexpected status");
+
+ torture_comment(tctx, "flush => EXPIRED\n");
+ ZERO_STRUCT(flsh);
+ flsh.in.file.handle = *h1;
+ status = smb2_flush(tree, &flsh);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_flush "
+ "returned unexpected status");
+
+ torture_comment(tctx, "read => EXPIRED\n");
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = *h1;
+ rd.in.length = 5;
+ rd.in.offset = 0;
+ status = smb2_read(tree, tctx, &rd);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_read "
+ "returned unexpected status");
+
+ torture_comment(tctx, "write => EXPIRED\n");
+ status = smb2_util_write(tree, *h1, &wd, 0, 1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_util_write "
+ "returned unexpected status");
+
+ torture_comment(tctx, "ioctl => EXPIRED\n");
+ ZERO_STRUCT(ctl);
+ ctl.in.file.handle = *h1;
+ ctl.in.function = FSCTL_SRV_ENUM_SNAPS;
+ ctl.in.max_output_response = 16;
+ ctl.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+ status = smb2_ioctl(tree, tctx, &ctl);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_ioctl "
+ "returned unexpected status");
+
+ torture_comment(tctx, "oplock ack => EXPIRED\n");
+ ZERO_STRUCT(oack);
+ oack.in.file.handle = *h1;
+ status = smb2_break(tree, &oack);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_break "
+ "returned unexpected status");
+
+ if (caps & SMB2_CAP_LEASING) {
+ torture_comment(tctx, "lease ack => EXPIRED\n");
+ ZERO_STRUCT(lack);
+ lack.in.lease.lease_version = 1;
+ lack.in.lease.lease_key.data[0] = 1;
+ lack.in.lease.lease_key.data[1] = 2;
+ status = smb2_lease_break_ack(tree, &lack);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_break "
+ "returned unexpected status");
+ }
+
+ torture_comment(tctx, "query directory => EXPIRED\n");
+ ZERO_STRUCT(fnd);
+ fnd.in.file.handle = dh;
+ fnd.in.pattern = "*";
+ fnd.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ fnd.in.max_response_size= 0x100;
+ fnd.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO;
+ status = smb2_find_level(tree, tree, &fnd, &count, &d);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_find_level "
+ "returned unexpected status");
+
+ torture_comment(tctx, "1st notify => CANCEL\n");
+ smb2_cancel(req);
+
+ torture_comment(tctx, "2nd notify => EXPIRED\n");
+ ZERO_STRUCT(ntf2);
+ ntf2.in.file.handle = dh;
+ ntf2.in.recursive = 0x0000;
+ ntf2.in.buffer_size = 128;
+ ntf2.in.completion_filter= FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ ntf2.in.unknown = 0x00000000;
+ status = smb2_notify(tree, tctx, &ntf2);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_notify "
+ "returned unexpected status");
+
+ torture_assert_goto(tctx, req->state > SMB2_REQUEST_RECV, ret, done,
+ "smb2_notify (1st) not finished");
+
+ status = smb2_notify_recv(req, tctx, &ntf1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_CANCELLED,
+ ret, done, "smb2_notify cancelled"
+ "returned unexpected status");
+
+ torture_comment(tctx, "tcon => EXPIRED\n");
+ tree2 = smb2_tree_init(tree->session, tctx, false);
+ torture_assert(tctx, tree2 != NULL, "smb2_tree_init");
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tree2, tctx->ev,
+ tree2->session->transport->conn,
+ timeout_msec,
+ tree2->session->smbXcli,
+ tree2->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2cli_tcon"
+ "returned unexpected status");
+
+ torture_comment(tctx, "create => EXPIRED\n");
+ status = smb2_util_roothandle(tree, &dh2);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_util_roothandle"
+ "returned unexpected status");
+
+ torture_comment(tctx, "tdis => EXPIRED\n");
+ status = smb2_tdis(tree);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2cli_tdis"
+ "returned unexpected status");
+
+ /*
+ * (Un)Lock, Close and Logoff are still possible
+ */
+
+ torture_comment(tctx, "1st unlock => OK\n");
+ el.flags = SMB2_LOCK_FLAG_UNLOCK;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_lock unlock failed");
+
+ torture_comment(tctx, "2nd unlock => RANGE_NOT_LOCKED\n");
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_RANGE_NOT_LOCKED,
+ ret, done, "smb2_lock 2nd unlock"
+ "returned unexpected status");
+
+ torture_comment(tctx, "lock => EXPIRED\n");
+ el.flags = SMB2_LOCK_FLAG_EXCLUSIVE |
+ SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
+ status = smb2_lock(tree, &lck);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_util_roothandle"
+ "returned unexpected status");
+
+ torture_comment(tctx, "close => OK\n");
+ status = smb2_util_close(tree, *h1);
+ h1 = NULL;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_close failed");
+
+ torture_comment(tctx, "echo without session => OK\n");
+ status = smb2_keepalive(tree->session->transport);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_keepalive without session failed");
+
+ torture_comment(tctx, "echo with session => OK\n");
+ req = smb2_keepalive_send(tree->session->transport, tree->session);
+ status = smb2_keepalive_recv(req);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_keepalive with session failed");
+
+ torture_comment(tctx, "logoff => OK\n");
+ status = smb2_logoff(tree->session);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_logoff failed");
+
+ ret = true;
+done:
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ talloc_free(tree);
+ lpcfg_set_option(tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(0));
+ return ret;
+}
+
+static bool test_session_expire2s(struct torture_context *tctx)
+{
+ return test_session_expire2i(tctx,
+ false); /* force_encryption */
+}
+
+static bool test_session_expire2e(struct torture_context *tctx)
+{
+ return test_session_expire2i(tctx,
+ true); /* force_encryption */
+}
+
+static bool test_session_expire_disconnect(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ bool ret = false;
+ struct smbcli_options options;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ struct smb2_tree *tree = NULL;
+ enum credentials_use_kerberos use_kerberos;
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo;
+ bool connected;
+ struct timeval endtime;
+
+ use_kerberos = cli_credentials_get_kerberos_state(credentials);
+ if (use_kerberos != CRED_USE_KERBEROS_REQUIRED) {
+ torture_warning(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ torture_skip(tctx,
+ "smb2.session.expire1 requires "
+ "--use-kerberos=required!");
+ }
+
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ lpcfg_set_option(
+ tctx->lp_ctx,
+ GENSEC_GSSAPI_REQUESTED_LIFETIME(KRB5_TICKET_LIFETIME));
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ options.signing = SMB_SIGNING_REQUIRED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ /*
+ * We request a ticket lifetime of KRB5_TICKET_LIFETIME seconds.
+ * Give the server at least KRB5_TICKET_LIFETIME + KRB5_CLOCKSKEW + a
+ * few more milliseconds for this to kick in.
+ */
+ endtime = timeval_current_ofs(KRB5_TICKET_EXPIRETIME, 500 * 1000);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+
+ smbXcli_session_set_disconnect_expired(tree->session->smbXcli);
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_expire1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+
+ status = smb2_create(tree, tctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* get the security descriptor */
+
+ ZERO_STRUCT(qfinfo);
+
+ qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION;
+ qfinfo.access_information.in.file.handle = _h1;
+
+ torture_comment(tctx, "query info => OK\n");
+
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ sleep_remaining(tctx, &endtime);
+
+ torture_comment(tctx, "query info => EXPIRED\n");
+ ZERO_STRUCT(qfinfo.access_information.out);
+ status = smb2_getinfo_file(tree, tctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_NETWORK_SESSION_EXPIRED,
+ ret, done, "smb2_getinfo_file "
+ "returned unexpected status");
+
+ connected = smbXcli_conn_is_connected(tree->session->transport->conn);
+ torture_assert_goto(tctx, !connected, ret, done, "connected\n");
+
+ ret = true;
+done:
+ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+
+ if (h1 != NULL) {
+ smb2_util_close(tree, *h1);
+ }
+
+ talloc_free(tree);
+ lpcfg_set_option(tctx->lp_ctx, GENSEC_GSSAPI_REQUESTED_LIFETIME(0));
+ return ret;
+}
+
+bool test_session_bind1(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo;
+ bool ret = false;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options options2;
+ struct smb2_transport *transport2 = NULL;
+ struct smb2_session *session1_1 = tree1->session;
+ struct smb2_session *session1_2 = NULL;
+ struct smb2_session *session2_1 = NULL;
+ struct smb2_session *session2_2 = NULL;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
+ }
+
+ /*
+ * We always want signing for this test!
+ */
+ smb2cli_tcon_should_sign(tree1->smbXcli, true);
+ options2 = transport1->options;
+ options2.signing = SMB_SIGNING_REQUIRED;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "session_bind1_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree1, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2,
+ tctx->ev,
+ &options2,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ session2_2 = tree2->session;
+ transport2 = tree2->session->transport;
+
+ /*
+ * Now bind the 2nd transport connection to the 1st session
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2,
+ session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_2,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* use the 1st connection, 1st session */
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ tree1->session = session1_1;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* use the 2nd connection, 1st session */
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ tree1->session = session1_2;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ tree1->session = session1_1;
+ status = smb2_util_close(tree1, *h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+ h1 = NULL;
+
+ /*
+ * Now bind the 1st transport connection to the 2nd session
+ */
+ session2_1 = smb2_session_channel(transport1,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree1,
+ session2_2);
+ torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_1,
+ samba_cmdline_get_creds(),
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ tree2->session = session2_1;
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed");
+ ret = true;
+done:
+ talloc_free(tree2);
+ tree1->session = session1_1;
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_util_unlink(tree1, fname);
+
+ talloc_free(tree1);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_session_bind2(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname1[256];
+ char fname2[256];
+ struct smb2_handle _h1f1;
+ struct smb2_handle *h1f1 = NULL;
+ struct smb2_handle _h1f2;
+ struct smb2_handle *h1f2 = NULL;
+ struct smb2_handle _h2f2;
+ struct smb2_handle *h2f2 = NULL;
+ struct smb2_create io1f1;
+ struct smb2_create io1f2;
+ struct smb2_create io2f1;
+ struct smb2_create io2f2;
+ union smb_fileinfo qfinfo;
+ bool ret = false;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options options2;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_transport *transport2 = NULL;
+ struct smbcli_options options3;
+ struct smb2_tree *tree3 = NULL;
+ struct smb2_transport *transport3 = NULL;
+ struct smb2_session *session1_1 = tree1->session;
+ struct smb2_session *session1_2 = NULL;
+ struct smb2_session *session1_3 = NULL;
+ struct smb2_session *session2_1 = NULL;
+ struct smb2_session *session2_2 = NULL;
+ struct smb2_session *session2_3 = NULL;
+ uint32_t caps;
+
+ caps = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
+ }
+
+ /*
+ * We always want signing for this test!
+ */
+ smb2cli_tcon_should_sign(tree1->smbXcli, true);
+ options2 = transport1->options;
+ options2.signing = SMB_SIGNING_REQUIRED;
+
+ /* Add some random component to the file name. */
+ snprintf(fname1, sizeof(fname1), "session_bind2_1_%s.dat",
+ generate_random_str(tctx, 8));
+ snprintf(fname2, sizeof(fname2), "session_bind2_2_%s.dat",
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+
+ smb2_oplock_create_share(&io1f1, fname1,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level(""));
+ smb2_oplock_create_share(&io1f2, fname2,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level(""));
+
+ status = smb2_create(tree1, mem_ctx, &io1f1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1f1 = io1f1.out.file.handle;
+ h1f1 = &_h1f1;
+ CHECK_CREATED(tctx, &io1f1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1f1.out.oplock_level,
+ smb2_util_oplock_level(""),
+ "oplock_level incorrect");
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2,
+ tctx->ev,
+ &options2,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ session2_2 = tree2->session;
+ transport2 = tree2->session->transport;
+ smb2cli_tcon_should_sign(tree2->smbXcli, true);
+
+ smb2_oplock_create_share(&io2f1, fname1,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level(""));
+ smb2_oplock_create_share(&io2f2, fname2,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level(""));
+
+ status = smb2_create(tree2, mem_ctx, &io2f2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h2f2 = io2f2.out.file.handle;
+ h2f2 = &_h2f2;
+ CHECK_CREATED(tctx, &io2f2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io2f2.out.oplock_level,
+ smb2_util_oplock_level(""),
+ "oplock_level incorrect");
+
+ options3 = transport1->options;
+ options3.signing = SMB_SIGNING_REQUIRED;
+ options3.only_negprot = true;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree3,
+ tctx->ev,
+ &options3,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ transport3 = tree3->session->transport;
+
+ /*
+ * Create a fake session for the 2nd transport connection to the 1st session
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree1,
+ session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ /*
+ * Now bind the 3rd transport connection to the 1st session
+ */
+ session1_3 = smb2_session_channel(transport3,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree1,
+ session1_1);
+ torture_assert(tctx, session1_3 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_3,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /*
+ * Create a fake session for the 1st transport connection to the 2nd session
+ */
+ session2_1 = smb2_session_channel(transport1,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2,
+ session2_2);
+ torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed");
+
+ /*
+ * Now bind the 3rd transport connection to the 2nd session
+ */
+ session2_3 = smb2_session_channel(transport3,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2,
+ session2_2);
+ torture_assert(tctx, session2_3 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_3,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1f1;
+ tree1->session = session1_1;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ tree1->session = session1_2;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_getinfo_file failed");
+ tree1->session = session1_3;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h2f2;
+ tree2->session = session2_1;
+ status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_getinfo_file failed");
+ tree2->session = session2_2;
+ status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ tree2->session = session2_3;
+ status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ tree1->session = session1_1;
+ status = smb2_create(tree1, mem_ctx, &io1f2);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "smb2_create failed");
+ tree1->session = session1_2;
+ status = smb2_create(tree1, mem_ctx, &io1f2);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_create failed");
+ tree1->session = session1_3;
+ status = smb2_create(tree1, mem_ctx, &io1f2);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "smb2_create failed");
+
+ tree2->session = session2_1;
+ status = smb2_create(tree2, mem_ctx, &io2f1);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_create failed");
+ tree2->session = session2_2;
+ status = smb2_create(tree2, mem_ctx, &io2f1);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "smb2_create failed");
+ tree2->session = session2_3;
+ status = smb2_create(tree2, mem_ctx, &io2f1);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "smb2_create failed");
+
+ smbXcli_conn_disconnect(transport3->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smb_msleep(500);
+
+ tree1->session = session1_1;
+ status = smb2_create(tree1, mem_ctx, &io1f2);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "smb2_create failed");
+ tree1->session = session1_2;
+ status = smb2_create(tree1, mem_ctx, &io1f2);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_create failed");
+
+ tree2->session = session2_1;
+ status = smb2_create(tree2, mem_ctx, &io2f1);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_create failed");
+ tree2->session = session2_2;
+ status = smb2_create(tree2, mem_ctx, &io2f1);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_SHARING_VIOLATION, ret, done,
+ "smb2_create failed");
+
+ smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smb_msleep(500);
+ h2f2 = NULL;
+
+ tree1->session = session1_1;
+ status = smb2_create(tree1, mem_ctx, &io1f2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1f2 = io1f2.out.file.handle;
+ h1f2 = &_h1f2;
+ CHECK_CREATED(tctx, &io1f2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1f2.out.oplock_level,
+ smb2_util_oplock_level(""),
+ "oplock_level incorrect");
+
+ tree1->session = session1_1;
+ status = smb2_util_close(tree1, *h1f1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+ h1f1 = NULL;
+
+ ret = true;
+done:
+
+ smbXcli_conn_disconnect(transport3->conn, NT_STATUS_LOCAL_DISCONNECT);
+ smbXcli_conn_disconnect(transport2->conn, NT_STATUS_LOCAL_DISCONNECT);
+
+ tree1->session = session1_1;
+ tree2->session = session2_2;
+
+ if (h1f1 != NULL) {
+ smb2_util_close(tree1, *h1f1);
+ }
+ if (h1f2 != NULL) {
+ smb2_util_close(tree1, *h1f2);
+ }
+ if (h2f2 != NULL) {
+ smb2_util_close(tree2, *h2f2);
+ }
+
+ smb2_util_unlink(tree1, fname1);
+ smb2_util_unlink(tree1, fname2);
+
+ talloc_free(tree1);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_session_bind_auth_mismatch(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ const char *testname,
+ struct cli_credentials *creds1,
+ struct cli_credentials *creds2,
+ bool creds2_require_ok)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo;
+ bool ret = false;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smbcli_options options2;
+ struct smb2_transport *transport2 = NULL;
+ struct smb2_session *session1_1 = tree1->session;
+ struct smb2_session *session1_2 = NULL;
+ struct smb2_session *session2_1 = NULL;
+ struct smb2_session *session2_2 = NULL;
+ struct smb2_session *session3_1 = NULL;
+ uint32_t caps;
+ bool encrypted;
+ bool creds2_got_ok = false;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree1->smbXcli);
+
+ caps = smb2cli_conn_server_capabilities(transport1->conn);
+ if (!(caps & SMB2_CAP_MULTI_CHANNEL)) {
+ torture_skip(tctx, "server doesn't support SMB2_CAP_MULTI_CHANNEL\n");
+ }
+
+ /*
+ * We always want signing for this test!
+ */
+ smb2cli_tcon_should_sign(tree1->smbXcli, true);
+ options2 = transport1->options;
+ options2.signing = SMB_SIGNING_REQUIRED;
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s_%s.dat", testname,
+ generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree1, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ status = smb2_create(tree1, mem_ctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ creds1,
+ &tree2,
+ tctx->ev,
+ &options2,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect failed");
+ session2_2 = tree2->session;
+ transport2 = tree2->session->transport;
+
+ /*
+ * Now bind the 2nd transport connection to the 1st session
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2,
+ session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_2,
+ creds1,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+
+ /* use the 1st connection, 1st session */
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ tree1->session = session1_1;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* use the 2nd connection, 1st session */
+ ZERO_STRUCT(qfinfo);
+ qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo.generic.in.file.handle = _h1;
+ tree1->session = session1_2;
+ status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ tree1->session = session1_1;
+ status = smb2_util_close(tree1, *h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+ h1 = NULL;
+
+ /*
+ * Create a 3rd session in order to check if the invalid (creds2)
+ * are mapped to guest.
+ */
+ session3_1 = smb2_session_init(transport1,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, session3_1 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session3_1,
+ creds2,
+ 0 /* previous_session_id */);
+ if (creds2_require_ok) {
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego worked");
+ creds2_got_ok = true;
+ } else if (NT_STATUS_IS_OK(status)) {
+ bool authentiated = smbXcli_session_is_authenticated(session3_1->smbXcli);
+ torture_assert(tctx, !authentiated, "Invalid credentials allowed!");
+ creds2_got_ok = true;
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done,
+ "smb2_session_setup_spnego worked");
+ }
+
+ /*
+ * Now bind the 1st transport connection to the 2nd session
+ */
+ session2_1 = smb2_session_channel(transport1,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree1,
+ session2_2);
+ torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed");
+
+ tree2->session = session2_1;
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_util_unlink worked on invalid channel");
+
+ status = smb2_session_setup_spnego(session2_1,
+ creds2,
+ 0 /* previous_session_id */);
+ if (creds2_got_ok) {
+ /*
+ * attaching with a different user (guest or anonymous) results
+ * in ACCESS_DENIED.
+ */
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ACCESS_DENIED, ret, done,
+ "smb2_session_setup_spnego worked");
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done,
+ "smb2_session_setup_spnego worked");
+ }
+
+ tree2->session = session2_1;
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_util_unlink worked on invalid channel");
+
+ tree2->session = session2_2;
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed");
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "smb2_util_unlink worked");
+ if (creds2_got_ok) {
+ /*
+ * We got ACCESS_DENIED on the session bind
+ * with a different user, now check that
+ * the correct user can actually bind on
+ * the same connection.
+ */
+ TALLOC_FREE(session2_1);
+ session2_1 = smb2_session_channel(transport1,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree1,
+ session2_2);
+ torture_assert(tctx, session2_1 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session2_1,
+ creds1,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_session_setup_spnego failed");
+ tree2->session = session2_1;
+ status = smb2_util_unlink(tree2, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "smb2_util_unlink worked");
+ tree2->session = session2_2;
+ }
+
+ tree1->session = session1_1;
+ status = smb2_util_unlink(tree1, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "smb2_util_unlink worked");
+
+ tree1->session = session1_2;
+ status = smb2_util_unlink(tree1, fname);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "smb2_util_unlink worked");
+
+ if (creds2_got_ok) {
+ /*
+ * With valid credentials, there's no point to test a failing
+ * reauth.
+ */
+ ret = true;
+ goto done;
+ }
+
+ /*
+ * Do a failing reauth the 2nd channel
+ */
+ status = smb2_session_setup_spnego(session1_2,
+ creds2,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_LOGON_FAILURE, ret, done,
+ "smb2_session_setup_spnego worked");
+
+ tree1->session = session1_1;
+ status = smb2_util_unlink(tree1, fname);
+ if (encrypted) {
+ torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport1->conn), ret, done,
+ "smb2_util_unlink worked");
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_util_unlink worked");
+ }
+
+ tree1->session = session1_2;
+ status = smb2_util_unlink(tree1, fname);
+ if (encrypted) {
+ torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport2->conn), ret, done,
+ "smb2_util_unlink worked");
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_USER_SESSION_DELETED, ret, done,
+ "smb2_util_unlink worked");
+ }
+
+ status = smb2_util_unlink(tree2, fname);
+ if (encrypted) {
+ torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport1->conn), ret, done,
+ "smb2_util_unlink worked");
+ torture_assert_goto(tctx, !smbXcli_conn_is_connected(transport2->conn), ret, done,
+ "smb2_util_unlink worked");
+ } else {
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "smb2_util_unlink worked");
+ }
+
+ ret = true;
+done:
+ talloc_free(tree2);
+ tree1->session = session1_1;
+
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+
+ smb2_util_unlink(tree1, fname);
+
+ talloc_free(tree1);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_session_bind_invalid_auth(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ struct cli_credentials *invalid_credentials = NULL;
+ bool ret = false;
+
+ invalid_credentials = cli_credentials_init(tctx);
+ torture_assert(tctx, (invalid_credentials != NULL), "talloc error");
+ cli_credentials_set_username(invalid_credentials, "__none__invalid__none__", CRED_SPECIFIED);
+ cli_credentials_set_domain(invalid_credentials, "__none__invalid__none__", CRED_SPECIFIED);
+ cli_credentials_set_password(invalid_credentials, "__none__invalid__none__", CRED_SPECIFIED);
+ cli_credentials_set_realm(invalid_credentials, NULL, CRED_SPECIFIED);
+ cli_credentials_set_workstation(invalid_credentials, "", CRED_UNINITIALISED);
+
+ ret = test_session_bind_auth_mismatch(tctx, tree1, __func__,
+ credentials,
+ invalid_credentials,
+ false);
+ return ret;
+}
+
+static bool test_session_bind_different_user(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+ struct cli_credentials *credentials1 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials2 = torture_user2_credentials(tctx, tctx);
+ char *u1 = cli_credentials_get_unparsed_name(credentials1, tctx);
+ char *u2 = cli_credentials_get_unparsed_name(credentials2, tctx);
+ bool ret = false;
+ bool bval;
+
+ torture_assert(tctx, (credentials2 != NULL), "talloc error");
+ bval = cli_credentials_is_anonymous(credentials2);
+ if (bval) {
+ torture_skip(tctx, "valid user2 credentials are required");
+ }
+ bval = strequal(u1, u2);
+ if (bval) {
+ torture_skip(tctx, "different user2 credentials are required");
+ }
+
+ ret = test_session_bind_auth_mismatch(tctx, tree1, __func__,
+ credentials1,
+ credentials2,
+ true);
+ return ret;
+}
+
+static bool test_session_bind_negative_smbXtoX(struct torture_context *tctx,
+ const char *testname,
+ struct cli_credentials *credentials,
+ const struct smbcli_options *options1,
+ const struct smbcli_options *options2,
+ NTSTATUS bind_reject_status)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ NTSTATUS status;
+ bool ret = false;
+ struct smb2_tree *tree1 = NULL;
+ struct smb2_session *session1_1 = NULL;
+ char fname[256];
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo1;
+ struct smb2_tree *tree2_0 = NULL;
+ struct smb2_transport *transport2 = NULL;
+ struct smb2_session *session1_2 = NULL;
+ uint64_t session1_id = 0;
+ uint16_t session1_flags = 0;
+ NTSTATUS deleted_status = NT_STATUS_USER_SESSION_DELETED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree1,
+ tctx->ev,
+ options1,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect options1 failed");
+ session1_1 = tree1->session;
+ session1_id = smb2cli_session_current_id(session1_1->smbXcli);
+ session1_flags = smb2cli_session_get_flags(session1_1->smbXcli);
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s_%s.dat",
+ testname, generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree1, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ status = smb2_create(tree1, tctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials,
+ &tree2_0,
+ tctx->ev,
+ options2,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect options2 failed");
+ transport2 = tree2_0->session->transport;
+
+ /*
+ * Now bind the 2nd transport connection to the 1st session
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2_0,
+ session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_2,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal_goto(tctx, status, bind_reject_status, ret, done,
+ "smb2_session_setup_spnego failed");
+ if (NT_STATUS_IS_OK(bind_reject_status)) {
+ ZERO_STRUCT(qfinfo1);
+ qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo1.generic.in.file.handle = _h1;
+ tree1->session = session1_2;
+ status = smb2_getinfo_file(tree1, tctx, &qfinfo1);
+ tree1->session = session1_1;
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+ }
+ TALLOC_FREE(session1_2);
+
+ /* Check the initial session is still alive */
+ ZERO_STRUCT(qfinfo1);
+ qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo1.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree1, tctx, &qfinfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ if (NT_STATUS_IS_OK(bind_reject_status)) {
+ deleted_status = NT_STATUS_ACCESS_DENIED;
+ bind_reject_status = NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * I guess this is not part of MultipleChannel_Negative_SMB2002,
+ * but we should also check the status without
+ * SMB2_SESSION_FLAG_BINDING.
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2_0,
+ session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+ session1_2->needs_bind = false;
+
+ status = smb2_session_setup_spnego(session1_2,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal_goto(tctx, status, deleted_status, ret, done,
+ "smb2_session_setup_spnego failed");
+ TALLOC_FREE(session1_2);
+
+ /*
+ * ... and we should also check the status without any existing
+ * session keys.
+ */
+ session1_2 = smb2_session_init(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2_0);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+ talloc_steal(tree2_0->session, transport2);
+ smb2cli_session_set_id_and_flags(session1_2->smbXcli,
+ session1_id, session1_flags);
+
+ status = smb2_session_setup_spnego(session1_2,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal_goto(tctx, status, deleted_status, ret, done,
+ "smb2_session_setup_spnego failed");
+ TALLOC_FREE(session1_2);
+
+ /* Check the initial session is still alive */
+ ZERO_STRUCT(qfinfo1);
+ qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo1.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree1, tctx, &qfinfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /*
+ * Now bind the 2nd transport connection to the 1st session (again)
+ */
+ session1_2 = smb2_session_channel(transport2,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tree2_0,
+ session1_1);
+ torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+ status = smb2_session_setup_spnego(session1_2,
+ credentials,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal_goto(tctx, status, bind_reject_status, ret, done,
+ "smb2_session_setup_spnego failed");
+ TALLOC_FREE(session1_2);
+
+ /* Check the initial session is still alive */
+ ZERO_STRUCT(qfinfo1);
+ qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo1.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree1, tctx, &qfinfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ ret = true;
+done:
+ talloc_free(tree2_0);
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+ talloc_free(tree1);
+
+ return ret;
+}
+
+/*
+ * This is similar to the MultipleChannel_Negative_SMB2002 test
+ * from the Windows Protocol Test Suite.
+ *
+ * It demonstrates that the server needs to do lookup
+ * in the global session table in order to get the signing
+ * and error code of invalid session setups correct.
+ *
+ * See: https://bugzilla.samba.org/show_bug.cgi?id=14512
+ *
+ * Note you can ignore tree0...
+ */
+static bool test_session_bind_negative_smb202(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.02 if encryption is required");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_zero();
+ options1.max_protocol = PROTOCOL_SMB2_02;
+
+ options2 = options1;
+ options2.only_negprot = true;
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_NOT_ACCEPTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb210s(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.max_protocol = PROTOCOL_SMB2_10;
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_NOT_ACCEPTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb210d(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.max_protocol = PROTOCOL_SMB2_10;
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_NOT_ACCEPTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb2to3s(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB2_02;
+ options1.max_protocol = PROTOCOL_SMB2_10;
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_00;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_INVALID_PARAMETER);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb2to3d(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB2_02;
+ options1.max_protocol = PROTOCOL_SMB2_10;
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_00;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_INVALID_PARAMETER);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3to2s(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_00;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB2_02;
+ options2.max_protocol = PROTOCOL_SMB2_10;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_NOT_ACCEPTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3to2d(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_00;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB2_02;
+ options2.max_protocol = PROTOCOL_SMB2_10;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_NOT_ACCEPTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3to3s(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_02;
+ options1.max_protocol = PROTOCOL_SMB3_02;
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_11;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_INVALID_PARAMETER);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3to3d(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_02;
+ options1.max_protocol = PROTOCOL_SMB3_02;
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_11;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_INVALID_PARAMETER);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3encGtoCs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_INVALID_PARAMETER);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3encGtoCd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_INVALID_PARAMETER);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signCtoHs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_OK);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signCtoHd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_OK);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signHtoCs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_OK);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signHtoCd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_OK);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signHtoGs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signHtoGd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signCtoGs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signCtoGd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoCs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoCd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoHs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoHd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneGtoCs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneGtoCd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneGtoHs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneGtoHd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneCtoGs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneCtoGd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneHtoGs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3sneHtoGd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+ options2.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signC30toGs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_00;
+ options1.max_protocol = PROTOCOL_SMB3_02;
+ options1.signing = SMB_SIGNING_REQUIRED;
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_11;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signC30toGd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_00;
+ options1.max_protocol = PROTOCOL_SMB3_02;
+ options1.signing = SMB_SIGNING_REQUIRED;
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_11;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signH2XtoGs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_OFF,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB2_02;
+ options1.max_protocol = PROTOCOL_SMB2_10;
+ options1.signing = SMB_SIGNING_REQUIRED;
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_11;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signH2XtoGd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_OFF,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB2_02;
+ options1.max_protocol = PROTOCOL_SMB2_10;
+ options1.signing = SMB_SIGNING_REQUIRED;
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_11;
+ options2.max_protocol = PROTOCOL_SMB3_11;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_NOT_SUPPORTED);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoC30s(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_00;
+ options2.max_protocol = PROTOCOL_SMB3_02;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoC30d(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB3_00;
+ options2.max_protocol = PROTOCOL_SMB3_02;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoH2Xs(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* same client guid */
+ options2 = options1;
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB2_02;
+ options2.max_protocol = PROTOCOL_SMB2_10;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_bind_negative_smb3signGtoH2Xd(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ struct smbcli_options options2;
+ bool ok;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test SMB 2.10 if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ /* different client guid */
+ options2 = options1;
+ options2.client_guid = GUID_random();
+ options2.only_negprot = true;
+ options2.min_protocol = PROTOCOL_SMB2_02;
+ options2.max_protocol = PROTOCOL_SMB2_10;
+ options2.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_bind_negative_smbXtoX(tctx, __func__,
+ credentials,
+ &options1, &options2,
+ NT_STATUS_REQUEST_OUT_OF_SEQUENCE);
+ talloc_free(tree0);
+ return ret;
+}
+
+static bool test_session_two_logoff(struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct smbcli_options transport2_options;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_session *session2 = NULL;
+ struct smb2_session *session1 = tree1->session;
+ struct smb2_transport *transport1 = tree1->session->transport;
+ struct smb2_transport *transport2;
+ bool ok;
+
+ /* Connect 2nd connection */
+ torture_comment(tctx, "connect tree2 with the same client_guid\n");
+ transport2_options = transport1->options;
+ ok = torture_smb2_connection_ext(tctx, 0, &transport2_options, &tree2);
+ torture_assert(tctx, ok, "couldn't connect tree2\n");
+ transport2 = tree2->session->transport;
+ session2 = tree2->session;
+
+ torture_comment(tctx, "session2: logoff\n");
+ status = smb2_logoff(session2);
+ torture_assert_ntstatus_ok(tctx, status, "session2: logoff");
+ torture_comment(tctx, "transport2: keepalive\n");
+ status = smb2_keepalive(transport2);
+ torture_assert_ntstatus_ok(tctx, status, "transport2: keepalive");
+ torture_comment(tctx, "transport2: disconnect\n");
+ TALLOC_FREE(tree2);
+
+ torture_comment(tctx, "session1: logoff\n");
+ status = smb2_logoff(session1);
+ torture_assert_ntstatus_ok(tctx, status, "session1: logoff");
+ torture_comment(tctx, "transport1: keepalive\n");
+ status = smb2_keepalive(transport1);
+ torture_assert_ntstatus_ok(tctx, status, "transport1: keepalive");
+ torture_comment(tctx, "transport1: disconnect\n");
+ TALLOC_FREE(tree1);
+
+ return ret;
+}
+
+static bool test_session_sign_enc(struct torture_context *tctx,
+ const char *testname,
+ struct cli_credentials *credentials1,
+ const struct smbcli_options *options1)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ NTSTATUS status;
+ bool ret = false;
+ struct smb2_tree *tree1 = NULL;
+ char fname[256];
+ struct smb2_handle rh = {{0}};
+ struct smb2_handle _h1;
+ struct smb2_handle *h1 = NULL;
+ struct smb2_create io1;
+ union smb_fileinfo qfinfo1;
+ union smb_notify notify;
+ struct smb2_request *req = NULL;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ credentials1,
+ &tree1,
+ tctx->ev,
+ options1,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_connect options1 failed");
+
+ status = smb2_util_roothandle(tree1, &rh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_roothandle failed");
+
+ /* Add some random component to the file name. */
+ snprintf(fname, sizeof(fname), "%s_%s.dat",
+ testname, generate_random_str(tctx, 8));
+
+ smb2_util_unlink(tree1, fname);
+
+ smb2_oplock_create_share(&io1, fname,
+ smb2_util_share_access(""),
+ smb2_util_oplock_level("b"));
+
+ io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ status = smb2_create(tree1, tctx, &io1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed");
+ _h1 = io1.out.file.handle;
+ h1 = &_h1;
+ CHECK_CREATED(tctx, &io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ torture_assert_int_equal(tctx, io1.out.oplock_level,
+ smb2_util_oplock_level("b"),
+ "oplock_level incorrect");
+
+ /* Check the initial session is still alive */
+ ZERO_STRUCT(qfinfo1);
+ qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo1.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree1, tctx, &qfinfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ /* ask for a change notify,
+ on file or directory name changes */
+ ZERO_STRUCT(notify);
+ notify.smb2.level = RAW_NOTIFY_SMB2;
+ notify.smb2.in.buffer_size = 1000;
+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
+ notify.smb2.in.file.handle = rh;
+ notify.smb2.in.recursive = true;
+
+ req = smb2_notify_send(tree1, &(notify.smb2));
+ WAIT_FOR_ASYNC_RESPONSE(req);
+
+ status = smb2_cancel(req);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_cancel failed");
+
+ status = smb2_notify_recv(req, tctx, &(notify.smb2));
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
+ ret, done,
+ "smb2_notify_recv failed");
+
+ /* Check the initial session is still alive */
+ ZERO_STRUCT(qfinfo1);
+ qfinfo1.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
+ qfinfo1.generic.in.file.handle = _h1;
+ status = smb2_getinfo_file(tree1, tctx, &qfinfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ ret = true;
+done:
+ if (h1 != NULL) {
+ smb2_util_close(tree1, *h1);
+ }
+ TALLOC_FREE(tree1);
+
+ return ret;
+}
+
+static bool test_session_signing_hmac_sha_256(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test signing only if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_HMAC_SHA256,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_signing_aes_128_cmac(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test signing only if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_CMAC,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_signing_aes_128_gmac(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool encrypted;
+
+ encrypted = smb2cli_tcon_is_encryption_on(tree0->smbXcli);
+ if (encrypted) {
+ torture_skip(tctx,
+ "Can't test signing only if encryption is required");
+ }
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.signing = (struct smb3_signing_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_SIGNING_AES128_GMAC,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_encryption_aes_128_ccm(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_CCM,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_encryption_aes_128_gcm(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES128_GCM,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_encryption_aes_256_ccm(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES256_CCM,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_encryption_aes_256_gcm(struct torture_context *tctx, struct smb2_tree *tree0)
+{
+ struct cli_credentials *credentials0 = samba_cmdline_get_creds();
+ struct cli_credentials *credentials = NULL;
+ bool ret = false;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct smbcli_options options1;
+ bool ok;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_11) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 support");
+ }
+
+ if (smb2cli_conn_server_signing_algo(transport0->conn) < SMB2_SIGNING_AES128_GMAC) {
+ torture_skip(tctx,
+ "Can't test without SMB 3.1.1 signing negotiation support");
+ }
+
+ credentials = cli_credentials_shallow_copy(tctx, credentials0);
+ torture_assert(tctx, credentials != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(credentials,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options1 = transport0->options;
+ options1.client_guid = GUID_random();
+ options1.min_protocol = PROTOCOL_SMB3_11;
+ options1.max_protocol = PROTOCOL_SMB3_11;
+ options1.signing = SMB_SIGNING_REQUIRED;
+ options1.smb3_capabilities.encryption = (struct smb3_encryption_capabilities) {
+ .num_algos = 1,
+ .algos = {
+ SMB2_ENCRYPTION_AES256_GCM,
+ },
+ };
+
+ ret = test_session_sign_enc(tctx,
+ __func__,
+ credentials,
+ &options1);
+ TALLOC_FREE(tree0);
+ return ret;
+}
+
+static bool test_session_ntlmssp_bug14932(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct cli_credentials *ntlm_creds =
+ cli_credentials_shallow_copy(tctx, samba_cmdline_get_creds());
+ NTSTATUS status;
+ bool ret = true;
+ /*
+ * This is a NTLMv2_RESPONSE with the strange
+ * NTLMv2_CLIENT_CHALLENGE used by the net diag
+ * tool.
+ *
+ * As we expect an error anyway we fill the
+ * Response part with 0xab...
+ */
+ static const char *netapp_magic =
+ "\xab\xab\xab\xab\xab\xab\xab\xab"
+ "\xab\xab\xab\xab\xab\xab\xab\xab"
+ "\x01\x01\x00\x00\x00\x00\x00\x00"
+ "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f"
+ "\xb8\x82\x3a\xf1\xb3\xdd\x08\x15"
+ "\x00\x00\x00\x00\x11\xa2\x08\x81"
+ "\x50\x38\x22\x78\x2b\x94\x47\xfe"
+ "\x54\x94\x7b\xff\x17\x27\x5a\xb4"
+ "\xf4\x18\xba\xdc\x2c\x38\xfd\x5b"
+ "\xfb\x0e\xc1\x85\x1e\xcc\x92\xbb"
+ "\x9b\xb1\xc4\xd5\x53\x14\xff\x8c"
+ "\x76\x49\xf5\x45\x90\x19\xa2";
+ DATA_BLOB lm_response = data_blob_talloc_zero(tctx, 24);
+ DATA_BLOB lm_session_key = data_blob_talloc_zero(tctx, 16);
+ DATA_BLOB nt_response = data_blob_const(netapp_magic, 95);
+ DATA_BLOB nt_session_key = data_blob_talloc_zero(tctx, 16);
+
+ cli_credentials_set_kerberos_state(ntlm_creds,
+ CRED_USE_KERBEROS_DISABLED,
+ CRED_SPECIFIED);
+ cli_credentials_set_ntlm_response(ntlm_creds,
+ &lm_response,
+ &lm_session_key,
+ &nt_response,
+ &nt_session_key,
+ CRED_SPECIFIED);
+ status = smb2_session_setup_spnego(tree->session,
+ ntlm_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER,
+ "smb2_session_setup_spnego failed");
+
+ return ret;
+}
+
+struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "session");
+
+ torture_suite_add_1smb2_test(suite, "reconnect1", test_session_reconnect1);
+ torture_suite_add_1smb2_test(suite, "reconnect2", test_session_reconnect2);
+ torture_suite_add_1smb2_test(suite, "reauth1", test_session_reauth1);
+ torture_suite_add_1smb2_test(suite, "reauth2", test_session_reauth2);
+ torture_suite_add_1smb2_test(suite, "reauth3", test_session_reauth3);
+ torture_suite_add_1smb2_test(suite, "reauth4", test_session_reauth4);
+ torture_suite_add_1smb2_test(suite, "reauth5", test_session_reauth5);
+ torture_suite_add_1smb2_test(suite, "reauth6", test_session_reauth6);
+ torture_suite_add_simple_test(suite, "expire1n", test_session_expire1n);
+ torture_suite_add_simple_test(suite, "expire1s", test_session_expire1s);
+ torture_suite_add_simple_test(suite, "expire1e", test_session_expire1e);
+ torture_suite_add_simple_test(suite, "expire2s", test_session_expire2s);
+ torture_suite_add_simple_test(suite, "expire2e", test_session_expire2e);
+ torture_suite_add_simple_test(suite, "expire_disconnect",
+ test_session_expire_disconnect);
+ torture_suite_add_1smb2_test(suite, "bind1", test_session_bind1);
+ torture_suite_add_1smb2_test(suite, "bind2", test_session_bind2);
+ torture_suite_add_1smb2_test(suite, "bind_invalid_auth", test_session_bind_invalid_auth);
+ torture_suite_add_1smb2_test(suite, "bind_different_user", test_session_bind_different_user);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb202", test_session_bind_negative_smb202);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb210s", test_session_bind_negative_smb210s);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb210d", test_session_bind_negative_smb210d);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb2to3s", test_session_bind_negative_smb2to3s);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb2to3d", test_session_bind_negative_smb2to3d);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3to2s", test_session_bind_negative_smb3to2s);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3to2d", test_session_bind_negative_smb3to2d);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3to3s", test_session_bind_negative_smb3to3s);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3to3d", test_session_bind_negative_smb3to3d);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3encGtoCs", test_session_bind_negative_smb3encGtoCs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3encGtoCd", test_session_bind_negative_smb3encGtoCd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoHs", test_session_bind_negative_smb3signCtoHs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoHd", test_session_bind_negative_smb3signCtoHd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoGs", test_session_bind_negative_smb3signCtoGs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signCtoGd", test_session_bind_negative_smb3signCtoGd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoCs", test_session_bind_negative_smb3signHtoCs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoCd", test_session_bind_negative_smb3signHtoCd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoGs", test_session_bind_negative_smb3signHtoGs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signHtoGd", test_session_bind_negative_smb3signHtoGd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoCs", test_session_bind_negative_smb3signGtoCs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoCd", test_session_bind_negative_smb3signGtoCd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoHs", test_session_bind_negative_smb3signGtoHs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoHd", test_session_bind_negative_smb3signGtoHd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoCs", test_session_bind_negative_smb3sneGtoCs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoCd", test_session_bind_negative_smb3sneGtoCd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoHs", test_session_bind_negative_smb3sneGtoHs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneGtoHd", test_session_bind_negative_smb3sneGtoHd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneCtoGs", test_session_bind_negative_smb3sneCtoGs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneCtoGd", test_session_bind_negative_smb3sneCtoGd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneHtoGs", test_session_bind_negative_smb3sneHtoGs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3sneHtoGd", test_session_bind_negative_smb3sneHtoGd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signC30toGs", test_session_bind_negative_smb3signC30toGs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signC30toGd", test_session_bind_negative_smb3signC30toGd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signH2XtoGs", test_session_bind_negative_smb3signH2XtoGs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signH2XtoGd", test_session_bind_negative_smb3signH2XtoGd);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoC30s", test_session_bind_negative_smb3signGtoC30s);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoC30d", test_session_bind_negative_smb3signGtoC30d);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoH2Xs", test_session_bind_negative_smb3signGtoH2Xs);
+ torture_suite_add_1smb2_test(suite, "bind_negative_smb3signGtoH2Xd", test_session_bind_negative_smb3signGtoH2Xd);
+ torture_suite_add_1smb2_test(suite, "two_logoff", test_session_two_logoff);
+ torture_suite_add_1smb2_test(suite, "signing-hmac-sha-256", test_session_signing_hmac_sha_256);
+ torture_suite_add_1smb2_test(suite, "signing-aes-128-cmac", test_session_signing_aes_128_cmac);
+ torture_suite_add_1smb2_test(suite, "signing-aes-128-gmac", test_session_signing_aes_128_gmac);
+ torture_suite_add_1smb2_test(suite, "encryption-aes-128-ccm", test_session_encryption_aes_128_ccm);
+ torture_suite_add_1smb2_test(suite, "encryption-aes-128-gcm", test_session_encryption_aes_128_gcm);
+ torture_suite_add_1smb2_test(suite, "encryption-aes-256-ccm", test_session_encryption_aes_256_ccm);
+ torture_suite_add_1smb2_test(suite, "encryption-aes-256-gcm", test_session_encryption_aes_256_gcm);
+ torture_suite_add_1smb2_test(suite, "ntlmssp_bug14932", test_session_ntlmssp_bug14932);
+
+ suite->description = talloc_strdup(suite, "SMB2-SESSION tests");
+
+ return suite;
+}
+
+static bool test_session_require_sign_bug15397(struct torture_context *tctx,
+ struct smb2_tree *_tree)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct cli_credentials *_creds = samba_cmdline_get_creds();
+ struct cli_credentials *creds = NULL;
+ struct smbcli_options options;
+ struct smb2_tree *tree = NULL;
+ uint8_t security_mode;
+ NTSTATUS status;
+ bool ok = true;
+
+ /*
+ * Setup our own connection so we can control the signing flags
+ */
+
+ creds = cli_credentials_shallow_copy(tctx, _creds);
+ torture_assert(tctx, creds != NULL, "cli_credentials_shallow_copy");
+
+ options = _tree->session->transport->options;
+ options.client_guid = GUID_random();
+ options.signing = SMB_SIGNING_IF_REQUIRED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ creds,
+ &tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "smb2_connect failed");
+
+ security_mode = smb2cli_session_security_mode(tree->session->smbXcli);
+
+ torture_assert_int_equal_goto(
+ tctx,
+ security_mode,
+ SMB2_NEGOTIATE_SIGNING_REQUIRED | SMB2_NEGOTIATE_SIGNING_ENABLED,
+ ok,
+ done,
+ "Signing not required");
+
+done:
+ return ok;
+}
+
+struct torture_suite *torture_smb2_session_req_sign_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "session-require-signing");
+
+ torture_suite_add_1smb2_test(suite, "bug15397",
+ test_session_require_sign_bug15397);
+
+ suite->description = talloc_strdup(suite, "SMB2-SESSION require signing tests");
+ return suite;
+}
diff --git a/source4/torture/smb2/setinfo.c b/source4/torture/smb2/setinfo.c
new file mode 100644
index 0000000..3b01b05
--- /dev/null
+++ b/source4/torture/smb2/setinfo.c
@@ -0,0 +1,410 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 setinfo individual test suite
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+static bool find_returned_ea(union smb_fileinfo *finfo2,
+ const char *eaname,
+ const char *eavalue)
+{
+ unsigned int i;
+ unsigned int num_eas = finfo2->all_eas.out.num_eas;
+ struct ea_struct *eas = finfo2->all_eas.out.eas;
+
+ for (i = 0; i < num_eas; i++) {
+ if (eas[i].name.s == NULL) {
+ continue;
+ }
+ /* Windows capitalizes returned EA names. */
+ if (strcasecmp_m(eas[i].name.s, eaname)) {
+ continue;
+ }
+ if (eavalue == NULL && eas[i].value.length == 0) {
+ /* Null value, found it ! */
+ return true;
+ }
+ if (eas[i].value.length == strlen(eavalue) &&
+ memcmp(eas[i].value.data,
+ eavalue,
+ strlen(eavalue)) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#define BASEDIR ""
+
+#define FAIL_UNLESS(__cond) \
+ do { \
+ if (__cond) {} else { \
+ torture_result(tctx, TORTURE_FAIL, "%s) condition violated: %s\n", \
+ __location__, #__cond); \
+ ret = false; goto done; \
+ } \
+ } while(0)
+
+/* basic testing of all SMB2 setinfo calls
+ for each call we test that it succeeds, and where possible test
+ for consistency between the calls.
+*/
+bool torture_smb2_setinfo(struct torture_context *tctx)
+{
+ struct smb2_tree *tree;
+ bool ret = true;
+ struct smb2_handle handle;
+ char *fname;
+ union smb_fileinfo finfo2;
+ union smb_setfileinfo sfinfo;
+ struct security_ace ace;
+ struct security_descriptor *sd;
+ struct dom_sid *test_sid;
+ NTSTATUS status, status2=NT_STATUS_OK;
+ const char *call_name;
+ time_t basetime = (time(NULL) - 86400) & ~1;
+ int n = time(NULL) % 100;
+ struct ea_struct ea;
+
+ ZERO_STRUCT(handle);
+
+ fname = talloc_asprintf(tctx, BASEDIR "fnum_test_%d.txt", n);
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ return false;
+ }
+
+#define RECREATE_FILE(fname) do { \
+ smb2_util_close(tree, handle); \
+ status = smb2_create_complex_file(tctx, tree, fname, &handle); \
+ if (!NT_STATUS_IS_OK(status)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) ERROR: open of %s failed (%s)\n", \
+ __location__, fname, nt_errstr(status)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define RECREATE_BOTH do { \
+ RECREATE_FILE(fname); \
+ } while (0)
+
+ RECREATE_BOTH;
+
+#define CHECK_CALL(call, rightstatus) do { \
+ call_name = #call; \
+ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
+ sfinfo.generic.in.file.handle = handle; \
+ status = smb2_setinfo_file(tree, &sfinfo); \
+ if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s (should be %s)\n", __location__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = false; \
+ goto done; \
+ } \
+ } while (0)
+
+#define CHECK1(call) \
+ do { if (NT_STATUS_IS_OK(status)) { \
+ finfo2.generic.level = RAW_FILEINFO_ ## call; \
+ finfo2.generic.in.file.handle = handle; \
+ status2 = smb2_getinfo_file(tree, tctx, &finfo2); \
+ if (!NT_STATUS_IS_OK(status2)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__, #call, nt_errstr(status2)); \
+ ret = false; \
+ goto done; \
+ } \
+ }} while (0)
+
+#define CHECK_VALUE(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
+ call_name, #stype, #field, \
+ (unsigned int)value, (unsigned int)finfo2.stype.out.field); \
+ torture_smb2_all_info(tctx, tree, handle); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_TIME(call, stype, field, value) do { \
+ CHECK1(call); \
+ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \
+ call_name, #stype, #field, \
+ (unsigned int)value, \
+ (unsigned int)nt_time_to_unix(finfo2.stype.out.field)); \
+ torture_warning(tctx, "\t%s", timestring(tctx, value)); \
+ torture_warning(tctx, "\t%s\n", nt_time_string(tctx, finfo2.stype.out.field)); \
+ torture_smb2_all_info(tctx, tree, handle); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+ torture_smb2_all_info(tctx, tree, handle);
+
+ torture_comment(tctx, "Test basic_information level\n");
+ basetime += 86400;
+ unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100);
+ unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300);
+ unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
+ CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_READONLY);
+
+ torture_comment(tctx, "a zero time means don't change\n");
+ unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0);
+ unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300);
+ CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL);
+
+ torture_comment(tctx, "change the attribute\n");
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN;
+ CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN);
+
+ torture_comment(tctx, "zero attrib means don't change\n");
+ sfinfo.basic_info.in.attrib = 0;
+ CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN);
+
+ torture_comment(tctx, "can't change a file to a directory\n");
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY;
+ CHECK_CALL(BASIC_INFORMATION, NT_STATUS_INVALID_PARAMETER);
+
+ torture_comment(tctx, "restore attribute\n");
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+ CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL);
+
+ torture_comment(tctx, "Test disposition_information level\n");
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 1);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 0);
+
+ sfinfo.disposition_info.in.delete_on_close = 0;
+ CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 0);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 1);
+
+ torture_comment(tctx, "Test allocation_information level\n");
+ sfinfo.allocation_info.in.alloc_size = 0;
+ CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 0);
+
+ sfinfo.allocation_info.in.alloc_size = 4096;
+ CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 4096);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0);
+
+ torture_comment(tctx, "Test end_of_file_info level\n");
+ sfinfo.end_of_file_info.in.size = 37;
+ CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 37);
+
+ sfinfo.end_of_file_info.in.size = 7;
+ CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 7);
+
+ torture_comment(tctx, "Test position_information level\n");
+ sfinfo.position_information.in.position = 123456;
+ CHECK_CALL(POSITION_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, position, 123456);
+
+ torture_comment(tctx, "Test mode_information level\n");
+ sfinfo.mode_information.in.mode = 2;
+ CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2);
+ CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, mode, 2);
+
+ sfinfo.mode_information.in.mode = 1;
+ CHECK_CALL(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER);
+
+ sfinfo.mode_information.in.mode = 0;
+ CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK);
+ CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0);
+
+ torture_comment(tctx, "Test sec_desc level\n");
+ ZERO_STRUCT(finfo2);
+ finfo2.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ CHECK1(SEC_DESC);
+ sd = finfo2.query_secdesc.out.sd;
+
+ test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS);
+ ZERO_STRUCT(ace);
+ ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ ace.flags = 0;
+ ace.access_mask = SEC_STD_ALL;
+ ace.trustee = *test_sid;
+ status = security_descriptor_dacl_add(sd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "add a new ACE to the DACL\n");
+
+ sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags;
+ sfinfo.set_secdesc.in.sd = sd;
+ CHECK_CALL(SEC_DESC, NT_STATUS_OK);
+ FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, handle, sd));
+
+ torture_comment(tctx, "remove it again\n");
+
+ status = security_descriptor_dacl_del(sd, test_sid);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags;
+ sfinfo.set_secdesc.in.sd = sd;
+ CHECK_CALL(SEC_DESC, NT_STATUS_OK);
+ FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, handle, sd));
+
+ torture_comment(tctx, "Check zero length EA's behavior\n");
+
+ /* Set a new EA. */
+ sfinfo.full_ea_information.in.eas.num_eas = 1;
+ ea.flags = 0;
+ ea.name.private_length = 6;
+ ea.name.s = "NewEA";
+ ea.value = data_blob_string_const("testme");
+ sfinfo.full_ea_information.in.eas.eas = &ea;
+ CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK);
+
+ /* Does it still exist ? */
+ finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
+ finfo2.generic.in.file.handle = handle;
+ finfo2.all_eas.in.continue_flags = 1;
+ status2 = smb2_getinfo_file(tree, tctx, &finfo2);
+ if (!NT_STATUS_IS_OK(status2)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__,
+ "SMB2_ALL_EAS", nt_errstr(status2));
+ ret = false;
+ goto done;
+ }
+
+ /* Note on Windows EA name is returned capitalized. */
+ if (!find_returned_ea(&finfo2, "NewEA", "testme")) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'NewEA'\n", __location__);
+ ret = false;
+ }
+
+ /* Now zero it out (should delete it) */
+ sfinfo.full_ea_information.in.eas.num_eas = 1;
+ ea.flags = 0;
+ ea.name.private_length = 6;
+ ea.name.s = "NewEA";
+ ea.value = data_blob_null;
+ sfinfo.full_ea_information.in.eas.eas = &ea;
+ CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK);
+
+ /* Does it still exist ? */
+ finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
+ finfo2.generic.in.file.handle = handle;
+ finfo2.all_eas.in.continue_flags = 1;
+ status2 = smb2_getinfo_file(tree, tctx, &finfo2);
+ if (!NT_STATUS_IS_OK(status2)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__,
+ "SMB2_ALL_EAS", nt_errstr(status2));
+ ret = false;
+ goto done;
+ }
+
+ if (find_returned_ea(&finfo2, "NewEA", NULL)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) EA 'NewEA' should be deleted\n", __location__);
+ ret = false;
+ }
+
+ /* Set a zero length EA. */
+ sfinfo.full_ea_information.in.eas.num_eas = 1;
+ ea.flags = 0;
+ ea.name.private_length = 6;
+ ea.name.s = "ZeroEA";
+ ea.value = data_blob_null;
+ sfinfo.full_ea_information.in.eas.eas = &ea;
+ CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK);
+
+ /* Does it still exist ? */
+ finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
+ finfo2.generic.in.file.handle = handle;
+ finfo2.all_eas.in.continue_flags = 1;
+ status2 = smb2_getinfo_file(tree, tctx, &finfo2);
+ if (!NT_STATUS_IS_OK(status2)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__,
+ "SMB2_ALL_EAS", nt_errstr(status2));
+ ret = false;
+ goto done;
+ }
+
+ /* Over SMB2 ZeroEA should not exist. */
+ if (!find_returned_ea(&finfo2, "EAONE", "VALUE1")) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'EAONE'\n", __location__);
+ ret = false;
+ }
+ if (!find_returned_ea(&finfo2, "SECONDEA", "ValueTwo")) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'SECONDEA'\n", __location__);
+ ret = false;
+ }
+ if (find_returned_ea(&finfo2, "ZeroEA", NULL)) {
+ torture_result(tctx, TORTURE_FAIL, "(%s) Found null EA 'ZeroEA'\n", __location__);
+ ret = false;
+ }
+
+done:
+ status = smb2_util_close(tree, handle);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_warning(tctx, "Failed to delete %s - %s\n", fname, nt_errstr(status));
+ }
+ smb2_util_unlink(tree, fname);
+
+ return ret;
+}
+
+
diff --git a/source4/torture/smb2/sharemode.c b/source4/torture/smb2/sharemode.c
new file mode 100644
index 0000000..97381b5
--- /dev/null
+++ b/source4/torture/smb2/sharemode.c
@@ -0,0 +1,755 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test suite for SMB2 sharemodes
+
+ Copyright (C) Christof Schmitt 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/security/security.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "lib/util/smb_strtox.h"
+#include <tevent.h>
+
+#define BASEDIRHOLD "sharemode_hold_test"
+
+struct hold_sharemode_info {
+ const char *sharemode;
+ const char *filename;
+ struct smb2_handle handle;
+} hold_sharemode_table[] = {
+ {
+ .sharemode = "",
+ .filename = BASEDIRHOLD "\\N",
+ },
+ {
+ .sharemode = "R",
+ .filename = BASEDIRHOLD "\\R",
+ },
+ {
+ .sharemode = "W",
+ .filename = BASEDIRHOLD "\\W",
+ },
+ {
+ .sharemode = "D",
+ .filename = BASEDIRHOLD "\\D",
+ },
+ {
+ .sharemode = "RW",
+ .filename = BASEDIRHOLD "\\RW",
+ },
+ {
+ .sharemode = "RD",
+ .filename = BASEDIRHOLD "\\RD",
+ },
+ {
+ .sharemode = "WD",
+ .filename = BASEDIRHOLD "\\WD",
+ },
+ {
+ .sharemode = "RWD",
+ .filename = BASEDIRHOLD "\\RWD",
+ },
+};
+
+static void signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct torture_context *tctx = private_data;
+
+ torture_comment(tctx, "Received signal %d\n", signum);
+}
+
+/*
+ * Used for manual testing of sharemodes - especially interaction with
+ * other filesystems (such as NFS and local access). The scenario is
+ * that this test holds files open and then concurrent access to the same
+ * files outside of Samba can be tested.
+ */
+bool torture_smb2_hold_sharemode(struct torture_context *tctx)
+{
+ struct tevent_context *ev = tctx->ev;
+ struct smb2_tree *tree = NULL;
+ struct smb2_handle dir_handle;
+ struct tevent_signal *s;
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_comment(tctx, "Initializing smb2 connection failed.\n");
+ return false;
+ }
+
+ s = tevent_add_signal(ev, tctx, SIGINT, 0, signal_handler, tctx);
+ torture_assert_not_null_goto(tctx, s, ret, done,
+ "Error registering signal handler.");
+
+ torture_comment(tctx, "Setting up open files with sharemodes in %s\n",
+ BASEDIRHOLD);
+
+ status = torture_smb2_testdir(tree, BASEDIRHOLD, &dir_handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Error creating directory.");
+
+ for (i = 0; i < ARRAY_SIZE(hold_sharemode_table); i++) {
+ struct hold_sharemode_info *info = &hold_sharemode_table[i];
+ struct smb2_create create = { 0 };
+
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.alloc_size = 0;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access =
+ smb2_util_share_access(info->sharemode);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.create_options = 0;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.security_flags = 0;
+ create.in.fname = info->filename;
+ create.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ torture_comment(tctx, "opening %s\n", info->filename);
+
+ status = smb2_create(tree, tctx, &create);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ info->handle = create.out.file.handle;
+ }
+
+ torture_comment(tctx, "Waiting for SIGINT (ctrl-c)\n");
+ tevent_loop_wait(ev);
+
+ torture_comment(tctx, "Closing and deleting files\n");
+
+ for (i = 0; i < ARRAY_SIZE(hold_sharemode_table); i++) {
+ struct hold_sharemode_info *info = &hold_sharemode_table[i];
+
+ union smb_setfileinfo sfinfo = { };
+
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = info->handle;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "SETINFO failed\n");
+
+ status = smb2_util_close(tree, info->handle);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ torture_comment(tctx, "File %s not found, could have "
+ "been deleted outside of SMB\n",
+ info->filename);
+ continue;
+ }
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE failed\n");
+}
+
+done:
+ smb2_deltree(tree, BASEDIRHOLD);
+ return ret;
+}
+
+/*
+ * Used for manual testing of sharemodes, especially interaction with
+ * file systems that can enforce sharemodes. The scenario here is that
+ * a file is already open outside of Samba with a sharemode and this
+ * can be used to test accessing the same file from Samba.
+ */
+bool torture_smb2_check_sharemode(struct torture_context *tctx)
+{
+ const char *sharemode_string, *access_string, *filename, *operation;
+ uint32_t sharemode, access;
+ struct smb2_tree *tree;
+ struct smb2_create create = { 0 };
+ NTSTATUS status;
+ bool ret = true;
+ int error = 0;
+
+ sharemode_string = torture_setting_string(tctx, "sharemode", "RWD");
+ sharemode = smb2_util_share_access(sharemode_string);
+
+ access_string = torture_setting_string(tctx, "access", "0xf01ff");
+ access = smb_strtoul(access_string, NULL, 0, &error, SMB_STR_STANDARD);
+ if (error != 0) {
+ torture_comment(tctx, "Initializing access failed.\n");
+ return false;
+ }
+
+ filename = torture_setting_string(tctx, "filename", "testfile");
+ operation = torture_setting_string(tctx, "operation", "WD");
+
+ if (!torture_smb2_connection(tctx, &tree)) {
+ torture_comment(tctx, "Initializing smb2 connection failed.\n");
+ return false;
+ }
+
+ create.in.desired_access = access;
+ create.in.alloc_size = 0;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = sharemode;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.create_options = 0;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.security_flags = 0;
+ create.in.fname = filename;
+ create.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ create.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE failed\n");
+
+ if (strchr(operation, 'R')) {
+ struct smb2_read read = { 0 };
+
+ read.in.file.handle = create.out.file.handle;
+ read.in.offset = 0;
+ read.in.length = 1;
+
+ status = smb2_read(tree, tctx, &read);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "READ failed\n");
+ }
+
+ if (strchr(operation, 'W')) {
+ char buf[1];
+ status = smb2_util_write(tree, create.out.file.handle,
+ &buf, 0, sizeof(buf));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "WRITE failed\n");
+ }
+
+ if (strchr(operation, 'D')) {
+ union smb_setfileinfo sfinfo = { };
+
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = create.out.file.handle;
+
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "SETINFO failed\n");
+
+ status = smb2_util_close(tree, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE failed\n");
+ }
+
+done:
+ return ret;
+}
+
+struct sharemode_info {
+ const char *sharemode;
+ uint32_t access_mask;
+ bool expect_ok;
+} sharemode_table[] = {
+
+ /*
+ * Basic tests, check each permission bit against every
+ * possible sharemode combination.
+ */
+
+ { "R", SEC_FILE_READ_DATA, true, },
+ { "R", SEC_FILE_WRITE_DATA, false, },
+ { "R", SEC_FILE_APPEND_DATA, false, },
+ { "R", SEC_FILE_READ_EA, true, },
+ { "R", SEC_FILE_WRITE_EA, true, },
+ { "R", SEC_FILE_EXECUTE, true, },
+ { "R", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "R", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "R", SEC_STD_DELETE, false, },
+ { "R", SEC_STD_READ_CONTROL, true, },
+ { "R", SEC_STD_WRITE_DAC, true, },
+ { "R", SEC_STD_WRITE_OWNER, true, },
+ { "R", SEC_STD_SYNCHRONIZE, true, },
+
+ { "W", SEC_FILE_READ_DATA, false },
+ { "W", SEC_FILE_WRITE_DATA, true, },
+ { "W", SEC_FILE_APPEND_DATA, true, },
+ { "W", SEC_FILE_READ_EA, true, },
+ { "W", SEC_FILE_WRITE_EA, true, },
+ { "W", SEC_FILE_EXECUTE, false, },
+ { "W", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "W", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "W", SEC_STD_DELETE, false, },
+ { "W", SEC_STD_READ_CONTROL, true, },
+ { "W", SEC_STD_WRITE_DAC, true, },
+ { "W", SEC_STD_WRITE_OWNER, true, },
+ { "W", SEC_STD_SYNCHRONIZE, true, },
+
+ { "D", SEC_FILE_READ_DATA, false },
+ { "D", SEC_FILE_WRITE_DATA, false },
+ { "D", SEC_FILE_APPEND_DATA, false },
+ { "D", SEC_FILE_READ_EA, true, },
+ { "D", SEC_FILE_WRITE_EA, true, },
+ { "D", SEC_FILE_EXECUTE, false, },
+ { "D", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "D", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "D", SEC_STD_DELETE, true, },
+ { "D", SEC_STD_READ_CONTROL, true, },
+ { "D", SEC_STD_WRITE_DAC, true, },
+ { "D", SEC_STD_WRITE_OWNER, true, },
+ { "D", SEC_STD_SYNCHRONIZE, true, },
+
+ { "RW", SEC_FILE_READ_DATA, true, },
+ { "RW", SEC_FILE_WRITE_DATA, true, },
+ { "RW", SEC_FILE_APPEND_DATA, true, },
+ { "RW", SEC_FILE_READ_EA, true, },
+ { "RW", SEC_FILE_WRITE_EA, true, },
+ { "RW", SEC_FILE_EXECUTE, true, },
+ { "RW", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "RW", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "RW", SEC_STD_DELETE, false, },
+ { "RW", SEC_STD_READ_CONTROL, true, },
+ { "RW", SEC_STD_WRITE_DAC, true, },
+ { "RW", SEC_STD_WRITE_OWNER, true, },
+ { "RW", SEC_STD_SYNCHRONIZE, true, },
+
+ { "RD", SEC_FILE_READ_DATA, true, },
+ { "RD", SEC_FILE_WRITE_DATA, false, },
+ { "RD", SEC_FILE_APPEND_DATA, false, },
+ { "RD", SEC_FILE_READ_EA, true, },
+ { "RD", SEC_FILE_WRITE_EA, true, },
+ { "RD", SEC_FILE_EXECUTE, true, },
+ { "RD", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "RD", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "RD", SEC_STD_DELETE, true, },
+ { "RD", SEC_STD_READ_CONTROL, true, },
+ { "RD", SEC_STD_WRITE_DAC, true, },
+ { "RD", SEC_STD_WRITE_OWNER, true, },
+ { "RD", SEC_STD_SYNCHRONIZE, true, },
+
+ { "WD", SEC_FILE_READ_DATA, false },
+ { "WD", SEC_FILE_WRITE_DATA, true, },
+ { "WD", SEC_FILE_APPEND_DATA, true, },
+ { "WD", SEC_FILE_READ_EA, true },
+ { "WD", SEC_FILE_WRITE_EA, true, },
+ { "WD", SEC_FILE_EXECUTE, false },
+ { "WD", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "WD", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "WD", SEC_STD_DELETE, true, },
+ { "WD", SEC_STD_READ_CONTROL, true, },
+ { "WD", SEC_STD_WRITE_DAC, true, },
+ { "WD", SEC_STD_WRITE_OWNER, true, },
+ { "WD", SEC_STD_SYNCHRONIZE, true, },
+
+ { "RWD", SEC_FILE_READ_DATA, true },
+ { "RWD", SEC_FILE_WRITE_DATA, true, },
+ { "RWD", SEC_FILE_APPEND_DATA, true, },
+ { "RWD", SEC_FILE_READ_EA, true },
+ { "RWD", SEC_FILE_WRITE_EA, true, },
+ { "RWD", SEC_FILE_EXECUTE, true, },
+ { "RWD", SEC_FILE_READ_ATTRIBUTE, true, },
+ { "RWD", SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "RWD", SEC_STD_DELETE, true, },
+ { "RWD", SEC_STD_READ_CONTROL, true, },
+ { "RWD", SEC_STD_WRITE_DAC, true, },
+ { "RWD", SEC_STD_WRITE_OWNER, true, },
+ { "RWD", SEC_STD_SYNCHRONIZE, true, },
+
+ /*
+ * Some more interesting cases. Always request READ or WRITE
+ * access, as that will trigger the opening of a file
+ * description in Samba. This especially useful for file
+ * systems that enforce share modes on open file descriptors.
+ */
+
+ { "R", SEC_FILE_READ_DATA, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, false, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, false, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_STD_DELETE, false, },
+ { "R", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
+ { "R", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
+
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_READ_DATA, false, },
+ { "W", SEC_FILE_WRITE_DATA, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_READ_EA, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_EA, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_EXECUTE, false, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_STD_DELETE, false, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_STD_READ_CONTROL, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_DAC, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_OWNER, true, },
+ { "W", SEC_FILE_WRITE_DATA|SEC_STD_SYNCHRONIZE, true, },
+
+ { "RW", SEC_FILE_READ_DATA, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_STD_DELETE, false, },
+ { "RW", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
+ { "RW", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
+
+ { "RD", SEC_FILE_READ_DATA, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, false, },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, false, },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_STD_DELETE, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
+ { "RD", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
+
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_READ_DATA, false },
+ { "WD", SEC_FILE_WRITE_DATA, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_READ_EA, true },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_EA, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_EXECUTE, false },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_STD_DELETE, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_STD_READ_CONTROL, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_DAC, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_STD_WRITE_OWNER, true, },
+ { "WD", SEC_FILE_WRITE_DATA|SEC_STD_SYNCHRONIZE, true, },
+
+ { "RWD", SEC_FILE_READ_DATA, true },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_APPEND_DATA, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_READ_EA, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_EA, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_EXECUTE, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_FILE_WRITE_ATTRIBUTE, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_STD_DELETE, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_STD_READ_CONTROL, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_STD_WRITE_DAC, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_STD_WRITE_OWNER, true, },
+ { "RWD", SEC_FILE_READ_DATA|SEC_STD_SYNCHRONIZE, true, },
+};
+
+/*
+ * Test conflicting sharemodes through SMB2: First open takes a
+ * sharemode, second open with potentially conflicting access.
+ */
+static bool test_smb2_sharemode_access(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = "test_sharemode";
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sharemode_table); i++) {
+ struct sharemode_info *info = &sharemode_table[i];
+ struct smb2_create create1 = { 0 }, create2 = { 0 };
+ NTSTATUS expected_status;
+
+ torture_comment(tctx, "index %3d, sharemode %3s, "
+ "access mask 0x%06x\n",
+ i, info->sharemode, info->access_mask);
+
+ create1.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create1.in.alloc_size = 0;
+ create1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create1.in.share_access =
+ smb2_util_share_access(info->sharemode);
+ create1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create1.in.create_options = 0;
+ create1.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create1.in.fname = fname;
+ create1.in.security_flags = 0;
+ create1.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ create1.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ status = smb2_create(tree1, tctx, &create1);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ create2.in.desired_access = info->access_mask;
+ create2.in.alloc_size = 0;
+ create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create2.in.create_options = 0;
+ create2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create2.in.fname = fname;
+ create2.in.security_flags = 0;
+ create2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ create2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ status = smb2_create(tree2, tctx, &create2);
+ expected_status = info->expect_ok ?
+ NT_STATUS_OK : NT_STATUS_SHARING_VIOLATION;
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ expected_status, ret,
+ done, "Unexpected status on "
+ "second create.\n");
+
+ status = smb2_util_close(tree1, create1.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to close "
+ "first handle.\n");
+
+ if (info->expect_ok) {
+ status = smb2_util_close(tree2, create2.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to close "
+ "second handle.\n");
+ }
+ }
+
+done:
+ smb2_util_unlink(tree1, fname);
+ return ret;
+}
+
+/*
+ * Test conflicting sharemodes through SMB2: First open file with
+ * different access masks, second open requests potentially conflicting
+ * sharemode.
+ */
+static bool test_smb2_access_sharemode(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = "test_sharemode";
+ NTSTATUS status;
+ bool ret = true;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sharemode_table); i++) {
+ struct sharemode_info *info = &sharemode_table[i];
+ struct smb2_create create1 = { 0 }, create2 = { 0 };
+ NTSTATUS expected_status;
+
+ torture_comment(tctx, "index %3d, access mask 0x%06x, "
+ "sharemode %3s\n",
+ i, info->access_mask, info->sharemode);
+
+ create1.in.desired_access = info->access_mask;
+ create1.in.alloc_size = 0;
+ create1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ create1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create1.in.create_options = 0;
+ create1.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create1.in.fname = fname;
+ create1.in.security_flags = 0;
+ create1.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ create1.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ status = smb2_create(tree1, tctx, &create1);
+
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ create2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create2.in.alloc_size = 0;
+ create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create2.in.share_access =
+ smb2_util_share_access(info->sharemode);
+ create2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create2.in.create_options = 0;
+ create2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create2.in.fname = fname;
+ create2.in.security_flags = 0;
+ create2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
+ create2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+
+ status = smb2_create(tree2, tctx, &create2);
+
+ expected_status = info->expect_ok ?
+ NT_STATUS_OK : NT_STATUS_SHARING_VIOLATION;
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ expected_status, ret,
+ done, "Unexpected status on "
+ "second create.\n");
+
+ status = smb2_util_close(tree1, create1.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to close "
+ "first handle.\n");
+
+ if (info->expect_ok) {
+ status = smb2_util_close(tree2, create2.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Failed to close "
+ "second handle.\n");
+ }
+ }
+
+done:
+ smb2_util_unlink(tree1, fname);
+ return ret;
+}
+
+/*
+ * Test initial stat open with share nothing doesn't trigger SHARING_VIOLTION
+ * errors.
+ */
+static bool test_smb2_bug14375(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "test_bug14375";
+ struct smb2_create cr1;
+ struct smb2_create cr2;
+ struct smb2_create cr3;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ cr1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ cr2 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ cr3 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ status = smb2_util_close(tree, cr1.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE file failed\n");
+ status = smb2_util_close(tree, cr2.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE file failed\n");
+ status = smb2_util_close(tree, cr3.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CLOSE file failed\n");
+
+ cr1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ cr2 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_ATTRIBUTE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_NONE,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+ cr3 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tctx, &cr3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "CREATE file failed\n");
+
+done:
+ smb2_util_close(tree, cr1.out.file.handle);
+ smb2_util_close(tree, cr2.out.file.handle);
+ smb2_util_close(tree, cr3.out.file.handle);
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+struct torture_suite *torture_smb2_sharemode_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "sharemode");
+
+ torture_suite_add_2smb2_test(suite, "sharemode-access",
+ test_smb2_sharemode_access);
+ torture_suite_add_2smb2_test(suite, "access-sharemode",
+ test_smb2_access_sharemode);
+ torture_suite_add_1smb2_test(suite, "bug14375",
+ test_smb2_bug14375);
+
+ suite->description = talloc_strdup(suite, "SMB2-SHAREMODE tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
new file mode 100644
index 0000000..5b6477e
--- /dev/null
+++ b/source4/torture/smb2/smb2.c
@@ -0,0 +1,230 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+
+#include "torture/smbtorture.h"
+#include "torture/smb2/proto.h"
+#include "../lib/util/dlinklist.h"
+
+static bool wrap_simple_1smb2_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct smb2_tree *);
+ bool ret;
+ struct smb2_tree *tree1;
+ TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);
+
+ if (!torture_smb2_connection(torture_ctx, &tree1)) {
+ torture_fail(torture_ctx,
+ "Establishing SMB2 connection failed\n");
+ return false;
+ }
+
+ /*
+ * This is a trick:
+ * The test might close the connection. If we steal the tree context
+ * before that and free the parent instead of tree directly, we avoid
+ * a double free error.
+ */
+ talloc_steal(mem_ctx, tree1);
+
+ fn = test->fn;
+
+ ret = fn(torture_ctx, tree1);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+struct torture_test *torture_suite_add_1smb2_test(struct torture_suite *suite,
+ const char *name,
+ bool (*run)(struct torture_context *,
+ struct smb2_tree *))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_simple_1smb2_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+
+static bool wrap_simple_2smb2_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct smb2_tree *, struct smb2_tree *);
+ bool ret = false;
+
+ struct smb2_tree *tree1;
+ struct smb2_tree *tree2;
+ TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);
+
+ if (!torture_smb2_connection(torture_ctx, &tree1)) {
+ torture_fail(torture_ctx,
+ "Establishing SMB2 connection failed\n");
+ goto done;
+ }
+
+ talloc_steal(mem_ctx, tree1);
+
+ if (!torture_smb2_connection(torture_ctx, &tree2)) {
+ torture_fail(torture_ctx,
+ "Establishing SMB2 connection failed\n");
+ goto done;
+ }
+
+ talloc_steal(mem_ctx, tree2);
+
+ fn = test->fn;
+
+ ret = fn(torture_ctx, tree1, tree2);
+
+done:
+ /* the test may already have closed some of the connections */
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+
+struct torture_test *torture_suite_add_2smb2_test(struct torture_suite *suite,
+ const char *name,
+ bool (*run)(struct torture_context *,
+ struct smb2_tree *,
+ struct smb2_tree *))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_simple_2smb2_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "smb2");
+ torture_suite_add_simple_test(suite, "connect", torture_smb2_connect);
+ torture_suite_add_suite(suite, torture_smb2_scan_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_getinfo_init(suite));
+ torture_suite_add_simple_test(suite, "setinfo", torture_smb2_setinfo);
+ torture_suite_add_suite(suite, torture_smb2_lock_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_read_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_aio_delay_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_bench_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_create_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_twrp_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_fileid_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_acls_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_acls_non_canonical_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_notify_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_notify_inotify_init(suite));
+ torture_suite_add_suite(suite,
+ torture_smb2_notify_disabled_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_durable_open_init(suite));
+ torture_suite_add_suite(suite,
+ torture_smb2_durable_open_disconnect_init(suite));
+ torture_suite_add_suite(suite,
+ torture_smb2_durable_v2_open_init(suite));
+ torture_suite_add_suite(suite,
+ torture_smb2_durable_v2_delay_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_dir_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_lease_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_compound_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_compound_find_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_compound_async_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_oplocks_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_kernel_oplocks_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_streams_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_ioctl_init(suite));
+ torture_suite_add_simple_test(suite, "set-sparse-ioctl",
+ test_ioctl_set_sparse);
+ torture_suite_add_simple_test(suite, "zero-data-ioctl",
+ test_ioctl_zero_data);
+ torture_suite_add_simple_test(suite, "ioctl-on-stream",
+ test_ioctl_alternate_data_stream);
+ torture_suite_add_suite(suite, torture_smb2_rename_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_sharemode_init(suite));
+ torture_suite_add_1smb2_test(suite, "hold-oplock", test_smb2_hold_oplock);
+ torture_suite_add_suite(suite, torture_smb2_session_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_session_req_sign_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_replay_init(suite));
+ torture_suite_add_simple_test(suite, "dosmode", torture_smb2_dosmode);
+ torture_suite_add_simple_test(suite, "async_dosmode", torture_smb2_async_dosmode);
+ torture_suite_add_simple_test(suite, "maxfid", torture_smb2_maxfid);
+ torture_suite_add_simple_test(suite, "hold-sharemode",
+ torture_smb2_hold_sharemode);
+ torture_suite_add_simple_test(suite, "check-sharemode",
+ torture_smb2_check_sharemode);
+ torture_suite_add_suite(suite, torture_smb2_crediting_init(suite));
+
+ torture_suite_add_suite(suite, torture_smb2_doc_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_multichannel_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_samba3misc_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_timestamps_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_timestamp_resolution_init(suite));
+ torture_suite_add_1smb2_test(suite, "openattr", torture_smb2_openattrtest);
+ torture_suite_add_1smb2_test(suite, "winattr", torture_smb2_winattrtest);
+ torture_suite_add_1smb2_test(suite, "winattr2", torture_smb2_winattr2);
+ torture_suite_add_1smb2_test(suite, "sdread", torture_smb2_sdreadtest);
+ torture_suite_add_suite(suite, torture_smb2_readwrite_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_max_allowed(suite));
+ torture_suite_add_1smb2_test(suite, "tcon", run_tcon_test);
+ torture_suite_add_1smb2_test(suite, "mkdir", torture_smb2_mkdir);
+ torture_suite_add_suite(suite, torture_smb2_name_mangling_init(suite));
+
+ torture_suite_add_suite(suite, torture_smb2_charset(suite));
+ torture_suite_add_1smb2_test(suite, "secleak", torture_smb2_sec_leak);
+ torture_suite_add_1smb2_test(suite, "session-id", run_sessidtest);
+ torture_suite_add_suite(suite, torture_smb2_deny_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_ea(suite));
+ torture_suite_add_suite(suite, torture_smb2_create_no_streams_init(suite));
+
+ suite->description = talloc_strdup(suite, "SMB2-specific tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/smb2/streams.c b/source4/torture/smb2/streams.c
new file mode 100644
index 0000000..f18048f
--- /dev/null
+++ b/source4/torture/smb2/streams.c
@@ -0,0 +1,2424 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test alternate data streams
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+
+#include "smb_constants.h"
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "lib/util/tsort.h"
+
+#define DNAME "teststreams"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value %s=%d - should be %d\n", \
+ __location__, #v, (int)v, (int)correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_NTTIME(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value %s=%llu - should be %llu\n", \
+ __location__, #v, (unsigned long long)v, \
+ (unsigned long long)correct); \
+ ret = false; \
+ }} while (0)
+
+#define CHECK_STR(v, correct) do { \
+ bool ok; \
+ if ((v) && !(correct)) { \
+ ok = false; \
+ } else if (!(v) && (correct)) { \
+ ok = false; \
+ } else if (!(v) && !(correct)) { \
+ ok = true; \
+ } else if (strcmp((v), (correct)) == 0) { \
+ ok = true; \
+ } else { \
+ ok = false; \
+ } \
+ if (!ok) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value %s='%s' - " \
+ "should be '%s'\n", \
+ __location__, #v, (v)?(v):"NULL", \
+ (correct)?(correct):"NULL"); \
+ ret = false; \
+ }} while (0)
+
+
+static int qsort_string(char * const *s1, char * const *s2)
+{
+ return strcmp(*s1, *s2);
+}
+
+static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
+{
+ return strcmp(s1->stream_name.s, s2->stream_name.s);
+}
+
+static bool check_stream(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *location,
+ TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const char *sname,
+ const char *value)
+{
+ struct smb2_handle handle;
+ struct smb2_create create;
+ struct smb2_read r;
+ NTSTATUS status;
+ const char *full_name;
+
+ full_name = talloc_asprintf(mem_ctx, "%s:%s", fname, sname);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = full_name;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (value == NULL) {
+ return true;
+ } else {
+ torture_comment(tctx, "Unable to open stream %s\n",
+ full_name);
+ return false;
+ }
+ }
+
+ handle = create.out.file.handle;
+ if (value == NULL) {
+ return true;
+ }
+
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = handle;
+ r.in.length = strlen(value)+11;
+ r.in.offset = 0;
+
+ status = smb2_read(tree, tree, &r);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "(%s) Failed to read %lu bytes from "
+ "stream '%s'\n", location, (long)strlen(value), full_name);
+ return false;
+ }
+
+ if (memcmp(r.out.data.data, value, strlen(value)) != 0) {
+ torture_comment(tctx, "(%s) Bad data in stream\n", location);
+ return false;
+ }
+
+ smb2_util_close(tree, handle);
+ return true;
+}
+
+static bool check_stream_list(struct smb2_tree *tree,
+ struct torture_context *tctx,
+ const char *fname,
+ unsigned int num_exp,
+ const char **exp,
+ struct smb2_handle h)
+{
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ unsigned int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ char **exp_sort;
+ struct stream_struct *stream_sort;
+ bool ret = false;
+
+ finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
+ finfo.generic.in.file.handle = h;
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "(%s) smb_raw_pathinfo failed: %s\n",
+ __location__, nt_errstr(status));
+ goto fail;
+ }
+
+ if (finfo.stream_info.out.num_streams != num_exp) {
+ torture_comment(tctx, "(%s) expected %d streams, got %d\n",
+ __location__, num_exp, finfo.stream_info.out.num_streams);
+ goto fail;
+ }
+
+ if (num_exp == 0) {
+ ret = true;
+ goto fail;
+ }
+
+ exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
+
+ if (exp_sort == NULL) {
+ goto fail;
+ }
+
+ TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
+
+ stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
+ finfo.stream_info.out.num_streams *
+ sizeof(*stream_sort));
+
+ if (stream_sort == NULL) {
+ goto fail;
+ }
+
+ TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
+
+ for (i=0; i<num_exp; i++) {
+ if (strcmp(exp_sort[i], stream_sort[i].stream_name.s) != 0) {
+ torture_comment(tctx,
+ "(%s) expected stream name %s, got %s\n",
+ __location__, exp_sort[i],
+ stream_sort[i].stream_name.s);
+ goto fail;
+ }
+ }
+
+ ret = true;
+ fail:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+static bool test_stream_dir(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream.txt";
+ const char *sname1;
+ bool ret = true;
+ const char *basedir_data;
+ struct smb2_handle h;
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ basedir_data = talloc_asprintf(mem_ctx, "%s::$DATA", DNAME);
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
+ torture_comment(tctx, "%s\n", sname1);
+
+ torture_comment(tctx, "(%s) opening non-existent directory stream\n",
+ __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+ io.smb2.in.create_flags = 0;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
+
+ torture_comment(tctx, "(%s) opening basedir stream\n", __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = basedir_data;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY);
+
+ torture_comment(tctx, "(%s) opening basedir ::$DATA stream\n",
+ __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0x10;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = 0;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = basedir_data;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_FILE_IS_A_DIRECTORY);
+
+ torture_comment(tctx, "(%s) list the streams on the basedir\n",
+ __location__);
+ ret &= check_stream_list(tree, mem_ctx, DNAME, 0, NULL, h);
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_stream_io(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream.txt";
+ const char *sname1, *sname2;
+ bool ret = true;
+ struct smb2_handle h, h2;
+
+ const char *one[] = { "::$DATA" };
+ const char *two[] = { "::$DATA", ":Second Stream:$DATA" };
+ const char *three[] = { "::$DATA", ":Stream One:$DATA",
+ ":Second Stream:$DATA" };
+
+ ZERO_STRUCT(h);
+ ZERO_STRUCT(h2);
+
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
+ sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
+ "Second Stream");
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "(%s) creating a stream on a non-existent file\n",
+ __location__);
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Stream One", NULL);
+
+ torture_comment(tctx, "(%s) check that open of base file is allowed\n", __location__);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ torture_comment(tctx, "(%s) writing to stream\n", __location__);
+ status = smb2_util_write(tree, h2, "test data", 0, 9);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h2);
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Stream One", "test data");
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.fname = sname1;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ torture_comment(tctx, "(%s) modifying stream\n", __location__);
+ status = smb2_util_write(tree, h2, "MORE DATA ", 5, 10);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h2);
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Stream One:$FOO", NULL);
+
+ torture_comment(tctx, "(%s) creating a stream2 on a existing file\n",
+ __location__);
+ io.smb2.in.fname = sname2;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ torture_comment(tctx, "(%s) modifying stream\n", __location__);
+ status= smb2_util_write(tree, h2, "SECOND STREAM", 0, 13);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h2);
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Stream One", "test MORE DATA ");
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Stream One:$DATA", "test MORE DATA ");
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Stream One:", NULL);
+
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL,
+ "check_stream(\"Stream One:*\") failed\n");
+ goto done;
+ }
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Second Stream", "SECOND STREAM");
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "SECOND STREAM:$DATA", "SECOND STREAM");
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Second Stream:$DATA", "SECOND STREAM");
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Second Stream:", NULL);
+
+ ret &= check_stream(tctx, tree, __location__, mem_ctx, fname,
+ "Second Stream:$FOO", NULL);
+
+ if (!ret) {
+ torture_result(tctx, TORTURE_FAIL,
+ "check_stream(\"Second Stream:*\") failed\n");
+ goto done;
+ }
+
+ io.smb2.in.fname = sname2;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+ check_stream_list(tree, tctx, fname, 3, three, h2);
+
+ smb2_util_close(tree, h2);
+
+ torture_comment(tctx, "(%s) deleting stream\n", __location__);
+ status = smb2_util_unlink(tree, sname1);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ io.smb2.in.fname = sname2;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+ check_stream_list(tree, tctx, fname, 2, two, h2);
+ smb2_util_close(tree, h2);
+
+ torture_comment(tctx, "(%s) delete a stream via delete-on-close\n",
+ __location__);
+ io.smb2.in.fname = sname2;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ smb2_util_close(tree, h2);
+ status = smb2_util_unlink(tree, sname2);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ h2 = io.smb2.out.file.handle;
+ check_stream_list(tree,tctx, fname, 1, one, h2);
+ smb2_util_close(tree, h2);
+
+ if (!torture_setting_bool(tctx, "samba4", false)) {
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.fname = sname1;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, io.ntcreatex.out.file.handle);
+ io.smb2.in.fname = sname2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, io.ntcreatex.out.file.handle);
+ torture_comment(tctx, "(%s) deleting file\n", __location__);
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+
+done:
+ smb2_util_close(tree, h2);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_zero_byte_stream(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream.txt";
+ const char *sname;
+ bool ret = true;
+ struct smb2_handle h, bh;
+ const char *streams[] = { "::$DATA", ":foo:$DATA" };
+
+ sname = talloc_asprintf(mem_ctx, "%s:%s", fname, "foo");
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "testdir");
+ smb2_util_close(tree, h);
+
+ torture_comment(tctx, "(%s) Check 0 byte named stream\n",
+ __location__);
+
+ /* Create basefile */
+ ZERO_STRUCT(io);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.fname = fname;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /* Create named stream and close it */
+ ZERO_STRUCT(io);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.fname = sname;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "create");
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /*
+ * Check stream list, the 0 byte stream MUST be returned by
+ * the server.
+ */
+ ZERO_STRUCT(io);
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ bh = io.smb2.out.file.handle;
+
+ ret = check_stream_list(tree,tctx, fname, 2, streams, bh);
+ torture_assert_goto(tctx, ret == true, ret, done, "smb2_create");
+ smb2_util_close(tree, bh);
+
+done:
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ test stream sharemodes
+*/
+static bool test_stream_sharemodes(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream_share.txt";
+ const char *sname1, *sname2;
+ bool ret = true;
+ struct smb2_handle h, h1, h2;
+
+ ZERO_STRUCT(h);
+ ZERO_STRUCT(h1);
+ ZERO_STRUCT(h2);
+
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
+ sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
+ "Second Stream");
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "(%s) Testing stream share mode conflicts\n",
+ __location__);
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /*
+ * A different stream does not give a sharing violation
+ */
+
+ io.smb2.in.fname = sname2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ /*
+ * ... whereas the same stream does with unchanged access/share_access
+ * flags
+ */
+
+ io.smb2.in.fname = sname1;
+ io.smb2.in.create_disposition = 0;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.smb2.in.fname = sname2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ * Test FILE_SHARE_DELETE on streams
+ *
+ * A stream opened with !FILE_SHARE_DELETE prevents the main file to be opened
+ * with SEC_STD_DELETE.
+ *
+ * The main file opened with !FILE_SHARE_DELETE does *not* prevent a stream to
+ * be opened with SEC_STD_DELETE.
+ *
+ * A stream held open with FILE_SHARE_DELETE allows the file to be
+ * deleted. After the main file is deleted, access to the open file descriptor
+ * still works, but all name-based access to both the main file as well as the
+ * stream is denied with DELETE pending.
+ *
+ * This means, an open of the main file with SEC_STD_DELETE should walk all
+ * streams and also open them with SEC_STD_DELETE. If any of these opens gives
+ * SHARING_VIOLATION, the main open fails.
+ *
+ * Closing the main file after delete_on_close has been set does not really
+ * unlink it but leaves the corresponding share mode entry with
+ * delete_on_close being set around until all streams are closed.
+ *
+ * Opening a stream must also look at the main file's share mode entry, look
+ * at the delete_on_close bit and potentially return DELETE_PENDING.
+ */
+
+static bool test_stream_delete(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream_delete.txt";
+ const char *sname1;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h1 = {{0}};
+ struct smb2_read r;
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "Skipping test as samba4 is enabled\n");
+ goto done;
+ }
+
+ ZERO_STRUCT(h);
+ ZERO_STRUCT(h1);
+
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
+
+ /* clean slate .. */
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "(%s) opening non-existent file stream\n",
+ __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ status = smb2_util_write(tree, h1, "test data", 0, 9);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * One stream opened without FILE_SHARE_DELETE prevents the main file
+ * to be deleted or even opened with DELETE access
+ */
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.fname = fname;
+ io.smb2.in.desired_access = SEC_STD_DELETE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ smb2_util_close(tree, h1);
+
+ /*
+ * ... but unlink works if a stream is opened with FILE_SHARE_DELETE
+ */
+
+ io.smb2.in.fname = sname1;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ status = smb2_util_unlink(tree, fname);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * file access still works on the stream while the main file is closed
+ */
+ ZERO_STRUCT(r);
+ r.in.file.handle = h1;
+ r.in.length = 9;
+ r.in.offset = 0;
+
+ status = smb2_read(tree, tree, &r);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * name-based access to both the main file and the stream does not
+ * work anymore but gives DELETE_PENDING
+ */
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
+
+ /*
+ * older S3 doesn't do this
+ */
+
+ io.smb2.in.fname = sname1;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_DELETE_PENDING);
+
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ /*
+ * After closing the stream the file is really gone.
+ */
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ test stream names
+*/
+static bool test_stream_names(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ union smb_fileinfo finfo;
+ union smb_fileinfo stinfo;
+ union smb_setfileinfo sinfo;
+ const char *fname = DNAME "\\stream_names.txt";
+ const char *sname1, *sname1b, *sname1c, *sname1d;
+ const char *sname2, *snamew, *snamew2;
+ const char *snamer1;
+ bool ret = true;
+ struct smb2_handle h, h1, h2, h3;
+ int i;
+ const char *four[4] = {
+ "::$DATA",
+ ":\x05Stream\n One:$DATA",
+ ":MStream Two:$DATA",
+ ":?Stream*:$DATA"
+ };
+ const char *five1[5] = {
+ "::$DATA",
+ ":\x05Stream\n One:$DATA",
+ ":BeforeRename:$DATA",
+ ":MStream Two:$DATA",
+ ":?Stream*:$DATA"
+ };
+ const char *five2[5] = {
+ "::$DATA",
+ ":\x05Stream\n One:$DATA",
+ ":AfterRename:$DATA",
+ ":MStream Two:$DATA",
+ ":?Stream*:$DATA"
+ };
+
+ ZERO_STRUCT(h);
+ ZERO_STRUCT(h1);
+ ZERO_STRUCT(h2);
+ ZERO_STRUCT(h3);
+
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "\x05Stream\n One");
+ sname1b = talloc_asprintf(mem_ctx, "%s:", sname1);
+ sname1c = talloc_asprintf(mem_ctx, "%s:$FOO", sname1);
+ sname1d = talloc_asprintf(mem_ctx, "%s:?D*a", sname1);
+ sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname, "MStream Two");
+ snamew = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname, "?Stream*");
+ snamew2 = talloc_asprintf(mem_ctx, "%s\\stream*:%s:$DATA", DNAME,
+ "?Stream*");
+ snamer1 = talloc_asprintf(mem_ctx, "%s:%s:$DATA", fname,
+ "BeforeRename");
+
+ /* clean slate ...*/
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "(%s) testing stream names\n", __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /*
+ * A different stream does not give a sharing violation
+ */
+
+ io.smb2.in.fname = sname2;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h2 = io.smb2.out.file.handle;
+
+ /*
+ * ... whereas the same stream does with unchanged access/share_access
+ * flags
+ */
+
+ io.smb2.in.fname = sname1;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.smb2.in.fname = sname1b;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ io.smb2.in.fname = sname1c;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /* w2k returns INVALID_PARAMETER */
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
+ io.smb2.in.fname = sname1d;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /* w2k returns INVALID_PARAMETER */
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+ } else {
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
+ io.smb2.in.fname = sname2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ io.smb2.in.fname = snamew;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.smb2.out.file.handle;
+
+ io.smb2.in.fname = snamew2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID);
+
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ret &= check_stream_list(tree, tctx, fname, 4, four,
+ io.smb2.out.file.handle);
+ CHECK_VALUE(ret, true);
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ if (torture_setting_bool(tctx, "samba4", true)) {
+ goto done;
+ }
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.handle = io.smb2.out.file.handle;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ret &= check_stream_list(tree, tctx, fname, 4, four,
+ io.smb2.out.file.handle);
+
+ CHECK_VALUE(ret, true);
+ for (i=0; i < 4; i++) {
+ NTTIME write_time;
+ uint64_t stream_size;
+ char *path = talloc_asprintf(tctx, "%s%s",
+ fname, four[i]);
+
+ char *rpath = talloc_strdup(path, path);
+ char *p = strrchr(rpath, ':');
+ /* eat :$DATA */
+ *p = 0;
+ p--;
+ if (*p == ':') {
+ /* eat ::$DATA */
+ *p = 0;
+ }
+ torture_comment(tctx, "(%s): i[%u][%s]\n",
+ __location__, i,path);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.fname = path;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.path = fname;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ stinfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_NTTIME(stinfo.all_info.out.create_time,
+ finfo.all_info.out.create_time);
+ CHECK_NTTIME(stinfo.all_info.out.access_time,
+ finfo.all_info.out.access_time);
+ CHECK_NTTIME(stinfo.all_info.out.write_time,
+ finfo.all_info.out.write_time);
+ CHECK_NTTIME(stinfo.all_info.out.change_time,
+ finfo.all_info.out.change_time);
+ }
+ CHECK_VALUE(stinfo.all_info.out.attrib,
+ finfo.all_info.out.attrib);
+ CHECK_VALUE(stinfo.all_info.out.size,
+ finfo.all_info.out.size);
+ CHECK_VALUE(stinfo.all_info.out.delete_pending,
+ finfo.all_info.out.delete_pending);
+ CHECK_VALUE(stinfo.all_info.out.directory,
+ finfo.all_info.out.directory);
+ CHECK_VALUE(stinfo.all_info.out.ea_size,
+ finfo.all_info.out.ea_size);
+
+ stinfo.generic.level = RAW_FILEINFO_NAME_INFORMATION;
+ stinfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_STR(rpath, stinfo.name_info.out.fname.s);
+ }
+
+ write_time = finfo.all_info.out.write_time;
+ write_time += i*1000000;
+ write_time /= 1000000;
+ write_time *= 1000000;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sinfo.basic_info.in.file.handle = h1;
+ sinfo.basic_info.in.write_time = write_time;
+ sinfo.basic_info.in.attrib = stinfo.all_info.out.attrib;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ stream_size = i*8192;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level =
+ RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = h1;
+ sinfo.end_of_file_info.in.size = stream_size;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ stinfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ stinfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &stinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ CHECK_NTTIME(stinfo.all_info.out.write_time,
+ write_time);
+ CHECK_VALUE(stinfo.all_info.out.attrib,
+ finfo.all_info.out.attrib);
+ }
+ CHECK_VALUE(stinfo.all_info.out.size,
+ stream_size);
+ CHECK_VALUE(stinfo.all_info.out.delete_pending,
+ finfo.all_info.out.delete_pending);
+ CHECK_VALUE(stinfo.all_info.out.directory,
+ finfo.all_info.out.directory);
+ CHECK_VALUE(stinfo.all_info.out.ea_size,
+ finfo.all_info.out.ea_size);
+
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ ret &= check_stream_list(tree, tctx, fname, 4, four,
+ io.smb2.out.file.handle);
+
+ smb2_util_close(tree, h1);
+ talloc_free(path);
+ }
+
+ torture_comment(tctx, "(%s): testing stream renames\n", __location__);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.fname = snamer1;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+ ret &= check_stream_list(tree,tctx, fname, 5, five1,
+ io.smb2.out.file.handle);
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = ":AfterRename:$DATA";
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ret &= check_stream_list(tree,tctx, fname, 5, five2,
+ io.smb2.out.file.handle);
+
+ CHECK_VALUE(ret, true);
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = false;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
+
+ ret &= check_stream_list(tree,tctx, fname, 5, five2,
+ io.smb2.out.file.handle);
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = ":MStream Two:$DATA";
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
+
+ ret &= check_stream_list(tree,tctx, fname, 5, five2,
+ io.smb2.out.file.handle);
+
+ CHECK_VALUE(ret, true);
+ /* TODO: we need to test more rename combinations */
+
+done:
+ smb2_util_close(tree, h1);
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ test stream names
+*/
+static bool test_stream_names2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream_names2.txt";
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h1 = {{0}};
+ uint8_t i;
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "(%s) testing stream names\n", __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ for (i=0x01; i < 0x7F; i++) {
+ char *path = talloc_asprintf(mem_ctx, "%s:Stream%c0x%02X:$DATA",
+ fname, i, i);
+ NTSTATUS expected;
+
+ switch (i) {
+ case '/':/*0x2F*/
+ case ':':/*0x3A*/
+ case '\\':/*0x5C*/
+ expected = NT_STATUS_OBJECT_NAME_INVALID;
+ break;
+ default:
+ expected = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ break;
+ }
+
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.fname = path;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ if (!NT_STATUS_EQUAL(status, expected)) {
+ torture_comment(tctx,
+ "(%s) %s:Stream%c0x%02X:$DATA%s => expected[%s]\n",
+ __location__, fname, isprint(i)?(char)i:' ', i,
+ isprint(i)?"":" (not printable)",
+ nt_errstr(expected));
+ }
+ CHECK_STATUS(status, expected);
+
+ talloc_free(path);
+ }
+
+done:
+ smb2_util_close(tree, h1);
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/*
+ test case insensitive stream names
+*/
+static bool test_stream_names3(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_fsinfo info;
+ const char *fname = DNAME "\\stream_names3.txt";
+ const char *sname = NULL;
+ const char *snamel = NULL;
+ const char *snameu = NULL;
+ const char *sdname = NULL;
+ const char *sdnamel = NULL;
+ const char *sdnameu = NULL;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle hf = {{0}};
+ struct smb2_handle hs = {{0}};
+ struct smb2_handle hsl = {{0}};
+ struct smb2_handle hsu = {{0}};
+ struct smb2_handle hsd = {{0}};
+ struct smb2_handle hsdl = {{0}};
+ struct smb2_handle hsdu = {{0}};
+ const char *streams[] = { "::$DATA", ":StreamName:$DATA", };
+
+ smb2_deltree(tree, DNAME);
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(info);
+ info.generic.level = RAW_QFS_ATTRIBUTE_INFORMATION;
+ info.generic.handle = h;
+ status = smb2_getinfo_fs(tree, tree, &info);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!(info.attribute_info.out.fs_attr & FILE_CASE_SENSITIVE_SEARCH)) {
+ torture_skip(tctx, "No FILE_CASE_SENSITIVE_SEARCH supported");
+ }
+
+ /*
+ * We create the following file:
+ *
+ * teststreams\\stream_names3.txt
+ *
+ * and add a stream named 'StreamName'
+ *
+ * Then we try to open the stream using the following names:
+ *
+ * teststreams\\stream_names3.txt:StreamName
+ * teststreams\\stream_names3.txt:streamname
+ * teststreams\\stream_names3.txt:STREAMNAME
+ * teststreams\\stream_names3.txt:StreamName:$dAtA
+ * teststreams\\stream_names3.txt:streamname:$data
+ * teststreams\\stream_names3.txt:STREAMNAME:$DATA
+ */
+ sname = talloc_asprintf(tctx, "%s:StreamName", fname);
+ torture_assert_not_null(tctx, sname, __location__);
+ snamel = strlower_talloc(tctx, sname);
+ torture_assert_not_null(tctx, snamel, __location__);
+ snameu = strupper_talloc(tctx, sname);
+ torture_assert_not_null(tctx, snameu, __location__);
+
+ sdname = talloc_asprintf(tctx, "%s:$dAtA", sname);
+ torture_assert_not_null(tctx, sdname, __location__);
+ sdnamel = strlower_talloc(tctx, sdname);
+ torture_assert_not_null(tctx, sdnamel, __location__);
+ sdnameu = strupper_talloc(tctx, sdname);
+ torture_assert_not_null(tctx, sdnameu, __location__);
+
+ torture_comment(tctx, "(%s) testing case insensitive stream names\n",
+ __location__);
+ status = torture_smb2_testfile(tree, fname, &hf);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_testfile(tree, sname, &hs);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, hs);
+
+ torture_assert(tctx,
+ check_stream_list(tree, tctx, fname,
+ ARRAY_SIZE(streams),
+ streams,
+ hf),
+ "streams");
+
+ status = torture_smb2_open(tree, sname, SEC_RIGHTS_FILE_ALL, &hs);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_open(tree, snamel, SEC_RIGHTS_FILE_ALL, &hsl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_open(tree, snameu, SEC_RIGHTS_FILE_ALL, &hsu);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_open(tree, sdname, SEC_RIGHTS_FILE_ALL, &hsd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_open(tree, sdnamel, SEC_RIGHTS_FILE_ALL, &hsdl);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = torture_smb2_open(tree, sdnameu, SEC_RIGHTS_FILE_ALL, &hsdu);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ smb2_util_close(tree, hsdu);
+ smb2_util_close(tree, hsdl);
+ smb2_util_close(tree, hsd);
+ smb2_util_close(tree, hsu);
+ smb2_util_close(tree, hsl);
+ smb2_util_close(tree, hs);
+ smb2_util_close(tree, hf);
+ smb2_util_close(tree, h);
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+#define CHECK_CALL_HANDLE(call, rightstatus) do { \
+ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \
+ sfinfo.generic.in.file.handle = h1; \
+ status = smb2_setinfo_file(tree, &sfinfo); \
+ if (!NT_STATUS_EQUAL(status, rightstatus)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s - %s (should be %s)\n", \
+ __location__, #call, \
+ nt_errstr(status), nt_errstr(rightstatus)); \
+ ret = false; \
+ } \
+ finfo1.generic.level = RAW_FILEINFO_ALL_INFORMATION; \
+ finfo1.generic.in.file.handle = h1; \
+ status2 = smb2_getinfo_file(tree, tctx, &finfo1); \
+ if (!NT_STATUS_IS_OK(status2)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) %s pathinfo - %s\n", \
+ __location__, #call, nt_errstr(status)); \
+ ret = false; \
+ }} while (0)
+
+/*
+ test stream renames
+*/
+static bool test_stream_rename(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status, status2;
+ union smb_open io;
+ const char *fname = DNAME "\\stream_rename.txt";
+ const char *sname1, *sname2;
+ union smb_fileinfo finfo1;
+ union smb_setfileinfo sfinfo;
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h1 = {{0}};
+
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname, "Stream One");
+ sname2 = talloc_asprintf(mem_ctx, "%s:%s:$DaTa", fname,
+ "Second Stream");
+
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ torture_comment(tctx, "(%s) testing stream renames\n", __location__);
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+
+ /* Create two streams. */
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+ smb2_util_close(tree, h1);
+
+ io.smb2.in.fname = sname2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ smb2_util_close(tree, h1);
+
+ /*
+ * Open the second stream.
+ */
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /*
+ * Now rename the second stream onto the first.
+ */
+
+ ZERO_STRUCT(sfinfo);
+
+ sfinfo.rename_information.in.overwrite = 1;
+ sfinfo.rename_information.in.root_fid = 0;
+ sfinfo.rename_information.in.new_name = ":Stream One";
+ CHECK_CALL_HANDLE(RENAME_INFORMATION, NT_STATUS_OK);
+done:
+ smb2_util_close(tree, h1);
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_stream_rename2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname1 = DNAME "\\stream_rename2.txt";
+ const char *fname2 = DNAME "\\stream2_rename2.txt";
+ const char *stream_name1 = ":Stream One:$DATA";
+ const char *stream_name2 = ":Stream Two:$DATA";
+ const char *stream_name_default = "::$DATA";
+ const char *sname1;
+ const char *sname2;
+ bool ret = true;
+ struct smb2_handle h, h1;
+ union smb_setfileinfo sinfo;
+
+ ZERO_STRUCT(h);
+ ZERO_STRUCT(h1);
+
+ sname1 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream One");
+ sname2 = talloc_asprintf(mem_ctx, "%s:%s", fname1, "Stream Two");
+
+ smb2_util_unlink(tree, fname1);
+ smb2_util_unlink(tree, fname2);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_STD_DELETE |
+ SEC_FILE_APPEND_DATA |
+ SEC_STD_READ_CONTROL;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = sname1;
+
+ /* Open/create new stream. */
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /*
+ * Reopen the stream for SMB2 renames.
+ */
+ io.smb2.in.fname = sname1;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /*
+ * Check SMB2 rename of a stream using :<stream>.
+ */
+ torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
+ ":<stream>\n", __location__);
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = 1;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = stream_name1;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Check SMB2 rename of an overwriting stream using :<stream>.
+ */
+ torture_comment(tctx, "(%s) Checking SMB2 rename of an overwriting "
+ "stream using :<stream>\n", __location__);
+
+ /* Create second stream. */
+ io.smb2.in.fname = sname2;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /* Rename the first stream onto the second. */
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.new_name = stream_name2;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, h1);
+
+ /*
+ * Reopen the stream with the new name.
+ */
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.fname = sname2;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ /*
+ * Check SMB2 rename of a stream using <base>:<stream>.
+ */
+ torture_comment(tctx, "(%s) Checking SMB2 rename of a stream using "
+ "<base>:<stream>\n", __location__);
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.new_name = sname1;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ if (!torture_setting_bool(tctx, "samba4", false)) {
+ /*
+ * Check SMB2 rename to the default stream using :<stream>.
+ */
+ torture_comment(tctx, "(%s) Checking SMB2 rename to default stream "
+ "using :<stream>\n", __location__);
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.new_name = stream_name_default;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ }
+
+ smb2_util_close(tree, h1);
+
+ done:
+ smb2_util_close(tree, h1);
+ status = smb2_util_unlink(tree, fname1);
+ status = smb2_util_unlink(tree, fname2);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool create_file_with_stream(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ const char *base_fname,
+ const char *stream)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_open io;
+
+ /* Create a file with a stream */
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_STD_READ_CONTROL;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = stream;
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ done:
+ smb2_util_close(tree, io.smb2.out.file.handle);
+ return ret;
+}
+
+
+/* Test how streams interact with create dispositions */
+static bool test_stream_create_disposition(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream_create_disp.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream;
+ const char *default_stream_name = "::$DATA";
+ const char *stream_list[2];
+ bool ret = true;
+ struct smb2_handle h = {{0}};
+ struct smb2_handle h1 = {{0}};
+
+ /* clean slate .. */
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
+
+ stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
+ stream_list[1] = default_stream_name;
+
+ if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
+ fname_stream)) {
+ goto done;
+ }
+
+ /* Open the base file with OPEN */
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_STD_READ_CONTROL;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ /*
+ * check create open: sanity check
+ */
+ torture_comment(tctx, "(%s) Checking create disp: open\n",
+ __location__);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!check_stream_list(tree, tctx, fname, 2, stream_list,
+ io.smb2.out.file.handle)) {
+ goto done;
+ }
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /*
+ * check create overwrite
+ */
+ torture_comment(tctx, "(%s) Checking create disp: overwrite\n",
+ __location__);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
+ io.smb2.out.file.handle)) {
+ goto done;
+ }
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /*
+ * check create overwrite_if
+ */
+ torture_comment(tctx, "(%s) Checking create disp: overwrite_if\n",
+ __location__);
+ smb2_util_unlink(tree, fname);
+ if (!create_file_with_stream(tctx, tree, mem_ctx, fname, fname_stream))
+ goto done;
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
+ io.smb2.out.file.handle)) {
+ goto done;
+ }
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /*
+ * check create supersede
+ */
+ torture_comment(tctx, "(%s) Checking create disp: supersede\n",
+ __location__);
+ smb2_util_unlink(tree, fname);
+ if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
+ fname_stream)) {
+ goto done;
+ }
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_SUPERSEDE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!check_stream_list(tree, tctx, fname, 1, &default_stream_name,
+ io.smb2.out.file.handle)) {
+ goto done;
+ }
+ smb2_util_close(tree, io.smb2.out.file.handle);
+
+ /*
+ * check create overwrite_if on a stream.
+ */
+ torture_comment(tctx, "(%s) Checking create disp: overwrite_if on "
+ "stream\n", __location__);
+ smb2_util_unlink(tree, fname);
+ if (!create_file_with_stream(tctx, tree, mem_ctx, fname,
+ fname_stream)) {
+ goto done;
+ }
+
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.smb2.in.fname = fname_stream;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (!check_stream_list(tree, tctx, fname, 2, stream_list,
+ io.smb2.out.file.handle)) {
+ goto done;
+ }
+ smb2_util_close(tree, io.smb2.out.file.handle);
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool open_stream(struct smb2_tree *tree,
+ struct torture_context *mem_ctx,
+ const char *fname,
+ struct smb2_handle *h_out)
+{
+ NTSTATUS status;
+ union smb_open io;
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ io.smb2.in.create_options = 0;
+ io.smb2.in.file_attributes = 0;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = fname;
+
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ *h_out = io.smb2.out.file.handle;
+ return true;
+}
+
+
+/* Test the effect of setting attributes on a stream. */
+static bool test_stream_attributes1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname = DNAME "\\stream_attr.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream;
+ struct smb2_handle h, h1;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sfinfo;
+ time_t basetime = (time(NULL) - 86400) & ~1;
+
+ ZERO_STRUCT(h);
+ ZERO_STRUCT(h1);
+
+ torture_comment(tctx, "(%s) testing attribute setting on stream\n",
+ __location__);
+
+ /* clean slate .. */
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
+
+ /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
+ ret = create_file_with_stream(tctx, tree, mem_ctx, fname,
+ fname_stream);
+ if (!ret) {
+ goto done;
+ }
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ finfo.generic.in.file.handle = io.smb2.out.file.handle;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (finfo.basic_info.out.attrib != FILE_ATTRIBUTE_ARCHIVE) {
+ torture_comment(tctx, "(%s) Incorrect attrib %x - should be "
+ "%x\n", __location__,
+ (unsigned int)finfo.basic_info.out.attrib,
+ (unsigned int)FILE_ATTRIBUTE_ARCHIVE);
+ ret = false;
+ goto done;
+ }
+
+ smb2_util_close(tree, io.smb2.out.file.handle);
+ /* Now open the stream name. */
+
+ if (!open_stream(tree, tctx, fname_stream, &h1)) {
+ goto done;
+ }
+
+ /* Change the time on the stream. */
+ ZERO_STRUCT(sfinfo);
+ unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime);
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
+ __location__, "SETATTR",
+ nt_errstr(status), nt_errstr(NT_STATUS_OK));
+ ret = false;
+ goto done;
+ }
+
+ smb2_util_close(tree, h1);
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ finfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "(%s) %s pathinfo - %s\n",
+ __location__, "SETATTRE", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (nt_time_to_unix(finfo.basic_info.out.write_time) != basetime) {
+ torture_comment(tctx, "(%s) time incorrect.\n", __location__);
+ ret = false;
+ goto done;
+ }
+ smb2_util_close(tree, h1);
+
+ if (!open_stream(tree, tctx, fname_stream, &h1)) {
+ goto done;
+ }
+
+ /* Changing attributes on stream */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY;
+
+ sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+ torture_comment(tctx, "(%s) %s - %s (should be %s)\n",
+ __location__, "SETATTR",
+ nt_errstr(status), nt_errstr(NT_STATUS_OK));
+ ret = false;
+ goto done;
+ }
+
+ smb2_util_close(tree, h1);
+
+ ZERO_STRUCT(io.smb2);
+ io.smb2.in.fname = fname;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_READ_DATA;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h1 = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_BASIC_INFORMATION;
+ finfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+done:
+ smb2_util_close(tree, h1);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, DNAME);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool check_metadata(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *path,
+ struct smb2_handle _h,
+ NTTIME expected_btime,
+ uint32_t expected_attribs)
+{
+ struct smb2_handle h = _h;
+ union smb_fileinfo getinfo;
+ NTSTATUS status;
+ bool ret = true;
+
+ if (smb2_util_handle_empty(h)) {
+ struct smb2_create c;
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_HIDDEN,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = path,
+ };
+ status = smb2_create(tree, tctx, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ h = c.out.file.handle;
+ }
+
+ getinfo = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = h,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &getinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_assert_u64_equal_goto(tctx,
+ expected_btime,
+ getinfo.basic_info.out.create_time,
+ ret, done,
+ "btime was updated\n");
+
+ torture_assert_u32_equal_goto(tctx,
+ expected_attribs,
+ getinfo.basic_info.out.attrib,
+ ret, done,
+ "btime was updated\n");
+
+done:
+ if (smb2_util_handle_empty(_h)) {
+ smb2_util_close(tree, h);
+ }
+
+ return ret;
+}
+
+static bool test_stream_attributes2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ NTSTATUS status;
+ struct smb2_create c1;
+ struct smb2_handle h1 = {{0}};
+ const char *fname = DNAME "\\test_stream_btime";
+ const char *sname = DNAME "\\test_stream_btime:stream";
+ union smb_fileinfo getinfo;
+ union smb_setfileinfo setinfo;
+ const char *data = "test data";
+ struct timespec ts;
+ NTTIME btime;
+ uint32_t attrib = FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE;
+ bool ret;
+
+ smb2_deltree(tree, DNAME);
+
+ status = torture_smb2_testdir(tree, DNAME, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree, h1);
+
+ torture_comment(tctx, "Let's dance!\n");
+
+ /*
+ * Step 1: create file and get creation date
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_HIDDEN,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = fname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ getinfo = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tctx, &getinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ btime = getinfo.basic_info.out.create_time;
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ /*
+ * Step X: write to file, assert btime was not updated
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = attrib,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = fname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ status = smb2_util_write(tree, h1, data, 0, strlen(data));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ ret = check_metadata(tctx, tree, NULL, h1, btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ /*
+ * Step X: create stream, assert creation date is the same
+ * as the one on the basefile
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = attrib,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = sname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ /*
+ * Step X: set btime on stream, verify basefile has the same btime.
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = attrib,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = sname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ setinfo = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = h1,
+ };
+ clock_gettime_mono(&ts);
+ btime = setinfo.basic_info.in.create_time = full_timespec_to_nt_time(&ts);
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ ret = check_metadata(tctx, tree, NULL, h1, btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad time on stream\n");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad time on basefile\n");
+
+ ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad time on stream\n");
+
+ /*
+ * Step X: write to stream, assert btime was not updated
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = attrib,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = sname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ status = smb2_util_write(tree, h1, data, 0, strlen(data));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ ret = check_metadata(tctx, tree, NULL, h1, btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ /*
+ * Step X: modify attributes via stream, verify it's "also" set on the
+ * basefile.
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = attrib,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = sname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ attrib = FILE_ATTRIBUTE_NORMAL;
+
+ setinfo = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = h1,
+ .basic_info.in.attrib = attrib,
+ };
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ /*
+ * Step X: modify attributes via basefile, verify it's "also" set on the
+ * stream.
+ */
+
+ c1 = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = attrib,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION,
+ .in.fname = fname,
+ };
+ status = smb2_create(tree, tctx, &c1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = c1.out.file.handle;
+
+ attrib = FILE_ATTRIBUTE_HIDDEN;
+
+ setinfo = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = h1,
+ .basic_info.in.attrib = attrib,
+ };
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(h1);
+
+ ret = check_metadata(tctx, tree, fname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+ ret = check_metadata(tctx, tree, sname, (struct smb2_handle){{0}},
+ btime, attrib);
+ torture_assert_goto(tctx, ret, ret, done, "Bad metadata\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+
+ smb2_deltree(tree, DNAME);
+
+ return ret;
+}
+
+static bool test_basefile_rename_with_open_stream(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_tree *tree2 = NULL;
+ struct smb2_create create, create2;
+ struct smb2_handle h1 = {{0}}, h2 = {{0}};
+ const char *fname = "test_rename_openfile";
+ const char *sname = "test_rename_openfile:foo";
+ const char *fname_renamed = "test_rename_openfile_renamed";
+ union smb_setfileinfo sinfo;
+ const char *data = "test data";
+
+ ret = torture_smb2_connection(tctx, &tree2);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_smb2_connection failed\n");
+
+ torture_comment(tctx, "Creating file with stream\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ h1 = create.out.file.handle;
+
+ torture_comment(tctx, "Writing to stream\n");
+
+ status = smb2_util_write(tree, h1, data, 0, strlen(data));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ torture_comment(tctx, "Renaming base file\n");
+
+ ZERO_STRUCT(create2);
+ create2.in.desired_access = SEC_FILE_ALL;
+ create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ create2.in.fname = fname;
+
+ status = smb2_create(tree2, tctx, &create2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ h2 = create2.out.file.handle;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h2;
+ sinfo.rename_information.in.new_name = fname_renamed;
+
+ status = smb2_setinfo_file(tree2, &sinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_ACCESS_DENIED, ret, done,
+ "smb2_setinfo_file didn't return NT_STATUS_ACCESS_DENIED\n");
+
+ smb2_util_close(tree2, h2);
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree2, h2);
+ }
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname_renamed);
+
+ return ret;
+}
+
+/*
+ basic testing of streams calls SMB2
+*/
+struct torture_suite *torture_smb2_streams_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "streams");
+
+ torture_suite_add_1smb2_test(suite, "dir", test_stream_dir);
+ torture_suite_add_1smb2_test(suite, "io", test_stream_io);
+ torture_suite_add_1smb2_test(suite, "sharemodes", test_stream_sharemodes);
+ torture_suite_add_1smb2_test(suite, "names", test_stream_names);
+ torture_suite_add_1smb2_test(suite, "names2", test_stream_names2);
+ torture_suite_add_1smb2_test(suite, "names3", test_stream_names3);
+ torture_suite_add_1smb2_test(suite, "rename", test_stream_rename);
+ torture_suite_add_1smb2_test(suite, "rename2", test_stream_rename2);
+ torture_suite_add_1smb2_test(suite, "create-disposition", test_stream_create_disposition);
+ torture_suite_add_1smb2_test(suite, "attributes1", test_stream_attributes1);
+ torture_suite_add_1smb2_test(suite, "attributes2", test_stream_attributes2);
+ torture_suite_add_1smb2_test(suite, "delete", test_stream_delete);
+ torture_suite_add_1smb2_test(suite, "zero-byte", test_zero_byte_stream);
+ torture_suite_add_1smb2_test(suite, "basefile-rename-with-open-stream",
+ test_basefile_rename_with_open_stream);
+
+ suite->description = talloc_strdup(suite, "SMB2-STREAM tests");
+ return suite;
+}
diff --git a/source4/torture/smb2/tcon.c b/source4/torture/smb2/tcon.c
new file mode 100644
index 0000000..1e658af
--- /dev/null
+++ b/source4/torture/smb2/tcon.c
@@ -0,0 +1,146 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) David Mulder 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/smbtorture.h"
+#include "torture/smb2/proto.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "torture/util.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/events/events.h"
+#include "param/param.h"
+
+static void smb2cli_session_set_id(struct smbXcli_session *session,
+ uint64_t session_id)
+{
+ smb2cli_session_set_id_and_flags(session, session_id,
+ smb2cli_session_get_flags(session));
+}
+
+/**
+ this checks to see if a secondary tconx can use open files from an
+ earlier tconx
+ */
+bool run_tcon_test(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ const char *fname = "tcontest.tmp";
+ struct smb2_handle fnum1;
+ uint32_t cnum1, cnum2, cnum3;
+ uint64_t sessid1, sessid2;
+ uint8_t buf[4];
+ bool ret = true;
+ struct smb2_tree *tree1 = NULL;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ struct smb2_create io = {0};
+ NTSTATUS status;
+ bool ok;
+
+ if (smb2_deltree(tree, fname) == -1) {
+ torture_comment(tctx, "unlink of %s failed\n", fname);
+ }
+
+ io.in.fname = fname;
+ io.in.desired_access = SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE;
+ status = smb2_create(tree, tree, &io);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_result(tctx, TORTURE_FAIL, "open of %s failed (%s)\n", fname, nt_errstr(status));
+ return false;
+ }
+ fnum1 = io.out.file.handle;
+
+ cnum1 = smb2cli_tcon_current_id(tree->smbXcli);
+ sessid1 = smb2cli_session_current_id(tree->session->smbXcli);
+
+ memset(buf, 0, 4); /* init buf so valgrind won't complain */
+ status = smb2_util_write(tree, fnum1, buf, 130, 4);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_result(tctx, TORTURE_FAIL, "initial write failed (%s)\n", nt_errstr(status));
+ return false;
+ }
+
+ ok = torture_smb2_tree_connect(tctx, tree->session, tctx, &tree1);
+ if (!ok) {
+ torture_result(tctx, TORTURE_FAIL, "%s refused 2nd tree connect\n", host);
+ return false;
+ }
+
+ cnum2 = smb2cli_tcon_current_id(tree1->smbXcli);
+ cnum3 = MAX(cnum1, cnum2) + 1; /* any invalid number */
+ sessid2 = smb2cli_session_current_id(tree1->session->smbXcli) + 1;
+
+ /* try a write with the wrong tid */
+ smb2cli_tcon_set_id(tree1->smbXcli, cnum2);
+
+ status = smb2_util_write(tree1, fnum1, buf, 130, 4);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "* server allows write with wrong TID\n");
+ ret = false;
+ } else {
+ torture_comment(tctx, "server fails write with wrong TID : %s\n", nt_errstr(status));
+ }
+
+
+ /* try a write with an invalid tid */
+ smb2cli_tcon_set_id(tree1->smbXcli, cnum3);
+
+ status = smb2_util_write(tree1, fnum1, buf, 130, 4);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "* server allows write with invalid TID\n");
+ ret = false;
+ } else {
+ torture_comment(tctx, "server fails write with invalid TID : %s\n", nt_errstr(status));
+ }
+
+ /* try a write with an invalid session id */
+ smb2cli_session_set_id(tree1->session->smbXcli, sessid2);
+ smb2cli_tcon_set_id(tree1->smbXcli, cnum1);
+
+ status = smb2_util_write(tree1, fnum1, buf, 130, 4);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_result(tctx, TORTURE_FAIL, "* server allows write with invalid VUID\n");
+ ret = false;
+ } else {
+ torture_comment(tctx, "server fails write with invalid VUID : %s\n", nt_errstr(status));
+ }
+
+ smb2cli_session_set_id(tree1->session->smbXcli, sessid1);
+ smb2cli_tcon_set_id(tree1->smbXcli, cnum1);
+
+ status = smb2_util_close(tree1, fnum1);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_result(tctx, TORTURE_FAIL, "close failed (%s)\n", nt_errstr(status));
+ return false;
+ }
+
+ smb2cli_tcon_set_id(tree1->smbXcli, cnum2);
+
+ smb2_util_unlink(tree1, fname);
+
+ return ret;
+}
diff --git a/source4/torture/smb2/timestamps.c b/source4/torture/smb2/timestamps.c
new file mode 100644
index 0000000..3d6d3d1
--- /dev/null
+++ b/source4/torture/smb2/timestamps.c
@@ -0,0 +1,1344 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ test timestamps
+
+ Copyright (C) Ralph Boehme 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+
+#define BASEDIR "smb2-timestamps"
+#define FNAME "testfile.dat"
+
+static bool test_close_no_attrib(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *filename = BASEDIR "/" FNAME;
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle testdirh = {{0}};
+ struct smb2_close c;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree, testdirh);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = filename,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ c = (struct smb2_close) {
+ .in.file.handle = handle,
+ };
+
+ status = smb2_close(tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(handle);
+
+ torture_assert_u64_equal_goto(tctx, c.out.create_time, NTTIME_OMIT,
+ ret, done, "Unexpected create time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.access_time, NTTIME_OMIT,
+ ret, done, "Unexpected access time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.write_time, NTTIME_OMIT,
+ ret, done, "Unexpected write time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.change_time, NTTIME_OMIT,
+ ret, done, "Unexpected change time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.size, 0,
+ ret, done, "Unexpected size\n");
+ torture_assert_u64_equal_goto(tctx, c.out.file_attr, 0,
+ ret, done, "Unexpected attributes\n");
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_time_t(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ time_t t)
+{
+ char *filename = NULL;
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle testdirh = {{0}};
+ struct timespec ts = { .tv_sec = t };
+ uint64_t nttime;
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ struct smb2_find find;
+ unsigned int count;
+ union smb_search_data *d;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+
+ filename = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fname);
+ torture_assert_not_null_goto(tctx, filename, ret, done,
+ "talloc_asprintf failed\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = filename,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ si = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = handle,
+ };
+
+ nttime = full_timespec_to_nt_time(&ts);
+ si.basic_info.in.create_time = nttime;
+ si.basic_info.in.write_time = nttime;
+ si.basic_info.in.change_time = nttime;
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
+ nt_time_string(tctx, gi.basic_info.out.create_time),
+ nt_time_string(tctx, gi.basic_info.out.write_time),
+ nt_time_string(tctx, gi.basic_info.out.change_time));
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+ find = (struct smb2_find) {
+ .in.file.handle = testdirh,
+ .in.pattern = fname,
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree, tree, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ d[0].id_both_directory_info.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ d[0].id_both_directory_info.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ d[0].id_both_directory_info.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = filename,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
+ nt_time_string(tctx, gi.basic_info.out.create_time),
+ nt_time_string(tctx, gi.basic_info.out.write_time),
+ nt_time_string(tctx, gi.basic_info.out.change_time));
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+ find = (struct smb2_find) {
+ .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
+ .in.file.handle = testdirh,
+ .in.pattern = fname,
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree, tree, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ d[0].id_both_directory_info.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ d[0].id_both_directory_info.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ d[0].id_both_directory_info.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+ status = smb2_util_close(tree, handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ ZERO_STRUCT(handle);
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ if (!smb2_util_handle_empty(testdirh)) {
+ smb2_util_close(tree, testdirh);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_time_t_15032385535(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_15032385535.txt",
+ 15032385535 /* >> INT32_MAX, limit on ext */);
+}
+
+static bool test_time_t_10000000000(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_10000000000.txt",
+ 10000000000 /* >> INT32_MAX */);
+}
+
+static bool test_time_t_4294967295(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_4294967295.txt",
+ 4294967295 /* INT32_MAX */);
+}
+
+static bool test_time_t_1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_1.txt", 1);
+}
+
+static bool test_time_t_0(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_0.txt", 0);
+}
+
+static bool test_time_t_minus_1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_-1.txt", -1);
+}
+
+static bool test_time_t_minus_2(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_-2.txt", -2);
+}
+
+static bool test_time_t_1968(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ return test_time_t(tctx, tree, "test_time_t_1968.txt",
+ -63158400 /* 1968 */);
+}
+
+static bool test_freeze_thaw(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *filename = BASEDIR "\\test_freeze_thaw";
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle testdirh = {{0}};
+ struct timespec ts = { .tv_sec = time(NULL) };
+ uint64_t nttime;
+ union smb_fileinfo gi;
+ union smb_setfileinfo si;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = filename,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ si = (union smb_setfileinfo) {
+ .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ .basic_info.in.file.handle = handle,
+ };
+
+ /*
+ * Step 1:
+ * First set timestamps of testfile to current time
+ */
+
+ nttime = full_timespec_to_nt_time(&ts);
+ si.basic_info.in.create_time = nttime;
+ si.basic_info.in.write_time = nttime;
+ si.basic_info.in.change_time = nttime;
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ /*
+ * Step 2:
+ * Verify timestamps are indeed set to the value in "nttime".
+ */
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
+ nt_time_string(tctx, gi.basic_info.out.create_time),
+ nt_time_string(tctx, gi.basic_info.out.write_time),
+ nt_time_string(tctx, gi.basic_info.out.change_time));
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+ /*
+ * Step 3:
+ * First set timestamps with NTTIME_FREEZE, must not change any
+ * timestamp value.
+ */
+
+ si.basic_info.in.create_time = NTTIME_FREEZE;
+ si.basic_info.in.write_time = NTTIME_FREEZE;
+ si.basic_info.in.change_time = NTTIME_FREEZE;
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ /*
+ * Step 4:
+ * Verify timestamps are unmodified from step 2.
+ */
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
+ nt_time_string(tctx, gi.basic_info.out.create_time),
+ nt_time_string(tctx, gi.basic_info.out.write_time),
+ nt_time_string(tctx, gi.basic_info.out.change_time));
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+ /*
+ * Step 5:
+ * First set timestamps with NTTIME_THAW, must not change any timestamp
+ * value.
+ */
+
+ si.basic_info.in.create_time = NTTIME_THAW;
+ si.basic_info.in.write_time = NTTIME_THAW;
+ si.basic_info.in.change_time = NTTIME_THAW;
+
+ status = smb2_setinfo_file(tree, &si);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_setinfo_file failed\n");
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ /*
+ * Step 6:
+ * Verify timestamps are unmodified from step 2.
+ */
+
+ gi = (union smb_fileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ .generic.in.file.handle = handle,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &gi);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
+ nt_time_string(tctx, gi.basic_info.out.create_time),
+ nt_time_string(tctx, gi.basic_info.out.write_time),
+ nt_time_string(tctx, gi.basic_info.out.change_time));
+
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.create_time,
+ ret, done,
+ "Wrong create time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.write_time,
+ ret, done,
+ "Wrong write time\n");
+ torture_assert_u64_equal_goto(tctx,
+ nttime,
+ gi.basic_info.out.change_time,
+ ret, done,
+ "Wrong change time\n");
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ if (!smb2_util_handle_empty(testdirh)) {
+ smb2_util_close(tree, testdirh);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_delayed_write_vs_seteof(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create cr;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ NTTIME create_time;
+ NTTIME set_time;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo setinfo;
+ struct smb2_close c;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Open file-handle 1\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = BASEDIR "\\" FNAME,
+ };
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h1 = cr.out.file.handle;
+ create_time = cr.out.create_time;
+ sleep(1);
+
+ torture_comment(tctx, "Write to file-handle 1\n");
+
+ status = smb2_util_write(tree, h1, "s", 0, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+
+ torture_comment(tctx, "Check writetime hasn't been updated\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ torture_assert_nttime_equal(tctx,
+ finfo.all_info.out.write_time,
+ create_time,
+ "Writetime != set_time (wrong!)\n");
+
+ torture_comment(tctx, "Setinfo EOF on file-handle 1,"
+ " should flush pending writetime update\n");
+
+ setinfo = (union smb_setfileinfo) {
+ .generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION,
+ };
+ setinfo.end_of_file_info.in.file.handle = h1;
+ setinfo.end_of_file_info.in.size = 1; /* same size! */
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Check writetime has been updated "
+ "by the setinfo EOF\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+ if (!(finfo.all_info.out.write_time > create_time)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "setinfo EOF hasn't updated writetime\n");
+ }
+
+ torture_comment(tctx, "Open file-handle 2\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_WRITE_ATTRIBUTE,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = BASEDIR "\\" FNAME,
+ };
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h2 = cr.out.file.handle;
+
+ torture_comment(tctx, "Set write time on file-handle 2\n");
+
+ setinfo = (union smb_setfileinfo) {
+ .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
+ };
+ setinfo.generic.in.file.handle = h2;
+ unix_to_nt_time(&set_time, time(NULL) + 86400);
+ setinfo.basic_info.in.write_time = set_time;
+
+ status = smb2_setinfo_file(tree, &setinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ status = smb2_util_close(tree, h2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h2);
+
+ torture_comment(tctx, "Close file-handle 1, write-time should not be updated\n");
+
+ c = (struct smb2_close) {
+ .in.file.handle = h1,
+ .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+ };
+
+ status = smb2_close(tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h1);
+
+ torture_assert_nttime_equal(tctx,
+ c.out.write_time,
+ set_time,
+ "Writetime != set_time (wrong!)\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(h2)) {
+ smb2_util_close(tree, h2);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_delayed_write_vs_flush(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create cr;
+ struct smb2_handle h1 = {{0}};
+ union smb_fileinfo finfo;
+ struct smb2_flush f;
+ struct smb2_close c;
+ NTTIME create_time;
+ NTTIME flush_time;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Open file-handle 1\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = BASEDIR "\\" FNAME,
+ };
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h1 = cr.out.file.handle;
+ create_time = cr.out.create_time;
+ sleep(1);
+
+ torture_comment(tctx, "Write to file-handle 1\n");
+
+ status = smb2_util_write(tree, h1, "s", 0, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+
+ torture_comment(tctx, "Check writetime hasn't been updated\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ torture_assert_nttime_equal(tctx,
+ finfo.all_info.out.write_time,
+ create_time,
+ "Writetime != create_time (wrong!)\n");
+
+ torture_comment(tctx, "Flush file, "
+ "should flush pending writetime update\n");
+
+ f = (struct smb2_flush) {
+ .in.file.handle = h1,
+ };
+
+ status = smb2_flush(tree, &f);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "flush failed\n");
+
+ torture_comment(tctx, "Check writetime has been updated "
+ "by the setinfo EOF\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ flush_time = finfo.all_info.out.write_time;
+ if (!(flush_time > create_time)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "flush hasn't updated writetime\n");
+ }
+
+ torture_comment(tctx, "Close file-handle 1, write-time should not be updated\n");
+
+ c = (struct smb2_close) {
+ .in.file.handle = h1,
+ .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+ };
+
+ status = smb2_close(tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h1);
+
+ torture_assert_nttime_equal(tctx,
+ c.out.write_time,
+ flush_time,
+ "writetime != flushtime (wrong!)\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_delayed_write_vs_setbasic_do(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ union smb_setfileinfo *setinfo,
+ bool expect_update)
+{
+ char *path = NULL;
+ struct smb2_create cr;
+ struct smb2_handle h1 = {{0}};
+ NTTIME create_time;
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ bool ret = true;
+
+ torture_comment(tctx, "Create testfile\n");
+
+ path = talloc_asprintf(tree, BASEDIR "\\" FNAME ".%" PRIu32,
+ generate_random());
+ torture_assert_not_null_goto(tctx, path, ret, done, "OOM\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = path,
+ };
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h1 = cr.out.file.handle;
+ create_time = cr.out.create_time;
+
+ torture_comment(tctx, "Write to file\n");
+
+ status = smb2_util_write(tree, h1, "s", 0, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+
+ torture_comment(tctx, "Get timestamps\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ torture_assert_nttime_equal(tctx,
+ finfo.all_info.out.write_time,
+ create_time,
+ "Writetime != create_time (wrong!)\n");
+
+ torture_comment(tctx, "Set timestamps\n");
+
+ setinfo->end_of_file_info.in.file.handle = h1;
+ status = smb2_setinfo_file(tree, setinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Check timestamps\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ if (expect_update) {
+ if (!(finfo.all_info.out.write_time > create_time)) {
+ ret = false;
+ torture_fail_goto(tctx, done, "setinfo basicinfo "
+ "hasn't updated writetime\n");
+ }
+ } else {
+ if (finfo.all_info.out.write_time != create_time) {
+ ret = false;
+ torture_fail_goto(tctx, done, "setinfo basicinfo "
+ "hasn't updated writetime\n");
+ }
+ }
+
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h1);
+
+ status = smb2_util_unlink(tree, path);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+done:
+ TALLOC_FREE(path);
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ return ret;
+}
+
+static bool test_delayed_write_vs_setbasic(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle h1 = {{0}};
+ union smb_setfileinfo setinfo;
+ time_t t = time(NULL) - 86400;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ /*
+ * Yes, this is correct, tested against Windows 2016: even if all
+ * timestamp fields are 0, a pending write time is flushed.
+ */
+ torture_comment(tctx, "Test: setting all-0 timestamps flushes?\n");
+
+ setinfo = (union smb_setfileinfo) {
+ .generic.level = RAW_SFILEINFO_BASIC_INFORMATION,
+ };
+ ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
+ if (ret != true) {
+ goto done;
+ }
+
+ torture_comment(tctx, "Test: setting create_time flushes?\n");
+ unix_to_nt_time(&setinfo.basic_info.in.create_time, t);
+ ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
+ if (ret != true) {
+ goto done;
+ }
+
+ torture_comment(tctx, "Test: setting access_time flushes?\n");
+ unix_to_nt_time(&setinfo.basic_info.in.access_time, t);
+ ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
+ if (ret != true) {
+ goto done;
+ }
+
+ torture_comment(tctx, "Test: setting change_time flushes?\n");
+ unix_to_nt_time(&setinfo.basic_info.in.change_time, t);
+ ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
+ if (ret != true) {
+ goto done;
+ }
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_delayed_1write(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create cr;
+ struct smb2_handle h1 = {{0}};
+ union smb_fileinfo finfo;
+ struct smb2_close c;
+ NTTIME create_time;
+ NTTIME write_time;
+ NTTIME close_time;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Open file-handle 1\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = BASEDIR "\\" FNAME,
+ };
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h1 = cr.out.file.handle;
+ create_time = cr.out.create_time;
+ sleep(1);
+
+ torture_comment(tctx, "Write to file-handle 1\n");
+
+ status = smb2_util_write(tree, h1, "s", 0, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+ sleep(3);
+
+ torture_comment(tctx, "Check writetime has been updated\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+ write_time = finfo.all_info.out.write_time;
+
+ if (!(write_time > create_time)) {
+ ret = false;
+ torture_fail_goto(tctx, done,
+ "Write-time not updated (wrong!)\n");
+ }
+
+ torture_comment(tctx, "Close file-handle 1\n");
+ sleep(1);
+
+ c = (struct smb2_close) {
+ .in.file.handle = h1,
+ .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+ };
+
+ status = smb2_close(tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h1);
+ close_time = c.out.write_time;
+
+ torture_assert_nttime_equal(tctx, close_time, write_time,
+ "Writetime != close_time (wrong!)\n");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_delayed_2write(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create cr;
+ struct smb2_handle h1 = {{0}};
+ union smb_fileinfo finfo;
+ struct smb2_close c;
+ NTTIME create_time;
+ NTTIME write_time;
+ NTTIME write_time2;
+ NTTIME close_time;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Open file\n");
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = BASEDIR "\\" FNAME,
+ };
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h1 = cr.out.file.handle;
+ create_time = cr.out.create_time;
+ sleep(1);
+
+ torture_comment(tctx, "Write to file\n");
+
+ status = smb2_util_write(tree, h1, "s", 0, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+ sleep(3);
+
+ torture_comment(tctx, "Check writetime has been updated\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+ write_time = finfo.all_info.out.write_time;
+
+ if (!(write_time > create_time)) {
+ ret = false;
+ torture_fail_goto(tctx, done,
+ "Write-time not updated (wrong!)\n");
+ }
+
+ torture_comment(tctx, "Write a second time\n");
+
+ status = smb2_util_write(tree, h1, "s", 0, 1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+ sleep(3);
+
+ torture_comment(tctx, "Check writetime has NOT been updated\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+ write_time2 = finfo.all_info.out.write_time;
+
+ torture_assert_nttime_equal(tctx, write_time2, write_time,
+ "second write updated write-time (wrong!)\n");
+
+ torture_comment(tctx, "Close file-handle 1\n");
+ sleep(2);
+
+ torture_comment(tctx, "Check writetime has been updated\n");
+
+ c = (struct smb2_close) {
+ .in.file.handle = h1,
+ .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+ };
+
+ status = smb2_close(tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h1);
+ close_time = c.out.write_time;
+
+ if (!(close_time > write_time)) {
+ ret = false;
+ torture_fail_goto(tctx, done,
+ "Write-time not updated (wrong!)\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of SMB2 timestamps
+*/
+struct torture_suite *torture_smb2_timestamps_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "timestamps");
+
+ torture_suite_add_1smb2_test(suite, "test_close_not_attrib", test_close_no_attrib);
+ torture_suite_add_1smb2_test(suite, "time_t_15032385535", test_time_t_15032385535);
+ torture_suite_add_1smb2_test(suite, "time_t_10000000000", test_time_t_10000000000);
+ torture_suite_add_1smb2_test(suite, "time_t_4294967295", test_time_t_4294967295);
+ torture_suite_add_1smb2_test(suite, "time_t_1", test_time_t_1);
+ torture_suite_add_1smb2_test(suite, "time_t_0", test_time_t_0);
+ torture_suite_add_1smb2_test(suite, "time_t_-1", test_time_t_minus_1);
+ torture_suite_add_1smb2_test(suite, "time_t_-2", test_time_t_minus_2);
+ torture_suite_add_1smb2_test(suite, "time_t_1968", test_time_t_1968);
+ torture_suite_add_1smb2_test(suite, "freeze-thaw", test_freeze_thaw);
+
+ /*
+ * Testing of delayed write-time updates
+ */
+ torture_suite_add_1smb2_test(suite, "delayed-write-vs-seteof", test_delayed_write_vs_seteof);
+ torture_suite_add_1smb2_test(suite, "delayed-write-vs-flush", test_delayed_write_vs_flush);
+ torture_suite_add_1smb2_test(suite, "delayed-write-vs-setbasic", test_delayed_write_vs_setbasic);
+ torture_suite_add_1smb2_test(suite, "delayed-1write", test_delayed_1write);
+ torture_suite_add_1smb2_test(suite, "delayed-2write", test_delayed_2write);
+
+ suite->description = talloc_strdup(suite, "SMB2 timestamp tests");
+
+ return suite;
+}
+
+/*
+ * This test shows that Windows has a timestamp resolution of ~15ms. When so
+ * when a smaller amount of time than that has passed it's not necessarily
+ * detectable on a Windows 2019 and newer who implement immediate timestamp
+ * updates.
+ *
+ * Note that this test relies on a low latency SMB connection. Even with a low
+ * latency connection of eg 1m there's a chance of 1/15 that the first part of
+ * the test expecting no timestamp change fails as the writetime is updated.
+ *
+ * Due to this timing dependency this test is skipped in Samba CI, but it is
+ * preserved here for future SMB2 timestamps behaviour archealogists.
+ *
+ * See also: https://lists.samba.org/archive/cifs-protocol/2019-December/003358.html
+ */
+static bool test_timestamp_resolution1(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ union smb_fileinfo finfo1;
+ const char *fname = BASEDIR "\\" FNAME;
+ struct smb2_create cr;
+ struct smb2_handle h = {{0}};
+ struct smb2_close cl;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ status = smb2_util_close(tree, h );
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+
+ torture_comment(tctx, "Write without delay, expect no "
+ "write-time change\n");
+
+ smb2_generic_create(&cr, NULL, false, fname,
+ NTCREATEX_DISP_CREATE,
+ smb2_util_oplock_level(""), 0, 0);
+ status = smb2_create(tree, tree, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h = cr.out.file.handle;
+
+ finfo1 = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ status = smb2_util_write(tree, h, "123456789", 0, 9);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+
+ cl = (struct smb2_close) {
+ .in.file.handle = h,
+ .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+ };
+
+ status = smb2_close(tree, &cl);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h);
+
+ torture_comment(tctx, "Initial: %s\nClose: %s\n",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time),
+ nt_time_string(tctx, cl.out.write_time));
+
+ torture_assert_u64_equal_goto(tctx,
+ finfo1.basic_info.out.write_time,
+ cl.out.write_time,
+ ret, done,
+ "Write time changed (wrong!)\n");
+
+ torture_comment(tctx, "Write with 20 ms delay, expect "
+ "write-time change\n");
+
+ smb2_generic_create(&cr, NULL, false, fname,
+ NTCREATEX_DISP_OPEN,
+ smb2_util_oplock_level(""), 0, 0);
+ status = smb2_create(tree, tree, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "create failed\n");
+ h = cr.out.file.handle;
+
+ finfo1 = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+ .generic.in.file.handle = h,
+ };
+ status = smb2_getinfo_file(tree, tree, &finfo1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "getinfo failed\n");
+
+ smb_msleep(20);
+
+ status = smb2_util_write(tree, h, "123456789", 0, 9);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+
+ cl = (struct smb2_close) {
+ .in.file.handle = h,
+ .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+ };
+
+ status = smb2_close(tree, &cl);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(h);
+
+ torture_comment(tctx, "Initial: %s\nClose: %s\n",
+ nt_time_string(tctx, finfo1.basic_info.out.write_time),
+ nt_time_string(tctx, cl.out.write_time));
+
+ torture_assert_u64_not_equal_goto(
+ tctx,
+ finfo1.basic_info.out.write_time,
+ cl.out.write_time,
+ ret, done,
+ "Write time did not change (wrong!)\n");
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ basic testing of SMB2 timestamps
+*/
+struct torture_suite *torture_smb2_timestamp_resolution_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "timestamp_resolution");
+
+ torture_suite_add_1smb2_test(suite, "resolution1", test_timestamp_resolution1);
+
+ suite->description = talloc_strdup(suite, "SMB2 timestamp tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c
new file mode 100644
index 0000000..233f589
--- /dev/null
+++ b/source4/torture/smb2/util.c
@@ -0,0 +1,1045 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper functions for SMB2 test suite
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/security/security_descriptor.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/cmdline/cmdline.h"
+#include "system/time.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/util/tevent_ntstatus.h"
+
+#include "torture/torture.h"
+#include "torture/smb2/proto.h"
+#include "source4/torture/util.h"
+#include "libcli/security/dom_sid.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "libcli/util/clilsa.h"
+
+
+/*
+ write to a file on SMB2
+*/
+NTSTATUS smb2_util_write(struct smb2_tree *tree,
+ struct smb2_handle handle,
+ const void *buf, off_t offset, size_t size)
+{
+ struct smb2_write w;
+
+ ZERO_STRUCT(w);
+ w.in.file.handle = handle;
+ w.in.offset = offset;
+ w.in.data = data_blob_const(buf, size);
+
+ return smb2_write(tree, &w);
+}
+
+/*
+ create a complex file/dir using the SMB2 protocol
+*/
+static NTSTATUS smb2_create_complex(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ const char *fname,
+ struct smb2_handle *handle,
+ bool dir)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ char buf[7] = "abc";
+ struct smb2_create io;
+ union smb_setfileinfo setfile;
+ union smb_fileinfo fileinfo;
+ time_t t = (time(NULL) & ~1);
+ NTSTATUS status;
+
+ smb2_util_unlink(tree, fname);
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+ if (dir) {
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ }
+
+ /* it seems vista is now fussier about alignment? */
+ if (strchr(fname, ':') == NULL) {
+ /* setup some EAs */
+ io.in.eas.num_eas = 2;
+ io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2);
+ io.in.eas.eas[0].flags = 0;
+ io.in.eas.eas[0].name.s = "EAONE";
+ io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6);
+ io.in.eas.eas[1].flags = 0;
+ io.in.eas.eas[1].name.s = "SECONDEA";
+ io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8);
+ }
+
+ status = smb2_create(tree, tmp_ctx, &io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)) {
+ torture_comment(
+ tctx, "EAs not supported, creating: %s\n", fname);
+ io.in.eas.num_eas = 0;
+ status = smb2_create(tree, tmp_ctx, &io);
+ }
+
+ talloc_free(tmp_ctx);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *handle = io.out.file.handle;
+
+ if (!dir) {
+ status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ /* make sure all the timestamps aren't the same, and are also
+ in different DST zones*/
+ setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ setfile.generic.in.file.handle = *handle;
+
+ unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.write_time, t + 3*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60);
+ setfile.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL;
+
+ status = smb2_setinfo_file(tree, &setfile);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to setup file times - %s\n", nt_errstr(status));
+ return status;
+ }
+
+ /* make sure all the timestamps aren't the same */
+ fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ fileinfo.generic.in.file.handle = *handle;
+
+ status = smb2_getinfo_file(tree, tree, &fileinfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to query file times - %s\n", nt_errstr(status));
+ return status;
+
+ }
+
+#define CHECK_TIME(field) do {\
+ if (setfile.basic_info.in.field != fileinfo.all_info2.out.field) { \
+ torture_comment(tctx, "(%s) " #field " not setup correctly: %s(%llu) => %s(%llu)\n", \
+ __location__, \
+ nt_time_string(tree, setfile.basic_info.in.field), \
+ (unsigned long long)setfile.basic_info.in.field, \
+ nt_time_string(tree, fileinfo.basic_info.out.field), \
+ (unsigned long long)fileinfo.basic_info.out.field); \
+ status = NT_STATUS_INVALID_PARAMETER; \
+ } \
+} while (0)
+
+ CHECK_TIME(create_time);
+ CHECK_TIME(access_time);
+ CHECK_TIME(write_time);
+ CHECK_TIME(change_time);
+
+ return status;
+}
+
+/*
+ create a complex file using the SMB2 protocol
+*/
+NTSTATUS smb2_create_complex_file(struct torture_context *tctx,
+ struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle)
+{
+ return smb2_create_complex(tctx, tree, fname, handle, false);
+}
+
+/*
+ create a complex dir using the SMB2 protocol
+*/
+NTSTATUS smb2_create_complex_dir(struct torture_context *tctx,
+ struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle)
+{
+ return smb2_create_complex(tctx, tree, fname, handle, true);
+}
+
+/*
+ show lots of information about a file
+*/
+void torture_smb2_all_info(struct torture_context *tctx,
+ struct smb2_tree *tree, struct smb2_handle handle)
+{
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ union smb_fileinfo io;
+
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = handle;
+
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("getinfo failed - %s\n", nt_errstr(status)));
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ torture_comment(tctx, "all_info for '%s'\n", io.all_info2.out.fname.s);
+ torture_comment(tctx, "\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time));
+ torture_comment(tctx, "\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time));
+ torture_comment(tctx, "\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time));
+ torture_comment(tctx, "\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time));
+ torture_comment(tctx, "\tattrib: 0x%x\n", io.all_info2.out.attrib);
+ torture_comment(tctx, "\tunknown1: 0x%x\n", io.all_info2.out.unknown1);
+ torture_comment(tctx, "\talloc_size: %llu\n", (long long)io.all_info2.out.alloc_size);
+ torture_comment(tctx, "\tsize: %llu\n", (long long)io.all_info2.out.size);
+ torture_comment(tctx, "\tnlink: %u\n", io.all_info2.out.nlink);
+ torture_comment(tctx, "\tdelete_pending: %u\n", io.all_info2.out.delete_pending);
+ torture_comment(tctx, "\tdirectory: %u\n", io.all_info2.out.directory);
+ torture_comment(tctx, "\tfile_id: %llu\n", (long long)io.all_info2.out.file_id);
+ torture_comment(tctx, "\tea_size: %u\n", io.all_info2.out.ea_size);
+ torture_comment(tctx, "\taccess_mask: 0x%08x\n", io.all_info2.out.access_mask);
+ torture_comment(tctx, "\tposition: 0x%llx\n", (long long)io.all_info2.out.position);
+ torture_comment(tctx, "\tmode: 0x%llx\n", (long long)io.all_info2.out.mode);
+
+ /* short name, if any */
+ io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "\tshort name: '%s'\n", io.alt_name_info.out.fname.s);
+ }
+
+ /* the EAs, if any */
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ int i;
+ for (i=0;i<io.all_eas.out.num_eas;i++) {
+ torture_comment(tctx, "\tEA[%d] flags=%d len=%d '%s'\n", i,
+ io.all_eas.out.eas[i].flags,
+ (int)io.all_eas.out.eas[i].value.length,
+ io.all_eas.out.eas[i].name.s);
+ }
+ }
+
+ /* streams, if available */
+ io.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ int i;
+ for (i=0;i<io.stream_info.out.num_streams;i++) {
+ torture_comment(tctx, "\tstream %d:\n", i);
+ torture_comment(tctx, "\t\tsize %ld\n",
+ (long)io.stream_info.out.streams[i].size);
+ torture_comment(tctx, "\t\talloc size %ld\n",
+ (long)io.stream_info.out.streams[i].alloc_size);
+ torture_comment(tctx, "\t\tname %s\n", io.stream_info.out.streams[i].stream_name.s);
+ }
+ }
+
+ if (DEBUGLVL(1)) {
+ /* the security descriptor */
+ io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ io.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER|SECINFO_GROUP|
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd);
+ }
+ }
+
+ talloc_free(tmp_ctx);
+}
+
+/*
+ get granted access of a file handle
+*/
+NTSTATUS torture_smb2_get_allinfo_access(struct smb2_tree *tree,
+ struct smb2_handle handle,
+ uint32_t *granted_access)
+{
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ union smb_fileinfo io;
+
+ io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ io.generic.in.file.handle = handle;
+
+ status = smb2_getinfo_file(tree, tmp_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("getinfo failed - %s\n", nt_errstr(status)));
+ goto out;
+ }
+
+ *granted_access = io.all_info2.out.access_mask;
+
+out:
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+/**
+ * open a smb2 tree connect
+ */
+bool torture_smb2_tree_connect(struct torture_context *tctx,
+ struct smb2_session *session,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_tree **_tree)
+{
+ NTSTATUS status;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ const char *unc;
+ struct smb2_tree *tree;
+ struct tevent_req *subreq;
+ uint32_t timeout_msec;
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ tree = smb2_tree_init(session, mem_ctx, false);
+ torture_assert(tctx, tree != NULL, "smb2_tree_init");
+
+ timeout_msec = session->transport->options.request_timeout * 1000;
+
+ subreq = smb2cli_tcon_send(tree, tctx->ev,
+ session->transport->conn,
+ timeout_msec,
+ session->smbXcli,
+ tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
+
+ *_tree = tree;
+
+ return true;
+}
+
+/**
+ * do a smb2 session setup (without a tree connect)
+ */
+bool torture_smb2_session_setup(struct torture_context *tctx,
+ struct smb2_transport *transport,
+ uint64_t previous_session_id,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_session **_session)
+{
+ NTSTATUS status;
+ struct smb2_session *session;
+
+ session = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ mem_ctx);
+
+ if (session == NULL) {
+ return false;
+ }
+
+ status = smb2_session_setup_spnego(session,
+ samba_cmdline_get_creds(),
+ previous_session_id);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "session setup failed: %s\n", nt_errstr(status));
+ talloc_free(session);
+ return false;
+ }
+
+ *_session = session;
+
+ return true;
+}
+
+/*
+ open a smb2 connection
+*/
+bool torture_smb2_connection_ext(struct torture_context *tctx,
+ uint64_t previous_session_id,
+ const struct smbcli_options *options,
+ struct smb2_tree **tree)
+{
+ NTSTATUS status;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ const char *p = torture_setting_string(tctx, "unclist", NULL);
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ok;
+
+ if (p != NULL) {
+ char *host2 = NULL;
+ char *share2 = NULL;
+
+ mem_ctx = talloc_new(tctx);
+ if (mem_ctx == NULL) {
+ return false;
+ }
+
+ ok = torture_get_conn_index(tctx->conn_index++, mem_ctx, tctx,
+ &host2, &share2);
+ if (!ok) {
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
+
+ host = host2;
+ share = share2;
+ }
+
+ status = smb2_connect_ext(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ NULL, /* existing_conn */
+ previous_session_id,
+ tree,
+ tctx->ev,
+ options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
+ host, share, nt_errstr(status));
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
+
+ TALLOC_FREE(mem_ctx);
+ return true;
+}
+
+bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree)
+{
+ bool ret;
+ struct smbcli_options options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ ret = torture_smb2_connection_ext(tctx, 0, &options, tree);
+
+ return ret;
+}
+
+/**
+ * SMB2 connect with share from soption
+ **/
+bool torture_smb2_con_share(struct torture_context *tctx,
+ const char *share,
+ struct smb2_tree **tree)
+{
+ struct smbcli_options options;
+ NTSTATUS status;
+ const char *host = torture_setting_string(tctx, "host", NULL);
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+ );
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Failed to connect to SMB2 share \\\\%s\\%s - %s\n",
+ host, share, nt_errstr(status));
+ return false;
+ }
+ return true;
+}
+
+/**
+ * SMB2 connect with share from soption
+ **/
+bool torture_smb2_con_sopt(struct torture_context *tctx,
+ const char *soption,
+ struct smb2_tree **tree)
+{
+ const char *share = torture_setting_string(tctx, soption, NULL);
+
+ if (share == NULL) {
+ torture_comment(tctx, "No share for option %s\n", soption);
+ return false;
+ }
+
+ return torture_smb2_con_share(tctx, share, tree);
+}
+
+/*
+ create and return a handle to a test file
+ with a specific access mask
+*/
+NTSTATUS torture_smb2_testfile_access(struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle,
+ uint32_t desired_access)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = desired_access;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tree, &io);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *handle = io.out.file.handle;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create and return a handle to a test file
+*/
+NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle)
+{
+ return torture_smb2_testfile_access(tree, fname, handle,
+ SEC_RIGHTS_FILE_ALL);
+}
+
+/*
+ create and return a handle to a test file
+ with a specific access mask
+*/
+NTSTATUS torture_smb2_open(struct smb2_tree *tree,
+ const char *fname,
+ uint32_t desired_access,
+ struct smb2_handle *handle)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ io = (struct smb2_create) {
+ .in.fname = fname,
+ .in.desired_access = desired_access,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ };
+
+ status = smb2_create(tree, tree, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *handle = io.out.file.handle;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create and return a handle to a test directory
+ with specific desired access
+*/
+NTSTATUS torture_smb2_testdir_access(struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle,
+ uint32_t desired_access)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = desired_access;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.fname = fname;
+
+ status = smb2_create(tree, tree, &io);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *handle = io.out.file.handle;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create and return a handle to a test directory
+*/
+NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle)
+{
+ return torture_smb2_testdir_access(tree, fname, handle,
+ SEC_RIGHTS_DIR_ALL);
+}
+
+/*
+ create a simple file using the SMB2 protocol
+*/
+NTSTATUS smb2_create_simple_file(struct torture_context *tctx,
+ struct smb2_tree *tree, const char *fname,
+ struct smb2_handle *handle)
+{
+ char buf[7] = "abc";
+ NTSTATUS status;
+
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testfile_access(tree,
+ fname, handle,
+ SEC_FLAG_MAXIMUM_ALLOWED);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf));
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create a simple file using SMB2.
+*/
+NTSTATUS torture_setup_simple_file(struct torture_context *tctx,
+ struct smb2_tree *tree, const char *fname)
+{
+ struct smb2_handle handle;
+ NTSTATUS status = smb2_create_simple_file(tctx, tree, fname, &handle);
+ NT_STATUS_NOT_OK_RETURN(status);
+ return smb2_util_close(tree, handle);
+}
+
+/*
+ create a complex file using SMB2, to make it easier to
+ find fields in SMB2 getinfo levels
+*/
+NTSTATUS torture_setup_complex_file(struct torture_context *tctx,
+ struct smb2_tree *tree, const char *fname)
+{
+ struct smb2_handle handle;
+ NTSTATUS status = smb2_create_complex_file(tctx, tree, fname, &handle);
+ NT_STATUS_NOT_OK_RETURN(status);
+ return smb2_util_close(tree, handle);
+}
+
+
+/*
+ create a complex dir using SMB2, to make it easier to
+ find fields in SMB2 getinfo levels
+*/
+NTSTATUS torture_setup_complex_dir(struct torture_context *tctx,
+ struct smb2_tree *tree, const char *fname)
+{
+ struct smb2_handle handle;
+ NTSTATUS status = smb2_create_complex_dir(tctx, tree, fname, &handle);
+ NT_STATUS_NOT_OK_RETURN(status);
+ return smb2_util_close(tree, handle);
+}
+
+
+/*
+ return a handle to the root of the share
+*/
+NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.in.oplock_level = 0;
+ io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
+ io.in.file_attributes = 0;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT;
+ io.in.fname = "";
+
+ status = smb2_create(tree, tree, &io);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *handle = io.out.file.handle;
+
+ return NT_STATUS_OK;
+}
+
+/* Comparable to torture_setup_dir, but for SMB2. */
+bool smb2_util_setup_dir(struct torture_context *tctx, struct smb2_tree *tree,
+ const char *dname)
+{
+ NTSTATUS status;
+
+ /* XXX: smb_raw_exit equivalent?
+ smb_raw_exit(cli->session); */
+ if (smb2_deltree(tree, dname) == -1) {
+ torture_result(tctx, TORTURE_ERROR, "Unable to deltree when setting up %s.\n", dname);
+ return false;
+ }
+
+ status = smb2_util_mkdir(tree, dname);
+ if (NT_STATUS_IS_ERR(status)) {
+ torture_result(tctx, TORTURE_ERROR, "Unable to mkdir when setting up %s - %s\n", dname,
+ nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+/*
+ * Helper function to verify a security descriptor, by querying
+ * and comparing against the passed in sd.
+ */
+bool smb2_util_verify_sd(TALLOC_CTX *tctx, struct smb2_tree *tree,
+ struct smb2_handle handle, struct security_descriptor *sd)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_fileinfo q = {};
+
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = handle;
+ q.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (!security_acl_equal(
+ q.query_secdesc.out.sd->dacl, sd->dacl)) {
+ torture_warning(tctx, "%s: security descriptors don't match!\n",
+ __location__);
+ torture_warning(tctx, "got:\n");
+ NDR_PRINT_DEBUG(security_descriptor,
+ q.query_secdesc.out.sd);
+ torture_warning(tctx, "expected:\n");
+ NDR_PRINT_DEBUG(security_descriptor, sd);
+ ret = false;
+ }
+
+ done:
+ return ret;
+}
+
+/*
+ * Helper function to verify attributes, by querying
+ * and comparing against the passed in attrib.
+ */
+bool smb2_util_verify_attrib(TALLOC_CTX *tctx, struct smb2_tree *tree,
+ struct smb2_handle handle, uint32_t attrib)
+{
+ NTSTATUS status;
+ bool ret = true;
+ union smb_fileinfo q = {};
+
+ q.standard.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ q.standard.in.file.handle = handle;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ q.all_info2.out.attrib &= ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NONINDEXED);
+
+ if (q.all_info2.out.attrib != attrib) {
+ torture_warning(tctx, "%s: attributes don't match! "
+ "got %x, expected %x\n", __location__,
+ (uint32_t)q.standard.out.attrib,
+ (uint32_t)attrib);
+ ret = false;
+ }
+
+ done:
+ return ret;
+}
+
+
+uint32_t smb2_util_lease_state(const char *ls)
+{
+ uint32_t val = 0;
+ int i;
+
+ for (i = 0; i < strlen(ls); i++) {
+ switch (ls[i]) {
+ case 'R':
+ val |= SMB2_LEASE_READ;
+ break;
+ case 'H':
+ val |= SMB2_LEASE_HANDLE;
+ break;
+ case 'W':
+ val |= SMB2_LEASE_WRITE;
+ break;
+ }
+ }
+
+ return val;
+}
+
+char *smb2_util_lease_state_string(TALLOC_CTX *mem_ctx, uint32_t ls)
+{
+ return talloc_asprintf(mem_ctx, "0x%0x (%s%s%s)",
+ (unsigned)ls,
+ ls & SMB2_LEASE_READ ? "R": "",
+ ls & SMB2_LEASE_HANDLE ? "H": "",
+ ls & SMB2_LEASE_WRITE ? "W": "");
+}
+
+uint32_t smb2_util_share_access(const char *sharemode)
+{
+ uint32_t val = NTCREATEX_SHARE_ACCESS_NONE; /* 0 */
+ int i;
+
+ for (i = 0; i < strlen(sharemode); i++) {
+ switch(sharemode[i]) {
+ case 'R':
+ val |= NTCREATEX_SHARE_ACCESS_READ;
+ break;
+ case 'W':
+ val |= NTCREATEX_SHARE_ACCESS_WRITE;
+ break;
+ case 'D':
+ val |= NTCREATEX_SHARE_ACCESS_DELETE;
+ break;
+ }
+ }
+
+ return val;
+}
+
+uint8_t smb2_util_oplock_level(const char *op)
+{
+ uint8_t val = SMB2_OPLOCK_LEVEL_NONE;
+ int i;
+
+ for (i = 0; i < strlen(op); i++) {
+ switch (op[i]) {
+ case 's':
+ return SMB2_OPLOCK_LEVEL_II;
+ case 'x':
+ return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ case 'b':
+ return SMB2_OPLOCK_LEVEL_BATCH;
+ default:
+ continue;
+ }
+ }
+
+ return val;
+}
+
+/**
+ * Helper functions to fill a smb2_create struct for several
+ * open scenarios.
+ */
+void smb2_generic_create_share(struct smb2_create *io, struct smb2_lease *ls,
+ bool dir, const char *name, uint32_t disposition,
+ uint32_t share_access,
+ uint8_t oplock, uint64_t leasekey,
+ uint32_t leasestate)
+{
+ ZERO_STRUCT(*io);
+ io->in.security_flags = 0x00;
+ io->in.oplock_level = oplock;
+ io->in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io->in.create_flags = 0x00000000;
+ io->in.reserved = 0x00000000;
+ io->in.desired_access = SEC_RIGHTS_FILE_ALL;
+ io->in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io->in.share_access = share_access;
+ io->in.create_disposition = disposition;
+ io->in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
+ NTCREATEX_OPTIONS_ASYNC_ALERT |
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
+ 0x00200000;
+ io->in.fname = name;
+
+ if (dir) {
+ io->in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io->in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io->in.create_disposition = NTCREATEX_DISP_CREATE;
+ }
+
+ if (ls) {
+ ZERO_STRUCTPN(ls);
+ ls->lease_key.data[0] = leasekey;
+ ls->lease_key.data[1] = ~leasekey;
+ ls->lease_state = leasestate;
+ io->in.lease_request = ls;
+ }
+}
+
+void smb2_generic_create(struct smb2_create *io, struct smb2_lease *ls,
+ bool dir, const char *name, uint32_t disposition,
+ uint8_t oplock, uint64_t leasekey,
+ uint32_t leasestate)
+{
+ smb2_generic_create_share(io, ls, dir, name, disposition,
+ smb2_util_share_access("RWD"),
+ oplock,
+ leasekey, leasestate);
+}
+
+void smb2_lease_create_share(struct smb2_create *io, struct smb2_lease *ls,
+ bool dir, const char *name, uint32_t share_access,
+ uint64_t leasekey, uint32_t leasestate)
+{
+ smb2_generic_create_share(io, ls, dir, name, NTCREATEX_DISP_OPEN_IF,
+ share_access, SMB2_OPLOCK_LEVEL_LEASE,
+ leasekey, leasestate);
+}
+
+void smb2_lease_create(struct smb2_create *io, struct smb2_lease *ls,
+ bool dir, const char *name, uint64_t leasekey,
+ uint32_t leasestate)
+{
+ smb2_lease_create_share(io, ls, dir, name,
+ smb2_util_share_access("RWD"),
+ leasekey, leasestate);
+}
+
+void smb2_lease_v2_create_share(struct smb2_create *io,
+ struct smb2_lease *ls,
+ bool dir,
+ const char *name,
+ uint32_t share_access,
+ uint64_t leasekey,
+ const uint64_t *parentleasekey,
+ uint32_t leasestate,
+ uint16_t lease_epoch)
+{
+ smb2_generic_create_share(io, NULL, dir, name, NTCREATEX_DISP_OPEN_IF,
+ share_access, SMB2_OPLOCK_LEVEL_LEASE, 0, 0);
+
+ if (ls) {
+ ZERO_STRUCT(*ls);
+ ls->lease_key.data[0] = leasekey;
+ ls->lease_key.data[1] = ~leasekey;
+ ls->lease_state = leasestate;
+ if (parentleasekey != NULL) {
+ ls->lease_flags |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
+ ls->parent_lease_key.data[0] = *parentleasekey;
+ ls->parent_lease_key.data[1] = ~(*parentleasekey);
+ }
+ ls->lease_epoch = lease_epoch;
+ io->in.lease_request_v2 = ls;
+ }
+}
+
+void smb2_lease_v2_create(struct smb2_create *io,
+ struct smb2_lease *ls,
+ bool dir,
+ const char *name,
+ uint64_t leasekey,
+ const uint64_t *parentleasekey,
+ uint32_t leasestate,
+ uint16_t lease_epoch)
+{
+ smb2_lease_v2_create_share(io, ls, dir, name,
+ smb2_util_share_access("RWD"),
+ leasekey, parentleasekey,
+ leasestate, lease_epoch);
+}
+
+
+void smb2_oplock_create_share(struct smb2_create *io, const char *name,
+ uint32_t share_access, uint8_t oplock)
+{
+ smb2_generic_create_share(io, NULL, false, name, NTCREATEX_DISP_OPEN_IF,
+ share_access, oplock, 0, 0);
+}
+void smb2_oplock_create(struct smb2_create *io, const char *name, uint8_t oplock)
+{
+ smb2_oplock_create_share(io, name, smb2_util_share_access("RWD"),
+ oplock);
+}
+
+/*
+ a wrapper around smblsa_sid_check_privilege, that tries to take
+ account of the fact that the lsa privileges calls don't expand
+ group memberships, using an explicit check for administrator. There
+ must be a better way ...
+ */
+NTSTATUS torture_smb2_check_privilege(struct smb2_tree *tree,
+ const char *sid_str,
+ const char *privilege)
+{
+ struct dom_sid *sid = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint32_t rid;
+ NTSTATUS status;
+
+ tmp_ctx = talloc_new(tree);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
+ if (sid == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INVALID_SID;
+ }
+
+ status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ if (rid == DOMAIN_RID_ADMINISTRATOR) {
+ /* assume the administrator has them all */
+ TALLOC_FREE(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ talloc_free(tmp_ctx);
+
+ return smb2lsa_sid_check_privilege(tree, sid_str, privilege);
+}
diff --git a/source4/torture/smb2/wscript_build b/source4/torture/smb2/wscript_build
new file mode 100644
index 0000000..533639c
--- /dev/null
+++ b/source4/torture/smb2/wscript_build
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_SMB2',
+ source='''
+ acls.c
+ attr.c
+ block.c
+ bench.c
+ charset.c
+ compound.c
+ connect.c
+ create.c
+ credits.c
+ delete-on-close.c
+ deny.c
+ dir.c
+ dosmode.c
+ durable_open.c
+ durable_v2_open.c
+ ea.c
+ getinfo.c
+ ioctl.c
+ lease.c
+ lease_break_handler.c
+ lock.c
+ max_allowed.c
+ mangle.c
+ maxfid.c
+ maxwrite.c
+ mkdir.c
+ multichannel.c
+ oplock_break_handler.c
+ notify.c
+ notify_disabled.c
+ oplock.c
+ read.c
+ read_write.c
+ rename.c
+ replay.c
+ scan.c
+ secleak.c
+ session.c
+ sessid.c
+ setinfo.c
+ sharemode.c
+ smb2.c
+ streams.c
+ samba3misc.c
+ tcon.c
+ timestamps.c
+ util.c
+ ''',
+ subsystem='smbtorture',
+ deps='LIBCLI_SMB2 torture NDR_IOCTL CMDLINE_S4',
+ internal_module=True,
+ autoproto='proto.h',
+ init_function='torture_smb2_init'
+ )
+
diff --git a/source4/torture/smbtorture.c b/source4/torture/smbtorture.c
new file mode 100644
index 0000000..d9e90ea
--- /dev/null
+++ b/source4/torture/smbtorture.c
@@ -0,0 +1,770 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006-2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "system/time.h"
+#include "system/wait.h"
+#include "system/filesys.h"
+#include "system/readline.h"
+#include "../libcli/smbreadline/smbreadline.h"
+#include "libcli/libcli.h"
+#include "lib/events/events.h"
+
+#include "torture/smbtorture.h"
+#include "librpc/rpc/dcerpc.h"
+#include "auth/gensec/gensec.h"
+#include "param/param.h"
+#include "lib/util/samba_modules.h"
+
+#ifdef HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+
+static int use_fullname;
+
+static char *prefix_name(TALLOC_CTX *mem_ctx, const char *prefix, const char *name)
+{
+ if (prefix == NULL)
+ return talloc_strdup(mem_ctx, name);
+ else
+ return talloc_asprintf(mem_ctx, "%s.%s", prefix, name);
+}
+
+static void print_test_list(const struct torture_suite *suite, const char *prefix, const char *expr)
+{
+ struct torture_suite *o;
+ struct torture_tcase *t;
+ struct torture_test *p;
+
+ for (o = suite->children; o; o = o->next) {
+ char *name = prefix_name(NULL, prefix, o->name);
+ print_test_list(o, name, expr);
+ talloc_free(name);
+ }
+
+ for (t = suite->testcases; t; t = t->next) {
+ for (p = t->tests; p; p = p->next) {
+ char *name = talloc_asprintf(NULL, "%s.%s.%s", prefix, t->name, p->name);
+ if (strncmp(name, expr, strlen(expr)) == 0) {
+ printf("%s\n", name);
+ }
+ talloc_free(name);
+ }
+ }
+}
+
+static bool run_matching(struct torture_context *torture,
+ const char *prefix,
+ const char *expr,
+ const char **restricted,
+ struct torture_suite *suite,
+ bool *matched)
+{
+ bool ret = true;
+ struct torture_suite *o;
+ struct torture_tcase *t;
+ struct torture_test *p;
+
+ for (o = suite->children; o; o = o->next) {
+ char *name = NULL;
+ name = prefix_name(torture, prefix, o->name);
+ if (gen_fnmatch(expr, name) == 0) {
+ *matched = true;
+ reload_charcnv(torture->lp_ctx);
+ if (use_fullname == 1) {
+ torture_subunit_prefix_reset(torture, prefix);
+ }
+ ret &= torture_run_suite_restricted(torture, o, restricted);
+ if (use_fullname == 1) {
+ torture_subunit_prefix_reset(torture, NULL);
+ }
+ /*
+ * torture_run_suite_restricted() already implements
+ * recursion, so we're done with this child suite.
+ */
+ continue;
+ }
+ ret &= run_matching(torture, name, expr, restricted, o, matched);
+ }
+
+ for (t = suite->testcases; t; t = t->next) {
+ char *tname = prefix_name(torture, prefix, t->name);
+ if (gen_fnmatch(expr, tname) == 0) {
+ *matched = true;
+ reload_charcnv(torture->lp_ctx);
+ if (use_fullname == 1) {
+ torture_subunit_prefix_reset(torture, prefix);
+ }
+ ret &= torture_run_tcase_restricted(torture, t, restricted);
+ if (use_fullname == 1) {
+ torture_subunit_prefix_reset(torture, NULL);
+ }
+ /*
+ * torture_run_tcase_restricted() already implements
+ * recursion, so we're done for this tcase.
+ */
+ continue;
+ }
+ for (p = t->tests; p; p = p->next) {
+ char *pname = prefix_name(torture, tname, p->name);
+ if (gen_fnmatch(expr, pname) == 0) {
+ *matched = true;
+ reload_charcnv(torture->lp_ctx);
+ if (use_fullname == 1) {
+ torture_subunit_prefix_reset(torture,
+ tname);
+ }
+ ret &= torture_run_test_restricted(torture, t, p, restricted);
+ if (use_fullname == 1) {
+ torture_subunit_prefix_reset(torture,
+ NULL);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#define MAX_COLS 80 /* FIXME: Determine this at run-time */
+
+/****************************************************************************
+run a specified test or "ALL"
+****************************************************************************/
+bool torture_run_named_tests(struct torture_context *torture, const char *name,
+ const char **restricted)
+{
+ bool ret = true;
+ bool matched = false;
+ struct torture_suite *o;
+
+ torture_ui_report_time(torture);
+
+ if (strequal(name, "ALL")) {
+ if (restricted != NULL) {
+ printf("--load-list and ALL are incompatible\n");
+ return false;
+ }
+ for (o = torture_root->children; o; o = o->next) {
+ ret &= torture_run_suite(torture, o);
+ }
+ return ret;
+ }
+
+ ret = run_matching(torture, NULL, name, restricted, torture_root, &matched);
+
+ if (!matched) {
+ printf("Unknown torture operation '%s'\n", name);
+ return false;
+ }
+
+ return ret;
+}
+
+bool torture_parse_target(TALLOC_CTX *ctx,
+ struct loadparm_context *lp_ctx,
+ const char *target)
+{
+ char *host = NULL, *share = NULL;
+ struct dcerpc_binding *binding_struct;
+ NTSTATUS status;
+
+ /* see if its a RPC transport specifier */
+ if (!smbcli_parse_unc(target, NULL, &host, &share)) {
+ const char *h;
+
+ status = dcerpc_parse_binding(ctx, target, &binding_struct);
+ if (NT_STATUS_IS_ERR(status)) {
+ d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
+ return false;
+ }
+
+ h = dcerpc_binding_get_string_option(binding_struct, "host");
+ host = discard_const_p(char, h);
+ if (host != NULL) {
+ lpcfg_set_cmdline(lp_ctx, "torture:host", host);
+ }
+
+ if (lpcfg_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
+ lpcfg_set_cmdline(lp_ctx, "torture:share", "IPC$");
+ lpcfg_set_cmdline(lp_ctx, "torture:binding", target);
+ } else {
+ lpcfg_set_cmdline(lp_ctx, "torture:host", host);
+ lpcfg_set_cmdline(lp_ctx, "torture:share", share);
+ lpcfg_set_cmdline(lp_ctx, "torture:binding", host);
+ }
+
+ return true;
+}
+
+static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
+{
+ char *userdn, *basedn, *secret;
+ char *p, *d;
+
+ /* retrieve the userdn */
+ p = strchr_m(dns, '#');
+ if (!p) {
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", "");
+ return;
+ }
+ userdn = strndup(dns, p - dns);
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
+
+ /* retrieve the basedn */
+ d = p + 1;
+ p = strchr_m(d, '#');
+ if (!p) {
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", "");
+ return;
+ }
+ basedn = strndup(d, p - d);
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
+
+ /* retrieve the secret */
+ p = p + 1;
+ if (!p) {
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", "");
+ return;
+ }
+ secret = strdup(p);
+ lpcfg_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
+
+ printf ("%s - %s - %s\n", userdn, basedn, secret);
+
+}
+
+/* Print the full test list, formatted into separate labelled test
+ * groups.
+ */
+static void print_structured_testsuite_list(void)
+{
+ struct torture_suite *o;
+ struct torture_suite *s;
+ struct torture_tcase *t;
+ int i;
+
+ if (torture_root == NULL) {
+ printf("NO TESTS LOADED\n");
+ return;
+ }
+
+ for (o = torture_root->children; o; o = o->next) {
+ printf("\n%s (%s):\n ", o->description, o->name);
+
+ i = 0;
+ for (s = o->children; s; s = s->next) {
+ if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
+ printf("\n ");
+ i = 0;
+ }
+ i+=printf("%s.%s ", o->name, s->name);
+ }
+
+ for (t = o->testcases; t; t = t->next) {
+ if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
+ printf("\n ");
+ i = 0;
+ }
+ i+=printf("%s.%s ", o->name, t->name);
+ }
+
+ if (i) printf("\n");
+ }
+
+ printf("\nThe default test is ALL.\n");
+}
+
+static void print_testsuite_list(void)
+{
+ struct torture_suite *o;
+ struct torture_suite *s;
+ struct torture_tcase *t;
+
+ if (torture_root == NULL)
+ return;
+
+ for (o = torture_root->children; o; o = o->next) {
+ for (s = o->children; s; s = s->next) {
+ printf("%s.%s\n", o->name, s->name);
+ }
+
+ for (t = o->testcases; t; t = t->next) {
+ printf("%s.%s\n", o->name, t->name);
+ }
+ }
+}
+
+void torture_print_testsuites(bool structured)
+{
+ if (structured) {
+ print_structured_testsuite_list();
+ } else {
+ print_testsuite_list();
+ }
+}
+
+static void usage(poptContext pc)
+{
+ poptPrintUsage(pc, stdout, 0);
+ printf("\n");
+
+ printf("The binding format is:\n\n");
+
+ printf(" TRANSPORT:host[flags]\n\n");
+
+ printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
+ printf(" or ncalrpc for local connections.\n\n");
+
+ printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
+ printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
+ printf(" string.\n\n");
+
+ printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
+ printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
+ printf(" will be auto-determined.\n\n");
+
+ printf(" other recognised flags are:\n\n");
+
+ printf(" sign : enable ntlmssp signing\n");
+ printf(" seal : enable ntlmssp sealing\n");
+ printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
+ printf(" validate: enable the NDR validator\n");
+ printf(" print: enable debugging of the packets\n");
+ printf(" bigendian: use bigendian RPC\n");
+ printf(" padcheck: check reply data for non-zero pad bytes\n\n");
+
+ printf(" For example, these all connect to the samr pipe:\n\n");
+
+ printf(" ncacn_np:myserver\n");
+ printf(" ncacn_np:myserver[samr]\n");
+ printf(" ncacn_np:myserver[\\pipe\\samr]\n");
+ printf(" ncacn_np:myserver[/pipe/samr]\n");
+ printf(" ncacn_np:myserver[samr,sign,print]\n");
+ printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
+ printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
+ printf(" ncacn_np:\n");
+ printf(" ncacn_np:[/pipe/samr]\n\n");
+
+ printf(" ncacn_ip_tcp:myserver\n");
+ printf(" ncacn_ip_tcp:myserver[1024]\n");
+ printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
+
+ printf(" ncalrpc:\n\n");
+
+ printf("The UNC format is:\n\n");
+
+ printf(" //server/share\n\n");
+
+ printf("Tests are:");
+
+ print_structured_testsuite_list();
+
+}
+
+_NORETURN_ static void max_runtime_handler(int sig)
+{
+ DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
+ exit(1);
+}
+
+/****************************************************************************
+ main program
+****************************************************************************/
+int main(int argc, const char *argv[])
+{
+ int opt, i;
+ bool correct = true;
+ int max_runtime=0;
+ int argc_new;
+ struct torture_context *torture;
+ struct torture_results *results;
+ const struct torture_ui_ops *ui_ops;
+ char **argv_new;
+ poptContext pc;
+ static const char *target = "other";
+ NTSTATUS status;
+ int shell = false;
+ static const char *ui_ops_name = "subunit";
+ const char *basedir = NULL;
+ char *outputdir;
+ const char *extra_module = NULL;
+ static int list_tests = 0, list_testsuites = 0;
+ int num_extra_users = 0;
+ const char **restricted = NULL;
+ int num_restricted = -1;
+ const char *load_list = NULL;
+ enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
+ OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,
+ OPT_EXTRA_USER,};
+ TALLOC_CTX *mem_ctx = NULL;
+ struct loadparm_context *lp_ctx = NULL;
+ bool ok;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"fullname", 0, POPT_ARG_NONE, &use_fullname, 0,
+ "use full name for the test", NULL },
+ {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
+ {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
+ {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
+ {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
+ {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
+ {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
+ {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
+ {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
+ {"list-suites", 0, POPT_ARG_NONE, &list_testsuites, 0, "List available testsuites and exit", NULL },
+ {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests in specified suites and exit", NULL },
+ {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
+ {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
+ {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
+ {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
+ {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
+ "run dangerous tests (eg. wiping out password database)", NULL},
+ {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
+ {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
+ {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
+ {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
+ "run async tests", NULL},
+ {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
+ "number of simultaneous async requests", NULL},
+ {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
+ "set maximum time for smbtorture to live", "seconds"},
+ {"extra-user", 0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
+ "extra user credentials", NULL},
+ {"load-list", 0, POPT_ARG_STRING, &load_list, 0,
+ "load a test id list from a text file", NULL},
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CONNECTION
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+ POPT_LEGACY_S4
+ POPT_TABLEEND
+ };
+
+ setlinebuf(stdout);
+
+ mem_ctx = talloc_named_const(NULL, 0, "torture_ctx");
+ if (mem_ctx == NULL) {
+ printf("Unable to allocate torture_ctx\n");
+ exit(1);
+ }
+
+ printf("smbtorture %s\n", samba_version_string());
+
+ /* we are never interested in SIGPIPE */
+ BlockSignals(true, SIGPIPE);
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Unable to init cmdline parser\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ if (pc == NULL) {
+ DBG_ERR("Failed cmdline parser\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_LOADFILE:
+ lpcfg_set_cmdline(lp_ctx, "torture:loadfile", poptGetOptArg(pc));
+ break;
+ case OPT_UNCLIST:
+ lpcfg_set_cmdline(lp_ctx, "torture:unclist", poptGetOptArg(pc));
+ break;
+ case OPT_TIMELIMIT:
+ lpcfg_set_cmdline(lp_ctx, "torture:timelimit", poptGetOptArg(pc));
+ break;
+ case OPT_NUMPROGS:
+ lpcfg_set_cmdline(lp_ctx, "torture:nprocs", poptGetOptArg(pc));
+ break;
+ case OPT_DNS:
+ parse_dns(lp_ctx, poptGetOptArg(pc));
+ break;
+ case OPT_DANGEROUS:
+ lpcfg_set_cmdline(lp_ctx, "torture:dangerous", "Yes");
+ break;
+ case OPT_ASYNC:
+ lpcfg_set_cmdline(lp_ctx, "torture:async", "Yes");
+ break;
+ case OPT_SMB_PORTS:
+ lpcfg_set_cmdline(lp_ctx, "smb ports", poptGetOptArg(pc));
+ break;
+ case OPT_EXTRA_USER:
+ {
+ char *option = talloc_asprintf(mem_ctx,
+ "torture:extra_user%u",
+ ++num_extra_users);
+ const char *value = poptGetOptArg(pc);
+ if (option == NULL) {
+ printf("talloc fail\n");
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+ lpcfg_set_cmdline(lp_ctx, option, value);
+ talloc_free(option);
+ }
+ break;
+ default:
+ if (opt < 0) {
+ printf("Invalid command line option %s (%d)\n",
+ poptBadOption(pc, 0),
+ opt);
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+ }
+ }
+
+ if (load_list != NULL) {
+ char **r;
+ r = file_lines_load(load_list, &num_restricted, 0, mem_ctx);
+ restricted = discard_const_p(const char *, r);
+ if (restricted == NULL) {
+ printf("Unable to read load list file '%s'\n", load_list);
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+ }
+
+ if (strcmp(target, "samba3") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:samba3", "true");
+ lpcfg_set_cmdline(lp_ctx, "torture:resume_key_support", "false");
+ } else if (strcmp(target, "samba4") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:samba4", "true");
+ } else if (strcmp(target, "samba4-ntvfs") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:samba4", "true");
+ lpcfg_set_cmdline(lp_ctx, "torture:samba4-ntvfs", "true");
+ } else if (strcmp(target, "winxp") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:winxp", "true");
+ } else if (strcmp(target, "w2k3") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:w2k3", "true");
+ } else if (strcmp(target, "w2k8") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:w2k8", "true");
+ lpcfg_set_cmdline(lp_ctx,
+ "torture:invalid_lock_range_support", "false");
+ } else if (strcmp(target, "w2k12") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:w2k12", "true");
+ } else if (strcmp(target, "win7") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:win7", "true");
+ lpcfg_set_cmdline(lp_ctx, "torture:resume_key_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:rewind_support", "false");
+
+ /* RAW-SEARCH for fails for inexplicable reasons against win7 */
+ lpcfg_set_cmdline(lp_ctx, "torture:search_ea_support", "false");
+
+ lpcfg_set_cmdline(lp_ctx, "torture:hide_on_access_denied",
+ "true");
+ } else if (strcmp(target, "onefs") == 0) {
+ lpcfg_set_cmdline(lp_ctx, "torture:onefs", "true");
+ lpcfg_set_cmdline(lp_ctx, "torture:openx_deny_dos_support",
+ "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:range_not_locked_on_file_close", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:sacl_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:ea_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:smbexit_pdu_support",
+ "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:smblock_pdu_support",
+ "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:2_step_break_to_none",
+ "true");
+ lpcfg_set_cmdline(lp_ctx, "torture:deny_dos_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:deny_fcb_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:read_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:writeclose_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:resume_key_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:rewind_support", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:raw_search_search", "false");
+ lpcfg_set_cmdline(lp_ctx, "torture:search_ea_size", "false");
+ }
+
+ if (max_runtime) {
+ /* this will only work if nobody else uses alarm(),
+ which means it won't work for some tests, but we
+ can't use the event context method we use for smbd
+ as so many tests create their own event
+ context. This will at least catch most cases. */
+ signal(SIGALRM, max_runtime_handler);
+ alarm(max_runtime);
+ }
+
+ if (extra_module != NULL) {
+ init_module_fn fn = load_module(poptGetOptArg(pc), false, NULL);
+
+ if (fn == NULL)
+ d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
+ else {
+ status = fn(mem_ctx);
+ if (NT_STATUS_IS_ERR(status)) {
+ d_printf("Error initializing module %s: %s\n",
+ poptGetOptArg(pc), nt_errstr(status));
+ }
+ }
+ } else {
+ torture_init(mem_ctx);
+ }
+
+ if (list_testsuites) {
+ print_testsuite_list();
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ argv_new = discard_const_p(char *, poptGetArgs(pc));
+
+ argc_new = argc;
+ for (i=0; i<argc; i++) {
+ if (argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (list_tests) {
+ if (argc_new == 1) {
+ print_test_list(torture_root, NULL, "");
+ } else {
+ for (i=1;i<argc_new;i++) {
+ print_test_list(torture_root, NULL, argv_new[i]);
+ }
+ }
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ if (torture_seed == 0) {
+ torture_seed = time(NULL);
+ }
+ printf("Using seed %d\n", torture_seed);
+ srandom(torture_seed);
+
+ if (!strcmp(ui_ops_name, "simple")) {
+ ui_ops = &torture_simple_ui_ops;
+ } else if (!strcmp(ui_ops_name, "subunit")) {
+ ui_ops = &torture_subunit_ui_ops;
+ } else {
+ printf("Unknown output format '%s'\n", ui_ops_name);
+ talloc_free(mem_ctx);
+ exit(1);
+ }
+
+ results = torture_results_init(mem_ctx, ui_ops);
+
+ torture = torture_context_init(s4_event_context_init(mem_ctx),
+ results);
+ if (basedir != NULL) {
+ if (basedir[0] != '/') {
+ fprintf(stderr, "Please specify an absolute path to --basedir\n");
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return 1;
+ }
+ outputdir = talloc_asprintf(torture, "%s/smbtortureXXXXXX", basedir);
+ } else {
+ char *pwd = talloc_size(torture, PATH_MAX);
+ if (!getcwd(pwd, PATH_MAX)) {
+ fprintf(stderr, "Unable to determine current working directory\n");
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return 1;
+ }
+ outputdir = talloc_asprintf(torture, "%s/smbtortureXXXXXX", pwd);
+ }
+ if (!outputdir) {
+ fprintf(stderr, "Could not allocate per-run output dir\n");
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return 1;
+ }
+ torture->outputdir = mkdtemp(outputdir);
+ if (!torture->outputdir) {
+ perror("Failed to make temp output dir");
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return 1;
+ }
+
+ torture->lp_ctx = lp_ctx;
+
+ gensec_init();
+
+ if (shell) {
+ /* In shell mode, just ignore any remaining test names. */
+ torture_shell(torture);
+ } else {
+
+ /* At this point, we should just have a target string,
+ * followed by a series of test names. Unless we are in
+ * shell mode, in which case we don't need anything more.
+ */
+
+ if (argc_new < 3) {
+ printf("You must specify a test to run, or 'ALL'\n");
+ usage(pc);
+ torture->results->returncode = 1;
+ } else if (!torture_parse_target(torture,
+ lp_ctx, argv_new[1])) {
+ /* Take the target name or binding. */
+ usage(pc);
+ torture->results->returncode = 1;
+ } else {
+ for (i=2;i<argc_new;i++) {
+ if (!torture_run_named_tests(torture, argv_new[i],
+ (const char **)restricted)) {
+ correct = false;
+ }
+ }
+ }
+ }
+
+ /* Now delete the temp dir we created */
+ torture_deltree_outputdir(torture);
+
+ if (torture->results->returncode && correct) {
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return(0);
+ } else {
+ poptFreeContext(pc);
+ talloc_free(mem_ctx);
+ return(1);
+ }
+}
diff --git a/source4/torture/smbtorture.h b/source4/torture/smbtorture.h
new file mode 100644
index 0000000..3a72e29
--- /dev/null
+++ b/source4/torture/smbtorture.h
@@ -0,0 +1,146 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __SMBTORTURE_H__
+#define __SMBTORTURE_H__
+
+#include "../lib/torture/torture.h"
+
+struct smbcli_state;
+
+extern struct torture_suite *torture_root;
+
+extern int torture_entries;
+extern int torture_seed;
+extern int torture_numops;
+extern int torture_failures;
+extern int torture_numasync;
+
+struct torture_test;
+int torture_init(TALLOC_CTX *);
+bool torture_register_suite(TALLOC_CTX *, struct torture_suite *suite);
+void torture_shell(struct torture_context *tctx);
+void torture_print_testsuites(bool structured);
+bool torture_run_named_tests(struct torture_context *torture, const char *name,
+ const char **restricted);
+bool torture_parse_target(TALLOC_CTX *ctx,
+ struct loadparm_context *lp_ctx,
+ const char *target);
+
+/* Server Functionality Support */
+
+/* Not all SMB server implementations support every aspect of the protocol.
+ * To allow smbtorture to provide useful data when run against these servers we
+ * define support parameters here, that will cause some tests to be skipped or
+ * the correctness checking of some tests to be conditional.
+ *
+ * The idea is that different server implementations can be specified on the
+ * command line such as "--target=win7" which will define the list of server
+ * parameters that are not supported. This is mostly a black list of
+ * unsupported features with the default expectation being that all features are
+ * supported.
+ *
+ * Because we use parametric options we do not need to define these parameters
+ * anywhere, we just define the meaning of each here.*/
+
+/* torture:invalid_lock_range_support
+ *
+ * This parameter specifies whether the server will return
+ * STATUS_INVALID_LOCK_RANGE in response to a LockingAndX request where the
+ * combined offset and range overflow the 63-bit boundary. On Windows servers
+ * before Win7, this request would return STATUS_OK, but the actual lock
+ * behavior was undefined. */
+
+/* torture:openx_deny_dos_support
+ *
+ * This parameter specifies whether the server supports the DENY_DOS open mode
+ * of the SMBOpenX PDU. */
+
+/* torture:range_not_locked_on_file_close
+ *
+ * When a byte range lock is pending, and the file which is being locked is
+ * closed, Windows servers return the error NT_STATUS_RANGE_NOT_LOCKED. This
+ * is strange, as this error is meant to be returned only for unlock requests.
+ * When true, torture will expect the Windows behavior, otherwise it will
+ * expect the more logical NT_STATUS_LOCK_NOT_GRANTED.
+ */
+
+/* torture:sacl_support
+ *
+ * This parameter specifies whether the server supports the setting and
+ * retrieval of System Access Control Lists. This includes whether the server
+ * supports the use of the SEC_FLAG_SYSTEM_SECURITY bit in the open access
+ * mask.*/
+
+/* torture:smbexit_pdu_support
+ *
+ * This parameter specifies whether the server supports the SMBExit (0x11) PDU. */
+
+/* torture:smblock_pdu_support
+ *
+ * This parameter specifies whether the server supports the SMBLock (0x0C) PDU. */
+
+/* torture:2_step_break_to_none
+ *
+ * If true this parameter tests servers that break from level 1 to none in two
+ * steps rather than 1.
+ */
+
+/* torture:resume_key_support
+ *
+ * Server supports resuming search via key.
+ */
+
+/* torture:rewind_support
+ *
+ * Server supports rewinding during search.
+ */
+
+/* torture:ea_support
+ *
+ * Server supports OS/2 style EAs.
+ */
+
+/* torture:search_ea_support
+ *
+ * Server supports RAW_SEARCH_DATA_EA_LIST - Torture currently
+ * does not interact correctly with win7, this flag disables
+ * the appropriate test.
+ */
+
+/* torture:hide_on_acess_denied
+ *
+ * Some servers (win7) choose to hide files when certain access has been
+ * denied. When true, torture will expect NT_STATUS_OBJECT_NAME_NOT_FOUND
+ * rather than NT_STATUS_ACCESS_DENIED when trying to open one of these files.
+ */
+
+/* torture:raw_search_search
+ *
+ * Server supports RAW_SEARCH_SEARCH level.
+ */
+
+/* torture:search_ea_size
+ *
+ * Server supports RAW_SEARCH_DATA_EA_SIZE - This flag disables
+ * the appropriate test.
+ */
+
+#endif /* __SMBTORTURE_H__ */
diff --git a/source4/torture/tests/test_gentest.sh b/source4/torture/tests/test_gentest.sh
new file mode 100755
index 0000000..ad88bd4
--- /dev/null
+++ b/source4/torture/tests/test_gentest.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Blackbox tests for gentest
+# Copyright (C) 2008 Andrew Tridgell
+# based on test_smbclient.sh
+
+if [ $# -lt 4 ]; then
+ cat <<EOF
+Usage: test_gentest.sh SERVER USERNAME PASSWORD DOMAIN PREFIX
+EOF
+ exit 1
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+DOMAIN=$4
+PREFIX=$5
+shift 5
+failed=0
+
+samba4bindir="$BINDIR"
+gentest="$samba4bindir/gentest"
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+
+cat <<EOF >$PREFIX/gentest.ignore
+all_info.out.fname
+internal_information.out.file_id
+EOF
+
+testit "gentest" $VALGRIND $gentest //$SERVER/test1 //$SERVER/test2 --seed=1 --seedsfile=$PREFIX/gentest_seeds.dat --num-ops=100 --ignore=$PREFIX/gentest.ignore -W "$DOMAIN" --user1="$USERNAME%$PASSWORD" --user2="$USERNAME%$PASSWORD" "$@" || failed=$(expr $failed + 1)
+
+rm -f $PREFIX/gentest.ignore
+
+exit $failed
diff --git a/source4/torture/tests/test_locktest.sh b/source4/torture/tests/test_locktest.sh
new file mode 100755
index 0000000..2342d7a
--- /dev/null
+++ b/source4/torture/tests/test_locktest.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Blackbox tests for locktest
+# Copyright (C) 2008 Andrew Tridgell
+# based on test_smbclient.sh
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_locktest.sh SERVER USERNAME PASSWORD DOMAIN PREFIX
+EOF
+ exit 1
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+DOMAIN=$4
+PREFIX=$5
+shift 5
+failed=0
+
+samba4bindir="$BINDIR"
+locktest="$samba4bindir/locktest"
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+
+testit "locktest" $VALGRIND $locktest //$SERVER/test1 //$SERVER/test2 --num-ops=100 -W "$DOMAIN" --user1="$DOMAIN\\$USERNAME%$PASSWORD" "$@" || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source4/torture/tests/test_masktest.sh b/source4/torture/tests/test_masktest.sh
new file mode 100755
index 0000000..81adf8a
--- /dev/null
+++ b/source4/torture/tests/test_masktest.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Blackbox tests for masktest
+# Copyright (C) 2008 Andrew Tridgell
+# based on test_smbclient.sh
+
+if [ $# -lt 5 ]; then
+ cat <<EOF
+Usage: test_masktest.sh SERVER USERNAME PASSWORD DOMAIN PREFIX
+EOF
+ exit 1
+fi
+
+SERVER=$1
+USERNAME=$2
+PASSWORD=$3
+DOMAIN=$4
+PREFIX=$5
+shift 5
+failed=0
+
+samba4bindir="$BINDIR"
+masktest="$samba4bindir/masktest"
+
+. $(dirname $0)/../../../testprogs/blackbox/subunit.sh
+
+testit "masktest" $VALGRIND $masktest //$SERVER/tmp --num-ops=200 --dieonerror -W "$DOMAIN" -U"$USERNAME%$PASSWORD" "$@" || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/source4/torture/torture.c b/source4/torture/torture.c
new file mode 100644
index 0000000..c21c494
--- /dev/null
+++ b/source4/torture/torture.c
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "param/param.h"
+#include "torture/smbtorture.h"
+#include "lib/util/samba_modules.h"
+
+_PUBLIC_ int torture_numops=10;
+_PUBLIC_ int torture_entries=1000;
+_PUBLIC_ int torture_failures=1;
+_PUBLIC_ int torture_seed=0;
+_PUBLIC_ int torture_numasync=100;
+
+struct torture_suite *torture_root = NULL;
+
+bool torture_register_suite(TALLOC_CTX *mem_ctx, struct torture_suite *suite)
+{
+ if (!suite)
+ return true;
+
+ if (torture_root == NULL)
+ torture_root = talloc_zero(mem_ctx, struct torture_suite);
+
+ return torture_suite_add_suite(torture_root, suite);
+}
+
+_PUBLIC_ int torture_init(TALLOC_CTX *mem_ctx)
+{
+#define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
+ STATIC_smbtorture_MODULES_PROTO;
+ init_module_fn static_init[] = { STATIC_smbtorture_MODULES };
+ init_module_fn *shared_init = load_samba_modules(mem_ctx, "smbtorture");
+
+ run_init_functions(mem_ctx, static_init);
+ run_init_functions(mem_ctx, shared_init);
+
+ talloc_free(shared_init);
+
+ return 0;
+}
diff --git a/source4/torture/unix/unix.c b/source4/torture/unix/unix.c
new file mode 100644
index 0000000..8ee3d8d
--- /dev/null
+++ b/source4/torture/unix/unix.c
@@ -0,0 +1,40 @@
+/*
+ UNIX Extensions test registration.
+
+ Copyright (C) 2007 James Peach
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/unix/proto.h"
+
+NTSTATUS torture_unix_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "unix");
+
+ suite->description =
+ talloc_strdup(suite, "CIFS UNIX extensions tests");
+
+ torture_suite_add_simple_test(suite,
+ "whoami", torture_unix_whoami);
+ torture_suite_add_simple_test(suite,
+ "info2", unix_torture_unix_info2);
+
+ return (torture_register_suite(ctx, suite)) ? NT_STATUS_OK
+ : NT_STATUS_UNSUCCESSFUL;
+
+}
diff --git a/source4/torture/unix/unix_info2.c b/source4/torture/unix/unix_info2.c
new file mode 100644
index 0000000..cf3ea37
--- /dev/null
+++ b/source4/torture/unix/unix_info2.c
@@ -0,0 +1,503 @@
+/*
+ Test the SMB_QUERY_FILE_UNIX_INFO2 Unix extension.
+
+ Copyright (C) 2007 James Peach
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "torture/util.h"
+#include "torture/unix/proto.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+
+struct unix_info2 {
+ uint64_t end_of_file;
+ uint64_t num_bytes;
+ NTTIME status_change_time;
+ NTTIME access_time;
+ NTTIME change_time;
+ uint64_t uid;
+ uint64_t gid;
+ uint32_t file_type;
+ uint64_t dev_major;
+ uint64_t dev_minor;
+ uint64_t unique_id;
+ uint64_t permissions;
+ uint64_t nlink;
+ NTTIME create_time;
+ uint32_t file_flags;
+ uint32_t flags_mask;
+};
+
+static struct smbcli_state *connect_to_server(struct torture_context *tctx)
+{
+ NTSTATUS status;
+ struct smbcli_state *cli;
+
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+ struct smb_trans2 tp;
+ uint16_t setup;
+ uint8_t data[12];
+ uint8_t params[4];
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(tctx, &cli, host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share, NULL, lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "failed to connect to //%s/%s: %s\n",
+ host, share, nt_errstr(status));
+ torture_result(tctx, TORTURE_FAIL, "Failed to connect to server");
+ return NULL;
+ }
+
+ /* Setup POSIX on the server. */
+ SSVAL(data, 0, CIFS_UNIX_MAJOR_VERSION);
+ SSVAL(data, 2, CIFS_UNIX_MINOR_VERSION);
+ SBVAL(data,4,((uint64_t)(
+ CIFS_UNIX_POSIX_ACLS_CAP|
+ CIFS_UNIX_POSIX_PATHNAMES_CAP|
+ CIFS_UNIX_FCNTL_LOCKS_CAP|
+ CIFS_UNIX_EXTATTR_CAP|
+ CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
+ setup = TRANSACT2_SETFSINFO;
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.max_param = 0;
+ tp.in.max_data = 0;
+ tp.in.setup = &setup;
+ tp.in.trans_name = NULL;
+ SSVAL(params, 0, 0);
+ SSVAL(params, 2, SMB_SET_CIFS_UNIX_INFO);
+ tp.in.params = data_blob_talloc(tctx, params, 4);
+ tp.in.data = data_blob_talloc(tctx, data, 12);
+
+ status = smb_raw_trans2(cli->tree, tctx, &tp);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK,
+ "doing SMB_SET_CIFS_UNIX_INFO");
+
+ return cli;
+}
+
+static bool check_unix_info2(struct torture_context *torture,
+ struct unix_info2 *info2)
+{
+ printf("\tcreate_time=0x%016llu flags=0x%08x mask=0x%08x\n",
+ (unsigned long long)info2->create_time,
+ info2->file_flags, info2->flags_mask);
+
+ if (info2->file_flags == 0) {
+ return true;
+ }
+
+ /* If we have any file_flags set, they must be within the range
+ * defined by flags_mask.
+ */
+ if ((info2->flags_mask & info2->file_flags) == 0) {
+ torture_result(torture, TORTURE_FAIL,
+ __location__": UNIX_INFO2 flags field 0x%08x, "
+ "does not match mask 0x%08x\n",
+ info2->file_flags, info2->flags_mask);
+ }
+
+ return true;
+}
+
+static NTSTATUS set_path_info2(void *mem_ctx,
+ struct smbcli_state *cli,
+ const char *fname,
+ struct unix_info2 *info2)
+{
+ union smb_setfileinfo sfinfo;
+
+ ZERO_STRUCT(sfinfo.basic_info.in);
+ sfinfo.generic.level = RAW_SFILEINFO_UNIX_INFO2;
+ sfinfo.generic.in.file.path = fname;
+
+ sfinfo.unix_info2.in.end_of_file = info2->end_of_file;
+ sfinfo.unix_info2.in.num_bytes = info2->num_bytes;
+ sfinfo.unix_info2.in.status_change_time = info2->status_change_time;
+ sfinfo.unix_info2.in.access_time = info2->access_time;
+ sfinfo.unix_info2.in.change_time = info2->change_time;
+ sfinfo.unix_info2.in.uid = info2->uid;
+ sfinfo.unix_info2.in.gid = info2->gid;
+ sfinfo.unix_info2.in.file_type = info2->file_type;
+ sfinfo.unix_info2.in.dev_major = info2->dev_major;
+ sfinfo.unix_info2.in.dev_minor = info2->dev_minor;
+ sfinfo.unix_info2.in.unique_id = info2->unique_id;
+ sfinfo.unix_info2.in.permissions = info2->permissions;
+ sfinfo.unix_info2.in.nlink = info2->nlink;
+ sfinfo.unix_info2.in.create_time = info2->create_time;
+ sfinfo.unix_info2.in.file_flags = info2->file_flags;
+ sfinfo.unix_info2.in.flags_mask = info2->flags_mask;
+
+ return smb_raw_setpathinfo(cli->tree, &sfinfo);
+}
+
+static bool query_file_path_info2(void *mem_ctx,
+ struct torture_context *torture,
+ struct smbcli_state *cli,
+ int fnum,
+ const char *fname,
+ struct unix_info2 *info2)
+{
+ NTSTATUS result;
+ union smb_fileinfo finfo;
+
+ finfo.generic.level = RAW_FILEINFO_UNIX_INFO2;
+
+ if (fname) {
+ finfo.generic.in.file.path = fname;
+ result = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo);
+ } else {
+ finfo.generic.in.file.fnum = fnum;
+ result = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
+ }
+
+ torture_assert_ntstatus_equal(torture, result, NT_STATUS_OK,
+ smbcli_errstr(cli->tree));
+
+ info2->end_of_file = finfo.unix_info2.out.end_of_file;
+ info2->num_bytes = finfo.unix_info2.out.num_bytes;
+ info2->status_change_time = finfo.unix_info2.out.status_change_time;
+ info2->access_time = finfo.unix_info2.out.access_time;
+ info2->change_time = finfo.unix_info2.out.change_time;
+ info2->uid = finfo.unix_info2.out.uid;
+ info2->gid = finfo.unix_info2.out.gid;
+ info2->file_type = finfo.unix_info2.out.file_type;
+ info2->dev_major = finfo.unix_info2.out.dev_major;
+ info2->dev_minor = finfo.unix_info2.out.dev_minor;
+ info2->unique_id = finfo.unix_info2.out.unique_id;
+ info2->permissions = finfo.unix_info2.out.permissions;
+ info2->nlink = finfo.unix_info2.out.nlink;
+ info2->create_time = finfo.unix_info2.out.create_time;
+ info2->file_flags = finfo.unix_info2.out.file_flags;
+ info2->flags_mask = finfo.unix_info2.out.flags_mask;
+
+ if (!check_unix_info2(torture, info2)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool query_file_info2(void *mem_ctx,
+ struct torture_context *torture,
+ struct smbcli_state *cli,
+ int fnum,
+ struct unix_info2 *info2)
+{
+ return query_file_path_info2(mem_ctx, torture, cli,
+ fnum, NULL, info2);
+}
+
+static bool query_path_info2(void *mem_ctx,
+ struct torture_context *torture,
+ struct smbcli_state *cli,
+ const char *fname,
+ struct unix_info2 *info2)
+{
+ return query_file_path_info2(mem_ctx, torture, cli,
+ -1, fname, info2);
+}
+
+static bool search_callback(void *private_data, const union smb_search_data *fdata)
+{
+ struct unix_info2 *info2 = (struct unix_info2 *)private_data;
+
+ info2->end_of_file = fdata->unix_info2.end_of_file;
+ info2->num_bytes = fdata->unix_info2.num_bytes;
+ info2->status_change_time = fdata->unix_info2.status_change_time;
+ info2->access_time = fdata->unix_info2.access_time;
+ info2->change_time = fdata->unix_info2.change_time;
+ info2->uid = fdata->unix_info2.uid;
+ info2->gid = fdata->unix_info2.gid;
+ info2->file_type = fdata->unix_info2.file_type;
+ info2->dev_major = fdata->unix_info2.dev_major;
+ info2->dev_minor = fdata->unix_info2.dev_minor;
+ info2->unique_id = fdata->unix_info2.unique_id;
+ info2->permissions = fdata->unix_info2.permissions;
+ info2->nlink = fdata->unix_info2.nlink;
+ info2->create_time = fdata->unix_info2.create_time;
+ info2->file_flags = fdata->unix_info2.file_flags;
+ info2->flags_mask = fdata->unix_info2.flags_mask;
+
+ return true;
+}
+
+static bool find_single_info2(void *mem_ctx,
+ struct torture_context *torture,
+ struct smbcli_state *cli,
+ const char *fname,
+ struct unix_info2 *info2)
+{
+ union smb_search_first search;
+ NTSTATUS status;
+
+ /* Set up a new search for a single item, not using resume keys. */
+ ZERO_STRUCT(search);
+ search.t2ffirst.level = RAW_SEARCH_TRANS2;
+ search.t2ffirst.data_level = SMB_FIND_UNIX_INFO2;
+ search.t2ffirst.in.max_count = 1;
+ search.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
+ search.t2ffirst.in.pattern = fname;
+
+ status = smb_raw_search_first(cli->tree, mem_ctx,
+ &search, info2, search_callback);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ smbcli_errstr(cli->tree));
+
+ torture_assert_int_equal(torture, search.t2ffirst.out.count, 1,
+ "expected exactly one result");
+ /*
+ * In smbd directory listings using POSIX extensions
+ * always treat the search pathname as a wildcard,
+ * so don't expect end_of_search to be set here. Wildcard
+ * searches always need a findnext to end the search.
+ */
+ torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 0,
+ "expected end_of_search to be false");
+
+ return check_unix_info2(torture, info2);
+}
+
+#define ASSERT_FLAGS_MATCH(info2, expected) \
+ if ((info2)->file_flags != (1 << i)) { \
+ torture_result(torture, TORTURE_FAIL, \
+ __location__": INFO2 flags field was 0x%08x, "\
+ "expected 0x%08x\n",\
+ (info2)->file_flags, expected); \
+ }
+
+static void set_no_metadata_change(struct unix_info2 *info2)
+{
+ info2->uid = SMB_UID_NO_CHANGE;
+ info2->gid = SMB_GID_NO_CHANGE;
+ info2->permissions = SMB_MODE_NO_CHANGE;
+
+ info2->end_of_file =
+ ((uint64_t)SMB_SIZE_NO_CHANGE_HI << 32) | SMB_SIZE_NO_CHANGE_LO;
+
+ info2->status_change_time =
+ info2->access_time =
+ info2->change_time =
+ info2->create_time =
+ ((uint64_t)SMB_SIZE_NO_CHANGE_HI << 32) | SMB_SIZE_NO_CHANGE_LO;
+}
+
+static bool verify_setinfo_flags(void *mem_ctx,
+ struct torture_context *torture,
+ struct smbcli_state *cli,
+ const char *fname)
+{
+ struct unix_info2 info2;
+ uint32_t smb_fmask;
+ int i;
+
+ bool ret = true;
+ NTSTATUS status;
+
+ if (!query_path_info2(mem_ctx, torture, cli, fname, &info2)) {
+ return false;
+ }
+
+ smb_fmask = info2.flags_mask;
+
+ /* For each possible flag, ask to set exactly 1 flag, making sure
+ * that flag is in our requested mask.
+ */
+ for (i = 0; i < 32; ++i) {
+ info2.file_flags = ((uint32_t)1 << i);
+ info2.flags_mask = smb_fmask | info2.file_flags;
+
+ set_no_metadata_change(&info2);
+ status = set_path_info2(mem_ctx, cli, fname, &info2);
+
+ if (info2.file_flags & smb_fmask) {
+ torture_assert_ntstatus_equal(torture,
+ status, NT_STATUS_OK,
+ "setting valid UNIX_INFO2 flag");
+
+ if (!query_path_info2(mem_ctx, torture, cli,
+ fname, &info2)) {
+ return false;
+ }
+
+ ASSERT_FLAGS_MATCH(&info2, 1 << i);
+
+
+ } else {
+ /* We tried to set a flag the server doesn't
+ * understand.
+ */
+ torture_assert_ntstatus_equal(torture,
+ status, NT_STATUS_INVALID_PARAMETER,
+ "setting invalid UNIX_INFO2 flag");
+ }
+ }
+
+ /* Make sure that a zero flags field does nothing. */
+ set_no_metadata_change(&info2);
+ info2.file_flags = 0xFFFFFFFF;
+ info2.flags_mask = 0;
+ status = set_path_info2(mem_ctx, cli, fname, &info2);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "setting empty flags mask");
+
+ return ret;
+
+}
+
+static int create_file(struct smbcli_state *cli, const char * fname)
+{
+
+ return smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF,
+ 0, 0);
+}
+
+static bool match_info2(struct torture_context *torture,
+ const struct unix_info2 *pinfo,
+ const struct unix_info2 *finfo)
+{
+ printf("checking results match\n");
+
+ torture_assert_u64_equal(torture, finfo->end_of_file, 0,
+ "end_of_file should be 0");
+ torture_assert_u64_equal(torture, finfo->num_bytes, 0,
+ "num_bytes should be 0");
+
+ torture_assert_u64_equal(torture, finfo->end_of_file,
+ pinfo->end_of_file, "end_of_file mismatch");
+ torture_assert_u64_equal(torture, finfo->num_bytes, pinfo->num_bytes,
+ "num_bytes mismatch");
+
+ /* Don't match access_time. */
+
+ torture_assert_u64_equal(torture, finfo->status_change_time,
+ pinfo->status_change_time,
+ "status_change_time mismatch");
+ torture_assert_u64_equal(torture, finfo->change_time,
+ pinfo->change_time, "change_time mismatch");
+
+ torture_assert_u64_equal(torture, finfo->uid, pinfo->uid,
+ "UID mismatch");
+ torture_assert_u64_equal(torture, finfo->gid, pinfo->gid,
+ "GID mismatch");
+ torture_assert_int_equal(torture, finfo->file_type, pinfo->file_type,
+ "file_type mismatch");
+ torture_assert_u64_equal(torture, finfo->dev_major, pinfo->dev_major,
+ "dev_major mismatch");
+ torture_assert_u64_equal(torture, finfo->dev_minor, pinfo->dev_minor,
+ "dev_minor mismatch");
+ torture_assert_u64_equal(torture, finfo->unique_id, pinfo->unique_id,
+ "unique_id mismatch");
+ torture_assert_u64_equal(torture, finfo->permissions,
+ pinfo->permissions, "permissions mismatch");
+ torture_assert_u64_equal(torture, finfo->nlink, pinfo->nlink,
+ "nlink mismatch");
+ torture_assert_u64_equal(torture, finfo->create_time, pinfo->create_time,
+ "create_time mismatch");
+
+ return true;
+}
+
+
+#define FILENAME "\\smb_unix_info2.txt"
+
+bool unix_torture_unix_info2(struct torture_context *torture)
+{
+ void *mem_ctx;
+ struct smbcli_state *cli;
+ int fnum;
+
+ struct unix_info2 pinfo, finfo;
+
+ mem_ctx = talloc_init("smb_query_unix_info2");
+ torture_assert(torture, mem_ctx != NULL, "out of memory");
+
+ if (!(cli = connect_to_server(torture))) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ smbcli_unlink(cli->tree, FILENAME);
+
+ fnum = create_file(cli, FILENAME);
+ torture_assert(torture, fnum != -1, smbcli_errstr(cli->tree));
+
+ printf("checking SMB_QFILEINFO_UNIX_INFO2 for QueryFileInfo\n");
+ if (!query_file_info2(mem_ctx, torture, cli, fnum, &finfo)) {
+ goto fail;
+ }
+
+ printf("checking SMB_QFILEINFO_UNIX_INFO2 for QueryPathInfo\n");
+ if (!query_path_info2(mem_ctx, torture, cli, FILENAME, &pinfo)) {
+ goto fail;
+ }
+
+ if (!match_info2(torture, &pinfo, &finfo)) {
+ goto fail;
+ }
+
+ printf("checking SMB_FIND_UNIX_INFO2 for FindFirst\n");
+ if (!find_single_info2(mem_ctx, torture, cli, FILENAME, &pinfo)) {
+ goto fail;
+ }
+
+ if (!match_info2(torture, &pinfo, &finfo)) {
+ goto fail;
+ }
+
+ /* XXX: should repeat this test with SetFileInfo. */
+ printf("checking SMB_SFILEINFO_UNIX_INFO2 for SetPathInfo\n");
+ if (!verify_setinfo_flags(mem_ctx, torture, cli, FILENAME)) {
+ goto fail;
+ }
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, FILENAME);
+ torture_close_connection(cli);
+ talloc_free(mem_ctx);
+ return true;
+
+fail:
+
+ smbcli_close(cli->tree, fnum);
+ smbcli_unlink(cli->tree, FILENAME);
+ torture_close_connection(cli);
+ talloc_free(mem_ctx);
+ return false;
+
+}
+
+/* vim: set sts=8 sw=8 : */
diff --git a/source4/torture/unix/whoami.c b/source4/torture/unix/whoami.c
new file mode 100644
index 0000000..28b1f87
--- /dev/null
+++ b/source4/torture/unix/whoami.c
@@ -0,0 +1,433 @@
+/*
+ Test the SMB_WHOAMI Unix extension.
+
+ Copyright (C) 2007 James Peach
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/raw_proto.h"
+#include "torture/torture.h"
+#include "torture/unix/proto.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include <ldb.h>
+#include "lib/util/util_ldb.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "../libcli/security/security.h"
+
+#undef strcasecmp
+
+/* Size (in bytes) of the required fields in the SMBwhoami response. */
+#define WHOAMI_REQUIRED_SIZE 40
+
+/*
+ SMBWhoami - Query the user mapping performed by the server for the
+ connected tree. This is a subcommand of the TRANS2_QFSINFO.
+
+ Returns:
+ 4 bytes unsigned - mapping flags (smb_whoami_flags)
+ 4 bytes unsigned - flags mask
+
+ 8 bytes unsigned - primary UID
+ 8 bytes unsigned - primary GID
+ 4 bytes unsigned - number of supplementary GIDs
+ 4 bytes unsigned - number of SIDs
+ 4 bytes unsigned - SID list byte count
+ 4 bytes - pad / reserved (must be zero)
+
+ 8 bytes unsigned[] - list of GIDs (may be empty)
+ struct dom_sid[] - list of SIDs (may be empty)
+*/
+
+struct smb_whoami
+{
+ uint32_t mapping_flags;
+ uint32_t mapping_mask;
+ uint64_t server_uid;
+ uint64_t server_gid;
+ uint32_t num_gids;
+ uint32_t num_sids;
+ uint32_t num_sid_bytes;
+ uint32_t reserved; /* Must be zero */
+ uint64_t * gid_list;
+ struct dom_sid ** sid_list;
+};
+
+static struct smbcli_state *connect_to_server(struct torture_context *tctx,
+ struct cli_credentials *creds)
+{
+ NTSTATUS status;
+ struct smbcli_state *cli;
+
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = torture_setting_string(tctx, "share", NULL);
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ status = smbcli_full_connection(tctx, &cli, host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share, NULL, lpcfg_socket_options(tctx->lp_ctx),
+ creds, lpcfg_resolve_context(tctx->lp_ctx),
+ tctx->ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx,
+ "FATAL: Failed to connect to //%s/%s "
+ "with %s - %s\n",
+ host,
+ share,
+ cli_credentials_get_username(creds),
+ nt_errstr(status));
+ return NULL;
+ }
+
+ return cli;
+}
+
+static bool whoami_sid_parse(void *mem_ctx,
+ struct torture_context *torture,
+ DATA_BLOB *data, size_t *offset,
+ struct dom_sid **psid)
+{
+ size_t remain = data->length - *offset;
+ int i;
+
+ *psid = talloc_zero(mem_ctx, struct dom_sid);
+ torture_assert(torture, *psid != NULL, "out of memory");
+
+ torture_assert(torture, remain >= 8,
+ "invalid SID format");
+
+ (*psid)->sid_rev_num = CVAL(data->data, *offset);
+ (*psid)->num_auths = CVAL(data->data, *offset + 1);
+ memcpy((*psid)->id_auth, data->data + *offset + 2, 6);
+
+ (*offset) += 8;
+ remain = data->length - *offset;
+
+ torture_assert(torture, remain >= ((*psid)->num_auths * 4),
+ "invalid sub_auth byte count");
+ torture_assert(torture, (*psid)->num_auths >= 0,
+ "invalid sub_auth value");
+ torture_assert(torture, (*psid)->num_auths <= 15,
+ "invalid sub_auth value");
+
+ for (i = 0; i < (*psid)->num_auths; i++) {
+ (*psid)->sub_auths[i] = IVAL(data->data, *offset);
+ (*offset) += 4;
+ }
+
+ return true;
+}
+
+static bool smb_raw_query_posix_whoami(void *mem_ctx,
+ struct torture_context *torture,
+ struct smbcli_state *cli,
+ struct smb_whoami *whoami,
+ unsigned max_data)
+{
+ struct smb_trans2 tp;
+ NTSTATUS status;
+ size_t offset;
+ int i;
+
+ uint16_t setup = TRANSACT2_QFSINFO;
+ uint16_t info_level;
+
+ ZERO_STRUCTP(whoami);
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.max_param = 10;
+ tp.in.max_data = (uint16_t)max_data;
+ tp.in.setup = &setup;
+ tp.in.trans_name = NULL;
+ SSVAL(&info_level, 0, SMB_QFS_POSIX_WHOAMI);
+ tp.in.params = data_blob_talloc(mem_ctx, &info_level, 2);
+ tp.in.data = data_blob_talloc(mem_ctx, NULL, 0);
+
+ status = smb_raw_trans2(cli->tree, mem_ctx, &tp);
+ torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
+ "doing SMB_QFS_POSIX_WHOAMI");
+
+ /* Make sure we got back all the required fields. */
+ torture_assert(torture, tp.out.params.length == 0,
+ "trans2 params should be empty");
+ torture_assert(torture, tp.out.data.length >= WHOAMI_REQUIRED_SIZE,
+ "checking for required response fields");
+
+ whoami->mapping_flags = IVAL(tp.out.data.data, 0);
+ whoami->mapping_mask = IVAL(tp.out.data.data, 4);
+ whoami->server_uid = BVAL(tp.out.data.data, 8);
+ whoami->server_gid = BVAL(tp.out.data.data, 16);
+ whoami->num_gids = IVAL(tp.out.data.data, 24);
+ whoami->num_sids = IVAL(tp.out.data.data, 28);
+ whoami->num_sid_bytes = IVAL(tp.out.data.data, 32);
+ whoami->reserved = IVAL(tp.out.data.data, 36);
+
+ /* The GID list and SID list are optional, depending on the count
+ * and length fields.
+ */
+ if (whoami->num_sids != 0) {
+ torture_assert(torture, whoami->num_sid_bytes != 0,
+ "SID count does not match byte count");
+ }
+
+ printf("\tmapping_flags=0x%08x mapping_mask=0x%08x\n",
+ whoami->mapping_flags, whoami->mapping_mask);
+ printf("\tserver UID=%llu GID=%llu\n",
+ (unsigned long long)whoami->server_uid, (unsigned long long)whoami->server_gid);
+ printf("\t%u GIDs, %u SIDs, %u SID bytes\n",
+ whoami->num_gids, whoami->num_sids,
+ whoami->num_sid_bytes);
+
+ offset = WHOAMI_REQUIRED_SIZE;
+
+ torture_assert_int_equal(torture, whoami->reserved, 0,
+ "invalid reserved field");
+
+ if (tp.out.data.length == offset) {
+ /* No SIDs or GIDs returned */
+ torture_assert_int_equal(torture, whoami->num_gids, 0,
+ "invalid GID count");
+ torture_assert_int_equal(torture, whoami->num_sids, 0,
+ "invalid SID count");
+ torture_assert_int_equal(torture, whoami->num_sid_bytes, 0,
+ "invalid SID byte count");
+ return true;
+ }
+
+ if (whoami->num_gids != 0) {
+ int remain = tp.out.data.length - offset;
+ int gid_bytes = whoami->num_gids * 8;
+
+ if (whoami->num_sids == 0) {
+ torture_assert_int_equal(torture, remain, gid_bytes,
+ "GID count does not match data length");
+ } else {
+ torture_assert(torture, remain > gid_bytes,
+ "invalid GID count");
+ }
+
+ whoami->gid_list = talloc_array(mem_ctx, uint64_t, whoami->num_gids);
+ torture_assert(torture, whoami->gid_list != NULL, "out of memory");
+
+ torture_comment(torture, "\tGIDs:\n");
+
+ for (i = 0; i < whoami->num_gids; ++i) {
+ whoami->gid_list[i] = BVAL(tp.out.data.data, offset);
+ offset += 8;
+ torture_comment(torture, "\t\t%u\n", (unsigned int)whoami->gid_list[i]);
+ }
+ }
+
+ /* Check if there should be data left for the SID list. */
+ if (tp.out.data.length == offset) {
+ torture_assert_int_equal(torture, whoami->num_sids, 0,
+ "invalid SID count");
+ return true;
+ }
+
+ /* All the remaining bytes must be the SID list. */
+ torture_assert_int_equal(torture,
+ whoami->num_sid_bytes, (tp.out.data.length - offset),
+ "invalid SID byte count");
+
+ if (whoami->num_sids != 0) {
+
+ whoami->sid_list = talloc_array(mem_ctx, struct dom_sid *,
+ whoami->num_sids);
+ torture_assert(torture, whoami->sid_list != NULL,
+ "out of memory");
+
+ torture_comment(torture, "\tSIDs:\n");
+
+ for (i = 0; i < whoami->num_sids; ++i) {
+ if (!whoami_sid_parse(mem_ctx, torture,
+ &tp.out.data, &offset,
+ &whoami->sid_list[i])) {
+ return false;
+ }
+
+ torture_comment(torture, "\t\t%s\n",
+ dom_sid_string(torture, whoami->sid_list[i]));
+ }
+ }
+
+ /* We should be at the end of the response now. */
+ torture_assert_int_equal(torture, tp.out.data.length, offset,
+ "trailing garbage bytes");
+
+ return true;
+}
+
+static bool test_against_ldap(struct torture_context *torture, struct ldb_context *ldb, bool is_dc,
+ struct smb_whoami *whoami)
+{
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+
+ const char *attrs[] = { "tokenGroups", NULL };
+ int i;
+
+ torture_assert_int_equal(torture, dsdb_search_one(ldb, torture, &msg, NULL, LDB_SCOPE_BASE, attrs, 0, NULL), LDB_SUCCESS, "searching for tokenGroups");
+ el = ldb_msg_find_element(msg, "tokenGroups");
+ torture_assert(torture, el, "obtaining tokenGroups");
+ torture_assert(torture, el->num_values > 0, "Number of SIDs from LDAP needs to be more than 0");
+ torture_assert(torture, whoami->num_sids > 0, "Number of SIDs from LDAP needs to be more than 0");
+
+ if (is_dc) {
+ torture_assert_int_equal(torture, el->num_values, whoami->num_sids, "Number of SIDs from LDAP and number of SIDs from CIFS does not match!");
+
+ for (i = 0; i < el->num_values; i++) {
+ struct dom_sid *sid = talloc(torture, struct dom_sid);
+ ssize_t ret;
+ torture_assert(torture, sid != NULL, "talloc failed");
+
+ ret = sid_parse(el->values[i].data,
+ el->values[i].length, sid);
+ torture_assert(torture,
+ ret != -1,
+ "sid parse failed");
+ torture_assert_str_equal(torture, dom_sid_string(sid, sid), dom_sid_string(sid, whoami->sid_list[i]), "SID from LDAP and SID from CIFS does not match!");
+ talloc_free(sid);
+ }
+ } else {
+ unsigned int num_domain_sids_dc = 0, num_domain_sids_member = 0;
+ struct dom_sid *user_sid = talloc(torture, struct dom_sid);
+ struct dom_sid *dom_sid = talloc(torture, struct dom_sid);
+ struct dom_sid *dc_sids = talloc_array(torture, struct dom_sid, el->num_values);
+ struct dom_sid *member_sids = talloc_array(torture, struct dom_sid, whoami->num_sids);
+ ssize_t ret;
+ torture_assert(torture, user_sid != NULL, "talloc failed");
+ ret = sid_parse(el->values[0].data,
+ el->values[0].length,
+ user_sid);
+ torture_assert(torture,
+ ret != -1,
+ "sid parse failed");
+ torture_assert_ntstatus_equal(torture, dom_sid_split_rid(torture, user_sid, &dom_sid, NULL), NT_STATUS_OK, "failed to split domain SID from user SID");
+ for (i = 0; i < el->num_values; i++) {
+ struct dom_sid *sid = talloc(dc_sids, struct dom_sid);
+ torture_assert(torture, sid != NULL, "talloc failed");
+
+ ret = sid_parse(el->values[i].data,
+ el->values[i].length,
+ sid);
+ torture_assert(torture,
+ ret != -1,
+ "sid parse failed");
+ if (dom_sid_in_domain(dom_sid, sid)) {
+ dc_sids[num_domain_sids_dc] = *sid;
+ num_domain_sids_dc++;
+ }
+ talloc_free(sid);
+ }
+
+ for (i = 0; i < whoami->num_sids; i++) {
+ if (dom_sid_in_domain(dom_sid, whoami->sid_list[i])) {
+ member_sids[num_domain_sids_member] = *whoami->sid_list[i];
+ num_domain_sids_member++;
+ }
+ }
+
+ torture_assert_int_equal(torture, num_domain_sids_dc, num_domain_sids_member, "Number of Domain SIDs from LDAP DC and number of SIDs from CIFS member does not match!");
+ for (i = 0; i < num_domain_sids_dc; i++) {
+ torture_assert_str_equal(torture, dom_sid_string(dc_sids, &dc_sids[i]), dom_sid_string(member_sids, &member_sids[i]), "Domain SID from LDAP DC and SID from CIFS member server does not match!");
+ }
+ talloc_free(dc_sids);
+ talloc_free(member_sids);
+ }
+ return true;
+}
+
+bool torture_unix_whoami(struct torture_context *torture)
+{
+ struct smbcli_state *cli;
+ struct smb_whoami whoami;
+ bool ret = false;
+ struct ldb_context *ldb;
+ const char *addc, *host;
+
+ cli = connect_to_server(torture, samba_cmdline_get_creds());
+ torture_assert(torture, cli, "connecting to server with authenticated credentials");
+
+ /* Test basic authenticated mapping. */
+ torture_assert_goto(torture, smb_raw_query_posix_whoami(torture, torture,
+ cli, &whoami, 0xFFFF), ret, fail,
+ "calling SMB_QFS_POSIX_WHOAMI on an authenticated connection");
+
+ /* Check that our anonymous login mapped us to guest on the server, but
+ * only if the server supports this.
+ */
+ if (whoami.mapping_mask & SMB_WHOAMI_GUEST) {
+ bool guest = whoami.mapping_flags & SMB_WHOAMI_GUEST;
+ torture_comment(torture, "checking whether we were logged in as guest... %s\n",
+ guest ? "YES" : "NO");
+ torture_assert(torture,
+ cli_credentials_is_anonymous(
+ samba_cmdline_get_creds()) == guest,
+ "login did not credentials map to guest");
+ } else {
+ torture_comment(torture, "server does not support SMB_WHOAMI_GUEST flag\n");
+ }
+
+ addc = torture_setting_string(torture, "addc", NULL);
+ host = torture_setting_string(torture, "host", NULL);
+
+ if (addc) {
+ ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, talloc_asprintf(torture, "ldap://%s", addc),
+ NULL, samba_cmdline_get_creds(), 0);
+ torture_assert(torture, ldb, "ldb connect failed");
+
+ /* We skip this testing if we could not contact the LDAP server */
+ if (!test_against_ldap(torture, ldb, strcasecmp(addc, host) == 0, &whoami)) {
+ goto fail;
+ }
+ }
+
+ /* Test that the server drops the UID and GID list. */
+ torture_assert_goto(torture, smb_raw_query_posix_whoami(torture, torture,
+ cli, &whoami, 0x40), ret, fail,
+ "calling SMB_QFS_POSIX_WHOAMI with a small buffer\n");
+
+ torture_assert_int_equal(torture, whoami.num_gids, 0,
+ "invalid GID count");
+ torture_assert_int_equal(torture, whoami.num_sids, 0,
+ "invalid SID count");
+ torture_assert_int_equal(torture, whoami.num_sid_bytes, 0,
+ "invalid SID bytes count");
+
+ smbcli_tdis(cli);
+
+ return true;
+fail:
+
+ smbcli_tdis(cli);
+ return ret;
+}
+
+/* vim: set sts=8 sw=8 : */
diff --git a/source4/torture/util.h b/source4/torture/util.h
new file mode 100644
index 0000000..385ee15
--- /dev/null
+++ b/source4/torture/util.h
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TORTURE_UTIL_H_
+#define _TORTURE_UTIL_H_
+
+#include "lib/torture/torture.h"
+
+struct smbcli_state;
+struct smbcli_tree;
+struct cli_credentials;
+
+/**
+ * Useful target macros for handling server bugs in torture tests.
+ */
+#define TARGET_IS_WINXP(_tctx) (torture_setting_bool(_tctx, "winxp", false))
+#define TARGET_IS_W2K3(_tctx) (torture_setting_bool(_tctx, "w2k3", false))
+#define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false))
+#define TARGET_IS_W2K12(_tctx) (torture_setting_bool(_tctx, "w2k12", false))
+#define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false))
+#define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false))
+#define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false))
+
+/**
+ setup a directory ready for a test
+*/
+_PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname);
+NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum);
+
+/**
+ sometimes we need a fairly complex file to work with, so we can test
+ all possible attributes.
+*/
+_PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname);
+int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname);
+
+/**
+ check that a wire string matches the flags specified
+ not 100% accurate, but close enough for testing
+*/
+bool wire_bad_flags(struct smb_wire_string *str, int flags,
+ struct smbcli_transport *transport);
+void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo);
+void torture_all_info(struct smbcli_tree *tree, const char *fname);
+bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib);
+NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum);
+NTSTATUS torture_check_ea(struct smbcli_state *cli,
+ const char *fname, const char *eaname, const char *value);
+_PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
+ struct smbcli_state **c,
+ struct torture_context *tctx,
+ const char *hostname,
+ const char *sharename,
+ struct tevent_context *ev);
+_PUBLIC_ bool torture_get_conn_index(int conn_index,
+ TALLOC_CTX *mem_ctx,
+ struct torture_context *tctx,
+ char **host, char **share);
+_PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
+ int conn_index,
+ struct torture_context *tctx,
+ struct tevent_context *ev);
+_PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index);
+_PUBLIC_ bool torture_close_connection(struct smbcli_state *c);
+_PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
+ uint8_t eclass, uint32_t ecode, NTSTATUS nterr);
+double torture_create_procs(struct torture_context *tctx,
+ bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result);
+_PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *,
+ struct smbcli_state *,
+ int i));
+_PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *,
+ struct smbcli_state *,
+ struct smbcli_state *));
+_PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *, struct smbcli_state *));
+NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
+ struct smbcli_session *session,
+ const char *sharename,
+ struct smbcli_tree **res);
+
+
+NTSTATUS torture_check_privilege(struct smbcli_state *cli,
+ const char *sid_str,
+ const char *privilege);
+
+/*
+ * Use this to pass a 2nd user:
+ *
+ * --option='torture:user2name=user2'
+ * --option='torture:user2domain=domain2'
+ * --option='torture:user2password=password2'
+ */
+struct cli_credentials *torture_user2_credentials(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx);
+
+#endif /* _TORTURE_UTIL_H_ */
diff --git a/source4/torture/util_smb.c b/source4/torture/util_smb.c
new file mode 100644
index 0000000..6924164
--- /dev/null
+++ b/source4/torture/util_smb.c
@@ -0,0 +1,1020 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester utility functions
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2006
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "../libcli/smb/smb_constants.h"
+#include "libcli/libcli.h"
+#include "system/filesys.h"
+#include "system/shmem.h"
+#include "system/wait.h"
+#include "system/time.h"
+#include "torture/torture.h"
+#include "../lib/util/dlinklist.h"
+#include "libcli/resolve/resolve.h"
+#include "param/param.h"
+#include "libcli/security/security.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/util/clilsa.h"
+#include "torture/util.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+
+/**
+ setup a directory ready for a test
+*/
+_PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
+{
+ smb_raw_exit(cli->session);
+ if (smbcli_deltree(cli->tree, dname) == -1 ||
+ NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
+ printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
+ return false;
+ }
+ return true;
+}
+
+/*
+ create a directory, returning a handle to it
+*/
+NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
+{
+ NTSTATUS status;
+ union smb_open io;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
+
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid.fnum = 0;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+ io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = dname;
+
+ status = smb_raw_open(tree, mem_ctx, &io);
+ talloc_free(mem_ctx);
+
+ if (NT_STATUS_IS_OK(status)) {
+ *fnum = io.ntcreatex.out.file.fnum;
+ }
+
+ return status;
+}
+
+
+/**
+ sometimes we need a fairly complex file to work with, so we can test
+ all possible attributes.
+*/
+_PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
+{
+ int fnum;
+ char buf[7] = "abc";
+ union smb_setfileinfo setfile;
+ union smb_fileinfo fileinfo;
+ time_t t = (time(NULL) & ~1);
+ NTSTATUS status;
+
+ smbcli_unlink(cli->tree, fname);
+ fnum = smbcli_nt_create_full(cli->tree, fname, 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL,
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OVERWRITE_IF,
+ 0, 0);
+ if (fnum == -1) return -1;
+
+ smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+
+ if (strchr(fname, ':') == NULL) {
+ /* setup some EAs */
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.fnum = fnum;
+ setfile.ea_set.in.num_eas = 2;
+ setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "EAONE";
+ setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
+ setfile.ea_set.in.eas[1].flags = 0;
+ setfile.ea_set.in.eas[1].name.s = "SECONDEA";
+ setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to setup EAs\n");
+ }
+ }
+
+ /* make sure all the timestamps aren't the same */
+ ZERO_STRUCT(setfile);
+ setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ setfile.generic.in.file.fnum = fnum;
+
+ unix_to_nt_time(&setfile.basic_info.in.create_time,
+ t + 9*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.access_time,
+ t + 6*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.write_time,
+ t + 3*30*24*60*60);
+
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to setup file times - %s\n", nt_errstr(status));
+ }
+
+ /* make sure all the timestamps aren't the same */
+ fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
+ fileinfo.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to query file times - %s\n", nt_errstr(status));
+ }
+
+ if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
+ printf("create_time not setup correctly\n");
+ }
+ if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
+ printf("access_time not setup correctly\n");
+ }
+ if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
+ printf("write_time not setup correctly\n");
+ }
+
+ return fnum;
+}
+
+
+/*
+ sometimes we need a fairly complex directory to work with, so we can test
+ all possible attributes.
+*/
+int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
+{
+ int fnum;
+ union smb_setfileinfo setfile;
+ union smb_fileinfo fileinfo;
+ time_t t = (time(NULL) & ~1);
+ NTSTATUS status;
+
+ smbcli_deltree(cli->tree, dname);
+ fnum = smbcli_nt_create_full(cli->tree, dname, 0,
+ SEC_RIGHTS_DIR_ALL,
+ FILE_ATTRIBUTE_DIRECTORY,
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ NTCREATEX_DISP_OPEN_IF,
+ NTCREATEX_OPTIONS_DIRECTORY, 0);
+ if (fnum == -1) return -1;
+
+ if (strchr(dname, ':') == NULL) {
+ /* setup some EAs */
+ setfile.generic.level = RAW_SFILEINFO_EA_SET;
+ setfile.generic.in.file.fnum = fnum;
+ setfile.ea_set.in.num_eas = 2;
+ setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
+ setfile.ea_set.in.eas[0].flags = 0;
+ setfile.ea_set.in.eas[0].name.s = "EAONE";
+ setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
+ setfile.ea_set.in.eas[1].flags = 0;
+ setfile.ea_set.in.eas[1].name.s = "SECONDEA";
+ setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to setup EAs\n");
+ }
+ }
+
+ /* make sure all the timestamps aren't the same */
+ ZERO_STRUCT(setfile);
+ setfile.generic.level = RAW_SFILEINFO_BASIC_INFO;
+ setfile.generic.in.file.fnum = fnum;
+
+ unix_to_nt_time(&setfile.basic_info.in.create_time,
+ t + 9*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.access_time,
+ t + 6*30*24*60*60);
+ unix_to_nt_time(&setfile.basic_info.in.write_time,
+ t + 3*30*24*60*60);
+
+ status = smb_raw_setfileinfo(cli->tree, &setfile);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to setup file times - %s\n", nt_errstr(status));
+ }
+
+ /* make sure all the timestamps aren't the same */
+ fileinfo.generic.level = RAW_FILEINFO_BASIC_INFO;
+ fileinfo.generic.in.file.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to query file times - %s\n", nt_errstr(status));
+ }
+
+ if (setfile.basic_info.in.create_time != fileinfo.basic_info.out.create_time) {
+ printf("create_time not setup correctly\n");
+ }
+ if (setfile.basic_info.in.access_time != fileinfo.basic_info.out.access_time) {
+ printf("access_time not setup correctly\n");
+ }
+ if (setfile.basic_info.in.write_time != fileinfo.basic_info.out.write_time) {
+ printf("write_time not setup correctly\n");
+ }
+
+ return fnum;
+}
+
+/**
+ check that a wire string matches the flags specified
+ not 100% accurate, but close enough for testing
+*/
+bool wire_bad_flags(struct smb_wire_string *str, int flags,
+ struct smbcli_transport *transport)
+{
+ bool server_unicode;
+ int len;
+ if (!str || !str->s) return true;
+ len = strlen(str->s);
+ if (flags & STR_TERMINATE) len++;
+
+ server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
+ if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
+ server_unicode = false;
+ }
+
+ if ((flags & STR_UNICODE) || server_unicode) {
+ len *= 2;
+ } else if (flags & STR_TERMINATE_ASCII) {
+ len++;
+ }
+ if (str->private_length != len) {
+ printf("Expected wire_length %d but got %d for '%s'\n",
+ len, str->private_length, str->s);
+ return true;
+ }
+ return false;
+}
+
+/*
+ dump a all_info QFILEINFO structure
+*/
+void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
+{
+ d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
+ d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
+ d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
+ d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
+ d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
+ d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
+ d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
+ d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
+ d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
+ d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
+ d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
+ d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
+}
+
+/*
+ dump file info by name
+*/
+void torture_all_info(struct smbcli_tree *tree, const char *fname)
+{
+ TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+
+ finfo.generic.level = RAW_FILEINFO_ALL_INFO;
+ finfo.generic.in.file.path = fname;
+ status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("%s - %s\n", fname, nt_errstr(status));
+ return;
+ }
+
+ d_printf("%s:\n", fname);
+ dump_all_info(mem_ctx, &finfo);
+ talloc_free(mem_ctx);
+}
+
+
+/*
+ set a attribute on a file
+*/
+bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
+{
+ union smb_setfileinfo sfinfo;
+ NTSTATUS status;
+
+ ZERO_STRUCT(sfinfo.basic_info.in);
+ sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ sfinfo.basic_info.in.file.path = fname;
+ sfinfo.basic_info.in.attrib = attrib;
+ status = smb_raw_setpathinfo(tree, &sfinfo);
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/*
+ set a file descriptor as sparse
+*/
+NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
+{
+ union smb_ioctl nt;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
+ nt.ntioctl.in.function = FSCTL_SET_SPARSE;
+ nt.ntioctl.in.file.fnum = fnum;
+ nt.ntioctl.in.fsctl = true;
+ nt.ntioctl.in.filter = 0;
+ nt.ntioctl.in.max_data = 0;
+ nt.ntioctl.in.blob = data_blob(NULL, 0);
+
+ status = smb_raw_ioctl(tree, mem_ctx, &nt);
+
+ talloc_free(mem_ctx);
+
+ return status;
+}
+
+/*
+ check that an EA has the right value
+*/
+NTSTATUS torture_check_ea(struct smbcli_state *cli,
+ const char *fname, const char *eaname, const char *value)
+{
+ union smb_fileinfo info;
+ NTSTATUS status;
+ struct ea_name ea;
+ TALLOC_CTX *mem_ctx = talloc_new(cli);
+
+ info.ea_list.level = RAW_FILEINFO_EA_LIST;
+ info.ea_list.in.file.path = fname;
+ info.ea_list.in.num_names = 1;
+ info.ea_list.in.ea_names = &ea;
+
+ ea.name.s = eaname;
+
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ if (info.ea_list.out.num_eas != 1) {
+ printf("Expected 1 ea in ea_list\n");
+ talloc_free(mem_ctx);
+ return NT_STATUS_EA_CORRUPT_ERROR;
+ }
+
+ if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
+ printf("Expected ea '%s' not '%s' in ea_list\n",
+ eaname, info.ea_list.out.eas[0].name.s);
+ talloc_free(mem_ctx);
+ return NT_STATUS_EA_CORRUPT_ERROR;
+ }
+
+ if (value == NULL) {
+ if (info.ea_list.out.eas[0].value.length != 0) {
+ printf("Expected zero length ea for %s\n", eaname);
+ talloc_free(mem_ctx);
+ return NT_STATUS_EA_CORRUPT_ERROR;
+ }
+ talloc_free(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ if (strlen(value) == info.ea_list.out.eas[0].value.length &&
+ memcmp(value, info.ea_list.out.eas[0].value.data,
+ info.ea_list.out.eas[0].value.length) == 0) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ printf("Expected value '%s' not '%*.*s' for ea %s\n",
+ value,
+ (int)info.ea_list.out.eas[0].value.length,
+ (int)info.ea_list.out.eas[0].value.length,
+ info.ea_list.out.eas[0].value.data,
+ eaname);
+
+ talloc_free(mem_ctx);
+
+ return NT_STATUS_EA_CORRUPT_ERROR;
+}
+
+_PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
+ struct smbcli_state **c,
+ struct torture_context *tctx,
+ const char *hostname,
+ const char *sharename,
+ struct tevent_context *ev)
+{
+ NTSTATUS status;
+
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+
+ lpcfg_smbcli_options(tctx->lp_ctx, &options);
+ lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
+
+ options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
+ options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
+
+ status = smbcli_full_connection(mem_ctx, c, hostname,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ sharename, NULL,
+ lpcfg_socket_options(tctx->lp_ctx),
+ samba_cmdline_get_creds(),
+ lpcfg_resolve_context(tctx->lp_ctx),
+ ev, &options, &session_options,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to open connection - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+_PUBLIC_ bool torture_get_conn_index(int conn_index,
+ TALLOC_CTX *mem_ctx,
+ struct torture_context *tctx,
+ char **host, char **share)
+{
+ char **unc_list = NULL;
+ int num_unc_names = 0;
+ const char *p;
+
+ (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
+ (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
+
+ p = torture_setting_string(tctx, "unclist", NULL);
+ if (!p) {
+ return true;
+ }
+
+ unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
+ if (!unc_list || num_unc_names <= 0) {
+ DEBUG(0,("Failed to load unc names list from '%s'\n", p));
+ return false;
+ }
+
+ p = unc_list[conn_index % num_unc_names];
+ if (p[0] != '/' && p[0] != '\\') {
+ /* allow UNC lists of hosts */
+ (*host) = talloc_strdup(mem_ctx, p);
+ } else if (!smbcli_parse_unc(p, mem_ctx, host, share)) {
+ DEBUG(0, ("Failed to parse UNC name %s\n",
+ unc_list[conn_index % num_unc_names]));
+ return false;
+ }
+
+ talloc_free(unc_list);
+ return true;
+}
+
+
+
+_PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
+ int conn_index,
+ struct torture_context *tctx,
+ struct tevent_context *ev)
+{
+ char *host, *share;
+ bool ret;
+
+ if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
+ return false;
+ }
+
+ ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
+ talloc_free(host);
+ talloc_free(share);
+
+ return ret;
+}
+
+_PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
+{
+ return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
+}
+
+
+
+_PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
+{
+ bool ret = true;
+ if (!c) return true;
+ if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
+ printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
+ ret = false;
+ }
+ talloc_free(c);
+ return ret;
+}
+
+
+/* check if the server produced the expected error code */
+_PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
+ uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
+{
+ NTSTATUS status;
+
+ status = smbcli_nt_error(c->tree);
+ if (NT_STATUS_IS_DOS(status)) {
+ int classnum, num;
+ classnum = NT_STATUS_DOS_CLASS(status);
+ num = NT_STATUS_DOS_CODE(status);
+ if (eclass != classnum || ecode != num) {
+ printf("unexpected error code %s\n", nt_errstr(status));
+ printf(" expected %s or %s (at %s)\n",
+ nt_errstr(NT_STATUS_DOS(eclass, ecode)),
+ nt_errstr(nterr), location);
+ return false;
+ }
+ } else {
+ if (!NT_STATUS_EQUAL(nterr, status)) {
+ printf("unexpected error code %s\n", nt_errstr(status));
+ printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static struct smbcli_state *current_cli;
+static int procnum; /* records process count number when forking */
+
+static void sigcont(int sig)
+{
+}
+
+struct child_status {
+ pid_t pid;
+ bool start;
+ enum torture_result result;
+ char reason[1024];
+};
+
+double torture_create_procs(struct torture_context *tctx,
+ bool (*fn)(struct torture_context *, struct smbcli_state *, int),
+ bool *result)
+{
+ int status;
+ size_t i;
+ struct child_status *child_status;
+ size_t synccount;
+ size_t tries = 8;
+ size_t torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
+ double start_time_limit = 10 + (torture_nprocs * 1.5);
+ struct timeval tv;
+
+ *result = true;
+
+ synccount = 0;
+
+ signal(SIGCONT, sigcont);
+
+ child_status = (struct child_status *)anonymous_shared_allocate(
+ sizeof(struct child_status)*torture_nprocs);
+ if (child_status == NULL) {
+ printf("Failed to setup shared memory\n");
+ return -1;
+ }
+
+ for (i = 0; i < torture_nprocs; i++) {
+ ZERO_STRUCT(child_status[i]);
+ }
+
+ tv = timeval_current();
+
+ for (i=0;i<torture_nprocs;i++) {
+ procnum = i;
+ if (fork() == 0) {
+ char *myname;
+ bool ok;
+
+ pid_t mypid = getpid();
+ srandom(((int)mypid) ^ ((int)time(NULL)));
+
+ if (asprintf(&myname, "CLIENT%zu", i) == -1) {
+ printf("asprintf failed\n");
+ return -1;
+ }
+ lpcfg_set_cmdline(tctx->lp_ctx, "netbios name", myname);
+ free(myname);
+
+
+ while (1) {
+ if (torture_open_connection(&current_cli, tctx, i)) {
+ break;
+ }
+ if (tries-- == 0) {
+ printf("pid %d failed to start\n", (int)getpid());
+ _exit(1);
+ }
+ smb_msleep(100);
+ }
+
+ child_status[i].pid = getpid();
+
+ pause();
+
+ if (!child_status[i].start) {
+ child_status[i].result = TORTURE_ERROR;
+ printf("Child %zu failed to start!\n", i);
+ _exit(1);
+ }
+
+ ok = fn(tctx, current_cli, i);
+ if (!ok) {
+ if (tctx->last_result == TORTURE_OK) {
+ torture_result(tctx, TORTURE_ERROR,
+ "unknown error: missing "
+ "torture_result call?\n");
+ }
+
+ child_status[i].result = tctx->last_result;
+
+ if (strlen(tctx->last_reason) > 1023) {
+ /* note: reason already contains \n */
+ torture_comment(tctx,
+ "child %zu (pid %u) failed: %s",
+ i,
+ (unsigned)child_status[i].pid,
+ tctx->last_reason);
+ }
+
+ snprintf(child_status[i].reason,
+ 1024, "child %zu (pid %u) failed: %s",
+ i, (unsigned)child_status[i].pid,
+ tctx->last_reason);
+ /* ensure proper "\n\0" termination: */
+ if (child_status[i].reason[1022] != '\0') {
+ child_status[i].reason[1022] = '\n';
+ child_status[i].reason[1023] = '\0';
+ }
+ }
+ _exit(0);
+ }
+ }
+
+ do {
+ synccount = 0;
+ for (i=0;i<torture_nprocs;i++) {
+ if (child_status[i].pid != 0) {
+ synccount++;
+ }
+ }
+ if (synccount == torture_nprocs) {
+ break;
+ }
+ smb_msleep(100);
+ } while (timeval_elapsed(&tv) < start_time_limit);
+
+ if (synccount != torture_nprocs) {
+ printf("FAILED TO START %zu CLIENTS (started %zu)\n", torture_nprocs, synccount);
+
+ /* cleanup child processes */
+ for (i = 0; i < torture_nprocs; i++) {
+ if (child_status[i].pid != 0) {
+ kill(child_status[i].pid, SIGTERM);
+ }
+ }
+
+ *result = false;
+ return timeval_elapsed(&tv);
+ }
+
+ printf("Starting %zu clients\n", torture_nprocs);
+
+ /* start the client load */
+ tv = timeval_current();
+ for (i=0;i<torture_nprocs;i++) {
+ child_status[i].start = true;
+ }
+
+ printf("%zu clients started\n", torture_nprocs);
+
+ kill(0, SIGCONT);
+
+ for (i=0;i<torture_nprocs;i++) {
+ int ret;
+ while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
+ if (ret == -1 || WEXITSTATUS(status) != 0) {
+ *result = false;
+ }
+ }
+
+ printf("\n");
+
+ for (i=0;i<torture_nprocs;i++) {
+ if (child_status[i].result != TORTURE_OK) {
+ *result = false;
+ torture_result(tctx, child_status[i].result,
+ "%s", child_status[i].reason);
+ }
+ }
+
+ return timeval_elapsed(&tv);
+}
+
+static bool wrap_smb_multi_test(struct torture_context *torture,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
+ bool result;
+
+ torture_create_procs(torture, fn, &result);
+
+ return result;
+}
+
+_PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *,
+ struct smbcli_state *,
+ int i))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_smb_multi_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+
+}
+
+static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct smbcli_state *,
+ struct smbcli_state *);
+ bool ret = true;
+
+ struct smbcli_state *cli1 = NULL, *cli2 = NULL;
+
+ torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
+ torture_assert_goto(torture_ctx, torture_open_connection(&cli2, torture_ctx, 1), ret, fail, "Failed to open connection");
+
+ fn = test->fn;
+
+ ret = fn(torture_ctx, cli1, cli2);
+fail:
+ talloc_free(cli1);
+ talloc_free(cli2);
+
+ return ret;
+}
+
+
+
+_PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *,
+ struct smbcli_state *,
+ struct smbcli_state *))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_simple_2smb_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+
+}
+
+static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct smbcli_state *);
+ bool ret = true;
+
+ struct smbcli_state *cli1 = NULL;
+
+ torture_assert_goto(torture_ctx, torture_open_connection(&cli1, torture_ctx, 0), ret, fail, "Failed to open connection");
+
+ fn = test->fn;
+
+ ret = fn(torture_ctx, cli1);
+fail:
+ talloc_free(cli1);
+
+ return ret;
+}
+
+_PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
+ struct torture_suite *suite,
+ const char *name,
+ bool (*run) (struct torture_context *, struct smbcli_state *))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_simple_1smb_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+
+NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
+ struct smbcli_session *session,
+ const char *sharename,
+ struct smbcli_tree **res)
+{
+ union smb_tcon tcon;
+ struct smbcli_tree *result;
+ TALLOC_CTX *tmp_ctx;
+ NTSTATUS status;
+
+ if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ result = smbcli_tree_init(session, tmp_ctx, false);
+ if (result == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
+ tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
+
+ /* Ignore share mode security here */
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = sharename;
+ tcon.tconx.in.device = "?????";
+
+ status = smb_raw_tcon(result, tmp_ctx, &tcon);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ result->tid = tcon.tconx.out.tid;
+
+ if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
+ smb1cli_session_protect_session_key(result->session->smbXcli);
+ }
+
+ *res = talloc_steal(mem_ctx, result);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+/*
+ a wrapper around smblsa_sid_check_privilege, that tries to take
+ account of the fact that the lsa privileges calls don't expand
+ group memberships, using an explicit check for administrator. There
+ must be a better way ...
+ */
+NTSTATUS torture_check_privilege(struct smbcli_state *cli,
+ const char *sid_str,
+ const char *privilege)
+{
+ struct dom_sid *sid;
+ TALLOC_CTX *tmp_ctx = talloc_new(cli);
+ uint32_t rid;
+ NTSTATUS status;
+
+ sid = dom_sid_parse_talloc(tmp_ctx, sid_str);
+ if (sid == NULL) {
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INVALID_SID;
+ }
+
+ status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(tmp_ctx);
+ return status;
+ }
+
+ if (rid == DOMAIN_RID_ADMINISTRATOR) {
+ /* assume the administrator has them all */
+ return NT_STATUS_OK;
+ }
+
+ talloc_free(tmp_ctx);
+
+ return smblsa_sid_check_privilege(cli, sid_str, privilege);
+}
+
+/*
+ * Use this to pass a 2nd user:
+ *
+ * --option='torture:user2name=user2'
+ * --option='torture:user2domain=domain2'
+ * --option='torture:user2password=password2'
+ */
+struct cli_credentials *torture_user2_credentials(struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx)
+{
+ struct cli_credentials *credentials1 = samba_cmdline_get_creds();
+ const char *user1domain = cli_credentials_get_domain(credentials1);
+ const char *user2name = torture_setting_string(tctx, "user2name", NULL);
+ const char *user2domain = torture_setting_string(tctx, "user2domain", user1domain);
+ const char *user2password = torture_setting_string(tctx, "user2password", NULL);
+ struct cli_credentials *credentials2 = NULL;
+
+ credentials2 = cli_credentials_shallow_copy(mem_ctx, credentials1);
+ if (credentials2 == NULL) {
+ torture_comment(tctx,
+ "%s: cli_credentials_shallow_copy() failed\n",
+ __func__);
+ return NULL;
+ }
+ if (user2name != NULL) {
+ torture_comment(tctx,
+ "Using "
+ "'torture:user2name'='%s' "
+ "'torture:user2domain'='%s' "
+ "'torture:user2password'='REDACTED'",
+ user2name,
+ user2domain);
+ cli_credentials_set_username(credentials2, user2name, CRED_SPECIFIED);
+ cli_credentials_set_domain(credentials2, user2domain, CRED_SPECIFIED);
+ cli_credentials_set_password(credentials2, user2password, CRED_SPECIFIED);
+ } else {
+ torture_comment(tctx,
+ "Fallback to anonymous for "
+ "'torture:user2name'=NULL "
+ "'torture:user2domain'='%s' "
+ "'torture:user2password'='REDACTED'",
+ user2domain);
+ cli_credentials_set_anonymous(credentials2);
+ }
+
+ return credentials2;
+}
diff --git a/source4/torture/vfs/acl_xattr.c b/source4/torture/vfs/acl_xattr.c
new file mode 100644
index 0000000..1deb2b3
--- /dev/null
+++ b/source4/torture/vfs/acl_xattr.c
@@ -0,0 +1,281 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ralph Boehme 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "torture/torture.h"
+#include "torture/vfs/proto.h"
+#include "libcli/resolve/resolve.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/param/param.h"
+
+#define BASEDIR "smb2-testsd"
+
+#define CHECK_SECURITY_DESCRIPTOR(_sd1, _sd2) do { \
+ if (!security_descriptor_equal(_sd1, _sd2)) { \
+ torture_warning(tctx, "security descriptors don't match!\n"); \
+ torture_warning(tctx, "got:\n"); \
+ NDR_PRINT_DEBUG(security_descriptor, _sd1); \
+ torture_warning(tctx, "expected:\n"); \
+ NDR_PRINT_DEBUG(security_descriptor, _sd2); \
+ torture_result(tctx, TORTURE_FAIL, \
+ "%s: security descriptors don't match!\n", \
+ __location__); \
+ ret = false; \
+ } \
+} while (0)
+
+static bool test_default_acl_posix(struct torture_context *tctx,
+ struct smb2_tree *tree_unused)
+{
+ struct smb2_tree *tree = NULL;
+ NTSTATUS status;
+ bool ok;
+ bool ret = true;
+ const char *dname = BASEDIR "\\testdir";
+ const char *fname = BASEDIR "\\testdir\\testfile";
+ struct smb2_handle fhandle = {{0}};
+ struct smb2_handle dhandle = {{0}};
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd = NULL;
+ struct security_descriptor *exp_sd = NULL;
+ char *owner_sid = NULL;
+ char *group_sid = NULL;
+
+ ok = torture_smb2_con_share(tctx, "acl_xattr_ign_sysacl_posix", &tree);
+ torture_assert_goto(tctx, ok == true, ret, done,
+ "Unable to connect to 'acl_xattr_ign_sysacl_posix'\n");
+
+ ok = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n");
+
+ ZERO_STRUCT(dhandle);
+ status = torture_smb2_testdir(tree, dname, &dhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n");
+
+ torture_comment(tctx, "Get the original sd\n");
+
+ ZERO_STRUCT(q);
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = dhandle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n");
+
+ sd = q.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd->owner_sid);
+ group_sid = dom_sid_string(tctx, sd->group_sid);
+ torture_comment(tctx, "owner [%s] group [%s]\n", owner_sid, group_sid);
+
+ torture_comment(tctx, "Set ACL with no inheritable ACE\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_DIR_ALL,
+ 0,
+ NULL);
+
+ ZERO_STRUCT(set);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = dhandle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file\n");
+
+ TALLOC_FREE(sd);
+ smb2_util_close(tree, dhandle);
+
+ torture_comment(tctx, "Create file\n");
+
+ ZERO_STRUCT(fhandle);
+ status = torture_smb2_testfile(tree, fname, &fhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_complex_file\n");
+
+ torture_comment(tctx, "Query file SD\n");
+
+ ZERO_STRUCT(q);
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = fhandle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n");
+ sd = q.query_secdesc.out.sd;
+
+ smb2_util_close(tree, fhandle);
+ ZERO_STRUCT(fhandle);
+
+ torture_comment(tctx, "Checking actual file SD against expected SD\n");
+
+ exp_sd = security_descriptor_dacl_create(
+ tctx, 0, owner_sid, group_sid,
+ owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0,
+ group_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_READ|FILE_GENERIC_WRITE|FILE_GENERIC_EXECUTE, 0,
+ SID_WORLD, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_READ|FILE_GENERIC_WRITE|FILE_GENERIC_EXECUTE, 0,
+ SID_NT_SYSTEM, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0,
+ NULL);
+
+ CHECK_SECURITY_DESCRIPTOR(sd, exp_sd);
+
+done:
+ if (!smb2_util_handle_empty(fhandle)) {
+ smb2_util_close(tree, fhandle);
+ }
+ if (!smb2_util_handle_empty(dhandle)) {
+ smb2_util_close(tree, dhandle);
+ }
+ if (tree != NULL) {
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ }
+
+ return ret;
+}
+
+static bool test_default_acl_win(struct torture_context *tctx,
+ struct smb2_tree *tree_unused)
+{
+ struct smb2_tree *tree = NULL;
+ NTSTATUS status;
+ bool ok;
+ bool ret = true;
+ const char *dname = BASEDIR "\\testdir";
+ const char *fname = BASEDIR "\\testdir\\testfile";
+ struct smb2_handle fhandle = {{0}};
+ struct smb2_handle dhandle = {{0}};
+ union smb_fileinfo q;
+ union smb_setfileinfo set;
+ struct security_descriptor *sd = NULL;
+ struct security_descriptor *exp_sd = NULL;
+ char *owner_sid = NULL;
+ char *group_sid = NULL;
+
+ ok = torture_smb2_con_share(tctx, "acl_xattr_ign_sysacl_windows", &tree);
+ torture_assert_goto(tctx, ok == true, ret, done,
+ "Unable to connect to 'acl_xattr_ign_sysacl_windows'\n");
+
+ ok = smb2_util_setup_dir(tctx, tree, BASEDIR);
+ torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n");
+
+ ZERO_STRUCT(dhandle);
+ status = torture_smb2_testdir(tree, dname, &dhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n");
+
+ torture_comment(tctx, "Get the original sd\n");
+
+ ZERO_STRUCT(q);
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = dhandle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n");
+
+ sd = q.query_secdesc.out.sd;
+ owner_sid = dom_sid_string(tctx, sd->owner_sid);
+ group_sid = dom_sid_string(tctx, sd->group_sid);
+ torture_comment(tctx, "owner [%s] group [%s]\n", owner_sid, group_sid);
+
+ torture_comment(tctx, "Set ACL with no inheritable ACE\n");
+
+ sd = security_descriptor_dacl_create(tctx,
+ 0, NULL, NULL,
+ owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_DIR_ALL,
+ 0,
+ NULL);
+
+ ZERO_STRUCT(set);
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = dhandle;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = sd;
+ status = smb2_setinfo_file(tree, &set);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file\n");
+
+ TALLOC_FREE(sd);
+ smb2_util_close(tree, dhandle);
+
+ torture_comment(tctx, "Create file\n");
+
+ ZERO_STRUCT(fhandle);
+ status = torture_smb2_testfile(tree, fname, &fhandle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_complex_file\n");
+
+ torture_comment(tctx, "Query file SD\n");
+
+ ZERO_STRUCT(q);
+ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
+ q.query_secdesc.in.file.handle = fhandle;
+ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP;
+ status = smb2_getinfo_file(tree, tctx, &q);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n");
+ sd = q.query_secdesc.out.sd;
+
+ smb2_util_close(tree, fhandle);
+ ZERO_STRUCT(fhandle);
+
+ torture_comment(tctx, "Checking actual file SD against expected SD\n");
+
+ exp_sd = security_descriptor_dacl_create(
+ tctx, 0, owner_sid, group_sid,
+ owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0,
+ SID_NT_SYSTEM, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0,
+ NULL);
+
+ CHECK_SECURITY_DESCRIPTOR(sd, exp_sd);
+
+done:
+ if (!smb2_util_handle_empty(fhandle)) {
+ smb2_util_close(tree, fhandle);
+ }
+ if (!smb2_util_handle_empty(dhandle)) {
+ smb2_util_close(tree, dhandle);
+ }
+ if (tree != NULL) {
+ smb2_deltree(tree, BASEDIR);
+ smb2_tdis(tree);
+ }
+
+ return ret;
+}
+
+/*
+ basic testing of vfs_acl_xattr
+*/
+struct torture_suite *torture_acl_xattr(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "acl_xattr");
+
+ torture_suite_add_1smb2_test(suite, "default-acl-style-posix", test_default_acl_posix);
+ torture_suite_add_1smb2_test(suite, "default-acl-style-windows", test_default_acl_win);
+
+ suite->description = talloc_strdup(suite, "vfs_acl_xattr tests");
+
+ return suite;
+}
diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c
new file mode 100644
index 0000000..b9cab0c
--- /dev/null
+++ b/source4/torture/vfs/fruit.c
@@ -0,0 +1,8839 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ vfs_fruit tests
+
+ Copyright (C) Ralph Boehme 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/smb/smb2_create_ctx.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include "MacExtensions.h"
+#include "lib/util/tsort.h"
+
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smb2/proto.h"
+#include "torture/vfs/proto.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+#include "libcli/security/dom_sid.h"
+#include "../librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/secace.h"
+#include "libcli/security/security_descriptor.h"
+
+#define BASEDIR "vfs_fruit_dir"
+#define FNAME_CC_SRC "testfsctl.dat"
+#define FNAME_CC_DST "testfsctl2.dat"
+
+#define CHECK_STATUS(status, correct) do { \
+ if (!NT_STATUS_EQUAL(status, correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect status %s - should be %s\n", \
+ __location__, nt_errstr(status), nt_errstr(correct)); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+#define CHECK_VALUE(v, correct) do { \
+ if ((v) != (correct)) { \
+ torture_result(tctx, TORTURE_FAIL, \
+ "(%s) Incorrect value %s=%u - should be %u\n", \
+ __location__, #v, (unsigned)v, (unsigned)correct); \
+ ret = false; \
+ goto done; \
+ }} while (0)
+
+static bool check_stream_list(struct smb2_tree *tree,
+ struct torture_context *tctx,
+ const char *fname,
+ int num_exp,
+ const char **exp,
+ bool is_dir);
+
+static int qsort_string(char * const *s1, char * const *s2)
+{
+ return strcmp(*s1, *s2);
+}
+
+static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2)
+{
+ return strcmp(s1->stream_name.s, s2->stream_name.s);
+}
+
+/*
+ * REVIEW:
+ * This is hokey, but what else can we do?
+ */
+#if defined(HAVE_ATTROPEN) || defined(FREEBSD)
+#define AFPINFO_EA_NETATALK "org.netatalk.Metadata"
+#define AFPRESOURCE_EA_NETATALK "org.netatalk.ResourceFork"
+#else
+#define AFPINFO_EA_NETATALK "user.org.netatalk.Metadata"
+#define AFPRESOURCE_EA_NETATALK "user.org.netatalk.ResourceFork"
+#endif
+
+/*
+The metadata xattr char buf below contains the following attributes:
+
+-------------------------------------------------------------------------------
+Entry ID : 00000008 : File Dates Info
+Offset : 00000162 : 354
+Length : 00000010 : 16
+
+-DATE------: : (GMT) : (Local)
+create : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014
+modify : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014
+backup : 80000000 : Unknown or Initial
+access : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 1B 44 21 69 1B 44 21 69 80 00 00 00 1B 44 21 69 : .D!i.D!i.....D!i
+
+-------------------------------------------------------------------------------
+Entry ID : 00000009 : Finder Info
+Offset : 0000007A : 122
+Length : 00000020 : 32
+
+-FInfo-----:
+Type : 42415252 : BARR
+Creator : 464F4F4F : FOOO
+isAlias : 0
+Invisible : 1
+hasBundle : 0
+nameLocked : 0
+Stationery : 0
+CustomIcon : 0
+Reserved : 0
+Inited : 0
+NoINITS : 0
+Shared : 0
+SwitchLaunc: 0
+Hidden Ext : 0
+color : 000 : none
+isOnDesk : 0
+Location v : 0000 : 0
+Location h : 0000 : 0
+Fldr : 0000 : ..
+
+-FXInfo----:
+Rsvd|IconID: 0000 : 0
+Rsvd : 0000 : ..
+Rsvd : 0000 : ..
+Rsvd : 0000 : ..
+AreInvalid : 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+CustomBadge: 0
+ObjctIsBusy: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+RoutingInfo: 0
+unknown bit: 0
+unknown bit: 0
+Rsvd|commnt: 0000 : 0
+PutAway : 00000000 : 0
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 42 41 52 52 46 4F 4F 4F 40 00 00 00 00 00 00 00 : BARRFOOO@.......
+00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+
+-------------------------------------------------------------------------------
+Entry ID : 0000000E : AFP File Info
+Offset : 00000172 : 370
+Length : 00000004 : 4
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 00 00 01 A1 : ....
+ */
+
+char metadata_xattr[] = {
+ 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x01, 0x62, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x7a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+ 0x00, 0x0e, 0x00, 0x00, 0x01, 0x72, 0x00, 0x00,
+ 0x00, 0x04, 0x80, 0x44, 0x45, 0x56, 0x00, 0x00,
+ 0x01, 0x76, 0x00, 0x00, 0x00, 0x08, 0x80, 0x49,
+ 0x4e, 0x4f, 0x00, 0x00, 0x01, 0x7e, 0x00, 0x00,
+ 0x00, 0x08, 0x80, 0x53, 0x59, 0x4e, 0x00, 0x00,
+ 0x01, 0x86, 0x00, 0x00, 0x00, 0x08, 0x80, 0x53,
+ 0x56, 0x7e, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00,
+ 0x00, 0x04, 0x42, 0x41, 0x52, 0x52, 0x46, 0x4f,
+ 0x4f, 0x4f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1b, 0x44, 0x21, 0x69, 0x1b, 0x44,
+ 0x21, 0x69, 0x80, 0x00, 0x00, 0x00, 0x1b, 0x44,
+ 0x21, 0x69, 0x00, 0x00, 0x01, 0xa1, 0x00, 0xfd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x20,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xe3,
+ 0x86, 0x53, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x01,
+ 0x00, 0x00
+};
+
+/*
+The buf below contains the following AppleDouble encoded data:
+
+-------------------------------------------------------------------------------
+MagicNumber: 00051607 : AppleDouble
+Version : 00020000 : Version 2
+Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X
+Num. of ent: 0002 : 2
+
+-------------------------------------------------------------------------------
+Entry ID : 00000009 : Finder Info
+Offset : 00000032 : 50
+Length : 00000EB0 : 3760
+
+-FInfo-----:
+Type : 54455354 : TEST
+Creator : 534C4F57 : SLOW
+isAlias : 0
+Invisible : 0
+hasBundle : 0
+nameLocked : 0
+Stationery : 0
+CustomIcon : 0
+Reserved : 0
+Inited : 0
+NoINITS : 0
+Shared : 0
+SwitchLaunc: 0
+Hidden Ext : 0
+color : 100 : blue
+isOnDesk : 0
+Location v : 0000 : 0
+Location h : 0000 : 0
+Fldr : 0000 : ..
+
+-FXInfo----:
+Rsvd|IconID: 0000 : 0
+Rsvd : 0000 : ..
+Rsvd : 0000 : ..
+Rsvd : 0000 : ..
+AreInvalid : 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+CustomBadge: 0
+ObjctIsBusy: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+RoutingInfo: 0
+unknown bit: 0
+unknown bit: 0
+Rsvd|commnt: 0000 : 0
+PutAway : 00000000 : 0
+
+-EA--------:
+pad : 0000 : ..
+magic : 41545452 : ATTR
+debug_tag : 53D4580C : 1406425100
+total_size : 00000EE2 : 3810
+data_start : 000000BC : 188
+data_length: 0000005E : 94
+reserved[0]: 00000000 : ....
+reserved[1]: 00000000 : ....
+reserved[2]: 00000000 : ....
+flags : 0000 : ..
+num_attrs : 0002 : 2
+-EA ENTRY--:
+offset : 000000BC : 188
+length : 0000005B : 91
+flags : 0000 : ..
+namelen : 24 : 36
+-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 61 : com.apple.metada
+00000010 : 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 54 : ta:_kMDItemUserT
+00000020 : 61 67 73 00 : ags.
+-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 62 70 6C 69 73 74 30 30 A5 01 02 03 04 05 54 74 : bplist00......Tt
+00000010 : 65 73 74 66 00 47 00 72 00 FC 00 6E 00 0A 00 32 : estf.G.r...n...2
+00000020 : 56 4C 69 6C 61 0A 33 56 47 65 6C 62 0A 35 56 42 : VLila.3VGelb.5VB
+00000030 : 6C 61 75 0A 34 08 0E 13 20 27 2E 00 00 00 00 00 : lau.4... '......
+00000040 : 00 01 01 00 00 00 00 00 00 00 06 00 00 00 00 00 : ................
+00000050 : 00 00 00 00 00 00 00 00 00 00 35 : ..........5
+-EA ENTRY--:
+offset : 00000117 : 279
+length : 00000003 : 3
+flags : 0000 : ..
+namelen : 08 : 8
+-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 66 6F 6F 3A 62 61 72 00 : foo:bar.
+-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 62 61 7A : baz
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 54 45 53 54 53 4C 4F 57 00 08 00 00 00 00 00 00 : TESTSLOW........
+00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000020 : 00 00 41 54 54 52 53 D4 58 0C 00 00 0E E2 00 00 : ..ATTRS.X.......
+00000030 : 00 BC 00 00 00 5E 00 00 00 00 00 00 00 00 00 00 : .....^..........
+00000040 : 00 00 00 00 00 02 00 00 00 BC 00 00 00 5B 00 00 : .............[..
+00000050 : 24 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 : $com.apple.metad
+00000060 : 61 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 : ata:_kMDItemUser
+00000070 : 54 61 67 73 00 00 00 00 01 17 00 00 00 03 00 00 : Tags............
+00000080 : 08 66 6F 6F 3A 62 61 72 00 66 62 70 6C 69 73 74 : .foo:bar.fbplist
+00000090 : 30 30 A5 01 02 03 04 05 54 74 65 73 74 66 00 47 : 00......Ttestf.G
+000000A0 : 00 72 00 FC 00 6E 00 0A 00 32 56 4C 69 6C 61 0A : .r...n...2VLila.
+000000B0 : 33 56 47 65 6C 62 0A 35 56 42 6C 61 75 0A 34 08 : 3VGelb.5VBlau.4.
+000000C0 : 0E 13 20 27 2E 00 00 00 00 00 00 01 01 00 00 00 : .. '............
+000000D0 : 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000E0 : 00 00 00 00 35 62 61 7A 00 00 00 00 00 00 00 00 : ....5baz........
+000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+... all zeroes ...
+00000EA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+
+-------------------------------------------------------------------------------
+Entry ID : 00000002 : Resource Fork
+Offset : 00000EE2 : 3810
+Length : 0000011E : 286
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+00000010 : 54 68 69 73 20 72 65 73 6F 75 72 63 65 20 66 6F : This resource fo
+00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally
+00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank ..
+00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : ..............
+
+It was created with:
+$ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"'
+*/
+static char osx_adouble_w_xattr[] = {
+ 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+ 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x32, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x0e, 0xe2, 0x00, 0x00,
+ 0x01, 0x1e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x4c,
+ 0x4f, 0x57, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x54, 0x54, 0x52,
+ 0x53, 0xd4, 0x58, 0x0c, 0x00, 0x00, 0x0e, 0xe2,
+ 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5b,
+ 0x00, 0x00, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+ 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5f, 0x6b,
+ 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x55, 0x73,
+ 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x08, 0x66, 0x6f, 0x6f, 0x3a, 0x62,
+ 0x61, 0x72, 0x00, 0x66, 0x62, 0x70, 0x6c, 0x69,
+ 0x73, 0x74, 0x30, 0x30, 0xa5, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x54, 0x74, 0x65, 0x73, 0x74, 0x66,
+ 0x00, 0x47, 0x00, 0x72, 0x00, 0xfc, 0x00, 0x6e,
+ 0x00, 0x0a, 0x00, 0x32, 0x56, 0x4c, 0x69, 0x6c,
+ 0x61, 0x0a, 0x33, 0x56, 0x47, 0x65, 0x6c, 0x62,
+ 0x0a, 0x35, 0x56, 0x42, 0x6c, 0x61, 0x75, 0x0a,
+ 0x34, 0x08, 0x0e, 0x13, 0x20, 0x27, 0x2e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x62,
+ 0x61, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x54, 0x68, 0x69, 0x73, 0x20, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20,
+ 0x66, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
+ 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20,
+ 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff
+};
+
+/*
+ * The buf below contains the following AppleDouble encoded data:
+ *
+ * -------------------------------------------------------------------------------
+ * MagicNumber: 00051607 : AppleDouble
+ * Version : 00020000 : Version 2
+ * Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X
+ * Num. of ent: 0002 : 2
+ *
+ * -------------------------------------------------------------------------------
+ * Entry ID : 00000002 : Resource Fork
+ * Offset : 00000052 : 82
+ * Length : 0000011E : 286
+ *
+ * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+ * 00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+ * 00000010 : F0 F1 F2 F3 F5 F5 F6 F7 F8 F9 FA FB FC FD FE FF : ................
+ * 00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally
+ * 00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank ..
+ * 00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+ * 00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : ..............
+ *
+ * Entry ID : 00000009 : Finder Info
+ * Offset : 00000032 : 50
+ * Length : 00000020 : 32
+ *
+ * -NOTE------: cannot detect whether FInfo or DInfo. assume FInfo.
+ *
+ * -FInfo-----:
+ * Type : 57415645 : WAVE
+ * Creator : 5054756C : PTul
+ * isAlias : 0
+ * Invisible : 0
+ * hasBundle : 0
+ * nameLocked : 0
+ * Stationery : 0
+ * CustomIcon : 0
+ * Reserved : 0
+ * Inited : 0
+ * NoINITS : 0
+ * Shared : 0
+ * SwitchLaunc: 0
+ * Hidden Ext : 0
+ * color : 000 : none
+ * isOnDesk : 0
+ * Location v : 0000 : 0
+ * Location h : 0000 : 0
+ * Fldr : 0000 : ..
+ *
+ * -FXInfo----:
+ * Rsvd|IconID: 0000 : 0
+ * Rsvd : 0000 : ..
+ * Rsvd : 0000 : ..
+ * Rsvd : 0000 : ..
+ * AreInvalid : 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * CustomBadge: 0
+ * ObjctIsBusy: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * RoutingInfo: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * Rsvd|commnt: 0000 : 0
+ * PutAway : 00000000 : 0
+ *
+ * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+ * 00000000 : 57 41 56 45 50 54 75 6C 00 00 00 00 00 00 00 00 : WAVEPTul........
+ * 00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * *
+ * It was created with:
+ * $ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"'
+ */
+static char osx_adouble_without_xattr[] = {
+ 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+ 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x52, 0x00, 0x00, 0x01, 0x1e, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
+ 0x00, 0x20, 0x57, 0x41, 0x56, 0x45, 0x50, 0x54,
+ 0x75, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+ 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd,
+ 0xfe, 0xff, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
+ 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20,
+ 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff
+};
+
+/*
+The buf below contains the following AppleDouble encoded data:
+
+-------------------------------------------------------------------------------
+MagicNumber: 00051607 : AppleDouble
+Version : 00020000 : Version 2
+Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X
+Num. of ent: 0002 : 2
+
+-------------------------------------------------------------------------------
+Entry ID : 00000009 : Finder Info
+Offset : 00000032 : 50
+Length : 00000EB0 : 3760
+
+-FInfo-----:
+Type : 54455354 : TEST
+Creator : 534C4F57 : SLOW
+isAlias : 0
+Invisible : 0
+hasBundle : 0
+nameLocked : 0
+Stationery : 0
+CustomIcon : 0
+Reserved : 0
+Inited : 0
+NoINITS : 0
+Shared : 0
+SwitchLaunc: 0
+Hidden Ext : 0
+color : 100 : blue
+isOnDesk : 0
+Location v : 0000 : 0
+Location h : 0000 : 0
+Fldr : 0000 : ..
+
+-FXInfo----:
+Rsvd|IconID: 0000 : 0
+Rsvd : 0000 : ..
+Rsvd : 0000 : ..
+Rsvd : 0000 : ..
+AreInvalid : 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+CustomBadge: 0
+ObjctIsBusy: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+RoutingInfo: 0
+unknown bit: 0
+unknown bit: 0
+Rsvd|commnt: 0000 : 0
+PutAway : 00000000 : 0
+
+-EA--------:
+pad : 0000 : ..
+magic : 41545452 : ATTR
+debug_tag : 53D4580C : 1406425100
+total_size : 00000EE2 : 3810
+data_start : 000000BC : 188
+data_length: 0000005E : 94
+reserved[0]: 00000000 : ....
+reserved[1]: 00000000 : ....
+reserved[2]: 00000000 : ....
+flags : 0000 : ..
+num_attrs : 0002 : 2
+-EA ENTRY--:
+offset : 000000BC : 188
+length : 0000005B : 91
+flags : 0000 : ..
+namelen : 24 : 36
+-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 61 : com.apple.metada
+00000010 : 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 54 : ta:_kMDItemUserT
+00000020 : 61 67 73 00 : ags.
+-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 62 70 6C 69 73 74 30 30 A5 01 02 03 04 05 54 74 : bplist00......Tt
+00000010 : 65 73 74 66 00 47 00 72 00 FC 00 6E 00 0A 00 32 : estf.G.r...n...2
+00000020 : 56 4C 69 6C 61 0A 33 56 47 65 6C 62 0A 35 56 42 : VLila.3VGelb.5VB
+00000030 : 6C 61 75 0A 34 08 0E 13 20 27 2E 00 00 00 00 00 : lau.4... '......
+00000040 : 00 01 01 00 00 00 00 00 00 00 06 00 00 00 00 00 : ................
+00000050 : 00 00 00 00 00 00 00 00 00 00 35 : ..........5
+-EA ENTRY--:
+offset : 00000117 : 279
+length : 00000003 : 3
+flags : 0000 : ..
+namelen : 08 : 8
+-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 66 6F 6F 3A 62 61 72 00 : foo:bar.
+-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 62 61 7A : baz
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 54 45 53 54 53 4C 4F 57 00 08 00 00 00 00 00 00 : TESTSLOW........
+00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000020 : 00 00 41 54 54 52 53 D4 58 0C 00 00 0E E2 00 00 : ..ATTRS.X.......
+00000030 : 00 BC 00 00 00 5E 00 00 00 00 00 00 00 00 00 00 : .....^..........
+00000040 : 00 00 00 00 00 02 00 00 00 BC 00 00 00 5B 00 00 : .............[..
+00000050 : 24 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 : $com.apple.metad
+00000060 : 61 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 : ata:_kMDItemUser
+00000070 : 54 61 67 73 00 00 00 00 01 17 00 00 00 03 00 00 : Tags............
+00000080 : 08 66 6F 6F 3A 62 61 72 00 66 62 70 6C 69 73 74 : .foo:bar.fbplist
+00000090 : 30 30 A5 01 02 03 04 05 54 74 65 73 74 66 00 47 : 00......Ttestf.G
+000000A0 : 00 72 00 FC 00 6E 00 0A 00 32 56 4C 69 6C 61 0A : .r...n...2VLila.
+000000B0 : 33 56 47 65 6C 62 0A 35 56 42 6C 61 75 0A 34 08 : 3VGelb.5VBlau.4.
+000000C0 : 0E 13 20 27 2E 00 00 00 00 00 00 01 01 00 00 00 : .. '............
+000000D0 : 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000E0 : 00 00 00 00 35 62 61 7A 00 00 00 00 00 00 00 00 : ....5baz........
+000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+... all zeroes ...
+00000EA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+
+-------------------------------------------------------------------------------
+Entry ID : 00000002 : Resource Fork
+Offset : 00000EE2 : 3810
+Length : 0000011E : 286
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+00000010 : F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF : This resource fo
+00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally
+00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank ..
+00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : ..............
+
+It was created with:
+$ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"'
+*/
+static char osx_adouble_non_empty_rfork_w_xattr[] = {
+ 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+ 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x32, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x0e, 0xe2, 0x00, 0x00,
+ 0x01, 0x1e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x4c,
+ 0x4f, 0x57, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x54, 0x54, 0x52,
+ 0x53, 0xd4, 0x58, 0x0c, 0x00, 0x00, 0x0e, 0xe2,
+ 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5b,
+ 0x00, 0x00, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+ 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x6d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5f, 0x6b,
+ 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x55, 0x73,
+ 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x08, 0x66, 0x6f, 0x6f, 0x3a, 0x62,
+ 0x61, 0x72, 0x00, 0x66, 0x62, 0x70, 0x6c, 0x69,
+ 0x73, 0x74, 0x30, 0x30, 0xa5, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x54, 0x74, 0x65, 0x73, 0x74, 0x66,
+ 0x00, 0x47, 0x00, 0x72, 0x00, 0xfc, 0x00, 0x6e,
+ 0x00, 0x0a, 0x00, 0x32, 0x56, 0x4c, 0x69, 0x6c,
+ 0x61, 0x0a, 0x33, 0x56, 0x47, 0x65, 0x6c, 0x62,
+ 0x0a, 0x35, 0x56, 0x42, 0x6c, 0x61, 0x75, 0x0a,
+ 0x34, 0x08, 0x0e, 0x13, 0x20, 0x27, 0x2e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x62,
+ 0x61, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+ 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd,
+ 0xfe, 0xff, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
+ 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20,
+ 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff
+};
+
+/**
+ * talloc and intialize an AfpInfo
+ **/
+static AfpInfo *torture_afpinfo_new(TALLOC_CTX *mem_ctx)
+{
+ AfpInfo *info;
+
+ info = talloc_zero(mem_ctx, AfpInfo);
+ if (info == NULL) {
+ return NULL;
+ }
+
+ info->afpi_Signature = AFP_Signature;
+ info->afpi_Version = AFP_Version;
+ info->afpi_BackupTime = AFP_BackupTime;
+
+ return info;
+}
+
+/**
+ * Pack AfpInfo into a talloced buffer
+ **/
+static char *torture_afpinfo_pack(TALLOC_CTX *mem_ctx,
+ AfpInfo *info)
+{
+ char *buf;
+
+ buf = talloc_zero_array(mem_ctx, char, AFP_INFO_SIZE);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ RSIVAL(buf, 0, info->afpi_Signature);
+ RSIVAL(buf, 4, info->afpi_Version);
+ RSIVAL(buf, 12, info->afpi_BackupTime);
+ memcpy(buf + 16, info->afpi_FinderInfo, sizeof(info->afpi_FinderInfo));
+
+ return buf;
+}
+
+/**
+ * Unpack AfpInfo
+ **/
+#if 0
+static void torture_afpinfo_unpack(AfpInfo *info, char *data)
+{
+ info->afpi_Signature = RIVAL(data, 0);
+ info->afpi_Version = RIVAL(data, 4);
+ info->afpi_BackupTime = RIVAL(data, 12);
+ memcpy(info->afpi_FinderInfo, (const char *)data + 16,
+ sizeof(info->afpi_FinderInfo));
+}
+#endif
+
+static bool torture_write_afpinfo(struct smb2_tree *tree,
+ struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const char *fname,
+ AfpInfo *info)
+{
+ struct smb2_handle handle;
+ struct smb2_create io;
+ NTSTATUS status;
+ const char *full_name;
+ char *infobuf;
+ bool ret = true;
+
+ full_name = talloc_asprintf(mem_ctx, "%s%s", fname, AFPINFO_STREAM_NAME);
+ if (full_name == NULL) {
+ torture_comment(tctx, "talloc_asprintf error\n");
+ return false;
+ }
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FILE_WRITE_DATA;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.create_options = 0;
+ io.in.fname = full_name;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ handle = io.out.file.handle;
+
+ infobuf = torture_afpinfo_pack(mem_ctx, info);
+ if (infobuf == NULL) {
+ return false;
+ }
+
+ status = smb2_util_write(tree, handle, infobuf, 0, AFP_INFO_SIZE);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, handle);
+
+done:
+ return ret;
+}
+
+/**
+ * Read 'count' bytes at 'offset' from stream 'fname:sname' and
+ * compare against buffer 'value'
+ **/
+static bool check_stream(struct smb2_tree *tree,
+ const char *location,
+ struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const char *sname,
+ off_t read_offset,
+ size_t read_count,
+ off_t comp_offset,
+ size_t comp_count,
+ const char *value)
+{
+ struct smb2_handle handle;
+ struct smb2_create create;
+ struct smb2_read r;
+ NTSTATUS status;
+ char *full_name;
+ bool ret = true;
+
+ full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname);
+ if (full_name == NULL) {
+ torture_comment(tctx, "talloc_asprintf error\n");
+ return false;
+ }
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_DATA;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = full_name;
+
+ torture_comment(tctx, "Open stream %s\n", full_name);
+
+ status = smb2_create(tree, mem_ctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (value == NULL) {
+ TALLOC_FREE(full_name);
+ return true;
+ }
+ torture_comment(tctx, "Unable to open stream %s: %s\n",
+ full_name, nt_errstr(status));
+ TALLOC_FREE(full_name);
+ return false;
+ }
+
+ handle = create.out.file.handle;
+ if (value == NULL) {
+ TALLOC_FREE(full_name);
+ smb2_util_close(tree, handle);
+ return true;
+ }
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = handle;
+ r.in.length = read_count;
+ r.in.offset = read_offset;
+
+ status = smb2_read(tree, tree, &r);
+
+ torture_assert_ntstatus_ok_goto(
+ tctx, status, ret, done,
+ talloc_asprintf(tctx, "(%s) Failed to read %lu bytes from stream '%s'\n",
+ location, (long)strlen(value), full_name));
+
+ torture_assert_goto(tctx, r.out.data.length == read_count, ret, done,
+ talloc_asprintf(tctx, "smb2_read returned %jd bytes, expected %jd\n",
+ (intmax_t)r.out.data.length, (intmax_t)read_count));
+
+ torture_assert_goto(
+ tctx, memcmp(r.out.data.data + comp_offset, value, comp_count) == 0,
+ ret, done,
+ talloc_asprintf(tctx, "(%s) Bad data in stream\n", location));
+
+done:
+ TALLOC_FREE(full_name);
+ smb2_util_close(tree, handle);
+ return ret;
+}
+
+/**
+ * Read 'count' bytes at 'offset' from stream 'fname:sname' and
+ * compare against buffer 'value'
+ **/
+static ssize_t read_stream(struct smb2_tree *tree,
+ const char *location,
+ struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const char *sname,
+ off_t read_offset,
+ size_t read_count)
+{
+ struct smb2_handle handle;
+ struct smb2_create create;
+ struct smb2_read r;
+ NTSTATUS status;
+ const char *full_name;
+ bool ret = true;
+
+ full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname);
+ if (full_name == NULL) {
+ torture_comment(tctx, "talloc_asprintf error\n");
+ return -1;
+ }
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_DATA;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = full_name;
+
+ torture_comment(tctx, "Open stream %s\n", full_name);
+
+ status = smb2_create(tree, mem_ctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "Unable to open stream %s: %s\n",
+ full_name, nt_errstr(status));
+ return -1;
+ }
+
+ handle = create.out.file.handle;
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = handle;
+ r.in.length = read_count;
+ r.in.offset = read_offset;
+
+ status = smb2_read(tree, tree, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
+ }
+
+ smb2_util_close(tree, handle);
+
+done:
+ if (ret == false) {
+ return -1;
+ }
+ return r.out.data.length;
+}
+
+/**
+ * Read 'count' bytes at 'offset' from stream 'fname:sname' and
+ * compare against buffer 'value'
+ **/
+static bool write_stream(struct smb2_tree *tree,
+ const char *location,
+ struct torture_context *tctx,
+ TALLOC_CTX *mem_ctx,
+ const char *fname,
+ const char *sname,
+ off_t offset,
+ size_t size,
+ const char *value)
+{
+ struct smb2_handle handle;
+ struct smb2_create create;
+ NTSTATUS status;
+ const char *full_name;
+
+ full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname ? sname : "");
+ if (full_name == NULL) {
+ torture_comment(tctx, "talloc_asprintf error\n");
+ return false;
+ }
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_WRITE_DATA;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.fname = full_name;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (value == NULL) {
+ return true;
+ } else {
+ torture_comment(tctx, "Unable to open stream %s: %s\n",
+ full_name, nt_errstr(status));
+ return false;
+ }
+ }
+
+ handle = create.out.file.handle;
+ if (value == NULL) {
+ return true;
+ }
+
+ status = smb2_util_write(tree, handle, value, offset, size);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_comment(tctx, "(%s) Failed to write %lu bytes to "
+ "stream '%s'\n", location, (long)size, full_name);
+ return false;
+ }
+
+ smb2_util_close(tree, handle);
+ return true;
+}
+
+static bool torture_setup_local_xattr(struct torture_context *tctx,
+ const char *path_option,
+ const char *name,
+ const char *xattr,
+ const char *metadata,
+ size_t size)
+{
+ int ret = true;
+ int result;
+ const char *spath;
+ char *path;
+
+ spath = torture_setting_string(tctx, path_option, NULL);
+ if (spath == NULL) {
+ printf("No sharepath for option %s\n", path_option);
+ return false;
+ }
+
+ path = talloc_asprintf(tctx, "%s/%s", spath, name);
+
+ result = setxattr(path, xattr, metadata, size, 0);
+ if (result != 0) {
+ ret = false;
+ }
+
+ TALLOC_FREE(path);
+
+ return ret;
+}
+
+/**
+ * Create a file or directory
+ **/
+static bool torture_setup_file(TALLOC_CTX *mem_ctx, struct smb2_tree *tree,
+ const char *name, bool dir)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ smb2_util_unlink(tree, name);
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.in.create_options = 0;
+ io.in.fname = name;
+ if (dir) {
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_CREATE;
+ }
+
+ status = smb2_create(tree, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool enable_aapl(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_create io;
+ DATA_BLOB data;
+ struct smb2_create_blob *aapl = NULL;
+ uint32_t aapl_server_caps;
+ uint32_t expected_scaps = (SMB2_CRTCTX_AAPL_UNIX_BASED |
+ SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR |
+ SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE |
+ SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE);
+ bool is_osx_server = torture_setting_bool(tctx, "osx", false);
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.share_access = (NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE);
+ io.in.fname = "";
+
+ /*
+ * Issuing an SMB2/CREATE with a suitably formed AAPL context,
+ * controls behaviour of Apple's SMB2 extensions for the whole
+ * session!
+ */
+
+ data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t));
+ SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
+ SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS |
+ SMB2_CRTCTX_AAPL_VOLUME_CAPS |
+ SMB2_CRTCTX_AAPL_MODEL_INFO));
+ SBVAL(data.data, 16, (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR |
+ SMB2_CRTCTX_AAPL_UNIX_BASED |
+ SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE));
+
+ status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_blob_add");
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close");
+
+ /*
+ * Now check returned AAPL context
+ */
+ torture_comment(tctx, "Comparing returned AAPL capabilities\n");
+
+ aapl = smb2_create_blob_find(&io.out.blobs,
+ SMB2_CREATE_TAG_AAPL);
+ torture_assert_goto(tctx, aapl != NULL, ret, done, "missing AAPL context");
+
+ if (!is_osx_server) {
+ size_t expected_aapl_ctx_size;
+
+ expected_aapl_ctx_size = strlen("MacSamba") * 2 + 40;
+
+ torture_assert_goto(
+ tctx, aapl->data.length == expected_aapl_ctx_size,
+ ret, done, "bad AAPL size");
+ }
+
+ aapl_server_caps = BVAL(aapl->data.data, 16);
+ torture_assert_goto(tctx, aapl_server_caps == expected_scaps,
+ ret, done, "bad AAPL caps");
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_read_netatalk_metadata(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_read_metadata";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ ssize_t len;
+ const char *localdir = NULL;
+
+ torture_comment(tctx, "Checking metadata access\n");
+
+ localdir = torture_setting_string(tctx, "localdir", NULL);
+ if (localdir == NULL) {
+ torture_skip(tctx, "Need localdir for test");
+ }
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ ret = torture_setup_local_xattr(tctx, "localdir",
+ BASEDIR "/torture_read_metadata",
+ AFPINFO_EA_NETATALK,
+ metadata_xattr, sizeof(metadata_xattr));
+ if (ret == false) {
+ goto done;
+ }
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 0, 4, "AFP");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, "BARRFOOO");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 16, 8, 0, 3, "AFP");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ /* Check reading offset and read size > sizeof(AFPINFO_STREAM) */
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 0, 61);
+ CHECK_VALUE(len, 60);
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 59, 2);
+ CHECK_VALUE(len, 2);
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 60, 1);
+ CHECK_VALUE(len, 1);
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 61, 1);
+ CHECK_VALUE(len, 0);
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_read_afpinfo(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_read_metadata";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ ssize_t len;
+ AfpInfo *info;
+ const char *type_creator = "SMB,OLE!";
+
+ torture_comment(tctx, "Checking metadata access\n");
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed");
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed");
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 0, 4, "AFP");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ /*
+ * OS X ignores offset <= 60 and treats the as
+ * offset=0. Reading from offsets > 60 returns EOF=0.
+ */
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 16, 8, 0, 8, "AFP\0\0\0\001\0");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 0, 61);
+ torture_assert_goto(tctx, len == 60, ret, done, "read_stream failed");
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 59, 2);
+ torture_assert_goto(tctx, len == 2, ret, done, "read_stream failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 59, 2, 0, 2, "AF");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 60, 1);
+ torture_assert_goto(tctx, len == 1, ret, done, "read_stream failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 60, 1, 0, 1, "A");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+ len = read_stream(tree, __location__, tctx, mem_ctx, fname,
+ AFPINFO_STREAM, 61, 1);
+ torture_assert_goto(tctx, len == 0, ret, done, "read_stream failed");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_write_atalk_metadata(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_write_metadata";
+ const char *type_creator = "SMB,OLE!";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ AfpInfo *info;
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ info = torture_afpinfo_new(mem_ctx);
+ if (info == NULL) {
+ goto done;
+ }
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ ret &= check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_write_atalk_rfork_io(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_write_rfork_io";
+ const char *rfork = BASEDIR "\\torture_write_rfork_io" AFPRESOURCE_STREAM_NAME;
+ const char *rfork_content = "1234567890";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+
+ union smb_open io;
+ struct smb2_handle filehandle;
+ union smb_fileinfo finfo;
+ union smb_setfileinfo sinfo;
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) writing to resource fork\n",
+ __location__);
+
+ ret &= write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 10, 10, rfork_content);
+
+ ret &= check_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 0, 20, 10, 10, rfork_content);
+
+ /* Check size after write */
+
+ ZERO_STRUCT(io);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ io.smb2.in.fname = rfork;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ filehandle = io.smb2.out.file.handle;
+
+ torture_comment(tctx, "(%s) check resource fork size after write\n",
+ __location__);
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.handle = filehandle;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (finfo.all_info.out.size != 20) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Incorrect resource fork size\n",
+ __location__);
+ ret = false;
+ smb2_util_close(tree, filehandle);
+ goto done;
+ }
+ smb2_util_close(tree, filehandle);
+
+ /* Write at large offset */
+
+ torture_comment(tctx, "(%s) writing to resource fork at large offset\n",
+ __location__);
+
+ ret &= write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ (off_t)64*1024*1024, 10, rfork_content);
+
+ /* Check size after write */
+
+ ZERO_STRUCT(io);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ io.smb2.in.fname = rfork;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ filehandle = io.smb2.out.file.handle;
+
+ torture_comment(tctx, "(%s) check resource fork size after write\n",
+ __location__);
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.handle = filehandle;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (finfo.all_info.out.size != 64*1024*1024 + 10) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Incorrect resource fork size\n",
+ __location__);
+ ret = false;
+ smb2_util_close(tree, filehandle);
+ goto done;
+ }
+ smb2_util_close(tree, filehandle);
+
+ ret &= check_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ (off_t)64*1024*1024, 10, 0, 10, rfork_content);
+
+ /* Truncate back to size of 1 byte */
+
+ torture_comment(tctx, "(%s) truncate resource fork and check size\n",
+ __location__);
+
+ ZERO_STRUCT(io);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_ALL;
+ io.smb2.in.fname = rfork;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ filehandle = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level =
+ RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = filehandle;
+ sinfo.end_of_file_info.in.size = 1;
+ status = smb2_setinfo_file(tree, &sinfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_close(tree, filehandle);
+
+ /* Now check size */
+ ZERO_STRUCT(io);
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_WRITE_ATTRIBUTE;
+ io.smb2.in.fname = rfork;
+ status = smb2_create(tree, mem_ctx, &(io.smb2));
+ CHECK_STATUS(status, NT_STATUS_OK);
+ filehandle = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.handle = filehandle;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ if (finfo.all_info.out.size != 1) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Incorrect resource fork size\n",
+ __location__);
+ ret = false;
+ smb2_util_close(tree, filehandle);
+ goto done;
+ }
+ smb2_util_close(tree, filehandle);
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_rfork_truncate(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_rfork_truncate";
+ const char *rfork = BASEDIR "\\torture_rfork_truncate" AFPRESOURCE_STREAM;
+ const char *rfork_content = "1234567890";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle fh1, fh2, fh3;
+ union smb_setfileinfo sinfo;
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ ret &= write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM,
+ 10, 10, rfork_content);
+
+ /* Truncate back to size 0, further access MUST return ENOENT */
+
+ torture_comment(tctx, "(%s) truncate resource fork to size 0\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = fname;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh1 = create.out.file.handle;
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh2 = create.out.file.handle;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = fh2;
+ sinfo.end_of_file_info.in.size = 0;
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file");
+
+ /*
+ * Now check size, we should get OBJECT_NAME_NOT_FOUND (!)
+ */
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create");
+
+ /*
+ * Do another open on the rfork and write to the new handle. A
+ * naive server might unlink the AppleDouble resource fork
+ * file when its truncated to 0 bytes above, so in case both
+ * open handles share the same underlying fd, the unlink would
+ * cause the below write to be lost.
+ */
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh3 = create.out.file.handle;
+
+ status = smb2_util_write(tree, fh3, "foo", 0, 3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write");
+
+ smb2_util_close(tree, fh3);
+ smb2_util_close(tree, fh2);
+ smb2_util_close(tree, fh1);
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM,
+ 0, 3, 0, 3, "foo");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_rfork_create(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_rfork_create";
+ const char *rfork = BASEDIR "\\torture_rfork_create" AFPRESOURCE_STREAM;
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle fh1;
+ const char *streams[] = {
+ "::$DATA"
+ };
+ union smb_fileinfo finfo;
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) open rfork, should return ENOENT\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create");
+
+ torture_comment(tctx, "(%s) create resource fork\n", __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh1 = create.out.file.handle;
+
+ torture_comment(tctx, "(%s) getinfo on create handle\n",
+ __location__);
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.handle = fh1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file");
+ if (finfo.all_info.out.size != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Incorrect resource fork size\n",
+ __location__);
+ ret = false;
+ smb2_util_close(tree, fh1);
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) open rfork, should still return ENOENT\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create");
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list");
+
+ torture_comment(tctx, "(%s) close empty created rfork, open should return ENOENT\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=15182
+ */
+
+static bool test_rfork_fsync(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_rfork_fsync";
+ const char *rfork = BASEDIR "\\torture_rfork_fsync" AFPRESOURCE_STREAM;
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle fh1;
+ struct smb2_flush f;
+
+ ZERO_STRUCT(fh1);
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ smb2_util_unlink(tree, fname);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx,
+ status,
+ ret,
+ done,
+ "torture_smb2_testdir");
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) create resource fork %s\n",
+ __location__,
+ rfork);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh1 = create.out.file.handle;
+
+ torture_comment(tctx, "(%s) Write 10 bytes to resource fork %s\n",
+ __location__,
+ rfork);
+
+ status = smb2_util_write(tree, fh1, "1234567890", 0, 10);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ torture_comment(tctx, "(%s) fsync on resource fork %s\n",
+ __location__,
+ rfork);
+
+ f.in.file.handle = fh1;
+ status = smb2_flush(tree, &f);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_flush failed\n");
+
+done:
+
+ smb2_util_close(tree, fh1);
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_rfork_create_ro(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_rfork_create";
+ const char *rfork = BASEDIR "\\torture_rfork_create" AFPRESOURCE_STREAM;
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create create;
+
+ smb2_util_unlink(tree, fname);
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) Try opening read-only with "
+ "open_if create disposition, should work\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.fname = rfork;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_FILE_READ_DATA | SEC_STD_READ_CONTROL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = FILE_SHARE_READ | FILE_SHARE_DELETE;
+ status = smb2_create(tree, mem_ctx, &(create));
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ smb2_util_close(tree, create.out.file.handle);
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_adouble_conversion(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\test_adouble_conversion";
+ const char *adname = BASEDIR "/._test_adouble_conversion";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ const char data[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ size_t datalen = sizeof(data);
+ const char *streams[] = {
+ "::$DATA",
+ AFPINFO_STREAM,
+ AFPRESOURCE_STREAM,
+ ":com.apple.metadata" "\xef\x80\xa2" "_kMDItemUserTags:$DATA",
+ ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */
+ };
+ bool is_osx = torture_setting_bool(tctx, "osx", false);
+
+ if (is_osx) {
+ torture_skip(tctx, "Test only works with Samba\n");
+ }
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = torture_setup_file(tctx, tree, adname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ adname, NULL,
+ 0,
+ sizeof(osx_adouble_non_empty_rfork_w_xattr),
+ osx_adouble_non_empty_rfork_w_xattr);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ torture_comment(tctx, "(%s) test OS X AppleDouble conversion\n",
+ __location__);
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM,
+ 16, datalen, 0, datalen, data);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check AFPRESOURCE_STREAM failed\n");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, "TESTSLOW");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check AFPINFO_STREAM failed\n");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname,
+ ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */
+ 0, 3, 0, 3, "baz");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check foo:bar stream failed\n");
+
+ ret = check_stream_list(tree, tctx, fname, 5, streams, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Test conversion of AppleDouble file without embedded xattr data
+ */
+static bool test_adouble_conversion_wo_xattr(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\test_adouble_conversion";
+ const char *adname = BASEDIR "/._test_adouble_conversion";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ const char *streams[] = {
+ "::$DATA",
+ AFPINFO_STREAM,
+ AFPRESOURCE_STREAM
+ };
+ struct smb2_create create;
+ struct smb2_find find;
+ unsigned int count;
+ union smb_search_data *d;
+ const char data[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ size_t datalen = sizeof(data);
+ bool is_osx = torture_setting_bool(tctx, "osx", false);
+
+ if (is_osx) {
+ torture_skip(tctx, "Test only works with Samba\n");
+ }
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree, testdirh);
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = torture_setup_file(tctx, tree, adname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ adname, NULL, 0,
+ sizeof(osx_adouble_without_xattr),
+ osx_adouble_without_xattr);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ /*
+ * Issue a smb2_find(), this triggers the server-side conversion
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_DIR_READ,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = BASEDIR,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ find = (struct smb2_find) {
+ .in.file.handle = create.out.file.handle,
+ .in.pattern = "*",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree, tree, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+
+ status = smb2_util_close(tree, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+
+ /*
+ * Check number of streams
+ */
+
+ ret = check_stream_list(tree, tctx, fname, 3, streams, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list");
+
+
+ /*
+ * Check Resourcefork data can be read.
+ */
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM,
+ 16, datalen, 0, datalen, data);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check AFPRESOURCE_STREAM failed\n");
+
+ /*
+ * Check FinderInfo data has been migrated to stream.
+ */
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, "WAVEPTul");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check AFPINFO_STREAM failed\n");
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_aapl(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\test_aapl";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create io;
+ DATA_BLOB data;
+ struct smb2_create_blob *aapl = NULL;
+ AfpInfo *info;
+ const char *type_creator = "SMB,OLE!";
+ char type_creator_buf[9];
+ uint32_t aapl_cmd;
+ uint32_t aapl_reply_bitmap;
+ uint32_t aapl_server_caps;
+ uint32_t aapl_vol_caps;
+ uint32_t expected_vol_caps = 0;
+ char *model;
+ struct smb2_find f;
+ unsigned int count;
+ union smb_search_data *d;
+ uint64_t rfork_len;
+ bool is_osx_server = torture_setting_bool(tctx, "osx", false);
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, testdirh);
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access = (NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE);
+ io.in.fname = fname;
+
+ /*
+ * Issuing an SMB2/CREATE with a suitably formed AAPL context,
+ * controls behaviour of Apple's SMB2 extensions for the whole
+ * session!
+ */
+
+ data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t));
+ SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
+ SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS |
+ SMB2_CRTCTX_AAPL_VOLUME_CAPS |
+ SMB2_CRTCTX_AAPL_MODEL_INFO));
+ SBVAL(data.data, 16, (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR |
+ SMB2_CRTCTX_AAPL_UNIX_BASED |
+ SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE));
+
+ torture_comment(tctx, "Testing SMB2 create context AAPL\n");
+ status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /*
+ * Now check returned AAPL context
+ */
+ torture_comment(tctx, "Comparing returned AAPL capabilities\n");
+
+ aapl = smb2_create_blob_find(&io.out.blobs,
+ SMB2_CREATE_TAG_AAPL);
+
+ if (aapl == NULL) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpectedly no AAPL capabilities were returned.",
+ __location__);
+ ret = false;
+ goto done;
+ }
+
+ if (!is_osx_server) {
+ size_t expected_aapl_ctx_size;
+ bool size_ok;
+
+ /*
+ * uint32_t CommandCode = kAAPL_SERVER_QUERY
+ * uint32_t Reserved = 0;
+ * uint64_t ReplyBitmap = kAAPL_SERVER_CAPS |
+ * kAAPL_VOLUME_CAPS |
+ * kAAPL_MODEL_INFO;
+ * uint64_t ServerCaps = kAAPL_SUPPORTS_READDIR_ATTR |
+ * kAAPL_SUPPORTS_OSX_COPYFILE;
+ * uint64_t VolumeCaps = kAAPL_SUPPORT_RESOLVE_ID |
+ * kAAPL_CASE_SENSITIVE;
+ * uint32_t Pad2 = 0;
+ * uint32_t ModelStringLen = 10;
+ * ucs2_t ModelString[5] = "MacSamba";
+ */
+ expected_aapl_ctx_size = strlen("MacSamba") * 2 + 40;
+
+ size_ok = aapl->data.length == expected_aapl_ctx_size;
+ torture_assert_goto(tctx, size_ok, ret, done, "bad AAPL size");
+ }
+
+ aapl_cmd = IVAL(aapl->data.data, 0);
+ if (aapl_cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected cmd: %d",
+ __location__, (int)aapl_cmd);
+ ret = false;
+ goto done;
+ }
+
+ aapl_reply_bitmap = BVAL(aapl->data.data, 8);
+ if (aapl_reply_bitmap != (SMB2_CRTCTX_AAPL_SERVER_CAPS |
+ SMB2_CRTCTX_AAPL_VOLUME_CAPS |
+ SMB2_CRTCTX_AAPL_MODEL_INFO)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected reply_bitmap: %d",
+ __location__, (int)aapl_reply_bitmap);
+ ret = false;
+ goto done;
+ }
+
+ aapl_server_caps = BVAL(aapl->data.data, 16);
+ if (aapl_server_caps != (SMB2_CRTCTX_AAPL_UNIX_BASED |
+ SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR |
+ SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE |
+ SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected server_caps: %d",
+ __location__, (int)aapl_server_caps);
+ ret = false;
+ goto done;
+ }
+
+ if (is_osx_server) {
+ expected_vol_caps = 5;
+ }
+ aapl_vol_caps = BVAL(aapl->data.data, 24);
+ if (aapl_vol_caps != expected_vol_caps) {
+ /* this will fail on a case insensitive fs ... */
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected vol_caps: %d",
+ __location__, (int)aapl_vol_caps);
+ }
+
+ ret = convert_string_talloc(mem_ctx,
+ CH_UTF16LE, CH_UNIX,
+ aapl->data.data + 40, 10,
+ &model, NULL);
+ if (ret == false) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) convert_string_talloc() failed",
+ __location__);
+ goto done;
+ }
+ torture_comment(tctx, "Got server model: \"%s\"\n", model);
+
+ /*
+ * Now that Requested AAPL extensions are enabled, setup some
+ * Mac files with metadata and resource fork
+ */
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ if (ret == false) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) torture_setup_file() failed",
+ __location__);
+ goto done;
+ }
+
+ info = torture_afpinfo_new(mem_ctx);
+ if (info == NULL) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) torture_afpinfo_new() failed",
+ __location__);
+ ret = false;
+ goto done;
+ }
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ if (ret == false) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) torture_write_afpinfo() failed",
+ __location__);
+ goto done;
+ }
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 0, 3, "foo");
+ if (ret == false) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) write_stream() failed",
+ __location__);
+ goto done;
+ }
+
+ /*
+ * Ok, file is prepared, now call smb2/find
+ */
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_RIGHTS_DIR_READ;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE);
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.fname = BASEDIR;
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = io.out.file.handle;
+ f.in.pattern = "test_aapl";
+ f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE;
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ if (strcmp(d[0].id_both_directory_info.name.s, "test_aapl") != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) write_stream() failed",
+ __location__);
+ ret = false;
+ goto done;
+ }
+
+ if (d[0].id_both_directory_info.short_name.private_length != 24) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) bad short_name length %" PRIu32 ", expected 24",
+ __location__, d[0].id_both_directory_info.short_name.private_length);
+ ret = false;
+ goto done;
+ }
+
+ torture_comment(tctx, "short_name buffer:\n");
+ dump_data(0, d[0].id_both_directory_info.short_name_buf, 24);
+
+ /*
+ * Extract data as specified by the AAPL extension:
+ * - ea_size contains max_access
+ * - short_name contains resource fork length + FinderInfo
+ * - reserved2 contains the unix mode
+ */
+ torture_comment(tctx, "mac_access: %" PRIx32 "\n",
+ d[0].id_both_directory_info.ea_size);
+
+ rfork_len = BVAL(d[0].id_both_directory_info.short_name_buf, 0);
+ if (rfork_len != 3) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) expected resource fork length 3, got: %" PRIu64,
+ __location__, rfork_len);
+ ret = false;
+ goto done;
+ }
+
+ memcpy(type_creator_buf, d[0].id_both_directory_info.short_name_buf + 8, 8);
+ type_creator_buf[8] = 0;
+ if (strcmp(type_creator, type_creator_buf) != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) expected type/creator \"%s\" , got: %s",
+ __location__, type_creator, type_creator_buf);
+ ret = false;
+ goto done;
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static uint64_t patt_hash(uint64_t off)
+{
+ return off;
+}
+
+static bool write_pattern(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle h, uint64_t off, uint64_t len,
+ uint64_t patt_off)
+{
+ NTSTATUS status;
+ uint64_t i;
+ uint8_t *buf;
+ uint64_t io_sz = MIN(1024 * 64, len);
+
+ if (len == 0) {
+ return true;
+ }
+
+ torture_assert(torture, (len % 8) == 0, "invalid write len");
+
+ buf = talloc_zero_size(mem_ctx, io_sz);
+ torture_assert(torture, (buf != NULL), "no memory for file data buf");
+
+ while (len > 0) {
+ for (i = 0; i <= io_sz - 8; i += 8) {
+ SBVAL(buf, i, patt_hash(patt_off));
+ patt_off += 8;
+ }
+
+ status = smb2_util_write(tree, h,
+ buf, off, io_sz);
+ torture_assert_ntstatus_ok(torture, status, "file write");
+
+ len -= io_sz;
+ off += io_sz;
+ }
+
+ talloc_free(buf);
+
+ return true;
+}
+
+static bool check_pattern(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ struct smb2_handle h, uint64_t off, uint64_t len,
+ uint64_t patt_off)
+{
+ if (len == 0) {
+ return true;
+ }
+
+ torture_assert(torture, (len % 8) == 0, "invalid read len");
+
+ while (len > 0) {
+ uint64_t i;
+ struct smb2_read r;
+ NTSTATUS status;
+ uint64_t io_sz = MIN(1024 * 64, len);
+
+ ZERO_STRUCT(r);
+ r.in.file.handle = h;
+ r.in.length = io_sz;
+ r.in.offset = off;
+ status = smb2_read(tree, mem_ctx, &r);
+ torture_assert_ntstatus_ok(torture, status, "read");
+
+ torture_assert_u64_equal(torture, r.out.data.length, io_sz,
+ "read data len mismatch");
+
+ for (i = 0; i <= io_sz - 8; i += 8, patt_off += 8) {
+ uint64_t data = BVAL(r.out.data.data, i);
+ torture_assert_u64_equal(torture, data, patt_hash(patt_off),
+ talloc_asprintf(torture, "read data "
+ "pattern bad at %llu\n",
+ (unsigned long long)off + i));
+ }
+ talloc_free(r.out.data.data);
+ len -= io_sz;
+ off += io_sz;
+ }
+
+ return true;
+}
+
+static bool test_setup_open(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ const char *fname,
+ struct smb2_handle *fh,
+ uint32_t desired_access,
+ uint32_t file_attributes)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = desired_access;
+ io.in.file_attributes = file_attributes;
+ io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ io.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ if (file_attributes & FILE_ATTRIBUTE_DIRECTORY) {
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ }
+ io.in.fname = fname;
+
+ status = smb2_create(tree, mem_ctx, &io);
+ torture_assert_ntstatus_ok(torture, status, "file create");
+
+ *fh = io.out.file.handle;
+
+ return true;
+}
+
+static bool test_setup_create_fill(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ const char *fname,
+ struct smb2_handle *fh,
+ uint64_t size,
+ uint32_t desired_access,
+ uint32_t file_attributes)
+{
+ bool ok;
+
+ ok = test_setup_open(torture, tree, mem_ctx,
+ fname,
+ fh,
+ desired_access,
+ file_attributes);
+ torture_assert(torture, ok, "file open");
+
+ if (size > 0) {
+ ok = write_pattern(torture, tree, mem_ctx, *fh, 0, size, 0);
+ torture_assert(torture, ok, "write pattern");
+ }
+ return true;
+}
+
+static bool test_setup_copy_chunk(struct torture_context *torture,
+ struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
+ uint32_t nchunks,
+ const char *src_name,
+ struct smb2_handle *src_h,
+ uint64_t src_size,
+ uint32_t src_desired_access,
+ const char *dst_name,
+ struct smb2_handle *dest_h,
+ uint64_t dest_size,
+ uint32_t dest_desired_access,
+ struct srv_copychunk_copy *cc_copy,
+ union smb_ioctl *io)
+{
+ struct req_resume_key_rsp res_key;
+ bool ok;
+ NTSTATUS status;
+ enum ndr_err_code ndr_ret;
+
+ ok = test_setup_create_fill(torture, tree, mem_ctx, src_name,
+ src_h, src_size, src_desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "src file create fill");
+
+ ok = test_setup_create_fill(torture, tree, mem_ctx, dst_name,
+ dest_h, dest_size, dest_desired_access,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "dest file create fill");
+
+ ZERO_STRUCTPN(io);
+ io->smb2.level = RAW_IOCTL_SMB2;
+ io->smb2.in.file.handle = *src_h;
+ io->smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY;
+ /* Allow for Key + ContextLength + Context */
+ io->smb2.in.max_output_response = 32;
+ io->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ status = smb2_ioctl(tree, mem_ctx, &io->smb2);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_SRV_REQUEST_RESUME_KEY");
+
+ ndr_ret = ndr_pull_struct_blob(&io->smb2.out.out, mem_ctx, &res_key,
+ (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
+
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_req_resume_key_rsp");
+
+ ZERO_STRUCTPN(io);
+ io->smb2.level = RAW_IOCTL_SMB2;
+ io->smb2.in.file.handle = *dest_h;
+ io->smb2.in.function = FSCTL_SRV_COPYCHUNK;
+ io->smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp);
+ io->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_STRUCTPN(cc_copy);
+ memcpy(cc_copy->source_key, res_key.resume_key, ARRAY_SIZE(cc_copy->source_key));
+ cc_copy->chunk_count = nchunks;
+ cc_copy->chunks = talloc_zero_array(mem_ctx, struct srv_copychunk, nchunks);
+ torture_assert(torture, (cc_copy->chunks != NULL), "no memory for chunks");
+
+ return true;
+}
+
+
+static bool check_copy_chunk_rsp(struct torture_context *torture,
+ struct srv_copychunk_rsp *cc_rsp,
+ uint32_t ex_chunks_written,
+ uint32_t ex_chunk_bytes_written,
+ uint32_t ex_total_bytes_written)
+{
+ torture_assert_int_equal(torture, cc_rsp->chunks_written,
+ ex_chunks_written, "num chunks");
+ torture_assert_int_equal(torture, cc_rsp->chunk_bytes_written,
+ ex_chunk_bytes_written, "chunk bytes written");
+ torture_assert_int_equal(torture, cc_rsp->total_bytes_written,
+ ex_total_bytes_written, "chunk total bytes");
+ return true;
+}
+
+static bool neg_aapl_copyfile(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ uint64_t flags)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = "aapl";
+ NTSTATUS status;
+ struct smb2_create io;
+ DATA_BLOB data;
+ struct smb2_create_blob *aapl = NULL;
+ uint32_t aapl_cmd;
+ uint32_t aapl_reply_bitmap;
+ uint32_t aapl_server_caps;
+ bool ret = true;
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
+ io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ io.in.share_access = (NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE);
+ io.in.fname = fname;
+
+ data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t));
+ SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY);
+ SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS));
+ SBVAL(data.data, 16, flags);
+
+ status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_create(tree, tctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ aapl = smb2_create_blob_find(&io.out.blobs,
+ SMB2_CREATE_TAG_AAPL);
+ if (aapl == NULL) {
+ ret = false;
+ goto done;
+
+ }
+ if (aapl->data.length < 24) {
+ ret = false;
+ goto done;
+ }
+
+ aapl_cmd = IVAL(aapl->data.data, 0);
+ if (aapl_cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected cmd: %d",
+ __location__, (int)aapl_cmd);
+ ret = false;
+ goto done;
+ }
+
+ aapl_reply_bitmap = BVAL(aapl->data.data, 8);
+ if (!(aapl_reply_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected reply_bitmap: %d",
+ __location__, (int)aapl_reply_bitmap);
+ ret = false;
+ goto done;
+ }
+
+ aapl_server_caps = BVAL(aapl->data.data, 16);
+ if (!(aapl_server_caps & flags)) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) unexpected server_caps: %d",
+ __location__, (int)aapl_server_caps);
+ ret = false;
+ goto done;
+ }
+
+done:
+ status = smb2_util_close(tree, io.out.file.handle);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ smb2_util_unlink(tree, "aapl");
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_copyfile(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl io;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+ const char *sname = ":foo" "\xef\x80\xa2" "bar:$DATA";
+
+ /*
+ * First test a copy_chunk with a 0 chunk count without having
+ * enabled this via AAPL. The request must not fail and the
+ * copied length in the response must be 0. This is verified
+ * against Windows 2008r2.
+ */
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 0, /* 0 chunks, copyfile semantics */
+ FNAME_CC_SRC,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ FNAME_CC_DST,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ if (!ok) {
+ torture_fail_goto(torture, done, "setup copy chunk error");
+ }
+
+ ndr_ret = ndr_push_struct_blob(&io.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&io.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 0, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 0); /* total bytes written */
+ if (!ok) {
+ torture_fail_goto(torture, done, "bad copy chunk response data");
+ }
+
+ /*
+ * Now enable AAPL copyfile and test again, the file and the
+ * stream must be copied by the server.
+ */
+ ok = neg_aapl_copyfile(torture, tree,
+ SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE);
+ if (!ok) {
+ torture_skip_goto(torture, done, "missing AAPL copyfile");
+ goto done;
+ }
+
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ smb2_util_unlink(tree, FNAME_CC_SRC);
+ smb2_util_unlink(tree, FNAME_CC_DST);
+
+ ok = torture_setup_file(tmp_ctx, tree, FNAME_CC_SRC, false);
+ if (!ok) {
+ torture_fail(torture, "setup file error");
+ }
+ ok = write_stream(tree, __location__, torture, tmp_ctx,
+ FNAME_CC_SRC, AFPRESOURCE_STREAM,
+ 10, 10, "1234567890");
+ if (!ok) {
+ torture_fail(torture, "setup stream error");
+ }
+
+ ok = write_stream(tree, __location__, torture, tmp_ctx,
+ FNAME_CC_SRC, sname,
+ 10, 10, "abcdefghij");
+ torture_assert_goto(torture, ok == true, ok, done, "write_stream failed\n");
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 0, /* 0 chunks, copyfile semantics */
+ FNAME_CC_SRC,
+ &src_h, 4096, /* fill 4096 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ FNAME_CC_DST,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ if (!ok) {
+ torture_fail_goto(torture, done, "setup copy chunk error");
+ }
+
+ ndr_ret = ndr_push_struct_blob(&io.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&io.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 0, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 4096); /* total bytes written */
+ if (!ok) {
+ torture_fail_goto(torture, done, "bad copy chunk response data");
+ }
+
+ ok = test_setup_open(torture, tree, tmp_ctx, FNAME_CC_DST, &dest_h,
+ SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL);
+ if (!ok) {
+ torture_fail_goto(torture, done,"open failed");
+ }
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0);
+ if (!ok) {
+ torture_fail_goto(torture, done, "inconsistent file data");
+ }
+
+ ok = check_stream(tree, __location__, torture, tmp_ctx,
+ FNAME_CC_DST, AFPRESOURCE_STREAM,
+ 0, 20, 10, 10, "1234567890");
+ if (!ok) {
+ torture_fail_goto(torture, done, "inconsistent stream data");
+ }
+
+ ok = check_stream(tree, __location__, torture, tmp_ctx,
+ FNAME_CC_DST, sname,
+ 0, 20, 10, 10, "abcdefghij");
+ torture_assert_goto(torture, ok == true, ok, done, "check_stream failed\n");
+
+done:
+ smb2_util_close(tree, src_h);
+ smb2_util_close(tree, dest_h);
+ smb2_util_unlink(tree, FNAME_CC_SRC);
+ smb2_util_unlink(tree, FNAME_CC_DST);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+static bool check_stream_list(struct smb2_tree *tree,
+ struct torture_context *tctx,
+ const char *fname,
+ int num_exp,
+ const char **exp,
+ bool is_dir)
+{
+ bool ret = true;
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ char **exp_sort;
+ struct stream_struct *stream_sort;
+ struct smb2_create create;
+ struct smb2_handle h;
+
+ ZERO_STRUCT(h);
+ torture_assert_goto(tctx, tmp_ctx != NULL, ret, done, "talloc_new failed");
+
+ ZERO_STRUCT(create);
+ create.in.fname = fname;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.create_options = is_dir ? NTCREATEX_OPTIONS_DIRECTORY : 0;
+ create.in.file_attributes = is_dir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ status = smb2_create(tree, tmp_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ h = create.out.file.handle;
+
+ finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
+ finfo.generic.in.file.handle = h;
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "get stream info");
+
+ smb2_util_close(tree, h);
+
+ torture_assert_int_equal_goto(tctx, finfo.stream_info.out.num_streams, num_exp,
+ ret, done, "stream count");
+
+ if (num_exp == 0) {
+ TALLOC_FREE(tmp_ctx);
+ goto done;
+ }
+
+ exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
+ torture_assert_goto(tctx, exp_sort != NULL, ret, done, __location__);
+
+ TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
+
+ stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
+ finfo.stream_info.out.num_streams *
+ sizeof(*stream_sort));
+ torture_assert_goto(tctx, stream_sort != NULL, ret, done, __location__);
+
+ TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
+
+ for (i=0; i<num_exp; i++) {
+ torture_comment(tctx, "i[%d] exp[%s] got[%s]\n",
+ i, exp_sort[i], stream_sort[i].stream_name.s);
+ torture_assert_str_equal_goto(tctx, stream_sort[i].stream_name.s, exp_sort[i],
+ ret, done, "stream name");
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+static bool check_stream_list_handle(struct smb2_tree *tree,
+ struct torture_context *tctx,
+ struct smb2_handle h,
+ int num_exp,
+ const char **exp,
+ bool is_dir)
+{
+ bool ret = true;
+ union smb_fileinfo finfo;
+ NTSTATUS status;
+ int i;
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ char **exp_sort;
+ struct stream_struct *stream_sort;
+
+ torture_assert_goto(tctx, tmp_ctx != NULL, ret, done,
+ "talloc_new failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .stream_info.level = RAW_FILEINFO_STREAM_INFORMATION,
+ .stream_info.in.file.handle = h,
+ };
+
+ status = smb2_getinfo_file(tree, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "get stream info\n");
+
+ torture_assert_int_equal_goto(tctx, finfo.stream_info.out.num_streams,
+ num_exp, ret, done, "stream count\n");
+
+ if (num_exp == 0) {
+ TALLOC_FREE(tmp_ctx);
+ goto done;
+ }
+
+ exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp));
+ torture_assert_goto(tctx, exp_sort != NULL, ret, done, __location__);
+
+ TYPESAFE_QSORT(exp_sort, num_exp, qsort_string);
+
+ stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams,
+ finfo.stream_info.out.num_streams *
+ sizeof(*stream_sort));
+ torture_assert_goto(tctx, stream_sort != NULL, ret, done, __location__);
+
+ TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream);
+
+ for (i=0; i<num_exp; i++) {
+ torture_comment(tctx, "i[%d] exp[%s] got[%s]\n",
+ i, exp_sort[i], stream_sort[i].stream_name.s);
+ torture_assert_str_equal_goto(tctx, stream_sort[i].stream_name.s,
+ exp_sort[i], ret, done,
+ "stream name\n");
+ }
+
+done:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+/*
+ test stream names
+*/
+static bool test_stream_names(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_handle h;
+ const char *fname = BASEDIR "\\stream_names.txt";
+ const char *sname1;
+ bool ret;
+ /* UTF8 private use are starts at 0xef 0x80 0x80 (0xf000) */
+ const char *streams[] = {
+ ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */
+ "::$DATA"
+ };
+
+ sname1 = talloc_asprintf(mem_ctx, "%s%s", fname, streams[0]);
+
+ /* clean slate ...*/
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret, ret, done, "torture_setup_file");
+
+ torture_comment(tctx, "(%s) testing stream names\n", __location__);
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_WRITE_DATA;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname1;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, create.out.file.handle, "foo", 0, 3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ smb2_util_close(tree, create.out.file.handle);
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams, false);
+ CHECK_VALUE(ret, true);
+
+done:
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+/* Renaming a directory with open file, should work for OS X AAPL clients */
+static bool test_rename_dir_openfile(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ union smb_open io;
+ union smb_close cl;
+ union smb_setfileinfo sinfo;
+ struct smb2_handle d1, h1;
+ const char *renamedir = BASEDIR "-new";
+ bool server_is_osx = torture_setting_bool(torture, "osx", false);
+
+ smb2_deltree(tree, BASEDIR);
+ smb2_util_rmdir(tree, BASEDIR);
+ smb2_deltree(tree, renamedir);
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ torture_assert_ntstatus_ok(torture, status, "smb2_create dir");
+ d1 = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.create_flags = 0;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR "\\file.txt";
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ torture_assert_ntstatus_ok(torture, status, "smb2_create file");
+ h1 = io.smb2.out.file.handle;
+
+ if (!server_is_osx) {
+ torture_comment(torture, "Renaming directory without AAPL, must fail\n");
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = d1;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = renamedir;
+ status = smb2_setinfo_file(tree, &sinfo);
+
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_ACCESS_DENIED,
+ "smb2_setinfo_file");
+ }
+
+ status = smb2_util_close(tree, d1);
+ torture_assert_ntstatus_ok(torture, status, "smb2_util_close\n");
+ ZERO_STRUCT(d1);
+
+ torture_comment(torture, "Enabling AAPL\n");
+
+ ret = enable_aapl(torture, tree);
+ torture_assert(torture, ret == true, "enable_aapl failed");
+
+ torture_comment(torture, "Renaming directory with AAPL\n");
+
+ ZERO_STRUCT(io.smb2);
+ io.generic.level = RAW_OPEN_SMB2;
+ io.smb2.in.desired_access = 0x0017019f;
+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.smb2.in.share_access = 0;
+ io.smb2.in.alloc_size = 0;
+ io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ io.smb2.in.security_flags = 0;
+ io.smb2.in.fname = BASEDIR;
+
+ status = smb2_create(tree, torture, &(io.smb2));
+ torture_assert_ntstatus_ok(torture, status, "smb2_create dir");
+ d1 = io.smb2.out.file.handle;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = d1;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = renamedir;
+
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_ok(torture, status, "smb2_setinfo_file");
+
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = d1;
+ status = smb2_close(tree, &(cl.smb2));
+ torture_assert_ntstatus_ok(torture, status, "smb2_close");
+ ZERO_STRUCT(d1);
+
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree, &(cl.smb2));
+ torture_assert_ntstatus_ok(torture, status, "smb2_close");
+ ZERO_STRUCT(h1);
+
+ torture_comment(torture, "Cleaning up\n");
+
+ if (h1.data[0] || h1.data[1]) {
+ ZERO_STRUCT(cl.smb2);
+ cl.smb2.level = RAW_CLOSE_SMB2;
+ cl.smb2.in.file.handle = h1;
+ status = smb2_close(tree, &(cl.smb2));
+ }
+
+ smb2_util_unlink(tree, BASEDIR "\\file.txt");
+ smb2_util_unlink(tree, BASEDIR "-new\\file.txt");
+ smb2_deltree(tree, renamedir);
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_afpinfo_enoent(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME;
+
+ torture_comment(tctx, "Opening file without AFP_AfpInfo\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ torture_comment(tctx, "Opening not existing AFP_AfpInfo\n");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; /* stat open */
+ create.in.fname = sname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpInfo stream");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_create_delete_on_close(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME;
+ const char *type_creator = "SMB,OLE!";
+ AfpInfo *info = NULL;
+ const char *streams_basic[] = {
+ "::$DATA"
+ };
+ const char *streams_afpinfo[] = {
+ "::$DATA",
+ AFPINFO_STREAM
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ torture_comment(tctx, "Checking whether create with delete-on-close work with AFP_AfpInfo\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ torture_comment(tctx, "Opening not existing AFP_AfpInfo\n");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; /* stat open */
+ create.in.fname = sname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpInfo stream");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpInfo stream");
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ torture_comment(tctx, "Deleting AFP_AfpInfo via create with delete-on-close\n");
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed");
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad type/creator in AFP_AfpInfo");
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+ smb2_util_close(tree, h1);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpInfo stream");
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_setinfo_delete_on_close(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ union smb_setfileinfo sfinfo;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME;
+ const char *type_creator = "SMB,OLE!";
+ AfpInfo *info = NULL;
+ const char *streams[] = {
+ AFPINFO_STREAM,
+ "::$DATA"
+ };
+ const char *streams_basic[] = {
+ "::$DATA"
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ torture_comment(tctx, "Deleting AFP_AfpInfo via setinfo with delete-on-close\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed");
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ /* Delete stream via setinfo delete-on-close */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set delete-on-close failed");
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_DELETE_PENDING,
+ ret, done, "Got unexpected AFP_AfpInfo stream");
+
+ smb2_util_close(tree, h1);
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpInfo stream");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_setinfo_eof(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ union smb_setfileinfo sfinfo;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME;
+ const char *type_creator = "SMB,OLE!";
+ AfpInfo *info = NULL;
+ const char *streams_afpinfo[] = {
+ "::$DATA",
+ AFPINFO_STREAM
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ torture_comment(tctx, "Set AFP_AfpInfo EOF to 61, 1 and 0\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed");
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ torture_comment(tctx, "Set AFP_AfpInfo EOF to 61\n");
+
+ /* Test setinfo end-of-file info */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 61;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ALLOTTED_SPACE_EXCEEDED,
+ ret, done, "set eof 61 failed");
+
+ torture_comment(tctx, "Set AFP_AfpInfo EOF to 1\n");
+
+ /* Truncation returns success, but has no effect */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status,
+ ret, done, "set eof 1 failed");
+ smb2_util_close(tree, h1);
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(tctx, ret == true, ret, done, "FinderInfo changed");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ /*
+ * Delete stream via setinfo end-of-file info to 0, should
+ * return success but stream MUST NOT deleted
+ */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 0;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set eof 0 failed");
+
+ smb2_util_close(tree, h1);
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(tctx, ret == true, ret, done, "FinderInfo changed");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_afpinfo_all0(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle baseh = {{0}};
+ union smb_setfileinfo setfinfo;
+ union smb_fileinfo getfinfo;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPINFO_STREAM;
+ const char *type_creator = "SMB,OLE!";
+ AfpInfo *info = NULL;
+ char *infobuf = NULL;
+ const char *streams_basic[] = {
+ "::$DATA"
+ };
+ const char *streams_afpinfo[] = {
+ "::$DATA",
+ AFPINFO_STREAM
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ torture_comment(tctx, "Write all 0 to AFP_AfpInfo and see what happens\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed");
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ /* Write all 0 to AFP_AfpInfo */
+ memset(info->afpi_FinderInfo, 0, AFP_FinderSize);
+ infobuf = torture_afpinfo_pack(mem_ctx, info);
+ torture_assert_not_null_goto(tctx, infobuf, ret, done,
+ "torture_afpinfo_pack failed\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.fname = fname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ baseh = create.out.file.handle;
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h1 = create.out.file.handle;
+
+ status = smb2_util_write(tree, h1, infobuf, 0, AFP_INFO_SIZE);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ /*
+ * Get stream information on open handle, must return only default
+ * stream, the AFP_AfpInfo stream must not be returned.
+ */
+
+ ZERO_STRUCT(getfinfo);
+ getfinfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION;
+ getfinfo.generic.in.file.handle = baseh;
+
+ status = smb2_getinfo_file(tree, tctx, &getfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "get stream info\n");
+
+ torture_assert_int_equal_goto(tctx, getfinfo.stream_info.out.num_streams,
+ 1, ret, done, "stream count");
+
+ smb2_util_close(tree, baseh);
+ ZERO_STRUCT(baseh);
+
+ /*
+ * Try to set some file-basic-info (time) on the stream. This catches
+ * naive implementation mistakes that simply deleted the backing store
+ * from the filesystem in the zero-out step.
+ */
+
+ ZERO_STRUCT(setfinfo);
+ unix_to_nt_time(&setfinfo.basic_info.in.write_time, time(NULL));
+ setfinfo.basic_info.in.attrib = 0x20;
+ setfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
+ setfinfo.generic.in.file.handle = h1;
+
+ status = smb2_setinfo_file(tree, &setfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list");
+
+ smb2_util_close(tree, h1);
+ ZERO_STRUCT(h1);
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+done:
+ if (!smb2_util_handle_empty(h1)) {
+ smb2_util_close(tree, h1);
+ }
+ if (!smb2_util_handle_empty(baseh)) {
+ smb2_util_close(tree, baseh);
+ }
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_create_delete_on_close_resource(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPRESOURCE_STREAM_NAME;
+ const char *streams_basic[] = {
+ "::$DATA"
+ };
+ const char *streams_afpresource[] = {
+ "::$DATA",
+ AFPRESOURCE_STREAM
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ torture_comment(tctx, "Checking whether create with delete-on-close is ignored for AFP_AfpResource\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok(tctx, status, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ torture_comment(tctx, "Opening not existing AFP_AfpResource\n");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; /* stat open */
+ create.in.fname = sname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpResource stream");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Got unexpected AFP_AfpResource stream");
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ torture_comment(tctx, "Trying to delete AFP_AfpResource via create with delete-on-close\n");
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 0, 10, "1234567890");
+ torture_assert_goto(tctx, ret == true, ret, done, "Writing to AFP_AfpResource failed");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM_NAME,
+ 0, 10, 0, 10, "1234567890");
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad content from AFP_AfpResource");
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpresource, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+ smb2_util_close(tree, h1);
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpresource, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM_NAME,
+ 0, 10, 0, 10, "1234567890");
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad content from AFP_AfpResource");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_setinfo_delete_on_close_resource(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ union smb_setfileinfo sfinfo;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPRESOURCE_STREAM_NAME;
+ const char *streams_afpresource[] = {
+ "::$DATA",
+ AFPRESOURCE_STREAM
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ torture_comment(tctx, "Trying to delete AFP_AfpResource via setinfo with delete-on-close\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 10, 10, "1234567890");
+ torture_assert_goto(tctx, ret == true, ret, done, "Writing to AFP_AfpResource failed");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ /* Try to delete stream via setinfo delete-on-close */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.disposition_info.in.delete_on_close = 1;
+ sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
+ sfinfo.generic.in.file.handle = h1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set delete-on-close failed");
+
+ smb2_util_close(tree, h1);
+
+ ret = check_stream_list(tree, tctx, fname, 2, streams_afpresource, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "Got unexpected AFP_AfpResource stream");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+static bool test_setinfo_eof_resource(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ union smb_setfileinfo sfinfo;
+ union smb_fileinfo finfo;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file" AFPRESOURCE_STREAM_NAME;
+ const char *streams_basic[] = {
+ "::$DATA"
+ };
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new");
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ torture_comment(tctx, "Set AFP_AfpResource EOF to 1 and 0\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree, h1);
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 10, 10, "1234567890");
+ torture_assert_goto(tctx, ret == true, ret, done, "Writing to AFP_AfpResource failed");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ torture_comment(tctx, "Set AFP_AfpResource EOF to 1\n");
+
+ /* Test setinfo end-of-file info */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status,
+ ret, done, "set eof 1 failed");
+
+ smb2_util_close(tree, h1);
+
+ /* Check size == 1 */
+ ZERO_STRUCT(create);
+ create.in.fname = sname;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
+ finfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed");
+
+ smb2_util_close(tree, h1);
+
+ torture_assert_goto(tctx, finfo.all_info.out.size == 1, ret, done, "size != 1");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ /*
+ * Delete stream via setinfo end-of-file info to 0, this
+ * should delete the stream.
+ */
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 0;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set eof 0 failed");
+
+ smb2_util_close(tree, h1);
+
+ ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.fname = sname;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "smb2_create failed");
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+/*
+ * This tests that right after creating the AFP_AfpInfo stream,
+ * reading from the stream returns an empty, default metadata blob of
+ * 60 bytes.
+ *
+ * NOTE: against OS X SMB server this only works if the read request
+ * is compounded with the create that created the stream, is fails
+ * otherwise. We don't care...
+ */
+static bool test_null_afpinfo(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = "test_null_afpinfo";
+ const char *sname = "test_null_afpinfo" AFPINFO_STREAM_NAME;
+ NTSTATUS status;
+ bool ret = true;
+ struct smb2_request *req[3];
+ struct smb2_handle handle;
+ struct smb2_create create;
+ struct smb2_read read;
+ AfpInfo *afpinfo = NULL;
+ char *afpinfo_buf = NULL;
+ const char *type_creator = "SMB,OLE!";
+ struct smb2_handle handle2;
+ struct smb2_read r;
+
+ torture_comment(tctx, "Checking create of AfpInfo stream\n");
+
+ smb2_util_unlink(tree, fname);
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
+ create.in.share_access = FILE_SHARE_READ | FILE_SHARE_DELETE;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.fname = sname;
+
+ smb2_transport_compound_start(tree->session->transport, 2);
+
+ req[0] = smb2_create_send(tree, &create);
+
+ handle.data[0] = UINT64_MAX;
+ handle.data[1] = UINT64_MAX;
+
+ smb2_transport_compound_set_related(tree->session->transport, true);
+
+ ZERO_STRUCT(read);
+ read.in.file.handle = handle;
+ read.in.length = AFP_INFO_SIZE;
+ req[1] = smb2_read_send(tree, &read);
+
+ status = smb2_create_recv(req[0], tree, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_recv failed");
+
+ handle = create.out.file.handle;
+
+ status = smb2_read_recv(req[1], tree, &read);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_read_recv failed");
+
+ status = torture_smb2_testfile_access(tree, sname, &handle2,
+ SEC_FILE_READ_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+ r = (struct smb2_read) {
+ .in.file.handle = handle2,
+ .in.length = AFP_INFO_SIZE,
+ };
+
+ status = smb2_read(tree, tree, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+ smb2_util_close(tree, handle2);
+
+ afpinfo = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, afpinfo != NULL, ret, done, "torture_afpinfo_new failed");
+
+ memcpy(afpinfo->afpi_FinderInfo, type_creator, 8);
+
+ afpinfo_buf = torture_afpinfo_pack(tctx, afpinfo);
+ torture_assert_goto(tctx, afpinfo_buf != NULL, ret, done, "torture_afpinfo_new failed");
+
+ status = smb2_util_write(tree, handle, afpinfo_buf, 0, AFP_INFO_SIZE);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write failed");
+
+ smb2_util_close(tree, handle);
+
+ ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+done:
+ smb2_util_unlink(tree, fname);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_delete_file_with_rfork(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "torture_write_rfork_io";
+ const char *rfork_content = "1234567890";
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_util_unlink(tree, fname);
+
+ torture_comment(tctx, "Test deleting file with resource fork\n");
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed\n");
+
+ ret = write_stream(tree, __location__, tctx, tctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 10, 10, rfork_content);
+ torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed\n");
+
+ ret = check_stream(tree, __location__, tctx, tctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 0, 20, 10, 10, rfork_content);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed\n");
+
+ status = smb2_util_unlink(tree, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "check_stream failed\n");
+
+done:
+ return ret;
+}
+
+static bool test_rename_and_read_rsrc(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create, create2;
+ struct smb2_handle h1, h2;
+ const char *fname = "test_rename_openfile";
+ const char *sname = "test_rename_openfile" AFPRESOURCE_STREAM_NAME;
+ const char *fname_renamed = "test_rename_openfile_renamed";
+ const char *data = "1234567890";
+ union smb_setfileinfo sinfo;
+ bool server_is_macos = torture_setting_bool(tctx, "osx", false);
+ NTSTATUS expected_status;
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ torture_comment(tctx, "Create file with resource fork\n");
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ ret = write_stream(tree, __location__, tctx, tctx,
+ fname, AFPRESOURCE_STREAM_NAME, 0, 10, data);
+ torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed");
+
+ torture_comment(tctx, "Open resource fork\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h1 = create.out.file.handle;
+
+ torture_comment(tctx, "Rename base file\n");
+
+ ZERO_STRUCT(create2);
+ create2.in.desired_access = SEC_FILE_ALL;
+ create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create2.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ create2.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &create2);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ h2 = create2.out.file.handle;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h2;
+ sinfo.rename_information.in.overwrite = 0;
+ sinfo.rename_information.in.root_fid = 0;
+ sinfo.rename_information.in.new_name = fname_renamed;
+
+ if (server_is_macos) {
+ expected_status = NT_STATUS_SHARING_VIOLATION;
+ } else {
+ expected_status = NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = smb2_setinfo_file(tree, &sinfo);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, expected_status, ret, done,
+ "smb2_setinfo_file failed");
+
+ smb2_util_close(tree, h2);
+
+ status = smb2_util_write(tree, h1, "foo", 0, 3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "write failed\n");
+
+ smb2_util_close(tree, h1);
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_unlink(tree, fname_renamed);
+
+ return ret;
+}
+
+static bool test_readdir_attr_illegal_ntfs(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *name = "test" "\xef\x80\xa2" "aapl"; /* "test:aapl" */
+ const char *fname = BASEDIR "\\test" "\xef\x80\xa2" "aapl"; /* "test:aapl" */
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create io;
+ AfpInfo *info;
+ const char *type_creator = "SMB,OLE!";
+ struct smb2_find f;
+ unsigned int count;
+ union smb_search_data *d;
+ uint64_t rfork_len;
+ unsigned int i;
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
+ smb2_util_close(tree, testdirh);
+
+ torture_comment(tctx, "Enabling AAPL\n");
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ /*
+ * Now that Requested AAPL extensions are enabled, setup some
+ * Mac files with metadata and resource fork
+ */
+
+ torture_comment(tctx, "Preparing file\n");
+
+ ret = torture_setup_file(mem_ctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed");
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_not_null_goto(tctx, info, ret, done, "torture_afpinfo_new failed");
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ret = write_stream(tree, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 0, 3, "foo");
+ torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed");
+
+ /*
+ * Ok, file is prepared, now call smb2/find
+ */
+
+ torture_comment(tctx, "Issue find\n");
+
+ ZERO_STRUCT(io);
+ io.in.desired_access = SEC_RIGHTS_DIR_READ;
+ io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+ io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ io.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE |
+ NTCREATEX_SHARE_ACCESS_DELETE);
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.fname = BASEDIR;
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
+
+ ZERO_STRUCT(f);
+ f.in.file.handle = io.out.file.handle;
+ f.in.pattern = "*";
+ f.in.max_response_size = 0x1000;
+ f.in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
+
+ status = smb2_find_level(tree, tree, &f, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_level failed");
+
+ status = smb2_util_close(tree, io.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed");
+
+ torture_comment(tctx, "Checking find response with enriched macOS metadata\n");
+
+ for (i = 0; i < count; i++) {
+ const char *found = d[i].id_both_directory_info.name.s;
+
+ if (!strcmp(found, ".") || !strcmp(found, ".."))
+ continue;
+ if (strncmp(found, "._", 2) == 0) {
+ continue;
+ }
+ break;
+ }
+
+ torture_assert_str_equal_goto(tctx,
+ d[i].id_both_directory_info.name.s, name,
+ ret, done, "bad name");
+
+ rfork_len = BVAL(d[i].id_both_directory_info.short_name_buf, 0);
+ torture_assert_int_equal_goto(tctx, rfork_len, 3, ret, done, "bad resource fork length");
+
+ torture_assert_mem_equal_goto(tctx, type_creator,
+ d[i].id_both_directory_info.short_name_buf + 8,
+ 8, ret, done, "Bad FinderInfo");
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_invalid_afpinfo(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = "filtest_invalid_afpinfo";
+ const char *sname = "filtest_invalid_afpinfo" AFPINFO_STREAM_NAME;
+ struct smb2_create create;
+ const char *streams_basic[] = {
+ "::$DATA"
+ };
+ const char *streams_afpinfo[] = {
+ "::$DATA",
+ AFPINFO_STREAM
+ };
+ NTSTATUS status;
+ bool ret = true;
+
+ if (tree2 == NULL) {
+ torture_skip_goto(tctx, done, "need second share without fruit\n");
+ }
+
+ torture_comment(tctx, "Testing invalid AFP_AfpInfo stream\n");
+
+ ret = torture_setup_file(tctx, tree2, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ ret = write_stream(tree2, __location__, tctx, tctx,
+ fname, AFPINFO_STREAM_NAME,
+ 0, 3, "foo");
+ torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed");
+
+ ret = check_stream_list(tree2, tctx, fname, 2, streams_afpinfo, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ torture_comment(tctx, "Listing streams, bad AFPINFO stream must not be present\n");
+
+ ret = check_stream_list(tree1, tctx, fname, 1, streams_basic, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ torture_comment(tctx, "Try to open AFPINFO stream, must fail\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
+ create.in.fname = sname;
+
+ status = smb2_create(tree1, tctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Stream still around?");
+
+done:
+ smb2_util_unlink(tree1, fname);
+ return ret;
+}
+
+static bool test_writing_afpinfo(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "filtest_invalid_afpinfo";
+ const char *sname = "filtest_invalid_afpinfo" AFPINFO_STREAM;
+ const char *streams_afpinfo[] = {
+ "::$DATA",
+ AFPINFO_STREAM
+ };
+ bool ret = true;
+ static AfpInfo *afpi = NULL;
+ char *buf = NULL;
+ char *afpi_buf = NULL;
+ char *zero_buf = NULL;
+ bool broken_osx = torture_setting_bool(tctx, "broken_osx_45759458", false);
+ off_t min_offset_for_2streams = 16;
+ int i;
+ NTSTATUS status;
+ struct test_sizes {
+ off_t offset;
+ size_t size;
+ bool expected_result;
+ } test_sizes[] = {
+ { 0, 1, false},
+ { 0, 2, false},
+ { 0, 3, true},
+ { 0, 4, true},
+ { 0, 14, true},
+ { 0, 15, true},
+ { 0, 16, true},
+ { 0, 24, true},
+ { 0, 34, true},
+ { 0, 44, true},
+ { 0, 54, true},
+ { 0, 55, true},
+ { 0, 56, true},
+ { 0, 57, true},
+ { 0, 58, true},
+ { 0, 59, true},
+ { 0, 60, true},
+ { 0, 61, true},
+ { 0, 64, true},
+ { 0, 1024, true},
+ { 0, 10064, true},
+
+ { 1, 1, false},
+ { 1, 2, false},
+ { 1, 3, false},
+ { 1, 4, false},
+ { 1, 14, false},
+ { 1, 15, false},
+ { 1, 16, false},
+ { 1, 24, false},
+ { 1, 34, false},
+ { 1, 44, false},
+ { 1, 54, false},
+ { 1, 55, false},
+ { 1, 56, false},
+ { 1, 57, false},
+ { 1, 58, false},
+ { 1, 59, false},
+ { 1, 60, true},
+ { 1, 61, true},
+ { 1, 1024, true},
+ { 1, 10064, true},
+
+ { 30, 1, false},
+ { 30, 2, false},
+ { 30, 3, false},
+ { 30, 4, false},
+ { 30, 14, false},
+ { 30, 15, false},
+ { 30, 16, false},
+ { 30, 24, false},
+ { 30, 34, false},
+ { 30, 44, false},
+ { 30, 54, false},
+ { 30, 55, false},
+ { 30, 56, false},
+ { 30, 57, false},
+ { 30, 58, false},
+ { 30, 59, false},
+ { 30, 60, true},
+ { 30, 61, true},
+ { 30, 1024, true},
+ { 30, 10064, true},
+
+ { 58, 1, false},
+ { 58, 2, false},
+ { 58, 3, false},
+ { 58, 4, false},
+ { 58, 14, false},
+ { 58, 15, false},
+ { 58, 16, false},
+ { 58, 24, false},
+ { 58, 34, false},
+ { 58, 44, false},
+ { 58, 54, false},
+ { 58, 55, false},
+ { 58, 56, false},
+ { 58, 57, false},
+ { 58, 58, false},
+ { 58, 59, false},
+ { 58, 60, true},
+ { 58, 61, true},
+ { 58, 1024, true},
+ { 58, 10064, true},
+
+ { 59, 1, false},
+ { 59, 2, false},
+ { 59, 3, false},
+ { 59, 4, false},
+ { 59, 14, false},
+ { 59, 15, false},
+ { 59, 16, false},
+ { 59, 24, false},
+ { 59, 34, false},
+ { 59, 44, false},
+ { 59, 54, false},
+ { 59, 55, false},
+ { 59, 56, false},
+ { 59, 57, false},
+ { 59, 58, false},
+ { 59, 59, false},
+ { 59, 60, true},
+ { 59, 61, true},
+ { 59, 1024, true},
+ { 59, 10064, true},
+
+ { 60, 1, false},
+ { 60, 2, false},
+ { 60, 3, false},
+ { 60, 4, false},
+ { 60, 14, false},
+ { 60, 15, false},
+ { 60, 16, false},
+ { 60, 24, false},
+ { 60, 34, false},
+ { 60, 44, false},
+ { 60, 54, false},
+ { 60, 55, false},
+ { 60, 56, false},
+ { 60, 57, false},
+ { 60, 58, false},
+ { 60, 59, false},
+ { 60, 60, true},
+ { 60, 61, true},
+ { 60, 1024, true},
+ { 60, 10064, true},
+
+ { 61, 1, false},
+ { 61, 2, false},
+ { 61, 3, false},
+ { 61, 4, false},
+ { 61, 14, false},
+ { 61, 15, false},
+ { 61, 16, false},
+ { 61, 24, false},
+ { 61, 34, false},
+ { 61, 44, false},
+ { 61, 54, false},
+ { 61, 55, false},
+ { 61, 56, false},
+ { 61, 57, false},
+ { 61, 58, false},
+ { 61, 59, false},
+ { 61, 60, true},
+ { 61, 61, true},
+ { 61, 1024, true},
+ { 61, 10064, true},
+
+ { 10000, 1, false},
+ { 10000, 2, false},
+ { 10000, 3, false},
+ { 10000, 4, false},
+ { 10000, 14, false},
+ { 10000, 15, false},
+ { 10000, 16, false},
+ { 10000, 24, false},
+ { 10000, 34, false},
+ { 10000, 44, false},
+ { 10000, 54, false},
+ { 10000, 55, false},
+ { 10000, 56, false},
+ { 10000, 57, false},
+ { 10000, 58, false},
+ { 10000, 59, false},
+ { 10000, 60, true},
+ { 10000, 61, true},
+ { 10000, 1024, true},
+ { 10000, 10064, true},
+
+ { -1, 0, false},
+ };
+
+ afpi = torture_afpinfo_new(tctx);
+ torture_assert_not_null_goto(tctx, afpi, ret, done,
+ "torture_afpinfo_new failed\n");
+
+ memcpy(afpi->afpi_FinderInfo, "FOO BAR ", 8);
+
+ buf = torture_afpinfo_pack(afpi, afpi);
+ torture_assert_not_null_goto(tctx, buf, ret, done,
+ "torture_afpinfo_pack failed\n");
+
+ afpi_buf = talloc_zero_array(tctx, char, 10064);
+ torture_assert_not_null_goto(tctx, afpi_buf, ret, done,
+ "talloc_zero_array failed\n");
+ memcpy(afpi_buf, buf, 60);
+
+ zero_buf = talloc_zero_array(tctx, char, 10064);
+ torture_assert_not_null_goto(tctx, zero_buf, ret, done,
+ "talloc_zero_array failed\n");
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file\n");
+
+ for (i = 0; test_sizes[i].offset != -1; i++) {
+ struct smb2_handle h;
+ struct smb2_create c;
+ int expected_num_streams;
+ size_t fi_check_size;
+
+ torture_comment(tctx,
+ "Test %d: offset=%jd size=%zu result=%s\n",
+ i,
+ (intmax_t)test_sizes[i].offset,
+ test_sizes[i].size,
+ test_sizes[i].expected_result ? "true":"false");
+
+
+ c = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_WRITE_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.fname = sname,
+ };
+
+ status = smb2_create(tree, tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h = c.out.file.handle;
+
+ status = smb2_util_write(tree,
+ h,
+ zero_buf,
+ test_sizes[i].offset,
+ test_sizes[i].size);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_INVALID_PARAMETER,
+ ret, done, "smb2_util_write\n");
+
+ status = smb2_util_write(tree,
+ h,
+ afpi_buf,
+ test_sizes[i].offset,
+ test_sizes[i].size);
+ smb2_util_close(tree, h);
+ if (test_sizes[i].expected_result == true) {
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write\n");
+ } else {
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_INVALID_PARAMETER,
+ ret, done, "smb2_util_write\n");
+ }
+
+ if (broken_osx) {
+ /*
+ * Currently macOS has a bug (Radar #45759458) where it
+ * writes more bytes then requested from uninitialized
+ * memory to the filesystem. That means it will likely
+ * write data to FinderInfo so the stream is not empty
+ * and thus listed when the number of streams is
+ * queried.
+ */
+ min_offset_for_2streams = 2;
+ }
+
+ if ((test_sizes[i].expected_result == true) &&
+ (test_sizes[i].size > min_offset_for_2streams))
+ {
+ expected_num_streams = 2;
+ } else {
+ expected_num_streams = 1;
+ }
+
+ ret = check_stream_list(tree, tctx, fname,
+ expected_num_streams,
+ streams_afpinfo, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "Bad streams\n");
+
+ if (test_sizes[i].expected_result == false) {
+ continue;
+ }
+
+ if (test_sizes[i].size <= 16) {
+ /*
+ * FinderInfo with the "FOO BAR " string we wrote above
+ * would start at offset 16. Check whether this test
+ * wrote 1 byte or more.
+ */
+ goto next;
+ }
+
+ fi_check_size = test_sizes[i].size - 16;
+ fi_check_size = MIN(fi_check_size, 8);
+
+ ret = check_stream(tree, __location__,
+ tctx, tctx,
+ fname, AFPINFO_STREAM,
+ 0, 60, 16, fi_check_size, "FOO BAR ");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "Bad streams\n");
+
+next:
+ status = smb2_util_unlink(tree, sname);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ bool missing_ok;
+
+ missing_ok = test_sizes[i].expected_result == false;
+ missing_ok |= test_sizes[i].size <= 16;
+
+ torture_assert_goto(tctx, missing_ok,
+ ret, done, "smb2_util_unlink\n");
+ }
+ }
+
+done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+static bool test_zero_file_id(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "filtest_file_id";
+ struct smb2_create create = {0};
+ NTSTATUS status;
+ bool ret = true;
+ uint8_t zero_file_id[8] = {0};
+
+ torture_comment(tctx, "Testing zero file id\n");
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = fname;
+ create.in.query_on_disk_id = true;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret,
+ done,
+ "test file could not be opened");
+ torture_assert_mem_not_equal_goto(tctx, create.out.on_disk_id,
+ zero_file_id, 8, ret, done,
+ "unexpected zero file id");
+
+ smb2_util_close(tree, create.out.file.handle);
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert(tctx, ret == true, "enable_aapl failed");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = fname;
+ create.in.query_on_disk_id = true;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_OK, ret, done,
+ "test file could not be opened with AAPL");
+ torture_assert_mem_equal_goto(tctx, create.out.on_disk_id, zero_file_id,
+ 8, ret, done, "non-zero file id");
+
+ smb2_util_close(tree, create.out.file.handle);
+
+done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
+
+static bool copy_one_stream(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *tmp_ctx,
+ const char *src_sname,
+ const char *dst_sname)
+{
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ NTSTATUS status;
+ union smb_ioctl io;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ bool ok = false;
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ src_sname,
+ &src_h, 256, /* fill 256 byte src file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ dst_sname,
+ &dest_h, 0, /* 0 byte dest file */
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "setup copy chunk error\n");
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 256;
+
+ ndr_ret = ndr_push_struct_blob(
+ &io.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &io.smb2.out.out, tmp_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 256); /* total bytes written */
+ torture_assert_goto(torture, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 256, 0);
+ if (!ok) {
+ torture_fail(torture, "inconsistent file data\n");
+ }
+
+done:
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree, dest_h);
+ }
+
+ return ok;
+}
+
+static bool copy_finderinfo_stream(struct torture_context *torture,
+ struct smb2_tree *tree,
+ TALLOC_CTX *tmp_ctx,
+ const char *src_name,
+ const char *dst_name)
+{
+ struct smb2_handle src_h = {{0}};
+ struct smb2_handle dest_h = {{0}};
+ NTSTATUS status;
+ union smb_ioctl io;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+ const char *type_creator = "SMB,OLE!";
+ AfpInfo *info = NULL;
+ const char *src_name_afpinfo = NULL;
+ const char *dst_name_afpinfo = NULL;
+ bool ok = false;
+
+ src_name_afpinfo = talloc_asprintf(tmp_ctx, "%s%s", src_name,
+ AFPINFO_STREAM);
+ torture_assert_not_null_goto(torture, src_name_afpinfo, ok, done,
+ "talloc_asprintf failed\n");
+
+ dst_name_afpinfo = talloc_asprintf(tmp_ctx, "%s%s", dst_name,
+ AFPINFO_STREAM);
+ torture_assert_not_null_goto(torture, dst_name_afpinfo, ok, done,
+ "talloc_asprintf failed\n");
+
+ info = torture_afpinfo_new(tmp_ctx);
+ torture_assert_not_null_goto(torture, info, ok, done,
+ "torture_afpinfo_new failed\n");
+
+ memcpy(info->afpi_FinderInfo, type_creator, 8);
+ ok = torture_write_afpinfo(tree, torture, tmp_ctx, src_name, info);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "torture_write_afpinfo failed\n");
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* 1 chunk */
+ src_name_afpinfo,
+ &src_h, 0,
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ dst_name_afpinfo,
+ &dest_h, 0,
+ SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA,
+ &cc_copy,
+ &io);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "setup copy chunk error\n");
+
+ /* copy all src file data (via a single chunk desc) */
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 60;
+
+ ndr_ret = ndr_push_struct_blob(
+ &io.smb2.in.out, tmp_ctx, &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_push_srv_copychunk_copy\n");
+
+ status = smb2_ioctl(tree, tmp_ctx, &io.smb2);
+ torture_assert_ntstatus_ok_goto(torture, status, ok, done,
+ "FSCTL_SRV_COPYCHUNK\n");
+
+ ndr_ret = ndr_pull_struct_blob(
+ &io.smb2.out.out, tmp_ctx, &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+
+ torture_assert_ndr_success_goto(torture, ndr_ret, ok, done,
+ "ndr_pull_srv_copychunk_rsp\n");
+
+ smb2_util_close(tree, src_h);
+ ZERO_STRUCT(src_h);
+ smb2_util_close(tree, dest_h);
+ ZERO_STRUCT(dest_h);
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ 60); /* total bytes written */
+ torture_assert_goto(torture, ok == true, ok, done,
+ "bad copy chunk response data\n");
+
+ ok = check_stream(tree, __location__, torture, tmp_ctx,
+ dst_name, AFPINFO_STREAM,
+ 0, 60, 16, 8, type_creator);
+ torture_assert_goto(torture, ok == true, ok, done, "check_stream failed\n");
+
+done:
+ if (!smb2_util_handle_empty(src_h)) {
+ smb2_util_close(tree, src_h);
+ }
+ if (!smb2_util_handle_empty(dest_h)) {
+ smb2_util_close(tree, dest_h);
+ }
+
+ return ok;
+}
+
+static bool test_copy_chunk_streams(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ const char *src_name = "src";
+ const char *dst_name = "dst";
+ struct names {
+ const char *src_sname;
+ const char *dst_sname;
+ } names[] = {
+ { "src:foo", "dst:foo" },
+ { "src" AFPRESOURCE_STREAM, "dst" AFPRESOURCE_STREAM }
+ };
+ size_t i;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool ok = false;
+
+ tmp_ctx = talloc_new(tree);
+ torture_assert_not_null_goto(torture, tmp_ctx, ok, done,
+ "torture_setup_file\n");
+
+ smb2_util_unlink(tree, src_name);
+ smb2_util_unlink(tree, dst_name);
+
+ ok = torture_setup_file(torture, tree, src_name, false);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+ ok = torture_setup_file(torture, tree, dst_name, false);
+ torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n");
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ ok = copy_one_stream(torture, tree, tmp_ctx,
+ names[i].src_sname,
+ names[i].dst_sname);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "copy_one_stream failed\n");
+ }
+
+ ok = copy_finderinfo_stream(torture, tree, tmp_ctx,
+ src_name, dst_name);
+ torture_assert_goto(torture, ok == true, ok, done,
+ "copy_finderinfo_stream failed\n");
+
+done:
+ smb2_util_unlink(tree, src_name);
+ smb2_util_unlink(tree, dst_name);
+ talloc_free(tmp_ctx);
+ return ok;
+}
+
+/*
+ * Ensure this security descriptor has exactly one mode, uid
+ * and gid.
+ */
+
+static NTSTATUS check_nfs_sd(const struct security_descriptor *psd)
+{
+ uint32_t i;
+ bool got_one_mode = false;
+ bool got_one_uid = false;
+ bool got_one_gid = false;
+
+ if (psd->dacl == NULL) {
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ for (i = 0; i < psd->dacl->num_aces; i++) {
+ if (dom_sid_compare_domain(&global_sid_Unix_NFS_Mode,
+ &psd->dacl->aces[i].trustee) == 0) {
+ if (got_one_mode == true) {
+ /* Can't have more than one. */
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+ got_one_mode = true;
+ }
+ }
+ for (i = 0; i < psd->dacl->num_aces; i++) {
+ if (dom_sid_compare_domain(&global_sid_Unix_NFS_Users,
+ &psd->dacl->aces[i].trustee) == 0) {
+ if (got_one_uid == true) {
+ /* Can't have more than one. */
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+ got_one_uid = true;
+ }
+ }
+ for (i = 0; i < psd->dacl->num_aces; i++) {
+ if (dom_sid_compare_domain(&global_sid_Unix_NFS_Groups,
+ &psd->dacl->aces[i].trustee) == 0) {
+ if (got_one_gid == true) {
+ /* Can't have more than one. */
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+ got_one_gid = true;
+ }
+ }
+ /* Must have at least one of each. */
+ if (got_one_mode == false ||
+ got_one_uid == false ||
+ got_one_gid == false) {
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+ return NT_STATUS_OK;
+}
+
+static bool test_nfs_aces(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct security_ace ace;
+ struct dom_sid sid;
+ const char *fname = BASEDIR "\\nfs_aces.txt";
+ struct smb2_handle h = {{0}};
+ union smb_fileinfo finfo2;
+ union smb_setfileinfo set;
+ struct security_descriptor *psd = NULL;
+ NTSTATUS status;
+ bool ret = true;
+ bool is_osx = torture_setting_bool(tctx, "osx", false);
+
+ if (is_osx) {
+ torture_skip(tctx, "Test only works with Samba\n");
+ }
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert(tctx, ret == true, "enable_aapl failed");
+
+ /* clean slate ...*/
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ /* Create a test file. */
+ status = torture_smb2_testfile_access(tree,
+ fname,
+ &h,
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_RIGHTS_FILE_ALL);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Get the ACL. */
+ finfo2.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ finfo2.generic.level = RAW_FILEINFO_SEC_DESC;
+ finfo2.generic.in.file.handle = h;
+ status = smb2_getinfo_file(tree, tctx, &finfo2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ psd = finfo2.query_secdesc.out.sd;
+
+ /* Ensure we have only single mode/uid/gid NFS entries. */
+ status = check_nfs_sd(psd);
+ if (!NT_STATUS_IS_OK(status)) {
+ NDR_PRINT_DEBUG(
+ security_descriptor,
+ discard_const_p(struct security_descriptor, psd));
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Add a couple of extra NFS uids and gids. */
+ sid_compose(&sid, &global_sid_Unix_NFS_Users, 27);
+ init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+ status = security_descriptor_dacl_add(psd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = security_descriptor_dacl_add(psd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ sid_compose(&sid, &global_sid_Unix_NFS_Groups, 300);
+ init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0);
+ status = security_descriptor_dacl_add(psd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ status = security_descriptor_dacl_add(psd, &ace);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Now set on the file handle. */
+ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
+ set.set_secdesc.in.file.handle = h;
+ set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
+ set.set_secdesc.in.sd = psd;
+ status = smb2_setinfo_file(tree, &set);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Get the ACL again. */
+ finfo2.query_secdesc.in.secinfo_flags =
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL;
+ finfo2.generic.level = RAW_FILEINFO_SEC_DESC;
+ finfo2.generic.in.file.handle = h;
+ status = smb2_getinfo_file(tree, tctx, &finfo2);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ psd = finfo2.query_secdesc.out.sd;
+
+ /* Ensure we have only single mode/uid/gid NFS entries. */
+ status = check_nfs_sd(psd);
+ if (!NT_STATUS_IS_OK(status)) {
+ NDR_PRINT_DEBUG(
+ security_descriptor,
+ discard_const_p(struct security_descriptor, psd));
+ }
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_setinfo_stream_eof(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_create create;
+ union smb_setfileinfo sfinfo;
+ union smb_fileinfo finfo;
+ struct smb2_handle h1;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\file";
+ const char *sname = BASEDIR "\\file:foo";
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done,
+ "talloc_new failed\n");
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert(tctx, ret == true, "enable_aapl failed");
+
+ torture_comment(tctx, "Test setting EOF on a stream\n");
+
+ smb2_deltree(tree, BASEDIR);
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+
+ status = torture_smb2_testfile(tree, fname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+ smb2_util_close(tree, h1);
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ status = smb2_util_write(tree, h1, "1234567890", 0, 10);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+ smb2_util_close(tree, h1);
+
+ /*
+ * Test setting EOF to 21
+ */
+
+ torture_comment(tctx, "Setting stream EOF to 21\n");
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 21;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status,
+ ret, done, "set EOF 21 failed\n");
+
+ smb2_util_close(tree, h1);
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_STANDARD_INFORMATION;
+ finfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed");
+
+ smb2_util_close(tree, h1);
+
+ torture_assert_goto(tctx, finfo.standard_info.out.size == 21,
+ ret, done, "size != 21\n");
+
+ /*
+ * Test setting EOF to 0
+ */
+
+ torture_comment(tctx, "Setting stream EOF to 0\n");
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 0;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "set eof 0 failed\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "Unexpected status\n");
+
+ smb2_util_close(tree, h1);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "Unexpected status\n");
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_STANDARD_INFORMATION;
+ finfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ smb2_util_close(tree, h1);
+
+ torture_assert_goto(tctx, finfo.standard_info.out.size == 0,
+ ret, done, "size != 0\n");
+
+ /*
+ * Test setinfo end-of-file info to 1
+ */
+
+ torture_comment(tctx, "Setting stream EOF to 1\n");
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "set EOF 1 failed\n");
+
+ smb2_util_close(tree, h1);
+
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_STANDARD_INFORMATION;
+ finfo.generic.in.file.handle = h1;
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ smb2_util_close(tree, h1);
+
+ torture_assert_goto(tctx, finfo.standard_info.out.size == 1,
+ ret, done, "size != 1\n");
+
+ /*
+ * Test setting EOF to 0 with AAPL enabled, should delete stream
+ */
+
+ torture_comment(tctx, "Enabling AAPL extensions\n");
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert(tctx, ret == true, "enable_aapl failed\n");
+
+ torture_comment(tctx, "Setting stream EOF to 0\n");
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 0;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "set eof 0 failed\n");
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "Unexpected status\n");
+
+ smb2_util_close(tree, h1);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = sname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done,
+ "Unexpected status\n");
+
+ torture_comment(
+ tctx, "Setting main file EOF to 1 to force 0-truncate\n");
+
+ status = torture_smb2_testfile_access(
+ tree,
+ fname,
+ &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 1;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "set eof 1 failed\n");
+
+ sfinfo.position_information.in.position = 0;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(
+ tctx,
+ status,
+ ret,
+ done,
+ "set eof 0 failed\n");
+
+ smb2_util_close(tree, h1);
+
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.fname = fname;
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+ smb2_util_close(tree, h1);
+
+ torture_comment(tctx, "Writing to stream after setting EOF to 0\n");
+ status = torture_smb2_testfile_access(tree, sname, &h1,
+ SEC_FILE_WRITE_DATA);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ status = smb2_util_write(tree, h1, "1234567890", 0, 10);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ ZERO_STRUCT(sfinfo);
+ sfinfo.generic.in.file.handle = h1;
+ sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sfinfo.position_information.in.position = 0;
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "set eof 0 failed\n");
+
+ status = smb2_util_write(tree, h1, "1234567890", 0, 10);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ smb2_util_close(tree, h1);
+
+done:
+ smb2_util_unlink(tree, fname);
+ smb2_util_rmdir(tree, BASEDIR);
+ return ret;
+}
+
+#define MAX_STREAMS 16
+
+struct tcase {
+ const char *name;
+ uint32_t access;
+ const char *write_data;
+ size_t write_size;
+ struct tcase_results {
+ size_t size;
+ NTSTATUS initial_status;
+ NTSTATUS final_status;
+ int num_streams_open_handle;
+ const char *streams_open_handle[MAX_STREAMS];
+ int num_streams_closed_handle;
+ const char *streams_closed_handle[MAX_STREAMS];
+ } create, write, overwrite, eof, doc;
+};
+
+typedef enum {T_CREATE, T_WRITE, T_OVERWRITE, T_EOF, T_DOC} subtcase_t;
+
+static bool test_empty_stream_do_checks(
+ struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2,
+ struct tcase *tcase,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_handle baseh,
+ struct smb2_handle streamh,
+ subtcase_t subcase)
+{
+ bool ret = false;
+ NTSTATUS status;
+ struct smb2_handle h1;
+ union smb_fileinfo finfo;
+ struct tcase_results *tcase_results = NULL;
+
+ switch (subcase) {
+ case T_CREATE:
+ tcase_results = &tcase->create;
+ break;
+ case T_OVERWRITE:
+ tcase_results = &tcase->overwrite;
+ break;
+ case T_WRITE:
+ tcase_results = &tcase->write;
+ break;
+ case T_EOF:
+ tcase_results = &tcase->eof;
+ break;
+ case T_DOC:
+ tcase_results = &tcase->doc;
+ break;
+ }
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_STANDARD_INFORMATION,
+ .generic.in.file.handle = streamh,
+ };
+
+ /*
+ * Test: check size, same client
+ */
+
+ status = smb2_getinfo_file(tree, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ torture_assert_int_equal_goto(tctx, finfo.standard_info.out.size,
+ tcase_results->size,
+ ret, done, "Wrong size\n");
+
+ /*
+ * Test: open, same client
+ */
+
+ status = torture_smb2_open(tree, tcase->name,
+ SEC_FILE_READ_ATTRIBUTE, &h1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ tcase_results->initial_status,
+ ret, done,
+ "smb2_create failed\n");
+ if (NT_STATUS_IS_OK(status)) {
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ }
+
+ /*
+ * Test: check streams, same client
+ */
+
+ ret = check_stream_list_handle(tree, tctx, baseh,
+ tcase_results->num_streams_open_handle,
+ tcase_results->streams_open_handle,
+ false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ /*
+ * Test: open, different client
+ */
+
+ status = torture_smb2_open(tree2, tcase->name,
+ SEC_FILE_READ_ATTRIBUTE, &h1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ tcase_results->initial_status,
+ ret, done,
+ "smb2_create failed\n");
+ if (NT_STATUS_IS_OK(status)) {
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_STANDARD_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ /*
+ * Test: check size, different client
+ */
+
+ status = smb2_getinfo_file(tree2, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_getinfo_file failed\n");
+
+ torture_assert_int_equal_goto(tctx, finfo.standard_info.out.size,
+ tcase_results->size,
+ ret, done, "Wrong size\n");
+
+ /*
+ * Test: check streams, different client
+ */
+
+ ret = check_stream_list(tree2, tctx, BASEDIR "\\file",
+ tcase_results->num_streams_open_handle,
+ tcase_results->streams_open_handle,
+ false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ status = smb2_util_close(tree2, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ }
+
+ status = smb2_util_close(tree, streamh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+
+ /*
+ * Test: open after close, same client
+ */
+
+ status = torture_smb2_open(tree, tcase->name,
+ SEC_FILE_READ_DATA, &h1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ tcase_results->final_status,
+ ret, done,
+ "smb2_create failed\n");
+ if (NT_STATUS_IS_OK(status)) {
+ status = smb2_util_close(tree, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ }
+
+ /*
+ * Test: open after close, different client
+ */
+
+ status = torture_smb2_open(tree2, tcase->name,
+ SEC_FILE_READ_DATA, &h1);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ tcase_results->final_status,
+ ret, done,
+ "smb2_create failed\n");
+ if (NT_STATUS_IS_OK(status)) {
+ status = smb2_util_close(tree2, h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed\n");
+ }
+
+ /*
+ * Test: check streams after close, same client
+ */
+
+ ret = check_stream_list_handle(tree, tctx, baseh,
+ tcase_results->num_streams_closed_handle,
+ tcase_results->streams_closed_handle,
+ false);
+ torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
+
+ ret = true;
+
+done:
+ smb2_util_close(tree, streamh);
+ smb2_util_close(tree, baseh);
+ return ret;
+}
+
+static bool test_empty_stream_do_one(
+ struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2,
+ struct tcase *tcase)
+{
+ bool ret = false;
+ NTSTATUS status;
+ struct smb2_handle baseh = {{0}};
+ struct smb2_handle streamh;
+ struct smb2_create create;
+ union smb_setfileinfo sfinfo;
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+
+ torture_comment(tctx, "Testing stream [%s]\n", tcase->name);
+
+ torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new\n");
+
+ /*
+ * Subtest: create
+ */
+ torture_comment(tctx, "Subtest: T_CREATE\n");
+
+ status = smb2_util_unlink(tree, BASEDIR "\\file");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed\n");
+
+ status = torture_smb2_testfile_access(tree, BASEDIR "\\file",
+ &baseh, SEC_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = torture_smb2_testfile_access(tree, tcase->name, &streamh,
+ tcase->access);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase,
+ mem_ctx, baseh, streamh, T_CREATE);
+ torture_assert_goto(tctx, ret, ret, done, "test failed\n");
+
+ if (!(tcase->access & SEC_FILE_WRITE_DATA)) {
+ /*
+ * All subsequent tests require write access
+ */
+ ret = true;
+ goto done;
+ }
+
+ /*
+ * Subtest: create and write
+ */
+ torture_comment(tctx, "Subtest: T_WRITE\n");
+
+ status = smb2_util_unlink(tree, BASEDIR "\\file");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed\n");
+
+ status = torture_smb2_testfile_access(tree, BASEDIR "\\file",
+ &baseh, SEC_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = torture_smb2_testfile_access(tree, tcase->name, &streamh,
+ tcase->access);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = smb2_util_write(tree, streamh, tcase->write_data, 0,
+ tcase->write_size);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_open failed\n");
+
+ ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase,
+ mem_ctx, baseh, streamh, T_WRITE);
+ torture_assert_goto(tctx, ret, ret, done, "test failed\n");
+
+ /*
+ * Subtest: overwrite
+ */
+ torture_comment(tctx, "Subtest: T_OVERWRITE\n");
+
+ status = smb2_util_unlink(tree, BASEDIR "\\file");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed\n");
+
+ status = torture_smb2_testfile_access(tree, BASEDIR "\\file",
+ &baseh, SEC_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_ALL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF,
+ .in.fname = tcase->name,
+ };
+
+ status = smb2_create(tree, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+ streamh = create.out.file.handle;
+
+ ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase,
+ mem_ctx, baseh, streamh, T_OVERWRITE);
+ torture_assert_goto(tctx, ret, ret, done, "test failed\n");
+
+ /*
+ * Subtest: setinfo EOF 0
+ */
+ torture_comment(tctx, "Subtest: T_EOF\n");
+
+ status = smb2_util_unlink(tree, BASEDIR "\\file");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed\n");
+
+ status = torture_smb2_testfile_access(tree, BASEDIR "\\file",
+ &baseh, SEC_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = torture_smb2_testfile_access(tree, tcase->name, &streamh,
+ tcase->access);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = smb2_util_write(tree, streamh, tcase->write_data, 0,
+ tcase->write_size);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_open failed\n");
+
+ sfinfo = (union smb_setfileinfo) {
+ .end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION,
+ .end_of_file_info.in.file.handle = streamh,
+ .end_of_file_info.in.size = 0,
+ };
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "set eof 0 failed\n");
+
+ ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase,
+ mem_ctx, baseh, streamh, T_EOF);
+ torture_assert_goto(tctx, ret, ret, done, "test failed\n");
+
+ /*
+ * Subtest: delete-on-close
+ */
+ torture_comment(tctx, "Subtest: T_DOC\n");
+
+ status = smb2_util_unlink(tree, BASEDIR "\\file");
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed\n");
+
+ status = torture_smb2_testfile_access(tree, BASEDIR "\\file",
+ &baseh, SEC_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = torture_smb2_testfile_access(tree, tcase->name, &streamh,
+ tcase->access);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile_access failed\n");
+
+ status = smb2_util_write(tree, streamh, tcase->write_data, 0,
+ tcase->write_size);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_open failed\n");
+
+ sfinfo = (union smb_setfileinfo) {
+ .disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFORMATION,
+ .disposition_info.in.file.handle = streamh,
+ .disposition_info.in.delete_on_close = true,
+ };
+ status = smb2_setinfo_file(tree, &sfinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "set eof 0 failed\n");
+
+ ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase,
+ mem_ctx, baseh, streamh,
+ T_DOC);
+ torture_assert_goto(tctx, ret, ret, done, "test failed\n");
+
+ ret = true;
+
+done:
+ smb2_util_close(tree, baseh);
+ TALLOC_FREE(mem_ctx);
+ return ret;
+}
+
+static bool test_empty_stream(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_tree *tree2 = NULL;
+ struct tcase *tcase = NULL;
+ const char *fname = BASEDIR "\\file";
+ struct smb2_handle h1;
+ bool ret = true;
+ NTSTATUS status;
+ AfpInfo ai = (AfpInfo) {
+ .afpi_Signature = AFP_Signature,
+ .afpi_Version = AFP_Version,
+ .afpi_BackupTime = AFP_BackupTime,
+ .afpi_FinderInfo = "FOO BAR ",
+ };
+ char *ai_blob = torture_afpinfo_pack(tctx, &ai);
+ struct tcase tcase_afpinfo_ro = (struct tcase) {
+ .name = BASEDIR "\\file" AFPINFO_STREAM,
+ .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE,
+ .create = {
+ .size = 60,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ };
+ struct tcase tcase_afpinfo_rw = (struct tcase) {
+ .name = BASEDIR "\\file" AFPINFO_STREAM,
+ .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_DATA|SEC_STD_DELETE,
+ .write_data = ai_blob,
+ .write_size = AFP_INFO_SIZE,
+ .create = {
+ .size = 60,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .write = {
+ .size = 60,
+ .initial_status = NT_STATUS_OK,
+ .final_status = NT_STATUS_OK,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 2,
+ .streams_open_handle = {"::$DATA", AFPINFO_STREAM},
+ .streams_closed_handle = {"::$DATA", AFPINFO_STREAM},
+ },
+ .overwrite = {
+ .size = 60,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .eof = {
+ .size = 60,
+ .initial_status = NT_STATUS_OK,
+ .final_status = NT_STATUS_OK,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 2,
+ .streams_open_handle = {"::$DATA", AFPINFO_STREAM},
+ .streams_closed_handle = {"::$DATA", AFPINFO_STREAM},
+ },
+ .doc = {
+ .size = 60,
+ .initial_status = NT_STATUS_DELETE_PENDING,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA", AFPINFO_STREAM},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ };
+
+ struct tcase tcase_afpresource_ro = (struct tcase) {
+ .name = BASEDIR "\\file" AFPRESOURCE_STREAM,
+ .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE,
+ .create = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ };
+ struct tcase tcase_afpresource_rw = (struct tcase) {
+ .name = BASEDIR "\\file" AFPRESOURCE_STREAM,
+ .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_DATA|SEC_STD_DELETE,
+ .write_data = "foo",
+ .write_size = 3,
+ .create = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .write = {
+ .size = 3,
+ .initial_status = NT_STATUS_OK,
+ .final_status = NT_STATUS_OK,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 2,
+ .streams_open_handle = {"::$DATA", AFPRESOURCE_STREAM},
+ .streams_closed_handle = {"::$DATA", AFPRESOURCE_STREAM},
+ },
+ .overwrite = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .eof = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .doc = {
+ .size = 3,
+ .initial_status = NT_STATUS_DELETE_PENDING,
+ .final_status = NT_STATUS_OK,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 2,
+ .streams_open_handle = {"::$DATA", AFPRESOURCE_STREAM},
+ .streams_closed_handle = {"::$DATA", AFPRESOURCE_STREAM},
+ },
+ };
+
+ struct tcase tcase_foo_ro = (struct tcase) {
+ .name = BASEDIR "\\file:foo",
+ .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE,
+ .write_data = "foo",
+ .write_size = 3,
+ .create = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ };
+
+ struct tcase tcase_foo_rw = (struct tcase) {
+ .name = BASEDIR "\\file:foo",
+ .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_DATA|SEC_STD_DELETE,
+ .write_data = "foo",
+ .write_size = 3,
+ .create = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .write = {
+ .size = 3,
+ .initial_status = NT_STATUS_OK,
+ .final_status = NT_STATUS_OK,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 2,
+ .streams_open_handle = {"::$DATA", ":foo:$DATA"},
+ .streams_closed_handle = {"::$DATA", ":foo:$DATA"},
+ },
+ .overwrite = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .eof = {
+ .size = 0,
+ .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 1,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ .doc = {
+ .size = 3,
+ .initial_status = NT_STATUS_DELETE_PENDING,
+ .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ .num_streams_open_handle = 2,
+ .num_streams_closed_handle = 1,
+ .streams_open_handle = {"::$DATA", ":foo:$DATA"},
+ .streams_closed_handle = {"::$DATA"},
+ },
+ };
+
+ struct tcase tcases[] = {
+ tcase_afpinfo_ro,
+ tcase_afpinfo_rw,
+ tcase_afpresource_ro,
+ tcase_afpresource_rw,
+ tcase_foo_ro,
+ tcase_foo_rw,
+ {0}
+ };
+
+ ret = torture_smb2_connection(tctx, &tree2);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_smb2_connection failed\n");
+
+ ret = enable_aapl(tctx, tree);
+ torture_assert(tctx, ret == true, "enable_aapl failed\n");
+
+ ret = enable_aapl(tctx, tree2);
+ torture_assert(tctx, ret == true, "enable_aapl failed\n");
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree, h1);
+
+ for (tcase = &tcases[0]; tcase->name != NULL; tcase++) {
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = test_empty_stream_do_one(tctx, tree, tree2, tcase);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "subtest failed\n");
+
+ status = smb2_util_unlink(tree, fname);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_unlink failed\n");
+ }
+
+done:
+ smb2_deltree(tree, BASEDIR);
+ TALLOC_FREE(tree2);
+ return ret;
+}
+
+/*
+-------------------------------------------------------------------------------
+MagicNumber: 00051607 : AppleDouble
+Version : 00020000 : Version 2
+Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X
+Num. of ent: 0002 : 2
+
+-------------------------------------------------------------------------------
+Entry ID : 00000009 : Finder Info
+Offset : 00000032 : 50
+Length : 00000EB0 : 3760
+
+-DInfo-----:
+Rect top : 0000 : 0
+Rect left : 0000 : 0
+Rect bottom: 0000 : 0
+Rect right : 0000 : 0
+isAlias : 0
+Invisible : 0
+hasBundle : 0
+nameLocked : 0
+Stationery : 0
+CustomIcon : 0
+Reserved : 0
+Inited : 1
+NoINITS : 0
+Shared : 0
+SwitchLaunc: 0
+Hidden Ext : 0
+color : 000 : none
+isOnDesk : 0
+Location v : 0000 : 0
+Location h : 0000 : 0
+View : 0000 : ..
+
+-DXInfo----:
+Scroll v : 0000 : 0
+Scroll h : 0000 : 0
+Rsvd|OpnChn: 00000000 : 0
+AreInvalid : 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+CustomBadge: 0
+ObjctIsBusy: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+unknown bit: 0
+RoutingInfo: 0
+unknown bit: 0
+unknown bit: 0
+Comment : 0000 : ..
+PutAway : 00000000 : 0
+
+-EA--------:
+pad : 0000 : ..
+magic : 41545452 : ATTR
+debug_tag : 0081714C : 8483148
+total_size : 00000EE2 : 3810
+data_start : 00000098 : 152
+data_length: 00000039 : 57
+reserved[0]: 00000000 : ....
+reserved[1]: 00000000 : ....
+reserved[2]: 00000000 : ....
+flags : 0000 : ..
+num_attrs : 0001 : 1
+-EA ENTRY--:
+offset : 00000098 : 152
+length : 00000039 : 57
+flags : 0000 : ..
+namelen : 15 : 21
+-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 63 6F 6D 2E 61 70 70 6C 65 2E 71 75 61 72 61 6E : com.apple.quaran
+00000010 : 74 69 6E 65 00 : tine.
+-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 30 30 38 31 3B 36 32 65 61 33 37 66 64 3B 43 68 : 0081;62ea37fd;Ch
+00000010 : 72 6F 6D 65 3B 42 35 39 46 42 39 45 44 2D 35 41 : rome;B59FB9ED-5A
+00000020 : 32 39 2D 34 45 35 42 2D 38 35 36 43 2D 37 45 44 : 29-4E5B-856C-7ED
+00000030 : 30 45 46 45 41 37 30 41 43 : 0EFEA70AC
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 : ................
+00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000020 : 00 00 41 54 54 52 00 81 71 4C 00 00 0E E2 00 00 : ..ATTR..qL......
+00000030 : 00 98 00 00 00 39 00 00 00 00 00 00 00 00 00 00 : .....9..........
+00000040 : 00 00 00 00 00 01 00 00 00 98 00 00 00 39 00 00 : .............9..
+00000050 : 15 63 6F 6D 2E 61 70 70 6C 65 2E 71 75 61 72 61 : .com.apple.quara
+00000060 : 6E 74 69 6E 65 00 30 30 38 31 3B 36 32 65 61 33 : ntine.0081;62ea3
+00000070 : 37 66 64 3B 43 68 72 6F 6D 65 3B 42 35 39 46 42 : 7fd;Chrome;B59FB
+00000080 : 39 45 44 2D 35 41 32 39 2D 34 45 35 42 2D 38 35 : 9ED-5A29-4E5B-85
+00000090 : 36 43 2D 37 45 44 30 45 46 45 41 37 30 41 43 00 : 6C-7ED0EFEA70AC.
+000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000100 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000110 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000120 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000130 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000140 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000150 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000160 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000170 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000180 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000190 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000001A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000001B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000001C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000001D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000001E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000001F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000200 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000210 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000220 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000230 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000240 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000250 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000260 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000270 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000280 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000290 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000002A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000002B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000002C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000002D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000002E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000002F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000300 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000310 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000320 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000330 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000340 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000350 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000360 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000370 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000380 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000390 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000003A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000003B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000003C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000003D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000003E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000003F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000400 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000410 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000420 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000430 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000440 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000450 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000460 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000470 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000480 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000490 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000004A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000004B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000004C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000004D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000004E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000004F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000500 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000510 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000520 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000530 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000540 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000550 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000560 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000570 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000580 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000590 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000005A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000005B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000005C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000005D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000005E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000005F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000600 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000610 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000620 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000630 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000640 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000650 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000660 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000670 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000680 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000690 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000006A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000006B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000006C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000006D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000006E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000006F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000700 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000710 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000720 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000730 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000740 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000750 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000760 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000770 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000780 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000790 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000007A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000007B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000007C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000007D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000007E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000007F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000800 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000810 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000820 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000830 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000840 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000850 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000860 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000870 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000880 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000890 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000008A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000008B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000008C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000008D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000008E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000008F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000900 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000910 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000920 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000930 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000940 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000950 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000960 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000970 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000980 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000990 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000009A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000009B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000009C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000009D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000009E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000009F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000A90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000AA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000AB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000AC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000AD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000AE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000AF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000B90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000BA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000BB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000BC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000BD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000BE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000BF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000C90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000CA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000CB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000CC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000CD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000CE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000CF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000D90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000DA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000DB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000DC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000DD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000DE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000DF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000E90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000EA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+
+-------------------------------------------------------------------------------
+Entry ID : 00000002 : Resource Fork
+Offset : 00000EE2 : 3810
+Length : 0000011E : 286
+
+-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+00000010 : 54 68 69 73 20 72 65 73 6F 75 72 63 65 20 66 6F : This resource fo
+00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally
+00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank ..
+00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................
+00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : ..............
+*/
+
+static char osx_adouble_dir_w_xattr[] = {
+ 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+ 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x32, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x0e, 0xe2, 0x00, 0x00,
+ 0x01, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x54, 0x54, 0x52,
+ 0x00, 0x81, 0x71, 0x4c, 0x00, 0x00, 0x0e, 0xe2,
+ 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x39,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x39,
+ 0x00, 0x00, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+ 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x71, 0x75, 0x61,
+ 0x72, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x00,
+ 0x30, 0x30, 0x38, 0x31, 0x3b, 0x36, 0x32, 0x65,
+ 0x61, 0x33, 0x37, 0x66, 0x64, 0x3b, 0x43, 0x68,
+ 0x72, 0x6f, 0x6d, 0x65, 0x3b, 0x42, 0x35, 0x39,
+ 0x46, 0x42, 0x39, 0x45, 0x44, 0x2d, 0x35, 0x41,
+ 0x32, 0x39, 0x2d, 0x34, 0x45, 0x35, 0x42, 0x2d,
+ 0x38, 0x35, 0x36, 0x43, 0x2d, 0x37, 0x45, 0x44,
+ 0x30, 0x45, 0x46, 0x45, 0x41, 0x37, 0x30, 0x41,
+ 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x54, 0x68, 0x69, 0x73, 0x20, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20,
+ 0x66, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
+ 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20,
+ 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff
+};
+
+static bool test_delete_trigger_convert_sharing_violation(
+ struct torture_context *tctx,
+ struct smb2_tree *tree1)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *dirname = BASEDIR "\\dir";
+ const char *adname = BASEDIR "\\._dir";
+ struct smb2_handle testdirh;
+ struct smb2_create create;
+ AfpInfo *info = NULL;
+ bool ret = true;
+ NTSTATUS status;
+
+ smb2_deltree(tree1, BASEDIR);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree1, testdirh);
+
+ status = torture_smb2_testdir(tree1, dirname, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree1, testdirh);
+
+ ret = torture_setup_file(tctx, tree1, adname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = write_stream(tree1, __location__, tctx, mem_ctx,
+ adname, NULL, 0,
+ sizeof(osx_adouble_dir_w_xattr),
+ osx_adouble_dir_w_xattr);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ /*
+ * 1) Create a non-empty AFP_AfpInfo stream
+ */
+
+ info = torture_afpinfo_new(mem_ctx);
+ torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed");
+
+ /* Set "Inited" flag (any other would do too) */
+ info->afpi_FinderInfo[8] = 0x01;
+
+ ret = torture_write_afpinfo(tree1, tctx, mem_ctx, dirname, info);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
+
+ ret = write_stream(tree1, __location__, tctx, mem_ctx,
+ adname, NULL, 0,
+ sizeof(osx_adouble_dir_w_xattr),
+ osx_adouble_dir_w_xattr);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ /*
+ * 2) Create a second stream
+ */
+
+ ret = write_stream(tree1, __location__, tctx, mem_ctx,
+ dirname, ":org.samba.boom", 0,
+ strlen("boom"),
+ "boom");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_STD_DELETE,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = dirname,
+ };
+
+ status = smb2_create(tree1, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ status = smb2_util_close(tree1, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+
+done:
+ smb2_deltree(tree1, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/*
+ * Note: This test depends on "vfs objects = catia fruit streams_xattr". For
+ * some tests torture must be run on the host it tests and takes an additional
+ * argument with the local path to the share:
+ * "--option=torture:localdir=<SHAREPATH>".
+ *
+ * When running against an OS X SMB server add "--option=torture:osx=true"
+ */
+struct torture_suite *torture_vfs_fruit(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "fruit");
+
+ suite->description = talloc_strdup(suite, "vfs_fruit tests");
+
+ torture_suite_add_1smb2_test(suite, "copyfile", test_copyfile);
+ torture_suite_add_1smb2_test(suite, "read metadata", test_read_afpinfo);
+ torture_suite_add_1smb2_test(suite, "write metadata", test_write_atalk_metadata);
+ torture_suite_add_1smb2_test(suite, "resource fork IO", test_write_atalk_rfork_io);
+ torture_suite_add_1smb2_test(suite, "SMB2/CREATE context AAPL", test_aapl);
+ torture_suite_add_1smb2_test(suite, "stream names", test_stream_names);
+ torture_suite_add_1smb2_test(suite, "truncate resource fork to 0 bytes", test_rfork_truncate);
+ torture_suite_add_1smb2_test(suite, "opening and creating resource fork", test_rfork_create);
+ torture_suite_add_1smb2_test(suite, "fsync_resource_fork", test_rfork_fsync);
+ torture_suite_add_1smb2_test(suite, "rename_dir_openfile", test_rename_dir_openfile);
+ torture_suite_add_1smb2_test(suite, "File without AFP_AfpInfo", test_afpinfo_enoent);
+ torture_suite_add_1smb2_test(suite, "create delete-on-close AFP_AfpInfo", test_create_delete_on_close);
+ torture_suite_add_1smb2_test(suite, "setinfo delete-on-close AFP_AfpInfo", test_setinfo_delete_on_close);
+ torture_suite_add_1smb2_test(suite, "setinfo eof AFP_AfpInfo", test_setinfo_eof);
+ torture_suite_add_1smb2_test(suite, "delete AFP_AfpInfo by writing all 0", test_afpinfo_all0);
+ torture_suite_add_1smb2_test(suite, "create delete-on-close AFP_AfpResource", test_create_delete_on_close_resource);
+ torture_suite_add_1smb2_test(suite, "setinfo delete-on-close AFP_AfpResource", test_setinfo_delete_on_close_resource);
+ torture_suite_add_1smb2_test(suite, "setinfo eof AFP_AfpResource", test_setinfo_eof_resource);
+ torture_suite_add_1smb2_test(suite, "setinfo eof stream", test_setinfo_stream_eof);
+ torture_suite_add_1smb2_test(suite, "null afpinfo", test_null_afpinfo);
+ torture_suite_add_1smb2_test(suite, "delete", test_delete_file_with_rfork);
+ torture_suite_add_1smb2_test(suite, "read open rsrc after rename", test_rename_and_read_rsrc);
+ torture_suite_add_1smb2_test(suite, "readdir_attr with names with illegal ntfs characters", test_readdir_attr_illegal_ntfs);
+ torture_suite_add_2ns_smb2_test(suite, "invalid AFP_AfpInfo", test_invalid_afpinfo);
+ torture_suite_add_1smb2_test(suite, "creating rsrc with read-only access", test_rfork_create_ro);
+ torture_suite_add_1smb2_test(suite, "copy-chunk streams", test_copy_chunk_streams);
+ torture_suite_add_1smb2_test(suite, "OS X AppleDouble file conversion", test_adouble_conversion);
+ torture_suite_add_1smb2_test(suite, "NFS ACE entries", test_nfs_aces);
+ torture_suite_add_1smb2_test(suite, "OS X AppleDouble file conversion without embedded xattr", test_adouble_conversion_wo_xattr);
+ torture_suite_add_1smb2_test(suite, "empty_stream", test_empty_stream);
+ torture_suite_add_1smb2_test(suite, "writing_afpinfo", test_writing_afpinfo);
+ torture_suite_add_1smb2_test(suite, "delete_trigger_convert_sharing_violation", test_delete_trigger_convert_sharing_violation);
+
+ return suite;
+}
+
+static bool test_stream_names_local(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ NTSTATUS status;
+ struct smb2_create create;
+ struct smb2_handle h;
+ const char *fname = BASEDIR "\\stream_names.txt";
+ const char *sname1;
+ bool ret;
+ /* UTF8 private use are starts at 0xef 0x80 0x80 (0xf000) */
+ const char *streams[] = {
+ ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */
+ ":bar" "\xef\x80\xa2" "baz:$DATA", /* "bar:baz:$DATA" */
+ "::$DATA"
+ };
+ const char *localdir = NULL;
+
+ localdir = torture_setting_string(tctx, "localdir", NULL);
+ if (localdir == NULL) {
+ torture_skip(tctx, "Need localdir for test");
+ }
+
+ sname1 = talloc_asprintf(mem_ctx, "%s%s", fname, streams[0]);
+
+ /* clean slate ...*/
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ torture_comment(tctx, "(%s) testing stream names\n", __location__);
+ ZERO_STRUCT(create);
+ create.in.desired_access = SEC_FILE_WRITE_DATA;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.share_access =
+ NTCREATEX_SHARE_ACCESS_DELETE|
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ create.in.create_disposition = NTCREATEX_DISP_CREATE;
+ create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
+ create.in.fname = sname1;
+
+ status = smb2_create(tree, mem_ctx, &create);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, create.out.file.handle, "foo", 0, 3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed\n");
+
+ smb2_util_close(tree, create.out.file.handle);
+
+ ret = torture_setup_local_xattr(tctx, "localdir", BASEDIR "/stream_names.txt",
+ "user.DosStream.bar:baz:$DATA",
+ "data", strlen("data"));
+ CHECK_VALUE(ret, true);
+
+ ret = check_stream_list(tree, tctx, fname, 3, streams, false);
+ CHECK_VALUE(ret, true);
+
+done:
+ status = smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+static bool test_fruit_locking_conflict(struct torture_context *tctx,
+ struct smb2_tree *tree,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx;
+ struct smb2_create create;
+ struct smb2_handle h;
+ struct smb2_lock lck;
+ struct smb2_lock_element el;
+ const char *fname = BASEDIR "\\locking_conflict.txt";
+ NTSTATUS status;
+ bool ret = false;
+
+ mem_ctx = talloc_new(tctx);
+ torture_assert_not_null(tctx, mem_ctx, "talloc_new failed");
+
+ /* clean slate ...*/
+ smb2_util_unlink(tree, fname);
+ smb2_deltree(tree, fname);
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ smb2_util_close(tree, h);
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_READ,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ|
+ NTCREATEX_SHARE_ACCESS_WRITE,
+ .in.create_disposition = NTCREATEX_DISP_CREATE,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, mem_ctx, &create);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h = create.out.file.handle;
+
+ /* Add AD_FILELOCK_RSRC_DENY_WR lock. */
+ el = (struct smb2_lock_element) {
+ .offset = 0xfffffffffffffffc,
+ .length = 1,
+ .flags = SMB2_LOCK_FLAG_EXCLUSIVE,
+ };
+ lck = (struct smb2_lock) {
+ .in.lock_count = 1,
+ .in.file.handle = h,
+ .in.locks = &el,
+ };
+
+ /*
+ * Lock up to and including:
+ * AD_FILELOCK_OPEN_WR
+ * AD_FILELOCK_OPEN_RD
+ * This is designed to cause a NetAtalk
+ * locking conflict on the next open,
+ * even though the share modes are
+ * compatible.
+ */
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ el = (struct smb2_lock_element) {
+ .offset = 0,
+ .length = 0x7ffffffffffffff7,
+ .flags = SMB2_LOCK_FLAG_EXCLUSIVE,
+ };
+ status = smb2_lock(tree, &lck);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ create = (struct smb2_create) {
+ .in.desired_access =
+ SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ /*
+ * Open on the second tree - ensure we are
+ * emulating trying to access with a NetATalk
+ * process with an existing open/deny mode.
+ */
+ status = smb2_create(tree2, mem_ctx, &create);
+ CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
+
+ {
+ struct smb2_close cl = {
+ .level = RAW_CLOSE_SMB2,
+ .in.file.handle = h,
+ };
+ smb2_close(tree, &cl);
+ }
+
+ ret = true;
+done:
+ return ret;
+}
+
+struct torture_suite *torture_vfs_fruit_netatalk(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "fruit_netatalk");
+
+ suite->description = talloc_strdup(suite, "vfs_fruit tests for Netatalk interop that require fruit:metadata=netatalk");
+
+ torture_suite_add_1smb2_test(suite, "read netatalk metadata", test_read_netatalk_metadata);
+ torture_suite_add_1smb2_test(suite, "stream names with locally created xattr", test_stream_names_local);
+ torture_suite_add_2smb2_test(
+ suite, "locking conflict", test_fruit_locking_conflict);
+
+ return suite;
+}
+
+struct torture_suite *torture_vfs_fruit_file_id(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite =
+ torture_suite_create(ctx, "fruit_file_id");
+
+ suite->description =
+ talloc_strdup(suite, "vfs_fruit tests for on-disk file ID that "
+ "require fruit:zero_file_id=yes");
+
+ torture_suite_add_1smb2_test(suite, "zero file id if AAPL negotiated",
+ test_zero_file_id);
+
+ return suite;
+}
+
+static bool test_timemachine_volsize(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_handle h = {{0}};
+ union smb_fsinfo fsinfo;
+ NTSTATUS status;
+ bool ok = true;
+ const char *info_plist =
+ "<dict>\n"
+ " <key>band-size</key>\n"
+ " <integer>8192</integer>\n"
+ "</dict>\n";
+
+ smb2_deltree(tree, "test.sparsebundle");
+
+ ok = enable_aapl(tctx, tree);
+ torture_assert_goto(tctx, ok, ok, done, "enable_aapl failed");
+
+ status = smb2_util_mkdir(tree, "test.sparsebundle");
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "smb2_util_mkdir\n");
+
+ ok = write_stream(tree, __location__, tctx, mem_ctx,
+ "test.sparsebundle/Info.plist", NULL,
+ 0, strlen(info_plist), info_plist);
+ torture_assert_goto(tctx, ok, ok, done, "write_stream failed\n");
+
+ status = smb2_util_mkdir(tree, "test.sparsebundle/bands");
+ torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
+ "smb2_util_mkdir\n");
+
+ ok = torture_setup_file(tctx, tree, "test.sparsebundle/bands/1", false);
+ torture_assert_goto(tctx, ok, ok, done, "torture_setup_file failed\n");
+
+ ok = torture_setup_file(tctx, tree, "test.sparsebundle/bands/2", false);
+ torture_assert_goto(tctx, ok, ok, done, "torture_setup_file failed\n");
+
+ status = smb2_util_roothandle(tree, &h);
+ torture_assert_ntstatus_ok(tctx, status, "Unable to create root handle");
+
+ ZERO_STRUCT(fsinfo);
+ fsinfo.generic.level = RAW_QFS_SIZE_INFORMATION;
+ fsinfo.generic.handle = h;
+
+ status = smb2_getinfo_fs(tree, tree, &fsinfo);
+ torture_assert_ntstatus_ok(tctx, status, "smb2_getinfo_fs failed");
+
+ torture_comment(tctx, "sectors_per_unit: %" PRIu32"\n"
+ "bytes_per_sector: %" PRIu32"\n"
+ "total_alloc_units: %" PRIu64"\n"
+ "avail_alloc_units: %" PRIu64"\n",
+ fsinfo.size_info.out.sectors_per_unit,
+ fsinfo.size_info.out.bytes_per_sector,
+ fsinfo.size_info.out.total_alloc_units,
+ fsinfo.size_info.out.avail_alloc_units);
+
+ /*
+ * Let me explain the numbers:
+ *
+ * - the share is set to "fruit:time machine max size = 32K"
+ * - we've faked a bandsize of 8 K in the Info.plist file
+ * - we've created two bands files
+ * - one allocation unit is made of two sectors with 512 B each
+ * => we've consumed 16 allocation units, there should be 16 free
+ */
+
+ torture_assert_goto(tctx, fsinfo.size_info.out.sectors_per_unit == 2,
+ ok, done, "Bad sectors_per_unit");
+
+ torture_assert_goto(tctx, fsinfo.size_info.out.bytes_per_sector == 512,
+ ok, done, "Bad bytes_per_sector");
+
+ torture_assert_goto(tctx, fsinfo.size_info.out.total_alloc_units == 32,
+ ok, done, "Bad total_alloc_units");
+
+ torture_assert_goto(tctx, fsinfo.size_info.out.avail_alloc_units == 16,
+ ok, done, "Bad avail_alloc_units");
+
+done:
+ if (!smb2_util_handle_empty(h)) {
+ smb2_util_close(tree, h);
+ }
+ smb2_deltree(tree, "test.sparsebundle");
+ talloc_free(mem_ctx);
+ return ok;
+}
+
+struct torture_suite *torture_vfs_fruit_timemachine(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "fruit_timemachine");
+
+ suite->description = talloc_strdup(
+ suite, "vfs_fruit tests for TimeMachine");
+
+ torture_suite_add_1smb2_test(suite, "Timemachine-volsize",
+ test_timemachine_volsize);
+
+ return suite;
+}
+
+static bool test_convert_xattr_and_empty_rfork_then_delete(
+ struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\test_adouble_conversion";
+ const char *adname = BASEDIR "/._test_adouble_conversion";
+ const char *rfork = BASEDIR "\\test_adouble_conversion" AFPRESOURCE_STREAM_NAME;
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ const char *streams[] = {
+ "::$DATA",
+ AFPINFO_STREAM,
+ ":com.apple.metadata" "\xef\x80\xa2" "_kMDItemUserTags:$DATA",
+ ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */
+ };
+ struct smb2_create create;
+ struct smb2_find find;
+ unsigned int count;
+ union smb_search_data *d;
+ bool delete_empty_adfiles;
+ int expected_num_files;
+
+ delete_empty_adfiles = torture_setting_bool(tctx,
+ "delete_empty_adfiles",
+ false);
+
+ smb2_deltree(tree1, BASEDIR);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree1, testdirh);
+
+ ret = torture_setup_file(tctx, tree1, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = torture_setup_file(tctx, tree1, adname, false);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_setup_file failed\n");
+
+ ret = write_stream(tree1, __location__, tctx, mem_ctx,
+ adname, NULL,
+ 0, sizeof(osx_adouble_w_xattr), osx_adouble_w_xattr);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ ret = enable_aapl(tctx, tree2);
+ torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
+
+ /*
+ * Issue a smb2_find(), this triggers the server-side conversion
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_DIR_READ,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = BASEDIR,
+ };
+
+ status = smb2_create(tree2, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ find = (struct smb2_find) {
+ .in.file.handle = create.out.file.handle,
+ .in.pattern = "*",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree2, tree2, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+
+ status = smb2_util_close(tree2, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+
+ /*
+ * Check number of streams
+ */
+
+ ret = check_stream_list(tree2, tctx, fname, 4, streams, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list");
+
+ /*
+ * Check Resource Fork is gone
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = rfork,
+ };
+
+ status = smb2_create(tree2, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ret, done, "Bad smb2_create return\n");
+
+ /*
+ * Check xattr data has been migrated from the AppleDouble file to
+ * streams.
+ */
+
+ ret = check_stream(tree2, __location__, tctx, mem_ctx,
+ fname, AFPINFO_STREAM,
+ 0, 60, 16, 8, "TESTSLOW");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check AFPINFO_STREAM failed\n");
+
+ ret = check_stream(tree2, __location__, tctx, mem_ctx,
+ fname, ":foo" "\xef\x80\xa2" "bar", /* foo:bar */
+ 0, 3, 0, 3, "baz");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check foo stream failed\n");
+
+ /*
+ * Now check number of files. If delete_empty_adfiles is set, the
+ * AppleDouble files should have been deleted.
+ */
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_DIR_READ,
+ .in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+ .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_READ,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = BASEDIR,
+ };
+
+ status = smb2_create(tree2, tctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ find = (struct smb2_find) {
+ .in.file.handle = create.out.file.handle,
+ .in.pattern = "*",
+ .in.max_response_size = 0x1000,
+ .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+ };
+
+ status = smb2_find_level(tree2, tree2, &find, &count, &d);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_find_level failed\n");
+
+ status = smb2_util_close(tree2, create.out.file.handle);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_close failed");
+
+ if (delete_empty_adfiles) {
+ expected_num_files = 3;
+ } else {
+ expected_num_files = 4;
+ }
+ torture_assert_int_equal_goto(tctx, count, expected_num_files, ret, done,
+ "Wrong number of files\n");
+
+done:
+ smb2_deltree(tree1, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+struct torture_suite *torture_vfs_fruit_conversion(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "fruit_conversion");
+
+ suite->description = talloc_strdup(
+ suite, "vfs_fruit conversion tests");
+
+ torture_suite_add_2ns_smb2_test(
+ suite, "convert_xattr_and_empty_rfork_then_delete",
+ test_convert_xattr_and_empty_rfork_then_delete);
+
+ return suite;
+}
+
+/*
+ * The buf below contains the following AppleDouble encoded data:
+ *
+ * -----------------------------------------------------------------------------
+ * MagicNumber: 00051607 : AppleDouble
+ * Version : 00020000 : Version 2
+ * Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X
+ * Num. of ent: 0002 : 2
+ *
+ * -----------------------------------------------------------------------------
+ * Entry ID : 00000002 : Resource Fork
+ * Offset : 0000009A : 154
+ * Length : 00000004 : 4
+ *
+ * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+ * 00000000 : 62 61 72 00 : bar.
+ *
+ * -----------------------------------------------------------------------------
+ * Entry ID : 00000009 : Finder Info
+ * Offset : 00000032 : 50
+ * Length : 00000068 : 104
+ *
+ * -FInfo-----:
+ * Type : 464F4F20 : FOO
+ * Creator : 42415220 : BAR
+ * isAlias : 0
+ * Invisible : 0
+ * hasBundle : 0
+ * nameLocked : 0
+ * Stationery : 0
+ * CustomIcon : 0
+ * Reserved : 0
+ * Inited : 0
+ * NoINITS : 0
+ * Shared : 0
+ * SwitchLaunc: 0
+ * Hidden Ext : 0
+ * color : 000 : none
+ * isOnDesk : 0
+ * Location v : 0000 : 0
+ * Location h : 0000 : 0
+ * Fldr : 0000 : ..
+ *
+ * -FXInfo----:
+ * Rsvd|IconID: 0000 : 0
+ * Rsvd : 0000 : ..
+ * Rsvd : 0000 : ..
+ * Rsvd : 0000 : ..
+ * AreInvalid : 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * CustomBadge: 0
+ * ObjctIsBusy: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * RoutingInfo: 0
+ * unknown bit: 0
+ * unknown bit: 0
+ * Rsvd|commnt: 0000 : 0
+ * PutAway : 00000000 : 0
+ *
+ * -EA--------:
+ * pad : 0000 :
+ * magic : 41545452 : ATTR
+ * debug_tag : 00000000 : 0
+ * total_size : 0000009A : 154
+ * data_start : 00000096 : 150
+ * data_length: 00000004 : 4
+ * reserved[0]: 00000000 : ....
+ * reserved[1]: 00000000 : ....
+ * reserved[2]: 00000000 : ....
+ * flags : 0000 : ..
+ * num_attrs : 0001 : 1
+ * -EA ENTRY--:
+ * offset : 00000096 : 150
+ * length : 00000004 : 4
+ * flags : 0000 : ..
+ * namelen : 13 : 19
+ * -EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+ * 00000000 : 6F 72 67 2E 73 61 6D 62 61 EF 80 A2 77 6F 6F 68 : org.samba...wooh
+ * 00000010 : 6F 6F 00 : oo.
+ * -EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+ * 00000000 : 62 61 72 00 : bar.
+ *
+ * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII)
+ * 00000000 : 46 4F 4F 20 42 41 52 20 00 00 00 00 00 00 00 00 : FOO BAR ........
+ * 00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000020 : 00 00 41 54 54 52 00 00 00 00 00 00 00 9A 00 00 : baATTR..........
+ * 00000030 : 00 96 00 00 00 04 00 00 00 00 00 00 00 00 00 00 : ................
+ * 00000040 : 00 00 00 00 00 01 00 00 00 96 00 00 00 04 00 00 : ................
+ * 00000050 : 13 6F 72 67 2E 73 61 6D 62 61 EF 80 A2 77 6F 6F : .org.samba...woo
+ * 00000060 : 68 6F 6F 00 62 61 72 00 : hoo.bar.
+ *
+ * It was created with:
+ *
+ * $ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"'
+ */
+static char unconvert_adfile_data[] = {
+ 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00,
+ 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
+ 0x00, 0x66, 0x46, 0x4f, 0x4f, 0x20, 0x42, 0x41,
+ 0x52, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x54, 0x54, 0x52,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x11, 0x6f, 0x72, 0x67, 0x2e, 0x73,
+ 0x61, 0x6d, 0x62, 0x61, 0x3a, 0x77, 0x6f, 0x6f,
+ 0x68, 0x6f, 0x6f, 0x00, 0x62, 0x61, 0x72, 0x00,
+ 0x62, 0x61, 0x72, 0x00
+};
+
+static bool test_unconvert(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ const char *fname = BASEDIR "\\unconvert";
+ const char *adname = BASEDIR "\\._unconvert";
+ const char *net = NULL;
+ const char *share = NULL;
+ AfpInfo *afpi = NULL;
+ char *cmd = NULL;
+ struct smb2_handle h1;
+ union smb_fileinfo finfo;
+ size_t adsize;
+ NTSTATUS status;
+ int result;
+ bool ret = true;
+
+ torture_assert_not_null_goto(tctx, tree2, ret, done,
+ "Need a second share without fruit\n");
+
+ net = torture_setting_string(tctx, "net", NULL);
+ torture_assert_not_null_goto(tctx, net, ret, done,
+ "Need path to 'net'");
+
+ share = torture_setting_string(tctx, "sharename", NULL);
+ torture_assert_not_null_goto(tctx, share, ret, done,
+ "Need sharename");
+
+ torture_comment(tctx, "Testing unconvert\n");
+
+ smb2_deltree(tree1, BASEDIR);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree1, h1);
+
+ ret = torture_setup_file(tctx, tree1, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
+
+ afpi = torture_afpinfo_new(tctx);
+ torture_assert_not_null_goto(tctx, afpi, ret, done,
+ "torture_afpinfo_new failed\n");
+
+ memcpy(afpi->afpi_FinderInfo, "FOO BAR ", 8);
+
+ ret = torture_write_afpinfo(tree1, tctx, tctx, fname, afpi);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_write_afpinfo failed\n");
+
+ ret = write_stream(tree1, __location__, tctx, tctx,
+ fname,
+ /*
+ * \xef\x80\xa2 is ':' mapped to Unicoe private range
+ */
+ ":org.samba" "\xef\x80\xa2" "woohoo",
+ 0, 4, "bar");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ ret = write_stream(tree1, __location__, tctx, tctx,
+ fname, AFPRESOURCE_STREAM_NAME,
+ 0, 4, "bar");
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "write_stream failed\n");
+
+ cmd = talloc_asprintf(tctx,
+ "%s --recursive vfs stream2adouble %s %s/",
+ net,
+ share,
+ BASEDIR);
+ torture_assert_not_null_goto(tctx, cmd, ret, done,
+ "talloc_asprintf failed\n");
+
+ torture_comment(tctx, "cmd: %s\n", cmd);
+
+ result = system(cmd);
+ torture_assert_int_equal_goto(tctx, result, 0, ret, done,
+ "command failed\n");
+
+ status = torture_smb2_testfile(tree2, adname, &h1);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testfile failed\n");
+
+ finfo = (union smb_fileinfo) {
+ .generic.level = RAW_FILEINFO_ALL_INFORMATION,
+ .generic.in.file.handle = h1,
+ };
+
+ status = smb2_getinfo_file(tree2, tctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir\n");
+ smb2_util_close(tree2, h1);
+
+ adsize = finfo.all_info.out.size;
+ torture_assert_int_equal_goto(tctx, adsize,
+ sizeof(unconvert_adfile_data),
+ ret, done, "wrong size\n");
+
+ ret = check_stream(tree2, __location__, tctx, tctx,
+ adname, "", 0, adsize, 0, adsize,
+ unconvert_adfile_data);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "check_stream failed\n");
+
+done:
+// smb2_deltree(tree1, BASEDIR);
+ return ret;
+}
+
+struct torture_suite *torture_vfs_fruit_unfruit(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "unfruit");
+
+ suite->description = talloc_strdup(
+ suite, "test converting back to AppleDouble");
+
+ torture_suite_add_2ns_smb2_test(suite,
+ "unconvert",
+ test_unconvert);
+
+ return suite;
+}
+
+/*
+ * Write an invalid AFP_AfpInfo stream header
+ */
+bool test_fruit_validate_afpinfo(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ bool expect_invalid_param = torture_setting_bool(tctx, "validate_afpinfo", true);
+ const char *fname = "test_fruit_validate_afpinfo";
+ const char *sname = "test_fruit_validate_afpinfo" AFPINFO_STREAM_NAME;
+ struct smb2_handle handle;
+ AfpInfo *afpinfo = NULL;
+ char *afpinfo_buf = NULL;
+ uint8_t valbuf[8];
+ NTSTATUS status;
+ bool ret = true;
+
+ torture_comment(tctx, "Checking create of AfpInfo stream\n");
+
+ smb2_util_unlink(tree, fname);
+
+ ret = torture_setup_file(tctx, tree, fname, false);
+ torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed");
+
+ afpinfo = torture_afpinfo_new(tctx);
+ torture_assert_not_null_goto(tctx, afpinfo, ret, done,
+ "torture_afpinfo_new failed\n");
+
+ memcpy(afpinfo->afpi_FinderInfo, "FOO BAR ", 8);
+
+ ret = torture_write_afpinfo(tree, tctx, tctx, fname, afpinfo);
+ torture_assert_goto(tctx, ret == true, ret, done,
+ "torture_write_afpinfo failed\n");
+
+ afpinfo_buf = talloc_zero_size(tctx, 60);
+ torture_assert_goto(tctx, afpinfo_buf != NULL, ret, done,
+ "torture_afpinfo_new failed");
+ memcpy(afpinfo_buf + 16, "FOO ", 4);
+
+ status = torture_smb2_testfile_access(
+ tree, sname, &handle, SEC_FILE_ALL);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+
+ status = smb2_util_write(tree, handle, afpinfo_buf, 0, AFP_INFO_SIZE);
+ if (expect_invalid_param) {
+ torture_assert_ntstatus_equal_goto(
+ tctx, status, NT_STATUS_INVALID_PARAMETER, ret, done,
+ "write didn't fail as expected\n");
+ } else {
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_util_write failed");
+ }
+
+ smb2_util_close(tree, handle);
+
+ /*
+ * Verify the server fixed the header
+ */
+ PUSH_BE_U32(valbuf, 0, AFP_Signature);
+ PUSH_BE_U32(valbuf + 4, 0, AFP_Version);
+ ret = check_stream(tree, __location__, tctx, tctx, fname,
+ AFPINFO_STREAM, 0, 60, 0, 8, (char *)valbuf);
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
+
+done:
+ smb2_util_unlink(tree, fname);
+ return ret;
+}
diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c
new file mode 100644
index 0000000..3d402ee
--- /dev/null
+++ b/source4/torture/vfs/vfs.c
@@ -0,0 +1,123 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ralph Boehme 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "../lib/util/dlinklist.h"
+
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+
+#include "torture/util.h"
+#include "torture/smbtorture.h"
+#include "torture/vfs/proto.h"
+#include "torture/smb2/proto.h"
+
+static bool wrap_2ns_smb2_test(struct torture_context *torture_ctx,
+ struct torture_tcase *tcase,
+ struct torture_test *test)
+{
+ bool (*fn) (struct torture_context *, struct smb2_tree *, struct smb2_tree *);
+ bool ok;
+
+ struct smb2_tree *tree1 = NULL;
+ struct smb2_tree *tree2 = NULL;
+ TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);
+
+ if (!torture_smb2_connection(torture_ctx, &tree1)) {
+ torture_fail(torture_ctx,
+ "Establishing SMB2 connection failed\n");
+ return false;
+ }
+
+ /*
+ * This is a trick:
+ * The test might close the connection. If we steal the tree context
+ * before that and free the parent instead of tree directly, we avoid
+ * a double free error.
+ */
+ talloc_steal(mem_ctx, tree1);
+
+ ok = torture_smb2_con_sopt(torture_ctx, "share2", &tree2);
+ if (ok) {
+ talloc_steal(mem_ctx, tree2);
+ }
+
+ fn = test->fn;
+
+ ok = fn(torture_ctx, tree1, tree2);
+
+ /* the test may already have closed some of the connections */
+ talloc_free(mem_ctx);
+
+ return ok;
+}
+
+/*
+ * Run a test with 2 connected trees, the default share and another
+ * taken from option strings "torture:share2"
+ */
+struct torture_test *torture_suite_add_2ns_smb2_test(struct torture_suite *suite,
+ const char *name,
+ bool (*run)(struct torture_context *,
+ struct smb2_tree *,
+ struct smb2_tree *))
+{
+ struct torture_test *test;
+ struct torture_tcase *tcase;
+
+ tcase = torture_suite_add_tcase(suite, name);
+
+ test = talloc(tcase, struct torture_test);
+
+ test->name = talloc_strdup(test, name);
+ test->description = NULL;
+ test->run = wrap_2ns_smb2_test;
+ test->fn = run;
+ test->dangerous = false;
+
+ DLIST_ADD_END(tcase->tests, test);
+
+ return test;
+}
+
+NTSTATUS torture_vfs_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(
+ ctx, "vfs");
+
+ suite->description = talloc_strdup(suite, "VFS modules tests");
+
+ torture_suite_add_suite(suite, torture_vfs_fruit(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_netatalk(suite));
+ torture_suite_add_suite(suite, torture_acl_xattr(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_file_id(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_timemachine(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_conversion(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_unfruit(suite));
+ torture_suite_add_1smb2_test(suite, "fruit_validate_afpinfo", test_fruit_validate_afpinfo);
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c
new file mode 100644
index 0000000..1c8751e
--- /dev/null
+++ b/source4/torture/winbind/struct_based.c
@@ -0,0 +1,1190 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester - winbind struct based protocol
+ Copyright (C) Stefan Metzmacher 2007
+ Copyright (C) Michael Adam 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "nsswitch/libwbclient/wbclient.h"
+#include "nsswitch/winbind_nss_config.h"
+#include "nsswitch/winbind_struct_protocol.h"
+#include "nsswitch/libwbclient/wbclient_internal.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "param/param.h"
+#include "../libcli/auth/pam_errors.h"
+#include "torture/winbind/proto.h"
+#include "lib/util/string_wrappers.h"
+
+#define DO_STRUCT_REQ_REP_EXT(op,req,rep,expected,strict,warnaction,cmt) do { \
+ const char *__cmt = (cmt); \
+ wbcErr __wbc_status = WBC_ERR_UNKNOWN_FAILURE; \
+ NSS_STATUS __got, __expected = (expected); \
+ __wbc_status = wbcRequestResponse(NULL, op, req, rep); \
+ switch (__wbc_status) { \
+ case WBC_ERR_SUCCESS: \
+ __got = NSS_STATUS_SUCCESS; \
+ break; \
+ case WBC_ERR_WINBIND_NOT_AVAILABLE: \
+ __got = NSS_STATUS_UNAVAIL; \
+ break; \
+ case WBC_ERR_DOMAIN_NOT_FOUND: \
+ __got = NSS_STATUS_NOTFOUND; \
+ break; \
+ default: \
+ torture_result(torture, TORTURE_FAIL, \
+ __location__ ": " __STRING(op) \
+ " returned unmapped %s, expected nss %d%s%s", \
+ wbcErrorString(__wbc_status), __expected, \
+ (__cmt) ? ": " : "", \
+ (__cmt) ? (__cmt) : ""); \
+ return false; \
+ } \
+ if (__got != __expected) { \
+ if (strict) { \
+ torture_result(torture, TORTURE_FAIL, \
+ __location__ ": " __STRING(op) \
+ " returned %s, got %d , expected %d%s%s", \
+ wbcErrorString(__wbc_status), __got, __expected, \
+ (__cmt) ? ": " : "", \
+ (__cmt) ? (__cmt) : ""); \
+ return false; \
+ } else { \
+ torture_warning(torture, \
+ __location__ ": " __STRING(op) \
+ " returned %s, got %d , expected %d%s%s", \
+ wbcErrorString(__wbc_status), __got, __expected, \
+ (__cmt) ? ": " : "", \
+ (__cmt) ? (__cmt) : ""); \
+ warnaction; \
+ } \
+ } \
+} while(0)
+
+#undef _STRUCT_NOOP
+#define _STRUCT_NOOP do {} while(0);
+#define DO_STRUCT_REQ_REP(op,req,rep) do { \
+ DO_STRUCT_REQ_REP_EXT(op,req,rep,NSS_STATUS_SUCCESS,true, _STRUCT_NOOP, NULL); \
+} while (0)
+
+static bool torture_winbind_struct_interface_version(struct torture_context *torture)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ torture_comment(torture, "Running WINBINDD_INTERFACE_VERSION (struct based)\n");
+
+ DO_STRUCT_REQ_REP(WINBINDD_INTERFACE_VERSION, &req, &rep);
+
+ torture_assert_int_equal(torture,
+ rep.data.interface_version,
+ WINBIND_INTERFACE_VERSION,
+ "winbind server and client doesn't match");
+
+ return true;
+}
+
+static bool torture_winbind_struct_ping(struct torture_context *torture)
+{
+ struct timeval tv = timeval_current();
+ int timelimit = torture_setting_int(torture, "timelimit", 5);
+ uint32_t total = 0;
+
+ torture_comment(torture,
+ "Running WINBINDD_PING (struct based) for %d seconds\n",
+ timelimit);
+
+ while (timeval_elapsed(&tv) < timelimit) {
+ DO_STRUCT_REQ_REP(WINBINDD_PING, NULL, NULL);
+ total++;
+ }
+
+ torture_comment(torture,
+ "%u (%.1f/s) WINBINDD_PING (struct based)\n",
+ total, total / timeval_elapsed(&tv));
+
+ return true;
+}
+
+
+static char winbind_separator(struct torture_context *torture)
+{
+ struct winbindd_response rep;
+
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep);
+
+ return rep.data.info.winbind_separator;
+}
+
+static bool torture_winbind_struct_info(struct torture_context *torture)
+{
+ struct winbindd_response rep;
+ const char *separator;
+
+ ZERO_STRUCT(rep);
+
+ torture_comment(torture, "Running WINBINDD_INFO (struct based)\n");
+
+ DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep);
+
+ separator = torture_setting_string(torture,
+ "winbindd_separator",
+ lpcfg_winbind_separator(torture->lp_ctx));
+
+ torture_assert_int_equal(torture,
+ rep.data.info.winbind_separator,
+ *separator,
+ "winbind separator doesn't match");
+
+ torture_comment(torture, "Samba Version '%s'\n",
+ rep.data.info.samba_version);
+
+ return true;
+}
+
+static bool torture_winbind_struct_priv_pipe_dir(struct torture_context *torture)
+{
+ struct winbindd_response rep;
+ const char *got_dir;
+
+ ZERO_STRUCT(rep);
+
+ torture_comment(torture, "Running WINBINDD_PRIV_PIPE_DIR (struct based)\n");
+
+ DO_STRUCT_REQ_REP(WINBINDD_PRIV_PIPE_DIR, NULL, &rep);
+
+ got_dir = (const char *)rep.extra_data.data;
+
+ torture_assert(torture, got_dir, "NULL WINBINDD_PRIV_PIPE_DIR\n");
+
+ SAFE_FREE(rep.extra_data.data);
+ return true;
+}
+
+static bool torture_winbind_struct_netbios_name(struct torture_context *torture)
+{
+ struct winbindd_response rep;
+ const char *expected;
+
+ ZERO_STRUCT(rep);
+
+ torture_comment(torture, "Running WINBINDD_NETBIOS_NAME (struct based)\n");
+
+ DO_STRUCT_REQ_REP(WINBINDD_NETBIOS_NAME, NULL, &rep);
+
+ expected = torture_setting_string(torture,
+ "winbindd_netbios_name",
+ lpcfg_netbios_name(torture->lp_ctx));
+ expected = strupper_talloc(torture, expected);
+
+ torture_assert_str_equal(torture,
+ rep.data.netbios_name, expected,
+ "winbindd's netbios name doesn't match");
+
+ return true;
+}
+
+static bool get_winbind_domain(struct torture_context *torture, char **domain)
+{
+ struct winbindd_response rep;
+
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_DOMAIN_NAME, NULL, &rep);
+
+ *domain = talloc_strdup(torture, rep.data.domain_name);
+ torture_assert(torture, domain, "talloc error");
+
+ return true;
+}
+
+static bool torture_winbind_struct_domain_name(struct torture_context *torture)
+{
+ const char *expected;
+ char *domain;
+
+ torture_comment(torture, "Running WINBINDD_DOMAIN_NAME (struct based)\n");
+
+ expected = torture_setting_string(torture,
+ "winbindd_netbios_domain",
+ lpcfg_workgroup(torture->lp_ctx));
+
+ get_winbind_domain(torture, &domain);
+
+ torture_assert_str_equal(torture, domain, expected,
+ "winbindd's netbios domain doesn't match");
+
+ return true;
+}
+
+static bool torture_winbind_struct_check_machacc(struct torture_context *torture)
+{
+ bool ok;
+ bool strict = torture_setting_bool(torture, "strict mode", false);
+ struct winbindd_response rep;
+
+ ZERO_STRUCT(rep);
+
+ torture_comment(torture, "Running WINBINDD_CHECK_MACHACC (struct based)\n");
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_CHECK_MACHACC, NULL, &rep,
+ NSS_STATUS_SUCCESS, strict, ok = false,
+ "WINBINDD_CHECK_MACHACC");
+
+ if (!ok) {
+ torture_assert(torture,
+ strlen(rep.data.auth.nt_status_string)>0,
+ "Failed with empty nt_status_string");
+
+ torture_warning(torture,"%s:%s:%s:%d\n",
+ nt_errstr(NT_STATUS(rep.data.auth.nt_status)),
+ rep.data.auth.nt_status_string,
+ rep.data.auth.error_string,
+ rep.data.auth.pam_error);
+ return true;
+ }
+
+ torture_assert_ntstatus_ok(torture,
+ NT_STATUS(rep.data.auth.nt_status),
+ "WINBINDD_CHECK_MACHACC ok: nt_status");
+
+ torture_assert_str_equal(torture,
+ rep.data.auth.nt_status_string,
+ nt_errstr(NT_STATUS_OK),
+ "WINBINDD_CHECK_MACHACC ok:nt_status_string");
+
+ torture_assert_str_equal(torture,
+ rep.data.auth.error_string,
+ get_friendly_nt_error_msg(NT_STATUS_OK),
+ "WINBINDD_CHECK_MACHACC ok: error_string");
+
+ torture_assert_int_equal(torture,
+ rep.data.auth.pam_error,
+ nt_status_to_pam(NT_STATUS_OK),
+ "WINBINDD_CHECK_MACHACC ok: pam_error");
+
+ return true;
+}
+
+struct torture_trust_domain {
+ const char *netbios_name;
+ const char *dns_name;
+ struct dom_sid *sid;
+};
+
+static bool get_trusted_domains(struct torture_context *torture,
+ struct torture_trust_domain **_d)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ struct torture_trust_domain *d = NULL;
+ uint32_t dcount = 0;
+ char line[256];
+ const char *extra_data;
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep);
+
+ extra_data = (char *)rep.extra_data.data;
+ torture_assert(torture, extra_data != NULL,
+ "Trust list was NULL: the list of trusted domain "
+ "should be returned, with at least 2 entries "
+ "(BUILTIN, and the local domain)");
+
+ while (next_token(&extra_data, line, "\n", sizeof(line))) {
+ char *p, *lp;
+
+ d = talloc_realloc(torture, d,
+ struct torture_trust_domain,
+ dcount + 2);
+ ZERO_STRUCT(d[dcount+1]);
+
+ lp = line;
+ p = strchr(lp, '\\');
+ torture_assert(torture, p, "missing 1st '\\' in line");
+ *p = 0;
+ d[dcount].netbios_name = talloc_strdup(d, lp);
+ torture_assert(torture, strlen(d[dcount].netbios_name) > 0,
+ "empty netbios_name");
+
+ lp = p+1;
+ p = strchr(lp, '\\');
+ torture_assert(torture, p, "missing 2nd '\\' in line");
+ *p = 0;
+ d[dcount].dns_name = talloc_strdup(d, lp);
+ /* it's ok to have an empty dns_name */
+
+ lp = p+1;
+ d[dcount].sid = dom_sid_parse_talloc(d, lp);
+ torture_assert(torture, d[dcount].sid,
+ "failed to parse sid");
+
+ dcount++;
+ }
+ SAFE_FREE(rep.extra_data.data);
+
+ torture_assert(torture, dcount >= 2,
+ "The list of trusted domain should contain 2 entries "
+ "(BUILTIN, and the local domain)");
+
+ *_d = d;
+ return true;
+}
+
+static bool torture_winbind_struct_list_trustdom(struct torture_context *torture)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ char *list1;
+ char *list2;
+ bool ok;
+ struct torture_trust_domain *listd = NULL;
+ uint32_t i;
+
+ torture_comment(torture, "Running WINBINDD_LIST_TRUSTDOM (struct based)\n");
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ req.data.list_all_domains = false;
+
+ DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep);
+
+ list1 = (char *)rep.extra_data.data;
+
+ torture_comment(torture, "%s\n", list1);
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ req.data.list_all_domains = true;
+
+ DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep);
+
+ list2 = (char *)rep.extra_data.data;
+
+ /*
+ * The list_all_domains parameter should be ignored
+ */
+ torture_assert_str_equal(torture, list2, list1, "list_all_domains not ignored");
+
+ SAFE_FREE(list1);
+ SAFE_FREE(list2);
+
+ ok = get_trusted_domains(torture, &listd);
+ torture_assert(torture, ok, "failed to get trust list");
+
+ for (i=0; listd && listd[i].netbios_name; i++) {
+ if (i == 0) {
+ struct dom_sid *builtin_sid;
+
+ builtin_sid = dom_sid_parse_talloc(torture, SID_BUILTIN);
+
+ torture_assert_str_equal(torture,
+ listd[i].netbios_name,
+ NAME_BUILTIN,
+ "first domain should be 'BUILTIN'");
+
+ torture_assert_str_equal(torture,
+ listd[i].dns_name,
+ "",
+ "BUILTIN domain should not have a dns name");
+
+ ok = dom_sid_equal(builtin_sid,
+ listd[i].sid);
+ torture_assert(torture, ok, "BUILTIN domain should have S-1-5-32");
+
+ continue;
+ }
+
+ /*
+ * TODO: verify the content of the 2nd and 3rd (in member server mode)
+ * domain entries
+ */
+ }
+
+ return true;
+}
+
+static bool torture_winbind_struct_domain_info(struct torture_context *torture)
+{
+ bool ok;
+ struct torture_trust_domain *listd = NULL;
+ uint32_t i;
+
+ torture_comment(torture, "Running WINBINDD_DOMAIN_INFO (struct based)\n");
+
+ ok = get_trusted_domains(torture, &listd);
+ torture_assert(torture, ok, "failed to get trust list");
+
+ for (i=0; listd && listd[i].netbios_name; i++) {
+ torture_comment(torture, "LIST[%u] '%s' => '%s' [%s]\n",
+ (unsigned)i,
+ listd[i].netbios_name,
+ listd[i].dns_name,
+ dom_sid_string(torture, listd[i].sid));
+ }
+
+ for (i=0; listd && listd[i].netbios_name; i++) {
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ struct dom_sid *sid;
+ char *flagstr = talloc_strdup(torture," ");
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ fstrcpy(req.domain_name, listd[i].netbios_name);
+
+ DO_STRUCT_REQ_REP(WINBINDD_DOMAIN_INFO, &req, &rep);
+
+ if (rep.data.domain_info.primary) {
+ flagstr = talloc_strdup_append(flagstr, "PR ");
+ }
+
+ if (rep.data.domain_info.active_directory) {
+ torture_assert(torture,
+ strlen(rep.data.domain_info.alt_name)>0,
+ "Active Directory without DNS name");
+ flagstr = talloc_strdup_append(flagstr, "AD ");
+ }
+
+ if (rep.data.domain_info.native_mode) {
+ torture_assert(torture,
+ rep.data.domain_info.active_directory,
+ "Native-Mode, but no Active Directory");
+ flagstr = talloc_strdup_append(flagstr, "NA ");
+ }
+
+ torture_comment(torture, "DOMAIN[%u] '%s' => '%s' [%s] [%s]\n",
+ (unsigned)i,
+ rep.data.domain_info.name,
+ rep.data.domain_info.alt_name,
+ flagstr,
+ rep.data.domain_info.sid);
+
+ sid = dom_sid_parse_talloc(torture, rep.data.domain_info.sid);
+ torture_assert(torture, sid, "Failed to parse SID");
+
+ ok = dom_sid_equal(listd[i].sid, sid);
+ torture_assert(torture, ok, talloc_asprintf(torture, "SID's doesn't match [%s] != [%s]",
+ dom_sid_string(torture, listd[i].sid),
+ dom_sid_string(torture, sid)));
+
+ torture_assert_str_equal(torture,
+ rep.data.domain_info.name,
+ listd[i].netbios_name,
+ "Netbios domain name doesn't match");
+
+ torture_assert_str_equal(torture,
+ rep.data.domain_info.alt_name,
+ listd[i].dns_name,
+ "DNS domain name doesn't match");
+ }
+
+ return true;
+}
+
+static bool torture_winbind_struct_getdcname(struct torture_context *torture)
+{
+ bool ok;
+ bool strict = torture_setting_bool(torture, "strict mode", false);
+ const char *domain_name = torture_setting_string(torture,
+ "winbindd_netbios_domain",
+ lpcfg_workgroup(torture->lp_ctx));
+ struct torture_trust_domain *listd = NULL;
+ uint32_t i, count = 0;
+
+ torture_comment(torture, "Running WINBINDD_GETDCNAME (struct based)\n");
+
+ ok = get_trusted_domains(torture, &listd);
+ torture_assert(torture, ok, "failed to get trust list");
+
+ for (i=0; listd && listd[i].netbios_name; i++) {
+ struct winbindd_request req;
+ struct winbindd_response rep;
+
+ /* getdcname is not expected to work on "BUILTIN" or our own
+ * domain */
+ if (strequal(listd[i].netbios_name, "BUILTIN") ||
+ strequal(listd[i].netbios_name, domain_name)) {
+ continue;
+ }
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ fstrcpy(req.domain_name, listd[i].netbios_name);
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_GETDCNAME, &req, &rep,
+ NSS_STATUS_SUCCESS,
+ (i <2 || strict), ok = false,
+ talloc_asprintf(torture, "DOMAIN '%s'",
+ req.domain_name));
+ if (!ok) continue;
+
+ /* TODO: check rep.data.dc_name; */
+ torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n",
+ req.domain_name, rep.data.dc_name);
+ count++;
+ }
+
+ if (strict) {
+ torture_assert(torture, count > 0,
+ "WiNBINDD_GETDCNAME was not tested");
+ }
+ return true;
+}
+
+static bool torture_winbind_struct_dsgetdcname(struct torture_context *torture)
+{
+ bool ok;
+ bool strict = torture_setting_bool(torture, "strict mode", false);
+ struct torture_trust_domain *listd = NULL;
+ uint32_t i;
+ uint32_t count = 0;
+
+ torture_comment(torture, "Running WINBINDD_DSGETDCNAME (struct based)\n");
+
+ ok = get_trusted_domains(torture, &listd);
+ torture_assert(torture, ok, "failed to get trust list");
+
+ for (i=0; listd && listd[i].netbios_name; i++) {
+ struct winbindd_request req;
+ struct winbindd_response rep;
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ if (strlen(listd[i].dns_name) == 0) continue;
+
+ /*
+ * TODO: remove this and let winbindd give no dns name
+ * for NT4 domains
+ */
+ if (strcmp(listd[i].dns_name, listd[i].netbios_name) == 0) {
+ continue;
+ }
+
+ fstrcpy(req.domain_name, listd[i].dns_name);
+
+ /* TODO: test more flag combinations */
+ req.flags = DS_DIRECTORY_SERVICE_REQUIRED;
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_DSGETDCNAME, &req, &rep,
+ NSS_STATUS_SUCCESS,
+ strict, ok = false,
+ talloc_asprintf(torture, "DOMAIN '%s'",
+ req.domain_name));
+ if (!ok) continue;
+
+ /* TODO: check rep.data.dc_name; */
+ torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n",
+ req.domain_name, rep.data.dc_name);
+
+ count++;
+ }
+
+ if (count == 0) {
+ torture_warning(torture, "WINBINDD_DSGETDCNAME"
+ " was not tested with %d non-AD domains",
+ i);
+ }
+
+ if (strict) {
+ torture_assert(torture, count > 0,
+ "WiNBINDD_DSGETDCNAME was not tested");
+ }
+
+ return true;
+}
+
+static bool get_user_list(struct torture_context *torture, char ***users)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ char **u = NULL;
+ uint32_t count;
+ char name[256];
+ const char *extra_data;
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_LIST_USERS, &req, &rep);
+
+ extra_data = (char *)rep.extra_data.data;
+ torture_assert(torture, extra_data, "NULL extra data");
+
+ for(count = 0;
+ next_token(&extra_data, name, ",", sizeof(name));
+ count++)
+ {
+ u = talloc_realloc(torture, u, char *, count + 2);
+ u[count+1] = NULL;
+ u[count] = talloc_strdup(u, name);
+ }
+
+ SAFE_FREE(rep.extra_data.data);
+
+ *users = u;
+ return true;
+}
+
+static bool torture_winbind_struct_list_users(struct torture_context *torture)
+{
+ char **users;
+ uint32_t count;
+ bool ok;
+
+ torture_comment(torture, "Running WINBINDD_LIST_USERS (struct based)\n");
+
+ ok = get_user_list(torture, &users);
+ torture_assert(torture, ok, "failed to get user list");
+
+ for (count = 0; users[count]; count++) { }
+
+ torture_comment(torture, "got %d users\n", count);
+
+ return true;
+}
+
+static bool get_group_list(struct torture_context *torture,
+ unsigned int *num_entries,
+ char ***groups)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ char **g = NULL;
+ uint32_t count;
+ char name[256];
+ const char *extra_data;
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_LIST_GROUPS, &req, &rep);
+ extra_data = (char *)rep.extra_data.data;
+
+ *num_entries = rep.data.num_entries;
+
+ if (*num_entries == 0) {
+ torture_assert(torture, extra_data == NULL,
+ "extra data is null for >0 reported entries\n");
+ *groups = NULL;
+ return true;
+ }
+
+ torture_assert(torture, extra_data, "NULL extra data");
+
+ for(count = 0;
+ next_token(&extra_data, name, ",", sizeof(name));
+ count++)
+ {
+ g = talloc_realloc(torture, g, char *, count + 2);
+ g[count+1] = NULL;
+ g[count] = talloc_strdup(g, name);
+ }
+
+ SAFE_FREE(rep.extra_data.data);
+
+ torture_assert_int_equal(torture, *num_entries, count,
+ "Wrong number of group entries reported.");
+
+ *groups = g;
+ return true;
+}
+
+static bool torture_winbind_struct_list_groups(struct torture_context *torture)
+{
+ char **groups;
+ uint32_t count;
+ bool ok;
+
+ torture_comment(torture, "Running WINBINDD_LIST_GROUPS (struct based)\n");
+
+ ok = get_group_list(torture, &count, &groups);
+ torture_assert(torture, ok, "failed to get group list");
+
+ torture_comment(torture, "got %d groups\n", count);
+
+ return true;
+}
+
+struct torture_domain_sequence {
+ const char *netbios_name;
+ uint32_t seq;
+};
+
+static bool get_sequence_numbers(struct torture_context *torture,
+ struct torture_domain_sequence **seqs)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ const char *extra_data;
+ char line[256];
+ uint32_t count = 0;
+ struct torture_domain_sequence *s = NULL;
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
+
+ extra_data = (char *)rep.extra_data.data;
+ torture_assert(torture, extra_data, "NULL sequence list");
+
+ while (next_token(&extra_data, line, "\n", sizeof(line))) {
+ char *p, *lp;
+ uint32_t seq;
+
+ s = talloc_realloc(torture, s, struct torture_domain_sequence,
+ count + 2);
+ ZERO_STRUCT(s[count+1]);
+
+ lp = line;
+ p = strchr(lp, ' ');
+ torture_assert(torture, p, "invalid line format");
+ *p = 0;
+ s[count].netbios_name = talloc_strdup(s, lp);
+
+ lp = p+1;
+ torture_assert(torture, strncmp(lp, ": ", 2) == 0,
+ "invalid line format");
+ lp += 2;
+ if (strcmp(lp, "DISCONNECTED") == 0) {
+ seq = (uint32_t)-1;
+ } else {
+ seq = (uint32_t)strtol(lp, &p, 10);
+ torture_assert(torture, (*p == '\0'),
+ "invalid line format");
+ torture_assert(torture, (seq != (uint32_t)-1),
+ "sequence number -1 encountered");
+ }
+ s[count].seq = seq;
+
+ count++;
+ }
+ SAFE_FREE(rep.extra_data.data);
+
+ torture_assert(torture, count >= 2, "The list of domain sequence "
+ "numbers should contain 2 entries");
+
+ *seqs = s;
+ return true;
+}
+
+static bool torture_winbind_struct_show_sequence(struct torture_context *torture)
+{
+ bool ok;
+ uint32_t i;
+ struct torture_trust_domain *domlist = NULL;
+ struct torture_domain_sequence *s = NULL;
+
+ torture_comment(torture, "Running WINBINDD_SHOW_SEQUENCE (struct based)\n");
+
+ ok = get_sequence_numbers(torture, &s);
+ torture_assert(torture, ok, "failed to get list of sequence numbers");
+
+ ok = get_trusted_domains(torture, &domlist);
+ torture_assert(torture, ok, "failed to get trust list");
+
+ for (i=0; domlist[i].netbios_name; i++) {
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ uint32_t seq;
+
+ torture_assert(torture, s[i].netbios_name,
+ "more domains received in second run");
+ torture_assert_str_equal(torture, domlist[i].netbios_name,
+ s[i].netbios_name,
+ "inconsistent order of domain lists");
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+ fstrcpy(req.domain_name, domlist[i].netbios_name);
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_SHOW_SEQUENCE, &req, &rep,
+ NSS_STATUS_SUCCESS,
+ false, ok = false,
+ "WINBINDD_SHOW_SEQUENCE");
+ if (ok == false) {
+ torture_warning(torture,
+ "WINBINDD_SHOW_SEQUENCE on "
+ "domain %s failed\n",
+ req.domain_name);
+
+ /*
+ * Only fail for the first two domain that we
+ * check specially below, otherwise we fail on
+ * trusts generated by the LSA torture test
+ * that do not really exist.
+ */
+ if (i > 1) {
+ /*
+ * Do not confirm the sequence numbers
+ * below
+ */
+ return true;
+ }
+
+ torture_comment(torture,
+ "Full trust list for "
+ "WINBINDD_SHOW_SEQUENCE "
+ "test was:\n");
+ for (i=0; domlist[i].netbios_name; i++) {
+ torture_comment(torture,
+ "%s\n",
+ domlist[i].netbios_name);
+ }
+
+ return false;
+ }
+
+ seq = rep.data.sequence_number;
+
+ if (i == 0) {
+ torture_assert(torture, (seq != (uint32_t)-1),
+ "BUILTIN domain disconnected");
+ } else if (i == 1) {
+ torture_assert(torture, (seq != (uint32_t)-1),
+ "local domain disconnected");
+ }
+
+
+ if (seq == (uint32_t)-1) {
+ torture_comment(torture, " * %s : DISCONNECTED\n",
+ req.domain_name);
+ } else {
+ torture_comment(torture, " * %s : %d\n",
+ req.domain_name, seq);
+ }
+ torture_assert(torture, (seq >= s[i].seq),
+ "illegal sequence number encountered");
+ }
+
+ return true;
+}
+
+static bool torture_winbind_struct_setpwent(struct torture_context *torture)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+
+ torture_comment(torture, "Running WINBINDD_SETPWENT (struct based)\n");
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
+
+ return true;
+}
+
+static bool torture_winbind_struct_getpwent(struct torture_context *torture)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ struct winbindd_pw *pwent;
+
+ torture_comment(torture, "Running WINBINDD_GETPWENT (struct based)\n");
+
+ torture_comment(torture, " - Running WINBINDD_SETPWENT first\n");
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+ DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep);
+
+ torture_comment(torture, " - Running WINBINDD_GETPWENT now\n");
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+ req.data.num_entries = 1;
+ if (torture_setting_bool(torture, "samba3", false)) {
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_GETPWENT, &req, &rep,
+ NSS_STATUS_SUCCESS, false, _STRUCT_NOOP,
+ NULL);
+ } else {
+ DO_STRUCT_REQ_REP(WINBINDD_GETPWENT, &req, &rep);
+ }
+ pwent = (struct winbindd_pw *)rep.extra_data.data;
+ if (!torture_setting_bool(torture, "samba3", false)) {
+ torture_assert(torture, (pwent != NULL), "NULL pwent");
+ }
+ if (pwent) {
+ torture_comment(torture, "name: %s, uid: %d, gid: %d, shell: %s\n",
+ pwent->pw_name, pwent->pw_uid, pwent->pw_gid,
+ pwent->pw_shell);
+ }
+
+ return true;
+}
+
+static bool torture_winbind_struct_endpwent(struct torture_context *torture)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+
+ torture_comment(torture, "Running WINBINDD_ENDPWENT (struct based)\n");
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ DO_STRUCT_REQ_REP(WINBINDD_ENDPWENT, &req, &rep);
+
+ return true;
+}
+
+/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
+ form DOMAIN/user into a domain and a user */
+
+static bool parse_domain_user(struct torture_context *torture,
+ const char *domuser, fstring domain,
+ fstring user)
+{
+ char *p = strchr(domuser, winbind_separator(torture));
+ char *dom = NULL;
+
+ if (!p) {
+ /* Maybe it was a UPN? */
+ if ((p = strchr(domuser, '@')) != NULL) {
+ fstrcpy(domain, "");
+ fstrcpy(user, domuser);
+ return true;
+ }
+
+ fstrcpy(user, domuser);
+ get_winbind_domain(torture, &dom);
+ fstrcpy(domain, dom);
+ return true;
+ }
+
+ fstrcpy(user, p+1);
+ fstrcpy(domain, domuser);
+ domain[PTR_DIFF(p, domuser)] = 0;
+
+ return true;
+}
+
+static bool lookup_name_sid_list(struct torture_context *torture, char **list)
+{
+ uint32_t count;
+
+ for (count = 0; list[count]; count++) {
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ char *sid;
+ char *name;
+ const char *domain_name = torture_setting_string(torture,
+ "winbindd_domain_without_prefix",
+ NULL);
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ parse_domain_user(torture, list[count], req.data.name.dom_name,
+ req.data.name.name);
+
+ DO_STRUCT_REQ_REP(WINBINDD_LOOKUPNAME, &req, &rep);
+
+ sid = talloc_strdup(torture, rep.data.sid.sid);
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ fstrcpy(req.data.sid, sid);
+
+ DO_STRUCT_REQ_REP(WINBINDD_LOOKUPSID, &req, &rep);
+
+ if (domain_name != NULL &&
+ strequal(rep.data.name.dom_name, domain_name))
+ {
+ name = talloc_asprintf(torture, "%s",
+ rep.data.name.name);
+ } else {
+ name = talloc_asprintf(torture, "%s%c%s",
+ rep.data.name.dom_name,
+ winbind_separator(torture),
+ rep.data.name.name);
+ }
+
+ torture_assert_casestr_equal(torture, list[count], name,
+ "LOOKUP_SID after LOOKUP_NAME != id");
+
+#if 0
+ torture_comment(torture, " %s -> %s -> %s\n", list[count],
+ sid, name);
+#endif
+
+ talloc_free(sid);
+ talloc_free(name);
+ }
+
+ return true;
+}
+
+static bool name_is_in_list(const char *name, char **list)
+{
+ uint32_t count;
+
+ for (count = 0; list && list[count]; count++) {
+ if (strequal(name, list[count])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool torture_winbind_struct_lookup_name_sid(struct torture_context *torture)
+{
+ struct winbindd_request req;
+ struct winbindd_response rep;
+ const char *invalid_sid = "S-0-0-7";
+ char *domain = NULL;
+ const char *invalid_user = "no one";
+ char *invalid_name;
+ bool strict = torture_setting_bool(torture, "strict mode", false);
+ char **users;
+ char **groups;
+ uint32_t count, num_groups;
+ bool ok;
+
+ torture_comment(torture, "Running WINBINDD_LOOKUP_NAME_SID (struct based)\n");
+
+ ok = get_user_list(torture, &users);
+ torture_assert(torture, ok, "failed to retrieve list of users");
+ lookup_name_sid_list(torture, users);
+
+ ok = get_group_list(torture, &num_groups, &groups);
+ torture_assert(torture, ok, "failed to retrieve list of groups");
+ if (num_groups > 0) {
+ lookup_name_sid_list(torture, groups);
+ }
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ fstrcpy(req.data.sid, invalid_sid);
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSID, &req, &rep,
+ NSS_STATUS_NOTFOUND,
+ strict,
+ ok=false,
+ talloc_asprintf(torture,
+ "invalid sid %s was resolved",
+ invalid_sid));
+
+ ZERO_STRUCT(req);
+ ZERO_STRUCT(rep);
+
+ /* try to find an invalid name... */
+
+ count = 0;
+ get_winbind_domain(torture, &domain);
+ do {
+ count++;
+ invalid_name = talloc_asprintf(torture, "%s/%s%u",
+ domain,
+ invalid_user, count);
+ } while(name_is_in_list(invalid_name, users) ||
+ name_is_in_list(invalid_name, groups));
+
+ fstrcpy(req.data.name.dom_name, domain);
+ fstrcpy(req.data.name.name,
+ talloc_asprintf(torture, "%s%u", invalid_user,
+ count));
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPNAME, &req, &rep,
+ NSS_STATUS_NOTFOUND,
+ strict,
+ ok=false,
+ talloc_asprintf(torture,
+ "invalid name %s was resolved",
+ invalid_name));
+
+ talloc_free(users);
+ talloc_free(groups);
+
+ return true;
+}
+
+static bool torture_winbind_struct_lookup_sids_invalid(
+ struct torture_context *torture)
+{
+ struct winbindd_request req = {0};
+ struct winbindd_response rep = {0};
+ bool strict = torture_setting_bool(torture, "strict mode", false);
+ bool ok;
+
+ torture_comment(torture,
+ "Running WINBINDD_LOOKUP_SIDS (struct based)\n");
+
+ ok = true;
+ DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSIDS, &req, &rep,
+ NSS_STATUS_NOTFOUND,
+ strict,
+ ok=false,
+ talloc_asprintf(
+ torture,
+ "invalid lookupsids succeeded"));
+
+ return ok;
+}
+
+struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "struct");
+
+ torture_suite_add_simple_test(suite, "interface_version", torture_winbind_struct_interface_version);
+ torture_suite_add_simple_test(suite, "ping", torture_winbind_struct_ping);
+ torture_suite_add_simple_test(suite, "info", torture_winbind_struct_info);
+ torture_suite_add_simple_test(suite, "priv_pipe_dir", torture_winbind_struct_priv_pipe_dir);
+ torture_suite_add_simple_test(suite, "netbios_name", torture_winbind_struct_netbios_name);
+ torture_suite_add_simple_test(suite, "domain_name", torture_winbind_struct_domain_name);
+ torture_suite_add_simple_test(suite, "check_machacc", torture_winbind_struct_check_machacc);
+ torture_suite_add_simple_test(suite, "list_trustdom", torture_winbind_struct_list_trustdom);
+ torture_suite_add_simple_test(suite, "domain_info", torture_winbind_struct_domain_info);
+ torture_suite_add_simple_test(suite, "getdcname", torture_winbind_struct_getdcname);
+ torture_suite_add_simple_test(suite, "dsgetdcname", torture_winbind_struct_dsgetdcname);
+ torture_suite_add_simple_test(suite, "list_users", torture_winbind_struct_list_users);
+ torture_suite_add_simple_test(suite, "list_groups", torture_winbind_struct_list_groups);
+ torture_suite_add_simple_test(suite, "show_sequence", torture_winbind_struct_show_sequence);
+ torture_suite_add_simple_test(suite, "setpwent", torture_winbind_struct_setpwent);
+ torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent);
+ torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent);
+ torture_suite_add_simple_test(suite, "lookup_name_sid", torture_winbind_struct_lookup_name_sid);
+ torture_suite_add_simple_test(
+ suite,
+ "lookup_sids_invalid",
+ torture_winbind_struct_lookup_sids_invalid);
+
+ suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests");
+
+ return suite;
+}
diff --git a/source4/torture/winbind/winbind.c b/source4/torture/winbind/winbind.c
new file mode 100644
index 0000000..4acfd38
--- /dev/null
+++ b/source4/torture/winbind/winbind.c
@@ -0,0 +1,335 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Stefan Metzmacher 2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2012
+ Copyright (C) Christof Schmit <christof.schmitt@us.ibm.com> 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "torture/winbind/proto.h"
+#include "auth/auth.h"
+#include "auth/auth_sam_reply.h"
+#include "auth/gensec/gensec.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+#include "lib/cmdline/cmdline.h"
+#include "auth/kerberos/pac_utils.h"
+#include "wbclient.h"
+
+struct pac_data {
+ DATA_BLOB pac_blob;
+};
+
+/* A helper function which avoids touching the local databases to
+ * generate the session info, as we just want to verify the PAC
+ * details, not the full local token */
+static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ DATA_BLOB *pac_blob,
+ const char *principal_name,
+ const struct tsocket_address *remote_address,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS nt_status;
+ struct auth_user_info_dc *user_info_dc;
+ TALLOC_CTX *tmp_ctx;
+ struct pac_data *pac_data;
+
+ if (pac_blob == NULL) {
+ DBG_ERR("pac_blob missing\n");
+ return NT_STATUS_NO_IMPERSONATION_TOKEN;
+ }
+
+ tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data);
+
+ pac_data->pac_blob = *pac_blob;
+
+ talloc_steal(pac_data, pac_data->pac_blob.data);
+ nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
+ *pac_blob,
+ smb_krb5_context->krb5_context,
+ &user_info_dc,
+ NULL, NULL);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
+ session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+ }
+
+ session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
+ nt_status = auth_generate_session_info(mem_ctx,
+ NULL,
+ NULL,
+ user_info_dc, session_info_flags,
+ session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(tmp_ctx);
+ return nt_status;
+ }
+
+ talloc_free(tmp_ctx);
+ return nt_status;
+}
+
+static bool torture_decode_compare_pac(struct torture_context *tctx,
+ DATA_BLOB pac)
+{
+ struct wbcAuthUserParams params;
+ struct wbcAuthUserInfo *info;
+ struct wbcAuthErrorInfo *error;
+ struct PAC_LOGON_INFO *logon_info;
+ struct netr_SamInfo3 *info3;
+ struct netr_SamBaseInfo *base;
+ struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
+ wbcErr wbc_err;
+ NTSTATUS status;
+ int sid_idx, i;
+ char sid_str[50];
+
+ /* Let winbind decode the PAC */
+ memset(&params, 0, sizeof(params));
+ params.level = WBC_AUTH_USER_LEVEL_PAC;
+ params.password.pac.data = pac.data;
+ params.password.pac.length = pac.length;
+
+ wbc_err = wbcAuthenticateUserEx(&params, &info, &error);
+ torture_assert(tctx, WBC_ERROR_IS_OK(wbc_err), wbcErrorString(wbc_err));
+
+ /* Decode the PAC internally */
+ status = kerberos_pac_logon_info(tctx, pac, NULL, NULL, NULL, NULL, 0,
+ &logon_info);
+ torture_assert(tctx, NT_STATUS_IS_OK(status), "pac_logon_info");
+ info3 = &logon_info->info3;
+ base = &info3->base;
+ resource_groups = &logon_info->resource_groups;
+
+ /* Compare the decoded data from winbind and from internal call */
+ torture_assert(tctx, info->user_flags == base->user_flags, "user_flags");
+ torture_assert_str_equal(tctx, info->account_name, base->account_name.string, "account_name");
+ torture_assert_str_equal(tctx, info->full_name, base->full_name.string, "full_name");
+ torture_assert_str_equal(tctx, info->domain_name, base->logon_domain.string, "domain_name");
+ torture_assert(tctx, info->acct_flags == base->acct_flags, "acct_flags");
+ torture_assert(tctx, info->logon_count == base->logon_count, "logon_count");
+ torture_assert(tctx, info->bad_password_count == base->bad_password_count, "bad_password_count");
+ torture_assert(tctx, info->logon_time == nt_time_to_unix(base->logon_time), "logon_time");
+ torture_assert(tctx, info->logoff_time == nt_time_to_unix(base->logoff_time), "logoff_time");
+ torture_assert(tctx, info->kickoff_time == nt_time_to_unix(base->kickoff_time), "kickoff_time");
+ torture_assert(tctx, info->pass_last_set_time == nt_time_to_unix(base->last_password_change), "last_password_change");
+ torture_assert(tctx, info->pass_can_change_time == nt_time_to_unix(base->allow_password_change), "allow_password_change");
+ torture_assert(tctx, info->pass_must_change_time == nt_time_to_unix(base->force_password_change), "force_password_change");
+ torture_assert(tctx, info->num_sids == 2 + base->groups.count + info3->sidcount + resource_groups->groups.count, "num_sids");
+
+ sid_idx = 0;
+ wbcSidToStringBuf(&info->sids[sid_idx].sid, sid_str, sizeof(sid_str));
+ torture_assert(tctx,
+ dom_sid_equal(dom_sid_parse_talloc(tctx, sid_str),
+ dom_sid_add_rid(tctx, base->domain_sid, base->rid)),
+ sid_str);
+
+ sid_idx++;
+ wbcSidToStringBuf(&info->sids[sid_idx].sid, sid_str, sizeof(sid_str));
+ torture_assert(tctx,
+ dom_sid_equal(dom_sid_parse_talloc(tctx, sid_str),
+ dom_sid_add_rid(tctx, base->domain_sid, base->primary_gid)),
+ sid_str);
+
+ for(i = 0; i < base->groups.count; i++ ) {
+ sid_idx++;
+ wbcSidToStringBuf(&info->sids[sid_idx].sid,
+ sid_str, sizeof(sid_str));
+ torture_assert_sid_equal(tctx,
+ dom_sid_parse_talloc(tctx, sid_str),
+ dom_sid_add_rid(tctx, base->domain_sid,
+ base->groups.rids[i].rid),
+ "base SID mismatch");
+ }
+
+ for(i = 0; i < info3->sidcount; i++) {
+ sid_idx++;
+ wbcSidToStringBuf(&info->sids[sid_idx].sid,
+ sid_str, sizeof(sid_str));
+ torture_assert_sid_equal(tctx,
+ dom_sid_parse_talloc(tctx, sid_str),
+ info3->sids[i].sid,
+ "extra SID mismatch");
+ }
+
+ for (i = 0; i < resource_groups->groups.count; i++) {
+ sid_idx++;
+ wbcSidToStringBuf(&info->sids[sid_idx].sid,
+ sid_str, sizeof(sid_str));
+ torture_assert_sid_equal(tctx,
+ dom_sid_parse_talloc(tctx, sid_str),
+ dom_sid_add_rid(tctx, resource_groups->domain_sid,
+ resource_groups->groups.rids[i].rid),
+ "resource SID mismatch");
+ }
+
+ sid_idx++;
+ torture_assert_int_equal(tctx, sid_idx, info->num_sids, "some SIDs still unaccounted for");
+
+ return true;
+}
+
+static bool torture_winbind_pac(struct torture_context *tctx,
+ const char *sasl_mech,
+ const char *mech)
+{
+ NTSTATUS status;
+
+ struct gensec_security *gensec_client_context;
+ struct gensec_security *gensec_server_context;
+ struct cli_credentials *machine_credentials;
+
+ DATA_BLOB client_to_server, server_to_client;
+
+ struct auth4_context *auth_context;
+ struct auth_session_info *session_info;
+ struct pac_data *pac_data;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(tctx);
+ torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");
+
+ machine_credentials = cli_credentials_init_server(tmp_ctx,
+ tctx->lp_ctx);
+ torture_assert(tctx, machine_credentials != NULL, "cli_credentials_init() failed");
+
+ auth_context = talloc_zero(tmp_ctx, struct auth4_context);
+ torture_assert(tctx, auth_context != NULL, "talloc_new() failed");
+
+ auth_context->generate_session_info_pac = test_generate_session_info_pac;
+
+ status = gensec_client_start(tctx, &gensec_client_context,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");
+
+ status = gensec_set_target_hostname(gensec_client_context, cli_credentials_get_workstation(machine_credentials));
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");
+
+ status = gensec_set_credentials(gensec_client_context,
+ samba_cmdline_get_creds());
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");
+
+ if (sasl_mech) {
+ status = gensec_start_mech_by_sasl_name(gensec_client_context, sasl_mech);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");
+ } else {
+ status = gensec_start_mech_by_name(gensec_client_context, mech);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (client) failed");
+ }
+
+
+ status = gensec_server_start(tctx,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ auth_context, &gensec_server_context);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");
+
+ status = gensec_set_credentials(gensec_server_context, machine_credentials);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");
+
+ if (sasl_mech) {
+ status = gensec_start_mech_by_sasl_name(gensec_server_context, sasl_mech);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");
+ } else {
+ status = gensec_start_mech_by_name(gensec_server_context, mech);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (server) failed");
+ }
+
+ server_to_client = data_blob(NULL, 0);
+
+ do {
+ /* Do a client-server update dance */
+ status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
+ }
+
+ status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
+ torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
+ }
+
+ if (NT_STATUS_IS_OK(status)) {
+ break;
+ }
+ } while (1);
+
+ /* Extract the PAC using Samba's code */
+
+ status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info);
+ torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");
+
+ pac_data = talloc_get_type(auth_context->private_data, struct pac_data);
+
+ torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context");
+ torture_assert(tctx, pac_data->pac_blob.data != NULL, "pac_blob not present");
+ torture_decode_compare_pac(tctx, pac_data->pac_blob);
+
+ return true;
+}
+
+static bool torture_winbind_pac_gssapi(struct torture_context *tctx)
+{
+ return torture_winbind_pac(tctx, "GSSAPI", NULL);
+}
+
+static bool torture_winbind_pac_gss_spnego(struct torture_context *tctx)
+{
+ return torture_winbind_pac(tctx, "GSS-SPNEGO", NULL);
+}
+
+static bool torture_winbind_pac_krb5(struct torture_context *tctx)
+{
+ return torture_winbind_pac(tctx, NULL, "krb5");
+}
+
+NTSTATUS torture_winbind_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "winbind");
+ struct torture_suite *pac_suite;
+ torture_suite_add_suite(suite, torture_winbind_struct_init(suite));
+ torture_suite_add_suite(suite, torture_wbclient(suite));
+
+ pac_suite = torture_suite_create(ctx, "pac");
+ torture_suite_add_simple_test(pac_suite,
+ "GSSAPI", torture_winbind_pac_gssapi);
+ torture_suite_add_simple_test(pac_suite,
+ "GSS-SPNEGO", torture_winbind_pac_gss_spnego);
+ torture_suite_add_simple_test(pac_suite,
+ "krb5", torture_winbind_pac_krb5);
+
+ pac_suite->description = talloc_strdup(suite, "Winbind Kerberos PAC tests");
+
+ torture_suite_add_suite(suite, pac_suite);
+
+ suite->description = talloc_strdup(suite, "WINBIND tests");
+
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/winbind/wscript_build b/source4/torture/winbind/wscript_build
new file mode 100644
index 0000000..07b0b2b
--- /dev/null
+++ b/source4/torture/winbind/wscript_build
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_WINBIND',
+ source='winbind.c struct_based.c ../../../nsswitch/libwbclient/tests/wbclient.c',
+ autoproto='proto.h',
+ subsystem='smbtorture',
+ init_function='torture_winbind_init',
+ deps='popt wbclient torture PAM_ERRORS winbindd-lib',
+ internal_module=True
+ )
diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build
new file mode 100644
index 0000000..1ddce71
--- /dev/null
+++ b/source4/torture/wscript_build
@@ -0,0 +1,361 @@
+#!/usr/bin/env python
+
+provision = bld.pyembed_libname('PROVISION')
+samba_net = bld.pyembed_libname('samba-net')
+
+bld.SAMBA_SUBSYSTEM('TORTURE_UTIL',
+ source='util_smb.c',
+ public_deps='torture',
+ deps='smbclient-raw CMDLINE_S4 CREDENTIALS_KRB5'
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_BASIC',
+ source='basic/base.c basic/misc.c basic/scanner.c basic/utable.c basic/charset.c basic/mangle_test.c basic/denytest.c basic/aliases.c basic/locking.c basic/secleak.c basic/rename.c basic/dir.c basic/delete.c basic/unlink.c basic/disconnect.c basic/delaywrite.c basic/attr.c basic/properties.c',
+ subsystem='smbtorture',
+ deps='LIBCLI_SMB TORTURE_UTIL smbclient-raw TORTURE_RAW',
+ internal_module=True,
+ autoproto='basic/proto.h',
+ init_function='torture_base_init',
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_RAW',
+ source='raw/qfsinfo.c raw/qfileinfo.c raw/setfileinfo.c raw/search.c raw/close.c raw/open.c raw/mkdir.c raw/oplock.c raw/notify.c raw/mux.c raw/ioctl.c raw/chkpath.c raw/unlink.c raw/read.c raw/context.c raw/session.c raw/write.c raw/lock.c raw/pingpong.c raw/lockbench.c raw/lookuprate.c raw/tconrate.c raw/openbench.c raw/rename.c raw/eas.c raw/streams.c raw/acls.c raw/seek.c raw/samba3hide.c raw/samba3misc.c raw/composite.c raw/raw.c raw/offline.c',
+ autoproto='raw/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_raw_init',
+ deps='LIBCLI_SMB LIBCLI_LSA LIBCLI_SMB_COMPOSITE TORTURE_UTIL',
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+bld.RECURSE('smb2')
+bld.RECURSE('winbind')
+bld.RECURSE('libnetapi')
+bld.RECURSE('libsmbclient')
+bld.RECURSE('gpo')
+
+ntvfs_specific = dict(source='', deps='')
+
+# Yes, the spoolss_notify test uses the NTVFS file server to run the SMB server expected
+# to handle the RPC callback!
+if bld.CONFIG_SET('WITH_NTVFS_FILESERVER'):
+ ntvfs_specific['source'] += ' rpc/spoolss_notify.c'
+ ntvfs_specific['deps'] += ' SMB_SERVER dcerpc_server ntvfs'
+
+bld.SAMBA_SUBSYSTEM('TORTURE_NDR',
+ source='''ndr/ndr.c
+ ndr/dcerpc.c
+ ndr/winreg.c
+ ndr/atsvc.c
+ ndr/lsa.c
+ ndr/epmap.c
+ ndr/dfs.c
+ ndr/netlogon.c
+ ndr/drsuapi.c
+ ndr/spoolss.c
+ ndr/ntprinting.c
+ ndr/samr.c
+ ndr/dfsblob.c
+ ndr/drsblobs.c
+ ndr/dnsp.c
+ ndr/nbt.c
+ ndr/ntlmssp.c
+ ndr/string.c
+ ndr/backupkey.c
+ ndr/witness.c
+ ndr/clusapi.c
+ ndr/negoex.c
+ ndr/krb5pac.c
+ ndr/winspool.c
+ ndr/cabinet.c
+ ndr/charset.c
+ ndr/svcctl.c
+ ndr/odj.c
+ ''',
+ autoproto='ndr/proto.h',
+ deps='torture krb5samba',
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+bld.SAMBA_SUBSYSTEM('IREMOTEWINSPOOL_COMMON',
+ source='rpc/iremotewinspool_common.c',
+ deps='talloc',
+ enabled=bld.PYTHON_BUILD_IS_ENABLED())
+
+bld.SAMBA_MODULE('torture_rpc',
+ source='''
+ rpc/join.c
+ rpc/lsa.c
+ rpc/forest_trust.c
+ rpc/lsa_lookup.c
+ rpc/session_key.c
+ rpc/echo.c
+ rpc/dfs.c
+ rpc/drsuapi.c
+ rpc/drsuapi_w2k8.c
+ rpc/drsuapi_cracknames.c
+ rpc/dsgetinfo.c
+ rpc/spoolss.c
+ rpc/spoolss_win.c
+ rpc/spoolss_access.c
+ rpc/unixinfo.c
+ rpc/samr.c
+ rpc/samr_accessmask.c
+ rpc/samr_handletype.c
+ rpc/samr_priv.c
+ rpc/wkssvc.c
+ rpc/srvsvc.c
+ rpc/svcctl.c
+ rpc/atsvc.c
+ rpc/eventlog.c
+ rpc/epmapper.c
+ rpc/winreg.c
+ rpc/initshutdown.c
+ rpc/mgmt.c
+ rpc/scanner.c
+ rpc/countcalls.c
+ rpc/testjoin.c
+ rpc/schannel.c
+ rpc/netlogon.c
+ rpc/netlogon_crypto.c
+ rpc/remote_pac.c
+ rpc/samlogon.c
+ rpc/samsync.c
+ rpc/dssetup.c
+ rpc/alter_context.c
+ rpc/bench.c
+ rpc/samba3rpc.c
+ rpc/rpc.c
+ rpc/async_bind.c
+ rpc/handles.c
+ rpc/frsapi.c
+ rpc/object_uuid.c
+ rpc/ntsvcs.c
+ rpc/browser.c
+ rpc/bind.c
+ rpc/fsrvp.c
+ rpc/clusapi.c
+ rpc/witness.c
+ rpc/iremotewinspool.c
+ rpc/iremotewinspool_driver.c
+ rpc/mdssvc.c
+ rpc/backupkey.c''' + ntvfs_specific['source'],
+ autoproto='rpc/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_rpc_init',
+ deps='''
+ ndr-table
+ RPC_NDR_UNIXINFO
+ dcerpc-samr
+ RPC_NDR_WINREG
+ RPC_NDR_INITSHUTDOWN
+ RPC_NDR_EVENTLOG
+ RPC_NDR_ECHO
+ RPC_NDR_SVCCTL
+ RPC_NDR_NETLOGON
+ RPC_NDR_ATSVC
+ RPC_NDR_DRSUAPI
+ RPC_NDR_LSA
+ RPC_NDR_EPMAPPER
+ RPC_NDR_DFS
+ RPC_NDR_FRSAPI
+ RPC_NDR_SPOOLSS
+ RPC_NDR_SRVSVC
+ RPC_NDR_WKSSVC
+ RPC_NDR_DSSETUP
+ RPC_NDR_NTSVCS
+ %s
+ LIBCLI_AUTH
+ popt
+ CMDLINE_S4
+ TORTURE_LDAP
+ TORTURE_UTIL
+ TORTURE_RAP
+ service
+ process_model
+ RPC_NDR_BROWSER
+ LIBCLI_DRSUAPI
+ TORTURE_DFS
+ RPC_NDR_FSRVP
+ RPC_NDR_CLUSAPI
+ RPC_NDR_WITNESS
+ RPC_NDR_BACKUPKEY
+ RPC_NDR_WINSPOOL
+ IREMOTEWINSPOOL_COMMON
+ printer_driver
+ RPC_NDR_MDSSVC
+ mdssvc
+ ''' % samba_net + ntvfs_specific['deps'],
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED())
+
+bld.RECURSE('drs')
+bld.RECURSE('dns')
+
+bld.SAMBA_MODULE('TORTURE_RAP',
+ source='rap/rap.c rap/rpc.c rap/printing.c rap/sam.c',
+ autoproto='rap/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_rap_init',
+ deps='TORTURE_UTIL LIBCLI_SMB NDR_RAP LIBCLI_RAP',
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+bld.SAMBA_MODULE('TORTURE_DFS',
+ source='dfs/domaindfs.c dfs/common.c',
+ autoproto='dfs/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_dfs_init',
+ deps='TORTURE_UTIL LIBCLI_SMB',
+ internal_module=True
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_AUTH',
+ source='auth/ntlmssp.c auth/pac.c auth/smbencrypt.c',
+ autoproto='auth/proto.h',
+ subsystem='smbtorture',
+ deps='LIBCLI_SMB gensec auth4 authkrb5 smbpasswdparser torture com_err gensec_ntlmssp CMDLINE_S4',
+ internal_module=True
+ )
+
+bld.RECURSE('local')
+bld.RECURSE('krb5')
+
+bld.SAMBA_MODULE('TORTURE_NBENCH',
+ source='nbench/nbio.c nbench/nbench.c',
+ autoproto='nbench/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_nbench_init',
+ deps='TORTURE_UTIL',
+ internal_module=True
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_UNIX',
+ source='unix/unix.c unix/whoami.c unix/unix_info2.c',
+ autoproto='unix/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_unix_init',
+ deps='TORTURE_UTIL',
+ internal_module=True
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_LDAP',
+ source='''
+ ldap/common.c
+ ldap/basic.c
+ ldap/schema.c
+ ldap/uptodatevector.c
+ ldap/cldap.c
+ ldap/netlogon.c
+ ldap/cldapbench.c
+ ldap/ldap_sort.c
+ ldap/nested_search.c
+ ldap/session_expiry.c
+ ''',
+ subsystem='smbtorture',
+ deps='cli-ldap cli_cldap samdb torture ldbsamba CMDLINE_S4',
+ internal_module=True,
+ autoproto='ldap/proto.h',
+ init_function='torture_ldap_init'
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_NBT',
+ source='nbt/query.c nbt/register.c nbt/wins.c nbt/winsbench.c nbt/winsreplication.c nbt/dgram.c nbt/nbt.c',
+ autoproto='nbt/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_nbt_init',
+ deps='LIBCLI_SMB cli-nbt LIBCLI_DGRAM LIBCLI_WREPL torture_rpc',
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_NET',
+ source='libnet/libnet.c libnet/utils.c libnet/userinfo.c libnet/userman.c libnet/groupinfo.c libnet/groupman.c libnet/domain.c libnet/libnet_lookup.c libnet/libnet_user.c libnet/libnet_group.c libnet/libnet_share.c libnet/libnet_rpc.c libnet/libnet_domain.c libnet/libnet_BecomeDC.c',
+ autoproto='libnet/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_net_init',
+ deps='%s torture_rpc %s' % (provision, samba_net),
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+
+bld.SAMBA_MODULE('TORTURE_NTP',
+ source='ntp/ntp_signd.c',
+ autoproto='ntp/proto.h',
+ subsystem='smbtorture',
+ init_function='torture_ntp_init',
+ deps='torture_rpc',
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+bld.SAMBA_MODULE('TORTURE_VFS',
+ source='vfs/vfs.c vfs/fruit.c vfs/acl_xattr.c',
+ subsystem='smbtorture',
+ deps='LIBCLI_SMB TORTURE_UTIL smbclient-raw TORTURE_RAW',
+ internal_module=True,
+ autoproto='vfs/proto.h',
+ init_function='torture_vfs_init'
+ )
+
+TORTURE_MODULES = 'TORTURE_BASIC TORTURE_RAW torture_rpc TORTURE_RAP TORTURE_AUTH TORTURE_NBENCH TORTURE_UNIX TORTURE_LDAP TORTURE_NBT TORTURE_NET TORTURE_NTP torture_registry TORTURE_VFS'
+
+bld.SAMBA_SUBSYSTEM('torturemain',
+ source='smbtorture.c torture.c shell.c',
+ subsystem_name='smbtorture',
+ deps='torture dcerpc LIBCLI_SMB SMBREADLINE ' + TORTURE_MODULES,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+bld.SAMBA_BINARY('smbtorture',
+ source=[],
+ manpages='man/smbtorture.1',
+ private_headers='smbtorture.h',
+ deps='torturemain torture popt CMDLINE_S4 dcerpc LIBCLI_SMB SMBREADLINE ' + TORTURE_MODULES,
+ pyembed=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )
+
+bld.SAMBA_BINARY('gentest',
+ source='gentest.c',
+ manpages='man/gentest.1',
+ deps='samba-hostconfig samba-util popt CMDLINE_S4 LIBCLI_SMB smbclient-raw param_options'
+ )
+
+
+bld.SAMBA_BINARY('masktest',
+ source='masktest.c',
+ manpages='man/masktest.1',
+ deps='samba-hostconfig samba-util popt CMDLINE_S4 LIBCLI_SMB param_options'
+ )
+
+
+bld.SAMBA_BINARY('locktest',
+ source='locktest.c',
+ # COV_TARGET='test',
+ #ldflags='--coverage',
+ #cflags='--coverage',
+ # GCOV='1',
+ manpages='man/locktest.1',
+ deps='popt CMDLINE_S4 samba-util LIBCLI_SMB samba-hostconfig param_options',
+ )
+
+bld.SAMBA_MODULE('TORTURE_DSDB',
+ source="../../source4/dsdb/common/tests/dsdb.c",
+ autoproto='dsdb_proto.h',
+ subsystem='smbtorture',
+ init_function='torture_dsdb_init',
+ deps="TORTURE_UTIL samba-util",
+ internal_module=True,
+ enabled=bld.PYTHON_BUILD_IS_ENABLED()
+ )